Unionfs: reorganize file_revalidate for un/locking callers
authorErez Zadok <ezk@cs.sunysb.edu>
Wed, 23 Apr 2008 23:05:22 +0000 (19:05 -0400)
committerErez Zadok <ezk@cs.sunysb.edu>
Fri, 12 Aug 2011 02:38:10 +0000 (22:38 -0400)
Also clean up deep nesting/indentation.

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
fs/unionfs/commonfops.c
fs/unionfs/union.h

index b7d3e38422219b6564c07b39fb7b1551d74d11ab..2706194feae2bb38fea83a5a7d13ddc91888d410 100644 (file)
@@ -298,6 +298,101 @@ out:
        return err;
 }
 
+/*
+ * Helper function for unionfs_file_revalidate/locked.
+ * Expects dentry/parent to be locked already, and revalidated.
+ */
+static int __unionfs_file_revalidate(struct file *file, struct dentry *dentry,
+                                    struct super_block *sb, int sbgen,
+                                    int dgen, bool willwrite)
+{
+       int fgen;
+       int bstart, bend, orig_brid;
+       int size;
+       int err = 0;
+
+       fgen = atomic_read(&UNIONFS_F(file)->generation);
+
+       /*
+        * There are two cases we are interested in.  The first is if the
+        * generation is lower than the super-block.  The second is if
+        * someone has copied up this file from underneath us, we also need
+        * to refresh things.
+        */
+       if (d_deleted(dentry) ||
+           (sbgen <= fgen && dbstart(dentry) == fbstart(file)))
+               goto out_may_copyup;
+
+       /* save orig branch ID */
+       orig_brid = UNIONFS_F(file)->saved_branch_ids[fbstart(file)];
+
+       /* First we throw out the existing files. */
+       cleanup_file(file);
+
+       /* Now we reopen the file(s) as in unionfs_open. */
+       bstart = fbstart(file) = dbstart(dentry);
+       bend = fbend(file) = dbend(dentry);
+
+       size = sizeof(struct file *) * sbmax(sb);
+       UNIONFS_F(file)->lower_files = kzalloc(size, GFP_KERNEL);
+       if (unlikely(!UNIONFS_F(file)->lower_files)) {
+               err = -ENOMEM;
+               goto out;
+       }
+       size = sizeof(int) * sbmax(sb);
+       UNIONFS_F(file)->saved_branch_ids = kzalloc(size, GFP_KERNEL);
+       if (unlikely(!UNIONFS_F(file)->saved_branch_ids)) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       if (S_ISDIR(dentry->d_inode->i_mode)) {
+               /* We need to open all the files. */
+               err = open_all_files(file);
+               if (err)
+                       goto out;
+       } else {
+               int new_brid;
+               /* We only open the highest priority branch. */
+               err = open_highest_file(file, willwrite);
+               if (err)
+                       goto out;
+               new_brid = UNIONFS_F(file)->saved_branch_ids[fbstart(file)];
+               if (unlikely(new_brid != orig_brid && sbgen > fgen)) {
+                       /*
+                        * If we re-opened the file on a different branch
+                        * than the original one, and this was due to a new
+                        * branch inserted, then update the mnt counts of
+                        * the old and new branches accordingly.
+                        */
+                       unionfs_mntget(dentry, bstart);
+                       unionfs_mntput(sb->s_root,
+                                      branch_id_to_idx(sb, orig_brid));
+               }
+       }
+       atomic_set(&UNIONFS_F(file)->generation,
+                  atomic_read(&UNIONFS_I(dentry->d_inode)->generation));
+
+out_may_copyup:
+       /* Copyup on the first write to a file on a readonly branch. */
+       if (willwrite && IS_WRITE_FLAG(file->f_flags) &&
+           !IS_WRITE_FLAG(unionfs_lower_file(file)->f_flags) &&
+           is_robranch(dentry)) {
+               pr_debug("unionfs: do delay copyup of \"%s\"\n",
+                        dentry->d_name.name);
+               err = do_delayed_copyup(file);
+       }
+
+out:
+       if (err) {
+               kfree(UNIONFS_F(file)->lower_files);
+               kfree(UNIONFS_F(file)->saved_branch_ids);
+       } else {
+               unionfs_check_file(file);
+       }
+       return err;
+}
+
 /*
  * Revalidate the struct file
  * @file: file to revalidate
@@ -308,29 +403,26 @@ int unionfs_file_revalidate(struct file *file, bool willwrite)
 {
        struct super_block *sb;
        struct dentry *dentry;
-       int sbgen, fgen, dgen;
-       int bstart, bend;
-       int size;
+       int sbgen, dgen;
        int err = 0;
 
        dentry = file->f_path.dentry;
-       verify_locked(dentry);
        sb = dentry->d_sb;
+       verify_locked(dentry);
 
        /*
         * First revalidate the dentry inside struct file,
         * but not unhashed dentries.
         */
 reval_dentry:
