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