Unionfs: implement native unionfs_fsync/unionfs_fasync methods
authorErez_Zadok <ezk@cs.sunysb.edu>
Sun, 22 Jul 2007 03:56:16 +0000 (23:56 -0400)
committerErez Zadok <ezk@cs.sunysb.edu>
Fri, 29 Apr 2011 02:24:23 +0000 (22:24 -0400)
Unionfs is not a block-based file system, but it has to work with both
block-based file systems and non-block-based ones (i.e., when
CONFIG_BLOCK=n).  We used to define our ->fsync method to file_fsync, but
that's wrong because file_fsync partially depends on CONFIG_BLOCK=y.  And we
didn't define an fasync method: now we have both.  Moreover, at best,
file_fsync would have caused unionfs to sync up one lower branch---but as a
fanout file system, we need to sync up all valid lower branches.

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
Conflicts:

fs/unionfs/file.c

fs/unionfs/dirfops.c
fs/unionfs/file.c
fs/unionfs/union.h

index 4ba8f6c64d81e67203f30eebd370b78105f89266..980f12587ff6f8da86e8c6cff285c5890aed7a29 100644 (file)
@@ -273,4 +273,6 @@ struct file_operations unionfs_dir_fops = {
        .open           = unionfs_open,
        .release        = unionfs_file_release,
        .flush          = unionfs_flush,
+       .fsync          = unionfs_fsync,
+       .fasync         = unionfs_fasync,
 };
index ab243ccae3f1d7a5abb1c73174d9693ad258a5fa..d08ef8ba3dc9d0b6de7580a1c1a0e1db9f898240 100644 (file)
@@ -140,6 +140,94 @@ out:
        return err;
 }
 
+int unionfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+       int bindex, bstart, bend;
+       struct file *lower_file;
+       struct dentry *lower_dentry;
+       struct inode *lower_inode, *inode;
+       int err = -EINVAL;
+
+       unionfs_read_lock(file->f_path.dentry->d_sb);
+       if ((err = unionfs_file_revalidate(file, 1)))
+               goto out;
+       unionfs_check_file(file);
+
+       bstart = fbstart(file);
+       bend = fbend(file);
+       if (bstart < 0 || bend < 0)
+               goto out;
+
+       inode = dentry->d_inode;
+       if (!inode) {
+               printk(KERN_ERR
+                      "unionfs: null lower inode in unionfs_fsync\n");
+               goto out;
+       }
+       for (bindex = bstart; bindex <= bend; bindex++) {
+               lower_inode = unionfs_lower_inode_idx(inode, bindex);
+               if (!lower_inode || !lower_inode->i_fop->fsync)
+                       continue;
+               lower_file = unionfs_lower_file_idx(file, bindex);
+               lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
+               mutex_lock(&lower_inode->i_mutex);
+               err = lower_inode->i_fop->fsync(lower_file,
+                                               lower_dentry,
+                                               datasync);
+               mutex_unlock(&lower_inode->i_mutex);
+               if (err)
+                       goto out;
+       }
+
+out:
+       unionfs_read_unlock(file->f_path.dentry->d_sb);
+       unionfs_check_file(file);
+       return err;
+}
+
+int unionfs_fasync(int fd, struct file *file, int flag)
+{
+       int bindex, bstart, bend;
+       struct file *lower_file;
+       struct dentry *dentry;
+       struct inode *lower_inode, *inode;
+       int err = 0;
+
+       unionfs_read_lock(file->f_path.dentry->d_sb);
+       if ((err = unionfs_file_revalidate(file, 1)))
+               goto out;
+       unionfs_check_file(file);
+
+       bstart = fbstart(file);
+       bend = fbend(file);
+       if (bstart < 0 || bend < 0)
+               goto out;
+
+       dentry = file->f_path.dentry;
+       inode = dentry->d_inode;
+       if (!inode) {
+               printk(KERN_ERR
+                      "unionfs: null lower inode in unionfs_fasync\n");
+               goto out;
+       }
+       for (bindex = bstart; bindex <= bend; bindex++) {
+               lower_inode = unionfs_lower_inode_idx(inode, bindex);
+               if (!lower_inode || !lower_inode->i_fop->fasync)
+                       continue;
+               lower_file = unionfs_lower_file_idx(file, bindex);
+               mutex_lock(&lower_inode->i_mutex);
+               err = lower_inode->i_fop->fasync(fd, lower_file, flag);
+               mutex_unlock(&lower_inode->i_mutex);
+               if (err)
+                       goto out;
+       }
+
+out:
+       unionfs_read_unlock(file->f_path.dentry->d_sb);
+       unionfs_check_file(file);
+       return err;
+}
+
 struct file_operations unionfs_main_fops = {
        .llseek         = generic_file_llseek,
        .read           = unionfs_read,
@@ -152,6 +240,7 @@ struct file_operations unionfs_main_fops = {
        .open           = unionfs_open,
        .flush          = unionfs_flush,
        .release        = unionfs_file_release,
-       .fsync          = file_fsync,
+       .fsync          = unionfs_fsync,
+       .fasync         = unionfs_fasync,
        .splice_read    = generic_file_splice_read,
 };
index a13052b62291b73551e02860fb727995fa56aef6..cd1f37c1026151a145fd31f3aaf6e0da3f867b01 100644 (file)
@@ -316,6 +316,9 @@ extern int unionfs_file_release(struct inode *inode, struct file *file);
 extern int unionfs_flush(struct file *file, fl_owner_t id);
 extern long unionfs_ioctl(struct file *file, unsigned int cmd,
                          unsigned long arg);
+extern int unionfs_fsync(struct file *file, struct dentry *dentry,
+                        int datasync);
+extern int unionfs_fasync(int fd, struct file *file, int flag);
 
 /* Inode operations */
 extern int unionfs_rename(struct inode *old_dir, struct dentry *old_dentry,