-       if (unlikely(!d_deleted(dentry) &&
-                    !__unionfs_d_revalidate_chain(dentry, NULL, willwrite))) {
+       if (!d_deleted(dentry) &&
+           !__unionfs_d_revalidate_chain(dentry, NULL, willwrite)) {
                err = -ESTALE;
-               goto out_nofree;
+               goto out;
        }
 
        sbgen = atomic_read(&UNIONFS_SB(sb)->generation);
        dgen = atomic_read(&UNIONFS_D(dentry)->generation);
-       fgen = atomic_read(&UNIONFS_F(file)->generation);
 
        if (unlikely(sbgen > dgen)) {
                pr_debug("unionfs: retry dentry revalidation\n");
@@ -339,86 +431,52 @@ reval_dentry:
        }
        BUG_ON(sbgen > dgen);
 
-       /*
-        * There are two cases we are interested in.  The first is if the
-        * generation is lower than the super-block.  The second is if
-        * someone has copied up this file from underneath us, we also need
-        * to refresh things.
-        */
-       if (unlikely(!d_deleted(dentry) &&
-                    (sbgen > fgen || dbstart(dentry) != fbstart(file)))) {
-               /* save orig branch ID */
-               int orig_brid =
-                       UNIONFS_F(file)->saved_branch_ids[fbstart(file)];
-
-               /* First we throw out the existing files. */
-               cleanup_file(file);
-
-               /* Now we reopen the file(s) as in unionfs_open. */
-               bstart = fbstart(file) = dbstart(dentry);
-               bend = fbend(file) = dbend(dentry);
-
-               size = sizeof(struct file *) * sbmax(sb);
-               UNIONFS_F(file)->lower_files = kzalloc(size, GFP_KERNEL);
-               if (unlikely(!UNIONFS_F(file)->lower_files)) {
-                       err = -ENOMEM;
-                       goto out;
-               }
-               size = sizeof(int) * sbmax(sb);
-               UNIONFS_F(file)->saved_branch_ids = kzalloc(size, GFP_KERNEL);
-               if (unlikely(!UNIONFS_F(file)->saved_branch_ids)) {
-                       err = -ENOMEM;
-                       goto out;
-               }
+       err = __unionfs_file_revalidate(file, dentry, sb,
+                                       sbgen, dgen, willwrite);
+out:
+       return err;
+}
 
-               if (S_ISDIR(dentry->d_inode->i_mode)) {
-                       /* We need to open all the files. */
-                       err = open_all_files(file);
-                       if (err)
-                               goto out;
-               } else {
-                       int new_brid;
-                       /* We only open the highest priority branch. */
-                       err = open_highest_file(file, willwrite);
-                       if (err)
-                               goto out;
-                       new_brid = UNIONFS_F(file)->
-                         saved_branch_ids[fbstart(file)];
-                       if (unlikely(new_brid != orig_brid && sbgen > fgen)) {
-                               /*
-                                * If we re-opened the file on a different
-                                * branch than the original one, and this
-                                * was due to a new branch inserted, then
-                                * update the mnt counts of the old and new
-                                * branches accordingly.
-                                */
-                               unionfs_mntget(dentry, bstart);
-                               unionfs_mntput(sb->s_root,
-                                              branch_id_to_idx(sb, orig_brid));
-                       }
-               }
-               atomic_set(&UNIONFS_F(file)->generation,
-                          atomic_read(
-                                  &UNIONFS_I(dentry->d_inode)->generation));
+/* same as unionfs_file_revalidate, but parent dentry must be locked too */
+int unionfs_file_revalidate_locked(struct file *file, bool willwrite)
+{
+       struct super_block *sb;
+       struct dentry *dentry;
+       int sbgen, dgen;
+       int err = 0, valid;
+
+       dentry = file->f_path.dentry;
+       sb = dentry->d_sb;
+       verify_locked(dentry);
+       verify_locked(dentry->d_parent);
+
+       /* first revalidate (locked) parent, then child */
+       valid = __unionfs_d_revalidate_chain(dentry->d_parent, NULL, false);
+       if (unlikely(!valid)) {
+               err = -ESTALE;  /* same as what real_lookup does */
+               goto out;
        }
 
-       /* Copyup on the first write to a file on a readonly branch. */
-       if (willwrite && IS_WRITE_FLAG(file->f_flags) &&
-           !IS_WRITE_FLAG(unionfs_lower_file(file)->f_flags) &&
-           is_robranch(dentry)) {
-               pr_debug("unionfs: do delay copyup of \"%s\"\n",
-                        dentry->d_name.name);
-               err = do_delayed_copyup(file);
+reval_dentry:
+       if (!d_deleted(dentry) &&
+           !__unionfs_d_revalidate_one_locked(dentry, NULL, willwrite)) {
+               err = -ESTALE;
+               goto out;
        }
 
-out:
-       if (err) {
-               kfree(UNIONFS_F(file)->lower_files);
-               kfree(UNIONFS_F(file)->saved_branch_ids);
+       sbgen = atomic_read(&UNIONFS_SB(sb)->generation);
+       dgen = atomic_read(&UNIONFS_D(dentry)->generation);
+
+       if (unlikely(sbgen > dgen)) {
+               pr_debug("unionfs: retry (locked) dentry revalidation\n");
+               schedule();
+               goto reval_dentry;
        }
-out_nofree:
-       if (!err)
-               unionfs_check_file(file);
+       BUG_ON(sbgen > dgen);
+
+       err = __unionfs_file_revalidate(file, dentry, sb,
+                                       sbgen, dgen, willwrite);
+out:
        return err;
 }
 
index 13dee5f1b9ca700e583071f573c93d4f653f5809..7420cb07d416822c85c93a3eaf81ca6b271dbf65 100644 (file)
@@ -365,6 +365,7 @@ extern int unionfs_getlk(struct file *file, struct file_lock *fl);
 
 /* Common file operations. */
 extern int unionfs_file_revalidate(struct file *file, bool willwrite);
+extern int unionfs_file_revalidate_locked(struct file *file, bool willwrite);
 extern int unionfs_open(struct inode *inode, struct file *file);
 extern int unionfs_file_release(struct inode *inode, struct file *file);
 extern int unionfs_flush(struct file *file, fl_owner_t id);