]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/nfsd/vfs.c
nfsd: don't hold i_mutex over userspace upcalls
[karo-tx-linux.git] / fs / nfsd / vfs.c
index 994d66fbb4467ac8892a4d2ae0e5e9fda2a05722..4212aaacbb5537610c7fa37aea478ed2b5216390 100644 (file)
@@ -217,10 +217,16 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
                host_err = PTR_ERR(dentry);
                if (IS_ERR(dentry))
                        goto out_nfserr;
-               /*
-                * check if we have crossed a mount point ...
-                */
                if (nfsd_mountpoint(dentry, exp)) {
+                       /*
+                        * We don't need the i_mutex after all.  It's
+                        * still possible we could open this (regular
+                        * files can be mountpoints too), but the
+                        * i_mutex is just there to prevent renames of
+                        * something that we might be about to delegate,
+                        * and a mountpoint won't be renamed:
+                        */
+                       fh_unlock(fhp);
                        if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
                                dput(dentry);
                                goto out_nfserr;
@@ -1809,7 +1815,6 @@ static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func,
        offset = *offsetp;
 
        while (1) {
-               struct inode *dir_inode = file_inode(file);
                unsigned int reclen;
 
                cdp->err = nfserr_eof; /* will be cleared on successful read */
@@ -1828,15 +1833,6 @@ static __be32 nfsd_buffered_readdir(struct file *file, nfsd_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;
@@ -1853,7 +1849,6 @@ static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func,
                        size -= reclen;
                        de = (struct buffered_dirent *)((char *)de + reclen);
                }
-               mutex_unlock(&dir_inode->i_mutex);
                if (size > 0) /* We bailed out early */
                        break;