Merge branch 'for-2.6.34' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 6 Mar 2010 19:31:38 +0000 (11:31 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 6 Mar 2010 19:31:38 +0000 (11:31 -0800)
* 'for-2.6.34' of git://linux-nfs.org/~bfields/linux: (22 commits)
  nfsd4: fix minor memory leak
  svcrpc: treat uid's as unsigned
  nfsd: ensure sockets are closed on error
  Revert "sunrpc: move the close processing after do recvfrom method"
  Revert "sunrpc: fix peername failed on closed listener"
  sunrpc: remove unnecessary svc_xprt_put
  NFSD: NFSv4 callback client should use RPC_TASK_SOFTCONN
  xfs_export_operations.commit_metadata
  commit_metadata export operation replacing nfsd_sync_dir
  lockd: don't clear sm_monitored on nsm_reboot_lookup
  lockd: release reference to nsm_handle in nlm_host_rebooted
  nfsd: Use vfs_fsync_range() in nfsd_commit
  NFSD: Create PF_INET6 listener in write_ports
  SUNRPC: NFS kernel APIs shouldn't return ENOENT for "transport not found"
  SUNRPC: Bury "#ifdef IPV6" in svc_create_xprt()
  NFSD: Support AF_INET6 in svc_addsock() function
  SUNRPC: Use rpc_pton() in ip_map_parse()
  nfsd: 4.1 has an rfc number
  nfsd41: Create the recovery entry for the NFSv4.1 client
  nfsd: use vfs_fsync for non-directories
  ...

1  2 
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/vfs.c

diff --combined fs/nfsd/nfs4state.c
@@@ -1998,9 -1998,7 +1998,9 @@@ nfs4_file_downgrade(struct file *filp, 
  {
        if (share_access & NFS4_SHARE_ACCESS_WRITE) {
                drop_file_write_access(filp);
 +              spin_lock(&filp->f_lock);
                filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE;
 +              spin_unlock(&filp->f_lock);
        }
  }
  
@@@ -2482,8 -2480,10 +2482,10 @@@ nfsd4_process_open2(struct svc_rqst *rq
        }
        memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t));
  
-       if (nfsd4_has_session(&resp->cstate))
+       if (nfsd4_has_session(&resp->cstate)) {
                open->op_stateowner->so_confirmed = 1;
+               nfsd4_create_clid_dir(open->op_stateowner->so_client);
+       }
  
        /*
        * Attempt to hand out a delegation. No error return, because the
diff --combined fs/nfsd/nfs4xdr.c
@@@ -1434,7 -1434,7 +1434,7 @@@ nfsd4_decode_compound(struct nfsd4_comp
                }
                op->opnum = ntohl(*argp->p++);
  
-               if (op->opnum >= OP_ACCESS && op->opnum < ops->nops)
+               if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP)
                        op->status = ops->decoders[op->opnum](argp, &op->u);
                else {
                        op->opnum = OP_ILLEGAL;
@@@ -2121,15 -2121,9 +2121,15 @@@ out_acl
                 * and this is the root of a cross-mounted filesystem.
                 */
                if (ignore_crossmnt == 0 &&
 -                  exp->ex_path.mnt->mnt_root->d_inode == dentry->d_inode) {
 -                      err = vfs_getattr(exp->ex_path.mnt->mnt_parent,
 -                              exp->ex_path.mnt->mnt_mountpoint, &stat);
 +                  dentry == exp->ex_path.mnt->mnt_root) {
 +                      struct path path = exp->ex_path;
 +                      path_get(&path);
 +                      while (follow_up(&path)) {
 +                              if (path.dentry != path.mnt->mnt_root)
 +                                      break;
 +                      }
 +                      err = vfs_getattr(path.mnt, path.dentry, &stat);
 +                      path_put(&path);
                        if (err)
                                goto out_nfserr;
                }
diff --combined fs/nfsd/vfs.c
  #include <linux/fcntl.h>
  #include <linux/namei.h>
  #include <linux/delay.h>
 -#include <linux/quotaops.h>
  #include <linux/fsnotify.h>
  #include <linux/posix_acl_xattr.h>
  #include <linux/xattr.h>
  #include <linux/jhash.h>
  #include <linux/ima.h>
  #include <asm/uaccess.h>
+ #include <linux/exportfs.h>
+ #include <linux/writeback.h>
  
  #ifdef CONFIG_NFSD_V3
  #include "xdr3.h"
@@@ -270,6 -273,32 +272,32 @@@ out
        return err;
  }
  
