aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/vfs.c
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2009-04-20 18:18:37 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2009-04-20 23:01:16 -0400
commit2f9092e1020246168b1309b35e085ecd7ff9ff72 (patch)
treef8318c1e62e789718ae7637869f6c075b815bcb2 /fs/nfsd/vfs.c
parent1ba0c7dbbbc24230394100c5f0d0df38cb400cff (diff)
Fix i_mutex vs. readdir handling in nfsd
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 <David.Woodhouse@intel.com> Umm-I-can-live-with-that-by: Al Viro <viro@zeniv.linux.org.uk> Reported-by: J. R. Okajima <hooanon05@yahoo.co.jp> Tested-by: J. Bruce Fields <bfields@citi.umich.edu> LKML-Reference: <8036.1237474444@jrobl> Cc: stable@kernel.org Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r--fs/nfsd/vfs.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 46e6bd2d4f07..6c68ffd6b4bb 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,
1890 return 0; 1890 return 0;
1891} 1891}
1892 1892
1893static int nfsd_buffered_readdir(struct file *file, filldir_t func, 1893static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
1894 struct readdir_cd *cdp, loff_t *offsetp) 1894 struct readdir_cd *cdp, loff_t *offsetp)
1895{ 1895{
1896 struct readdir_data buf; 1896 struct readdir_data buf;
1897 struct buffered_dirent *de; 1897 struct buffered_dirent *de;
@@ -1901,11 +1901,12 @@ static int nfsd_buffered_readdir(struct file *file, filldir_t func,
1901 1901
1902 buf.dirent = (void *)__get_free_page(GFP_KERNEL); 1902 buf.dirent = (void *)__get_free_page(GFP_KERNEL);
1903 if (!buf.dirent) 1903 if (!buf.dirent)
1904 return -ENOMEM; 1904 return nfserrno(-ENOMEM);
1905 1905
1906 offset = *offsetp; 1906 offset = *offsetp;
1907 1907
1908 while (1) { 1908 while (1) {
1909 struct inode *dir_inode = file->f_path.dentry->d_inode;
1909 unsigned int reclen; 1910 unsigned int reclen;
1910 1911
1911 cdp->err = nfserr_eof; /* will be cleared on successful read */ 1912 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,
1924 if (!size) 1925 if (!size)
1925 break; 1926 break;
1926 1927
1928 /*
1929 * Various filldir functions may end up calling back into
1930 * lookup_one_len() and the file system's ->lookup() method.
1931 * These expect i_mutex to be held, as it would within readdir.
1932 */
1933 host_err = mutex_lock_killable(&dir_inode->i_mutex);
1934 if (host_err)
1935 break;
1936
1927 de = (struct buffered_dirent *)buf.dirent; 1937 de = (struct buffered_dirent *)buf.dirent;
1928 while (size > 0) { 1938 while (size > 0) {
1929 offset = de->offset; 1939 offset = de->offset;
1930 1940
1931 if (func(cdp, de->name, de->namlen, de->offset, 1941 if (func(cdp, de->name, de->namlen, de->offset,
1932 de->ino, de->d_type)) 1942 de->ino, de->d_type))
1933 goto done; 1943 break;
1934 1944
1935 if (cdp->err != nfs_ok) 1945 if (cdp->err != nfs_ok)
1936 goto done; 1946 break;
1937 1947
1938 reclen = ALIGN(sizeof(*de) + de->namlen, 1948 reclen = ALIGN(sizeof(*de) + de->namlen,
1939 sizeof(u64)); 1949 sizeof(u64));
1940 size -= reclen; 1950 size -= reclen;
1941 de = (struct buffered_dirent *)((char *)de + reclen); 1951 de = (struct buffered_dirent *)((char *)de + reclen);
1942 } 1952 }
1953 mutex_unlock(&dir_inode->i_mutex);
1954 if (size > 0) /* We bailed out early */
1955 break;
1956
1943 offset = vfs_llseek(file, 0, SEEK_CUR); 1957 offset = vfs_llseek(file, 0, SEEK_CUR);
1944 } 1958 }
1945 1959
1946 done:
1947 free_page((unsigned long)(buf.dirent)); 1960 free_page((unsigned long)(buf.dirent));
1948 1961
1949 if (host_err) 1962 if (host_err)