From: Chris Wright Date: Wed, 22 Apr 2009 00:40:22 +0000 (-0700) Subject: 2.6.29: drop i_mutex readdir patch, doesn't apply X-Git-Tag: v2.6.29.2~9^2~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=62247dcacd32fe30ea61cab2fe7c90ebaf2fd9d6;p=thirdparty%2Fkernel%2Fstable-queue.git 2.6.29: drop i_mutex readdir patch, doesn't apply --- diff --git a/queue-2.6.29/fix-i_mutex-vs.-readdir-handling-in-nfsd.patch b/queue-2.6.29/fix-i_mutex-vs.-readdir-handling-in-nfsd.patch deleted file mode 100644 index db3cb3d2932..00000000000 --- a/queue-2.6.29/fix-i_mutex-vs.-readdir-handling-in-nfsd.patch +++ /dev/null @@ -1,229 +0,0 @@ -From stable-bounces@linux.kernel.org Tue Apr 21 21:20:16 2009 -Date: Tue, 21 Apr 2009 21:20:10 GMT -Message-Id: <200904212120.n3LLKAO9024993@hera.kernel.org> -From: David Woodhouse -To: jejb@kernel.org, stable@kernel.org -Subject: Fix i_mutex vs. readdir handling in nfsd - -upstream commit: 2f9092e1020246168b1309b35e085ecd7ff9ff72 - -Commit 14f7dd63 ("Copy XFS readdir hack into nfsd code") introduced a -bug to generic code which had been extant for a long time in the XFS -version -- it started to call through into lookup_one_len() and hence -into the file systems' ->lookup() methods without i_mutex held on the -directory. - -This patch fixes it by locking the directory's i_mutex again before -calling the filldir functions. The original deadlocks which commit -14f7dd63 was designed to avoid are still avoided, because they were due -to fs-internal locking, not i_mutex. - -While we're at it, fix the return type of nfsd_buffered_readdir() which -should be a __be32 not an int -- it's an NFS errno, not a Linux errno. -And return nfserrno(-ENOMEM) when allocation fails, not just -ENOMEM. -Sparse would have caught that, if it wasn't so busy bitching about -__cold__. - -Commit 05f4f678 ("nfsd4: don't do lookup within readdir in recovery -code") introduced a similar problem with calling lookup_one_len() -without i_mutex, which this patch also addresses. To fix that, it was -necessary to fix the called functions so that they expect i_mutex to be -held; that part was done by J. Bruce Fields. - -Signed-off-by: David Woodhouse -Umm-I-can-live-with-that-by: Al Viro -Reported-by: J. R. Okajima -Tested-by: J. Bruce Fields -LKML-Reference: <8036.1237474444@jrobl> -Cc: stable@kernel.org -Signed-off-by: Al Viro -Signed-off-by: Chris Wright ---- - fs/namei.c | 2 ++ - fs/nfsd/nfs4recover.c | 46 +++++++++------------------------------------- - fs/nfsd/vfs.c | 25 +++++++++++++++++++------ - 3 files changed, 30 insertions(+), 43 deletions(-) - -diff --git a/fs/namei.c b/fs/namei.c -index b8433eb..78f253c 100644 ---- a/fs/namei.c -+++ b/fs/namei.c -@@ -1248,6 +1248,8 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) - int err; - struct qstr this; - -+ WARN_ON_ONCE(!mutex_is_locked(&base->d_inode->i_mutex)); -+ - err = __lookup_one_len(name, &this, base, len); - if (err) - return ERR_PTR(err); -diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c -index 3444c00..5275097 100644 ---- a/fs/nfsd/nfs4recover.c -+++ b/fs/nfsd/nfs4recover.c -@@ -229,21 +229,23 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) - goto out; - status = vfs_readdir(filp, nfsd4_build_namelist, &names); - fput(filp); -+ mutex_lock(&dir->d_inode->i_mutex); - while (!list_empty(&names)) { - entry = list_entry(names.next, struct name_list, list); - - dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); - if (IS_ERR(dentry)) { - status = PTR_ERR(dentry); -- goto out; -+ break; - } - status = f(dir, dentry); - dput(dentry); - if (status) -- goto out; -+ break; - list_del(&entry->list); - kfree(entry); - } -+ mutex_unlock(&dir->d_inode->i_mutex); - out: - while (!list_empty(&names)) { - entry = list_entry(names.next, struct name_list, list); -@@ -255,36 +257,6 @@ out: - } - - static int --nfsd4_remove_clid_file(struct dentry *dir, struct dentry *dentry) --{ -- int status; -- -- if (!S_ISREG(dir->d_inode->i_mode)) { -- printk("nfsd4: non-file found in client recovery directory\n"); -- return -EINVAL; -- } -- mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); -- status = vfs_unlink(dir->d_inode, dentry); -- mutex_unlock(&dir->d_inode->i_mutex); -- return status; --} -- --static int --nfsd4_clear_clid_dir(struct dentry *dir, struct dentry *dentry) --{ -- int status; -- -- /* For now this directory should already be empty, but we empty it of -- * any regular files anyway, just in case the directory was created by -- * a kernel from the future.... */ -- nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file); -- mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); -- status = vfs_rmdir(dir->d_inode, dentry); -- mutex_unlock(&dir->d_inode->i_mutex); -- return status; --} -- --static int - nfsd4_unlink_clid_dir(char *name, int namlen) - { - struct dentry *dentry; -@@ -294,18 +266,18 @@ nfsd4_unlink_clid_dir(char *name, int namlen) - - mutex_lock(&rec_dir.dentry->d_inode->i_mutex); - dentry = lookup_one_len(name, rec_dir.dentry, namlen); -- mutex_unlock(&rec_dir.dentry->d_inode->i_mutex); - if (IS_ERR(dentry)) { - status = PTR_ERR(dentry); -- return status; -+ goto out_unlock; - } - status = -ENOENT; - if (!dentry->d_inode) - goto out; -- -- status = nfsd4_clear_clid_dir(rec_dir.dentry, dentry); -+ status = vfs_rmdir(rec_dir.dentry->d_inode, dentry); - out: - dput(dentry); -+out_unlock: -+ mutex_unlock(&rec_dir.dentry->d_inode->i_mutex); - return status; - } - -@@ -348,7 +320,7 @@ purge_old(struct dentry *parent, struct dentry *child) - if (nfs4_has_reclaimed_state(child->d_name.name, false)) - return 0; - -- status = nfsd4_clear_clid_dir(parent, child); -+ status = vfs_rmdir(parent->d_inode, child); - if (status) - printk("failed to remove client recovery directory %s\n", - child->d_name.name); -diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c -index 46e6bd2..6c68ffd 100644 ---- a/fs/nfsd/vfs.c -+++ b/fs/nfsd/vfs.c -@@ -1890,8 +1890,8 @@ static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen, - return 0; - } - --static int nfsd_buffered_readdir(struct file *file, filldir_t func, -- struct readdir_cd *cdp, loff_t *offsetp) -+static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func, -+ struct readdir_cd *cdp, loff_t *offsetp) - { - struct readdir_data buf; - struct buffered_dirent *de; -@@ -1901,11 +1901,12 @@ static int nfsd_buffered_readdir(struct file *file, filldir_t func, - - buf.dirent = (void *)__get_free_page(GFP_KERNEL); - if (!buf.dirent) -- return -ENOMEM; -+ return nfserrno(-ENOMEM); - - offset = *offsetp; - - while (1) { -+ struct inode *dir_inode = file->f_path.dentry->d_inode; - unsigned int reclen; - - cdp->err = nfserr_eof; /* will be cleared on successful read */ -@@ -1924,26 +1925,38 @@ static int nfsd_buffered_readdir(struct file *file, filldir_t func, - if (!size) - break; - -+ /* -+ * Various filldir functions may end up calling back into -+ * lookup_one_len() and the file system's ->lookup() method. -+ * These expect i_mutex to be held, as it would within readdir. -+ */ -+ host_err = mutex_lock_killable(&dir_inode->i_mutex); -+ if (host_err) -+ break; -+ - de = (struct buffered_dirent *)buf.dirent; - while (size > 0) { - offset = de->offset; - - if (func(cdp, de->name, de->namlen, de->offset, - de->ino, de->d_type)) -- goto done; -+ break; - - if (cdp->err != nfs_ok) -- goto done; -+ break; - - reclen = ALIGN(sizeof(*de) + de->namlen, - sizeof(u64)); - size -= reclen; - de = (struct buffered_dirent *)((char *)de + reclen); - } -+ mutex_unlock(&dir_inode->i_mutex); -+ if (size > 0) /* We bailed out early */ -+ break; -+ - offset = vfs_llseek(file, 0, SEEK_CUR); - } - -- done: - free_page((unsigned long)(buf.dirent)); - - if (host_err) diff --git a/queue-2.6.29/series b/queue-2.6.29/series index f1efdf83c28..bb08fdadd33 100644 --- a/queue-2.6.29/series +++ b/queue-2.6.29/series @@ -101,4 +101,3 @@ gso-fix-support-for-linear-packets.patch nfs-fix-the-xdr-iovec-calculation-in-nfs3_xdr_setaclargs.patch hugetlbfs-return-negative-error-code-for-bad-mount-option.patch scsi-mpt-suppress-debugobjects-warning.patch -fix-i_mutex-vs.-readdir-handling-in-nfsd.patch