+ /*
+  * Commit metadata changes to stable storage.
+  */
+ static int
+ commit_metadata(struct svc_fh *fhp)
+ {
+       struct inode *inode = fhp->fh_dentry->d_inode;
+       const struct export_operations *export_ops = inode->i_sb->s_export_op;
+       int error = 0;
+       if (!EX_ISSYNC(fhp->fh_export))
+               return 0;
+       if (export_ops->commit_metadata) {
+               error = export_ops->commit_metadata(inode);
+       } else {
+               struct writeback_control wbc = {
+                       .sync_mode = WB_SYNC_ALL,
+                       .nr_to_write = 0, /* metadata only */
+               };
+               error = sync_inode(inode, &wbc);
+       }
+       return error;
+ }
  
  /*
   * Set various file attributes.
@@@ -360,7 -389,7 +388,7 @@@ nfsd_setattr(struct svc_rqst *rqstp, st
                 * If we are changing the size of the file, then
                 * we need to break all leases.
                 */
 -              host_err = break_lease(inode, FMODE_WRITE | O_NONBLOCK);
 +              host_err = break_lease(inode, O_WRONLY | O_NONBLOCK);
                if (host_err == -EWOULDBLOCK)
                        host_err = -ETIMEDOUT;
                if (host_err) /* ENOMEM or EWOULDBLOCK */
                        put_write_access(inode);
                        goto out_nfserr;
                }
 -              vfs_dq_init(inode);
        }
  
        /* sanitize the mode change */
@@@ -732,7 -762,7 +760,7 @@@ nfsd_open(struct svc_rqst *rqstp, struc
         * Check to see if there are any leases on this file.
         * This may block while leases are broken.
         */
 -      host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? FMODE_WRITE : 0));
 +      host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0));
        if (host_err == -EWOULDBLOCK)
                host_err = -ETIMEDOUT;
        if (host_err) /* NOMEM or WOULDBLOCK */
                        flags = O_RDWR|O_LARGEFILE;
                else
                        flags = O_WRONLY|O_LARGEFILE;
 -
 -              vfs_dq_init(inode);
        }
        *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt),
                            flags, current_cred());
@@@ -766,43 -798,6 +794,6 @@@ nfsd_close(struct file *filp
        fput(filp);
  }
  
- /*
-  * Sync a file
-  * As this calls fsync (not fdatasync) there is no need for a write_inode
-  * after it.
-  */
- static inline int nfsd_dosync(struct file *filp, struct dentry *dp,
-                             const struct file_operations *fop)
- {
-       struct inode *inode = dp->d_inode;
-       int (*fsync) (struct file *, struct dentry *, int);
-       int err;
-       err = filemap_write_and_wait(inode->i_mapping);
-       if (err == 0 && fop && (fsync = fop->fsync))
-               err = fsync(filp, dp, 0);
-       return err;
- }
- static int
- nfsd_sync(struct file *filp)
- {
-         int err;
-       struct inode *inode = filp->f_path.dentry->d_inode;
-       dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name);
-       mutex_lock(&inode->i_mutex);
-       err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op);
-       mutex_unlock(&inode->i_mutex);
-       return err;
- }
- int
- nfsd_sync_dir(struct dentry *dp)
- {
-       return nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
- }
  /*
   * Obtain the readahead parameters for the file
   * specified by (dev, ino).
@@@ -1006,7 -1001,7 +997,7 @@@ static int wait_for_concurrent_writes(s
  
        if (inode->i_state & I_DIRTY) {
                dprintk("nfsd: write sync %d\n", task_pid_nr(current));
-               err = nfsd_sync(file);
+               err = vfs_fsync(file, file->f_path.dentry, 0);
        }
        last_ino = inode->i_ino;
        last_dev = inode->i_sb->s_dev;
@@@ -1154,8 -1149,9 +1145,9 @@@ out
  #ifdef CONFIG_NFSD_V3
  /*
   * Commit all pending writes to stable storage.
-  * Strictly speaking, we could sync just the indicated file region here,
-  * but there's currently no way we can ask the VFS to do so.
+  *
+  * Note: we only guarantee that data that lies within the range specified
+  * by the 'offset' and 'count' parameters will be synced.
   *
   * Unfortunately we cannot lock the file to make sure we return full WCC
   * data to the client, as locking happens lower down in the filesystem.
@@@ -1165,23 -1161,32 +1157,32 @@@ nfsd_commit(struct svc_rqst *rqstp, str
                 loff_t offset, unsigned long count)
  {
        struct file     *file;
-       __be32          err;
+       loff_t          end = LLONG_MAX;
+       __be32          err = nfserr_inval;
  
-       if ((u64)count > ~(u64)offset)
-               return nfserr_inval;
+       if (offset < 0)
+               goto out;
+       if (count != 0) {
+               end = offset + (loff_t)count - 1;
+               if (end < offset)
+                       goto out;
+       }
  
        err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file);
        if (err)
-               return err;
+               goto out;
        if (EX_ISSYNC(fhp->fh_export)) {
-               if (file->f_op && file->f_op->fsync) {
-                       err = nfserrno(nfsd_sync(file));
-               } else {
+               int err2 = vfs_fsync_range(file, file->f_path.dentry,
+                               offset, end, 0);
+               if (err2 != -EINVAL)
+                       err = nfserrno(err2);
+               else
                        err = nfserr_notsupp;
-               }
        }
  
        nfsd_close(file);
+ out:
        return err;
  }
  #endif /* CONFIG_NFSD_V3 */
