Merge branch 'for-2.6.40' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 29 May 2011 18:21:12 +0000 (11:21 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 29 May 2011 18:21:12 +0000 (11:21 -0700)
* 'for-2.6.40' of git://linux-nfs.org/~bfields/linux: (22 commits)
  nfsd: make local functions static
  NFSD: Remove unused variable from nfsd4_decode_bind_conn_to_session()
  NFSD: Check status from nfsd4_map_bcts_dir()
  NFSD: Remove setting unused variable in nfsd_vfs_read()
  nfsd41: error out on repeated RECLAIM_COMPLETE
  nfsd41: compare request's opcnt with session's maxops at nfsd4_sequence
  nfsd v4.1 lOCKT clientid field must be ignored
  nfsd41: add flag checking for create_session
  nfsd41: make sure nfs server process OPEN with EXCLUSIVE4_1 correctly
  nfsd4: fix wrongsec handling for PUTFH + op cases
  nfsd4: make fh_verify responsibility of nfsd_lookup_dentry caller
  nfsd4: introduce OPDESC helper
  nfsd4: allow fh_verify caller to skip pseudoflavor checks
  nfsd: distinguish functions of NFSD_MAY_* flags
  svcrpc: complete svsk processing on cb receive failure
  svcrpc: take advantage of tcp autotuning
  SUNRPC: Don't wait for full record to receive tcp data
  svcrpc: copy cb reply instead of pages
  svcrpc: close connection if client sends short packet
  svcrpc: note network-order types in svc_process_calldir
  ...

1  2 
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4state.c
fs/nfsd/vfs.c
include/linux/nfs4.h

diff --combined fs/nfsd/nfs3xdr.c
index ad48faca20fc7f777dfcd76dbd35b7e62a197eca,291f2d2551b37a111ce95dcc178fa3174a75a60d..08c6e36ab2eb05d8c28f68394a326573a7f52658
@@@ -702,7 -702,7 +702,7 @@@ nfs3svc_encode_readres(struct svc_rqst 
                *p++ = htonl(resp->eof);
                *p++ = htonl(resp->count);      /* xdr opaque count */
                xdr_ressize_check(rqstp, p);
 -              /* now update rqstp->rq_res to reflect data aswell */
 +              /* now update rqstp->rq_res to reflect data as well */
                rqstp->rq_res.page_len = resp->count;
                if (resp->count & 3) {
                        /* need to pad the tail */
@@@ -842,7 -842,7 +842,7 @@@ out
        return rv;
  }
  
- __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen)
static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen)
  {
        struct svc_fh   fh;
        int err;
diff --combined fs/nfsd/nfs4state.c
index 4cf04e11c66ca39c80dc6b54b6854842de246826,a8e4e91587ab1a9df5e8126a94b15b1705d70544..e98f3c2e9492a9d2dd3e86e6e443e924c9f04187
@@@ -258,7 -258,6 +258,7 @@@ static void nfs4_put_deleg_lease(struc
        if (atomic_dec_and_test(&fp->fi_delegees)) {
                vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease);
                fp->fi_lease = NULL;
 +              fput(fp->fi_deleg_file);
                fp->fi_deleg_file = NULL;
        }
  }
