upgrade to linux 2.6.10-1.12_FC2
[linux-2.6.git] / fs / reiserfs / super.c
index 3a7f6c6..192b73c 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/blkdev.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
+#include <linux/namespace.h>
 
 struct file_system_type reiserfs_fs_type;
 
@@ -66,11 +67,14 @@ static void reiserfs_sync_fs (struct super_block * s)
     if (!(s->s_flags & MS_RDONLY)) {
         struct reiserfs_transaction_handle th;
        reiserfs_write_lock(s);
-       journal_begin(&th, s, 1);
-       journal_end_sync(&th, s, 1);
-       reiserfs_flush_old_commits(s);
-       s->s_dirt = 0;
+       if (!journal_begin(&th, s, 1))
+            if (!journal_end_sync(&th, s, 1))
+                reiserfs_flush_old_commits(s);
+       s->s_dirt = 0; /* Even if it's not true.
+                        * We'll loop forever in sync_supers otherwise */
        reiserfs_write_unlock(s);
+    } else {
+        s->s_dirt = 0;
     }
 }
 
@@ -84,11 +88,15 @@ static void reiserfs_write_super_lockfs (struct super_block * s)
   struct reiserfs_transaction_handle th ;
   reiserfs_write_lock(s);
   if (!(s->s_flags & MS_RDONLY)) {
-    journal_begin(&th, s, 1) ;
-    reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
-    journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
-    reiserfs_block_writes(&th) ;
-    journal_end_sync(&th, s, 1) ;
+    int err = journal_begin(&th, s, 1) ;
+    if (err) {
+        reiserfs_block_writes(&th) ;
+    } else {
+        reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
+        journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
+        reiserfs_block_writes(&th) ;
+        journal_end_sync(&th, s, 1) ;
+    }
   }
   s->s_dirt = 0;
   reiserfs_write_unlock(s);
@@ -98,7 +106,7 @@ void reiserfs_unlockfs(struct super_block *s) {
   reiserfs_allow_writes(s) ;
 }
 
-extern const struct key  MAX_KEY;
+extern const struct reiserfs_key  MAX_KEY;
 
 
 /* this is used to delete "save link" when there are no items of a
@@ -108,29 +116,32 @@ extern const struct key  MAX_KEY;
    protecting unlink is bigger that a key lf "save link" which
    protects truncate), so there left no items to make truncate
    completion on */
-static void remove_save_link_only (struct super_block * s, struct key * key, int oid_free)
+static int remove_save_link_only (struct super_block * s, struct reiserfs_key * key, int oid_free)
 {
     struct reiserfs_transaction_handle th;
+    int err;
 
      /* we are going to do one balancing */
-     journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT);
+     err = journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT);
+     if (err)
+        return err;
  
      reiserfs_delete_solid_item (&th, NULL, key);
      if (oid_free)
         /* removals are protected by direct items */
         reiserfs_release_objectid (&th, le32_to_cpu (key->k_objectid));
 
-     journal_end (&th, s, JOURNAL_PER_BALANCE_CNT);
+     return journal_end (&th, s, JOURNAL_PER_BALANCE_CNT);
 }
  
  
 /* look for uncompleted unlinks and truncates and complete them */