@@@ -1334,12 -1339,14 +1335,14 @@@ nfsd_create(struct svc_rqst *rqstp, str
                goto out_nfserr;
        }
  
-       if (EX_ISSYNC(fhp->fh_export)) {
-               err = nfserrno(nfsd_sync_dir(dentry));
-               write_inode_now(dchild->d_inode, 1);
-       }
+       err = nfsd_create_setattr(rqstp, resfhp, iap);
  
-       err2 = nfsd_create_setattr(rqstp, resfhp, iap);
+       /*
+        * nfsd_setattr already committed the child.  Transactional filesystems
+        * had a chance to commit changes for both parent and child
+        * simultaneously making the following commit_metadata a noop.
+        */
+       err2 = nfserrno(commit_metadata(fhp));
        if (err2)
                err = err2;
        mnt_drop_write(fhp->fh_export->ex_path.mnt);
@@@ -1371,7 -1378,6 +1374,6 @@@ nfsd_create_v3(struct svc_rqst *rqstp, 
        struct dentry   *dentry, *dchild = NULL;
        struct inode    *dirp;
        __be32          err;
-       __be32          err2;
        int             host_err;
        __u32           v_mtime=0, v_atime=0;
  
        if (created)
                *created = 1;
  
-       if (EX_ISSYNC(fhp->fh_export)) {
-               err = nfserrno(nfsd_sync_dir(dentry));
-               /* setattr will sync the child (or not) */
-       }
        nfsd_check_ignore_resizing(iap);
  
        if (createmode == NFS3_CREATE_EXCLUSIVE) {
        }
  
   set_attr:
-       err2 = nfsd_create_setattr(rqstp, resfhp, iap);
-       if (err2)
-               err = err2;
+       err = nfsd_create_setattr(rqstp, resfhp, iap);
+       /*
+        * nfsd_setattr already committed the child (and possibly also the parent).
+        */
+       if (!err)
+               err = nfserrno(commit_metadata(fhp));
  
        mnt_drop_write(fhp->fh_export->ex_path.mnt);
        /*
@@@ -1602,12 -1607,9 +1603,9 @@@ nfsd_symlink(struct svc_rqst *rqstp, st
                }
        } else
                host_err = vfs_symlink(dentry->d_inode, dnew, path);
-       if (!host_err) {
-               if (EX_ISSYNC(fhp->fh_export))
-                       host_err = nfsd_sync_dir(dentry);
-       }
        err = nfserrno(host_err);
+       if (!err)
+               err = nfserrno(commit_metadata(fhp));
        fh_unlock(fhp);
  
        mnt_drop_write(fhp->fh_export->ex_path.mnt);
@@@ -1669,11 -1671,9 +1667,9 @@@ nfsd_link(struct svc_rqst *rqstp, struc
        }
        host_err = vfs_link(dold, dirp, dnew);
        if (!host_err) {
-               if (EX_ISSYNC(ffhp->fh_export)) {
-                       err = nfserrno(nfsd_sync_dir(ddir));
-                       write_inode_now(dest, 1);
-               }
-               err = 0;
+               err = nfserrno(commit_metadata(ffhp));
+               if (!err)
+                       err = nfserrno(commit_metadata(tfhp));
        } else {
                if (host_err == -EXDEV && rqstp->rq_vers == 2)
                        err = nfserr_acces;
@@@ -1769,10 -1769,10 +1765,10 @@@ nfsd_rename(struct svc_rqst *rqstp, str
                goto out_dput_new;
  
        host_err = vfs_rename(fdir, odentry, tdir, ndentry);
-       if (!host_err && EX_ISSYNC(tfhp->fh_export)) {
-               host_err = nfsd_sync_dir(tdentry);
+       if (!host_err) {
+               host_err = commit_metadata(tfhp);
                if (!host_err)
-                       host_err = nfsd_sync_dir(fdentry);
+                       host_err = commit_metadata(ffhp);
        }
  
        mnt_drop_write(ffhp->fh_export->ex_path.mnt);
@@@ -1853,12 -1853,9 +1849,9 @@@ nfsd_unlink(struct svc_rqst *rqstp, str
  
        dput(rdentry);
  
-       if (host_err)
-               goto out_drop;
-       if (EX_ISSYNC(fhp->fh_export))
-               host_err = nfsd_sync_dir(dentry);
+       if (!host_err)
+               host_err = commit_metadata(fhp);
  
- out_drop:
        mnt_drop_write(fhp->fh_export->ex_path.mnt);
  out_nfserr:
        err = nfserrno(host_err);