@@@ -398,12 -397,9 +398,12 @@@ static void unhash_generic_stateid(stru
  
  static void free_generic_stateid(struct nfs4_stateid *stp)
  {
 -      int oflag = nfs4_access_bmap_to_omode(stp);
 +      int oflag;
  
 -      nfs4_file_put_access(stp->st_file, oflag);
 +      if (stp->st_access_bmap) {
 +              oflag = nfs4_access_bmap_to_omode(stp);
 +              nfs4_file_put_access(stp->st_file, oflag);
 +      }
        put_nfs4_file(stp->st_file);
        kmem_cache_free(stateid_slab, stp);
  }
@@@ -1519,6 -1515,9 +1519,9 @@@ nfsd4_create_session(struct svc_rqst *r
        bool confirm_me = false;
        int status = 0;
  
+       if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
+               return nfserr_inval;
        nfs4_lock_state();
        unconf = find_unconfirmed_client(&cr_ses->clientid);
        conf = find_confirmed_client(&cr_ses->clientid);
@@@ -1637,8 -1636,9 +1640,9 @@@ __be32 nfsd4_bind_conn_to_session(struc
                return nfserr_badsession;
  
        status = nfsd4_map_bcts_dir(&bcts->dir);
-       nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
-       return nfs_ok;
+       if (!status)
+               nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
+       return status;
  }
  
  static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
@@@ -1725,6 -1725,13 +1729,13 @@@ static void nfsd4_sequence_check_conn(s
        return;
  }
  
+ static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
+ {
+       struct nfsd4_compoundargs *args = rqstp->rq_argp;
+       return args->opcnt > session->se_fchannel.maxops;
+ }
  __be32
  nfsd4_sequence(struct svc_rqst *rqstp,
               struct nfsd4_compound_state *cstate,
        if (!session)
                goto out;
  
+       status = nfserr_too_many_ops;
+       if (nfsd4_session_too_many_ops(rqstp, session))
+               goto out;
        status = nfserr_badslot;
        if (seq->slotid >= session->se_fchannel.maxreqs)
                goto out;
@@@ -1808,6 -1819,8 +1823,8 @@@ out
  __be32
  nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc)
  {
+       int status = 0;
        if (rc->rca_one_fs) {
                if (!cstate->current_fh.fh_dentry)
                        return nfserr_nofilehandle;
                 */
                 return nfs_ok;
        }
        nfs4_lock_state();
-       if (is_client_expired(cstate->session->se_client)) {
-               nfs4_unlock_state();
+       status = nfserr_complete_already;
+       if (cstate->session->se_client->cl_firststate)
+               goto out;
+       status = nfserr_stale_clientid;
+       if (is_client_expired(cstate->session->se_client))
                /*
                 * The following error isn't really legal.
                 * But we only get here if the client just explicitly
                 * error it gets back on an operation for the dead
                 * client.
                 */
-               return nfserr_stale_clientid;
-       }
+               goto out;
+       status = nfs_ok;
        nfsd4_create_clid_dir(cstate->session->se_client);
+ out:
        nfs4_unlock_state();
-       return nfs_ok;
+       return status;
  }
  
  __be32
@@@ -2462,7 -2482,7 +2486,7 @@@ find_delegation_file(struct nfs4_file *
        return NULL;
  }
  
- int share_access_to_flags(u32 share_access)
static int share_access_to_flags(u32 share_access)
  {
        share_access &= ~NFS4_SHARE_WANT_MASK;
  
@@@ -2882,7 -2902,7 +2906,7 @@@ out
        return status;
  }
  
- struct lock_manager nfsd4_manager = {
+ static struct lock_manager nfsd4_manager = {
  };
  
  static void
@@@ -3059,7 -3079,7 +3083,7 @@@ check_special_stateids(svc_fh *current_
        if (ONE_STATEID(stateid) && (flags & RD_STATE))
                return nfs_ok;
        else if (locks_in_grace()) {
 -              /* Answer in remaining cases depends on existance of
 +              /* Answer in remaining cases depends on existence of
                 * conflicting state; so we must wait out the grace period. */
                return nfserr_grace;
        } else if (flags & WR_STATE)
@@@ -3679,7 -3699,7 +3703,7 @@@ find_lockstateowner_str(struct inode *i
  /*
   * Alloc a lock owner structure.
   * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 
 - * occured. 
 + * occurred. 
   *
   * strhashval = lock_ownerstr_hashval 
   */
diff --combined fs/nfsd/vfs.c
index 129f3c9f62d589f44b947fccd04c8f745cdfb485,f4e056ae53e4bafaf1f45fb415046788bd6b23fb..d5718273bb32f216922c474635ad479c7912064d
@@@ -181,16 -181,10 +181,10 @@@ nfsd_lookup_dentry(struct svc_rqst *rqs
        struct svc_export       *exp;
        struct dentry           *dparent;
        struct dentry           *dentry;
-       __be32                  err;
        int                     host_err;
  
        dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);
  
-       /* Obtain dentry and export. */
-       err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
-       if (err)
-               return err;
        dparent = fhp->fh_dentry;
        exp  = fhp->fh_export;
        exp_get(exp);
@@@ -254,6 -248,9 +248,9 @@@ nfsd_lookup(struct svc_rqst *rqstp, str
        struct dentry           *dentry;
        __be32 err;
  
+       err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
+       if (err)
+               return err;
        err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry);
        if (err)
                return err;
@@@ -877,13 -874,11 +874,11 @@@ static __be3
  nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
                loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
  {
-       struct inode *inode;
        mm_segment_t    oldfs;
        __be32          err;
        int             host_err;
  
        err = nfserr_perm;
-       inode = file->f_path.dentry->d_inode;
  
        if (file->f_op->splice_read && rqstp->rq_splice_ok) {
                struct splice_desc sd = {
@@@ -1340,11 -1335,18 +1335,18 @@@ out_nfserr
  }
  
  #ifdef CONFIG_NFSD_V3
+ static inline int nfsd_create_is_exclusive(int createmode)
+ {
+       return createmode == NFS3_CREATE_EXCLUSIVE
+              || createmode == NFS4_CREATE_EXCLUSIVE4_1;
+ }
  /*
-  * NFSv3 version of nfsd_create
+  * NFSv3 and NFSv4 version of nfsd_create
   */
  __be32
nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
                char *fname, int flen, struct iattr *iap,
                struct svc_fh *resfhp, int createmode, u32 *verifier,
                int *truncp, int *created)
                goto out;
        if (!(iap->ia_valid & ATTR_MODE))
                iap->ia_mode = 0;
 -      err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
 +      err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
        if (err)
                goto out;
  
        if (IS_ERR(dchild))
                goto out_nfserr;
  
 +      /* If file doesn't exist, check for permissions to create one */
 +      if (!dchild->d_inode) {
 +              err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
 +              if (err)
 +                      goto out;
 +      }
 +
        err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
        if (err)
                goto out;
  
-       if (createmode == NFS3_CREATE_EXCLUSIVE) {
+       if (nfsd_create_is_exclusive(createmode)) {
                /* solaris7 gets confused (bugid 4218508) if these have
                 * the high bit set, so just clear the high bits. If this is
                 * ever changed to use different attrs for storing the
                            && dchild->d_inode->i_atime.tv_sec == v_atime
                            && dchild->d_inode->i_size  == 0 )
                                break;
+               case NFS4_CREATE_EXCLUSIVE4_1:
+                       if (   dchild->d_inode->i_mtime.tv_sec == v_mtime
+                           && dchild->d_inode->i_atime.tv_sec == v_atime
+                           && dchild->d_inode->i_size  == 0 )
+                               goto set_attr;
                         /* fallthru */
                case NFS3_CREATE_GUARDED:
                        err = nfserr_exist;
  
        nfsd_check_ignore_resizing(iap);
  
-       if (createmode == NFS3_CREATE_EXCLUSIVE) {
+       if (nfsd_create_is_exclusive(createmode)) {
                /* Cram the verifier into atime/mtime */
                iap->ia_valid = ATTR_MTIME|ATTR_ATIME
                        | ATTR_MTIME_SET|ATTR_ATIME_SET;
@@@ -2034,7 -2034,7 +2041,7 @@@ nfsd_permission(struct svc_rqst *rqstp
        struct inode    *inode = dentry->d_inode;
        int             err;
  
-       if (acc == NFSD_MAY_NOP)
+       if ((acc & NFSD_MAY_MASK) == NFSD_MAY_NOP)
                return 0;
  #if 0
        dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n",
diff --combined include/linux/nfs4.h
index 178fafe0ff9303426675f3b0134b01202de3ade1,8937727e7039119214ba45bbe35e71fb4692981a..8e66c5ccc1c47a37750cf8304344f4492fcacd07
@@@ -359,7 -359,7 +359,7 @@@ enum nfsstat4 
                                                /* Error 10073 is unused. */
        NFS4ERR_CLIENTID_BUSY   = 10074,        /* clientid has state */
        NFS4ERR_PNFS_IO_HOLE    = 10075,        /* IO to _SPARSE file hole */
 -      NFS4ERR_SEQ_FALSE_RETRY = 10076,        /* retry not origional */
 +      NFS4ERR_SEQ_FALSE_RETRY = 10076,        /* retry not original */
        NFS4ERR_BAD_HIGH_SLOT   = 10077,        /* sequence arg bad */
        NFS4ERR_DEADSESSION     = 10078,        /* persistent session dead */
        NFS4ERR_ENCR_ALG_UNSUPP = 10079,        /* SSV alg mismatch */
@@@ -570,9 -570,11 +570,11 @@@ struct nfs4_sessionid 
  };
  
  /* Create Session Flags */
- #define SESSION4_PERSIST       0x001
- #define SESSION4_BACK_CHAN     0x002
- #define SESSION4_RDMA          0x004
+ #define SESSION4_PERSIST      0x001
+ #define SESSION4_BACK_CHAN    0x002
+ #define SESSION4_RDMA         0x004
+ #define SESSION4_FLAG_MASK_A  0x007
  
  enum state_protect_how4 {
        SP4_NONE        = 0,