-static void finish_unfinished (struct super_block * s)
+static int finish_unfinished (struct super_block * s)
 {
     INITIALIZE_PATH (path);
     struct cpu_key max_cpu_key, obj_key;
-    struct key save_link_key;
-    int retval;
+    struct reiserfs_key save_link_key;
+    int retval = 0;
     struct item_head * ih;
     struct buffer_head * bh;
     int item_pos;
@@ -147,7 +158,7 @@ static void finish_unfinished (struct super_block * s)
  
     done = 0;
     REISERFS_SB(s)->s_is_unlinked_ok = 1;
-    while (1) {
+    while (!retval) {
         retval = search_item (s, &max_cpu_key, &path);
         if (retval != ITEM_NOT_FOUND) {
             reiserfs_warning (s, "vs-2140: finish_unfinished: search_by_key returned %d",
@@ -189,7 +200,7 @@ static void finish_unfinished (struct super_block * s)
               "save" link and release objectid */
             reiserfs_warning (s, "vs-2180: finish_unfinished: iget failed for %K",
                               &obj_key);
-            remove_save_link_only (s, &save_link_key, 1);
+            retval = remove_save_link_only (s, &save_link_key, 1);
             continue;
         }
 
@@ -197,7 +208,7 @@ static void finish_unfinished (struct super_block * s)
            /* file is not unlinked */
             reiserfs_warning (s, "vs-2185: finish_unfinished: file %K is not unlinked",
                               &obj_key);
-            remove_save_link_only (s, &save_link_key, 0);
+            retval = remove_save_link_only (s, &save_link_key, 0);
             continue;
        }
 
@@ -207,7 +218,7 @@ static void finish_unfinished (struct super_block * s)
               then boot into old kernel, remove the file and create dir with
               the same key. */
            reiserfs_warning(s, "green-2101: impossible truncate on a directory %k. Please report", INODE_PKEY (inode));
-           remove_save_link_only (s, &save_link_key, 0);
+           retval = remove_save_link_only (s, &save_link_key, 0);
            truncate = 0;
            iput (inode); 
            continue;
@@ -220,12 +231,13 @@ static void finish_unfinished (struct super_block * s)
             reiserfs_info (s, "Truncating %k to %Ld ..",
                               INODE_PKEY (inode), inode->i_size);
             reiserfs_truncate_file (inode, 0/*don't update modification time*/);
-            remove_save_link (inode, truncate);
+            retval = remove_save_link (inode, truncate);
         } else {
             REISERFS_I(inode) -> i_flags |= i_link_saved_unlink_mask;
             /* not completed unlink (rmdir) found */
             reiserfs_info (s, "Removing %k..", INODE_PKEY (inode));
             /* removal gets completed in iput */
+            retval = 0;
         }
  
         iput (inode);
@@ -238,6 +250,7 @@ static void finish_unfinished (struct super_block * s)
     if (done)
         reiserfs_info (s, "There were %d uncompleted unlinks/truncates. "
                           "Completed\n", done);
+    return retval;
 }
  
 /* to protect file being unlinked from getting lost we "safe" link files
@@ -253,6 +266,8 @@ void add_save_link (struct reiserfs_transaction_handle * th,
     struct item_head ih;
     __u32 link;
 
+    BUG_ON (!th->t_trans_id);
+
     /* file can only get one "save link" of each kind */
     RFALSE( truncate && 
            ( REISERFS_I(inode) -> i_flags & i_link_saved_truncate_mask ),
@@ -317,14 +332,16 @@ void add_save_link (struct reiserfs_transaction_handle * th,
 
 
 /* this opens transaction unlike add_save_link */
-void remove_save_link (struct inode * inode, int truncate)
+int remove_save_link (struct inode * inode, int truncate)
 {
     struct reiserfs_transaction_handle th;
-    struct key key;
+    struct reiserfs_key key;
+    int err;
  
     /* we are going to do one balancing only */
-    journal_begin (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
+    err = journal_begin (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
+    if (err)
+        return err;
  
     /* setup key of "save" link */
     key.k_dir_id = cpu_to_le32 (MAX_KEY_OBJECTID);
@@ -352,7 +369,7 @@ void remove_save_link (struct inode * inode, int truncate)
     } else
        REISERFS_I(inode) -> i_flags &= ~i_link_saved_truncate_mask;
  
-    journal_end (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
+    return journal_end (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
 }
 
 
@@ -360,6 +377,7 @@ static void reiserfs_put_super (struct super_block * s)
 {
   int i;
   struct reiserfs_transaction_handle th ;
+  th.t_trans_id = 0;
 
   if (REISERFS_SB(s)->xattr_root) {
     d_invalidate (REISERFS_SB(s)->xattr_root);
@@ -373,10 +391,11 @@ static void reiserfs_put_super (struct super_block * s)
 
   /* change file system state to current state if it was mounted with read-write permissions */
   if (!(s->s_flags & MS_RDONLY)) {
-    journal_begin(&th, s, 10) ;
-    reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
-    set_sb_umount_state( SB_DISK_SUPER_BLOCK(s), REISERFS_SB(s)->s_mount_state );
-    journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
+    if (!journal_begin(&th, s, 10)) {
+        reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
+        set_sb_umount_state( SB_DISK_SUPER_BLOCK(s), REISERFS_SB(s)->s_mount_state );
+        journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
+    }
   }
 
   /* note, journal_release checks for readonly mount, and can decide not
@@ -461,6 +480,7 @@ static void destroy_inodecache(void)
 static void reiserfs_dirty_inode (struct inode * inode) {
     struct reiserfs_transaction_handle th ;
 
+    int err = 0;
     if (inode->i_sb->s_flags & MS_RDONLY) {
         reiserfs_warning(inode->i_sb, "clm-6006: writing inode %lu on readonly FS",
                          inode->i_ino) ;
@@ -471,7 +491,11 @@ static void reiserfs_dirty_inode (struct inode * inode) {
     /* this is really only used for atime updates, so they don't have
     ** to be included in O_SYNC or fsync
     */
-    journal_begin(&th, inode->i_sb, 1) ;
+    err = journal_begin(&th, inode->i_sb, 1) ;
+    if (err) {
+        reiserfs_write_unlock (inode->i_sb);
+        return;
+    }
     reiserfs_update_sd (&th, inode);
     journal_end(&th, inode->i_sb, 1) ;
     reiserfs_write_unlock(inode->i_sb);
@@ -575,6 +599,18 @@ static const arg_desc_t tails[] = {
     {NULL, 0, 0}
 };
 
+static const arg_desc_t error_actions[] = {
+    {"panic", 1 << REISERFS_ERROR_PANIC,
+              (1 << REISERFS_ERROR_RO | 1 << REISERFS_ERROR_CONTINUE)},
+    {"ro-remount", 1 << REISERFS_ERROR_RO,
+              (1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_CONTINUE)},
+#ifdef REISERFS_JOURNAL_ERROR_ALLOWS_NO_LOG
+    {"continue", 1 << REISERFS_ERROR_CONTINUE,
+              (1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_RO)},
+#endif
+    {NULL, 0, 0},
+};
+
 int reiserfs_default_io_size = 128 * 1024; /* Default recommended I/O size is 128k.
                                              There might be broken applications that are
                                              confused by this. Use nolargeio mount option
@@ -626,8 +662,14 @@ static int reiserfs_getopt ( struct super_block * s, char ** cur, opt_desc_t * o
     for (opt = opts; opt->option_name; opt ++) {
        if (!strncmp (p, opt->option_name, strlen (opt->option_name))) {
            if (bit_flags) {
-               *bit_flags &= ~opt->clrmask;
-               *bit_flags |= opt->setmask;
+                if (opt->clrmask == (1 << REISERFS_UNSUPPORTED_OPT))
+                    reiserfs_warning (s, "%s not supported.", p);
+                else
+                    *bit_flags &= ~opt->clrmask;
+                if (opt->setmask == (1 << REISERFS_UNSUPPORTED_OPT))
+                    reiserfs_warning (s, "%s not supported.", p);
+                else
+                    *bit_flags |= opt->setmask;
            }
            break;
        }
@@ -708,12 +750,20 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st
        {"conv",        .setmask = 1<<REISERFS_CONVERT},
        {"attrs",       .setmask = 1<<REISERFS_ATTRS},
        {"noattrs",     .clrmask = 1<<REISERFS_ATTRS},
+#ifdef CONFIG_REISERFS_FS_XATTR
        {"user_xattr",  .setmask = 1<<REISERFS_XATTRS_USER},
        {"nouser_xattr",.clrmask = 1<<REISERFS_XATTRS_USER},
+#else
+       {"user_xattr",  .setmask = 1<<REISERFS_UNSUPPORTED_OPT},
+       {"nouser_xattr",.clrmask = 1<<REISERFS_UNSUPPORTED_OPT},
+#endif
        {"tagxid",      .setmask = 1<<REISERFS_TAGXID},
 #ifdef CONFIG_REISERFS_FS_POSIX_ACL
        {"acl",         .setmask = 1<<REISERFS_POSIXACL},
        {"noacl",       .clrmask = 1<<REISERFS_POSIXACL},
+#else
+       {"acl",         .setmask = 1<<REISERFS_UNSUPPORTED_OPT},
+       {"noacl",       .clrmask = 1<<REISERFS_UNSUPPORTED_OPT},
 #endif
        {"nolog",},      /* This is unsupported */
        {"replayonly",  .setmask = 1<<REPLAYONLY},
@@ -726,6 +776,7 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st
        {"commit",      .arg_required = 'c', .values = NULL},
        {"usrquota",},
        {"grpquota",},
+       {"errors",      .arg_required = 'e', .values = error_actions},
        {NULL,}
     };
        
@@ -862,6 +913,8 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
   unsigned long mount_options = REISERFS_SB(s)->s_mount_opt;
   unsigned long safe_mask = 0;
   unsigned int commit_max_age = (unsigned int)-1;
+  struct reiserfs_journal *journal = SB_JOURNAL(s);
+  int err;
 
   rs = SB_DISK_SUPER_BLOCK (s);
 
@@ -882,20 +935,23 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
   safe_mask |= 1 << REISERFS_POSIXACL;
   safe_mask |= 1 << REISERFS_BARRIER_FLUSH;
   safe_mask |= 1 << REISERFS_BARRIER_NONE;
+  safe_mask |= 1 << REISERFS_ERROR_RO;
+  safe_mask |= 1 << REISERFS_ERROR_CONTINUE;
+  safe_mask |= 1 << REISERFS_ERROR_PANIC;
 
   /* Update the bitmask, taking care to keep
    * the bits we're not allowed to change here */
   REISERFS_SB(s)->s_mount_opt = (REISERFS_SB(s)->s_mount_opt & ~safe_mask) |  (mount_options & safe_mask);
 
   if(commit_max_age != 0 && commit_max_age != (unsigned int)-1) {
-    SB_JOURNAL_MAX_COMMIT_AGE(s) = commit_max_age;
-    SB_JOURNAL_MAX_TRANS_AGE(s) = commit_max_age;
+    journal->j_max_commit_age = commit_max_age;
+    journal->j_max_trans_age = commit_max_age;
   }
   else if(commit_max_age == 0)
   {
     /* 0 means restore defaults. */
-    SB_JOURNAL_MAX_COMMIT_AGE(s) = SB_JOURNAL_DEFAULT_MAX_COMMIT_AGE(s);
-    SB_JOURNAL_MAX_TRANS_AGE(s) = JOURNAL_MAX_TRANS_AGE;
+    journal->j_max_commit_age = journal->j_default_max_commit_age;
+    journal->j_max_trans_age = JOURNAL_MAX_TRANS_AGE;
   }
 
   if(blocks) {
@@ -915,7 +971,10 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
       return 0;
     }
 
-    journal_begin(&th, s, 10) ;
+    err = journal_begin(&th, s, 10) ;
+    if (err)
+        return err;
+
     /* Mounting a rw partition read-only. */
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
     set_sb_umount_state( rs, REISERFS_SB(s)->s_mount_state );
@@ -927,11 +986,16 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
        return 0; /* We are read-write already */
     }
 
+    if (reiserfs_is_journal_aborted (journal))
+       return journal->j_errno;
+
     handle_data_mode(s, mount_options);
     handle_barrier_mode(s, mount_options);
     REISERFS_SB(s)->s_mount_state = sb_umount_state(rs) ;
     s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */
-    journal_begin(&th, s, 10) ;
+    err = journal_begin(&th, s, 10) ;
+    if (err)
+       return err;
     
     /* Mount a partition which is read-only, read-write */
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
@@ -944,7 +1008,9 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
   }
   /* this will force a full flush of all journal lists */
   SB_JOURNAL(s)->j_must_wait = 1 ;
-  journal_end(&th, s, 10) ;
+  err = journal_end(&th, s, 10) ;
+  if (err)
+    return err;
   s->s_dirt = 0;
 
   if (!( *mount_flags & MS_RDONLY ) ) {
@@ -1372,8 +1438,9 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
     }
     s->s_fs_info = sbi;
     memset (sbi, 0, sizeof (struct reiserfs_sb_info));
-    /* Set default values for options: non-aggressive tails */
-    REISERFS_SB(s)->s_mount_opt = ( 1 << REISERFS_SMALLTAIL );
+    /* Set default values for options: non-aggressive tails, RO on errors */
+    REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_SMALLTAIL);
+    REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_ERROR_RO);
     /* no preallocation minimum, be smart in
        reiserfs_file_write instead */
     REISERFS_SB(s)->s_alloc_options.preallocmin = 0;
@@ -1501,7 +1568,12 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
     
     if (!(s->s_flags & MS_RDONLY)) {
 
-       journal_begin(&th, s, 1) ;
+       errval = journal_begin(&th, s, 1) ;
+        if (errval) {
+           dput (s->s_root);
+           s->s_root = NULL;
+           goto error;
+        }
        reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
 
         set_sb_umount_state( rs, REISERFS_ERROR_FS );
@@ -1531,9 +1603,14 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
        }
 
        journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
-       journal_end(&th, s, 1) ;
+       errval = journal_end(&th, s, 1) ;
+       if (errval) {
+           dput (s->s_root);
+           s->s_root = NULL;
+           goto error;
+       }
 
-       if (reiserfs_xattr_init (s, s->s_flags)) {
+       if ((errval = reiserfs_xattr_init (s, s->s_flags))) {
            dput (s->s_root);
            s->s_root = NULL;
            goto error;
@@ -1546,7 +1623,7 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
            reiserfs_info (s, "using 3.5.x disk format\n") ;
        }
 
-       if (reiserfs_xattr_init (s, s->s_flags)) {
+       if ((errval = reiserfs_xattr_init (s, s->s_flags))) {
            dput (s->s_root);
            s->s_root = NULL;
            goto error;