commit e65b147a9e1d496bf1b4266e796f567f36ba4ab4
Author: Rachita Kothiyal <[EMAIL PROTECTED]>
Date:   Sun May 18 03:37:20 2008 -0400

    Unionfs ODF: Fix a lockdep warning on nfsd_readdir of exported unionfs mount
    
    nfsd_readdir calls vfs_llseek and vfs_readdir. Following is the locking
    order seen by lockdep:
        vfs_llseek: sb -> dentry -> inode
        vfs_readdir: inode -> sb -> dentry
    Lockdep reports this as a possible circular locking order bug.
    
    To fix this, we define our own unionfs_file_llseek_locked function,
    which is essentially the vfs generic_file_llseek function, but with
    the inode locking moved into the caller. This now changes the locking
    order in vfs_llseek call to be: inode -> sb -> dentry, and satisfies
    lockdep too.
    
    Signed-off-by: Rachita Kothiyal <[EMAIL PROTECTED]>

diff --git a/fs/unionfs/dirfops.c b/fs/unionfs/dirfops.c
index 8e578af..27b55ca 100644
--- a/fs/unionfs/dirfops.c
+++ b/fs/unionfs/dirfops.c
@@ -137,11 +137,48 @@ out:
        return err;
 }
 
+/*
+ * Heavily borrowed from the vfs generic_file_llseek.  This version expects
+ * an already locked inode.  This was done to fix a lockdep warning arising
+ * from the following locking order in nfs_readdir on an exported unionfs
+ * mount:
+ * nfs_readdir
+ *     --> vfs_llseek(): sb -> dentry -> inode
+ *     --> vfs_readdir(): inode -> sb -> dentry
+ *
+ * A better fix would be to have this as a vfs function.
+ */
+static loff_t unionfs_file_llseek_locked(struct file *file, loff_t offset,
+                                        int origin)
+{
+       long long retval;
+       struct inode *inode = file->f_mapping->host;
+
+       switch (origin) {
+       case SEEK_END:
+               offset += inode->i_size;
+               break;
+       case SEEK_CUR:
+               offset += file->f_pos;
+       }
+       retval = -EINVAL;
+       if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
+               if (offset != file->f_pos) {
+                       file->f_pos = offset;
+                       file->f_version = 0;
+               }
+               retval = offset;
+       }
+       return retval;
+}
+
 static loff_t unionfs_dir_llseek(struct file *file, loff_t offset, int origin)
 {
        struct dentry *dentry = file->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
        loff_t err;
 
+       mutex_lock(&inode->i_mutex);
        unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
        unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
 
@@ -150,9 +187,10 @@ static loff_t unionfs_dir_llseek(struct file *file, loff_t 
offset, int origin)
        if (unlikely(err))
                goto out;
 
-       err = generic_file_llseek(file, offset, origin);
+       err = unionfs_file_llseek_locked(file, offset, origin);
 out:
        unionfs_read_unlock(dentry->d_sb);
+       mutex_unlock(&inode->i_mutex);
        return err;
 }
 
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to