Merge commit 'v2.6.30' into for-2.6.31
authorJ. Bruce Fields <bfields@citi.umich.edu>
Tue, 16 Jun 2009 01:08:07 +0000 (18:08 -0700)
committerJ. Bruce Fields <bfields@citi.umich.edu>
Tue, 16 Jun 2009 01:08:07 +0000 (18:08 -0700)
1  2 
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
include/linux/fs.h
net/sunrpc/svcsock.c

diff --combined fs/nfsd/nfs4state.c
@@@ -182,7 -182,7 +182,7 @@@ alloc_init_deleg(struct nfs4_client *cl
  {
        struct nfs4_delegation *dp;
        struct nfs4_file *fp = stp->st_file;
 -      struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;
 +      struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn;
  
        dprintk("NFSD alloc_init_deleg\n");
        if (fp->fi_had_conflict)
        get_file(stp->st_vfs_file);
        dp->dl_vfs_file = stp->st_vfs_file;
        dp->dl_type = type;
 -      dp->dl_recall.cbr_dp = NULL;
 -      dp->dl_recall.cbr_ident = cb->cb_ident;
 -      dp->dl_recall.cbr_trunc = 0;
 -      dp->dl_stateid.si_boot = boot_time;
 +      dp->dl_ident = cb->cb_ident;
 +      dp->dl_stateid.si_boot = get_seconds();
        dp->dl_stateid.si_stateownerid = current_delegid++;
        dp->dl_stateid.si_fileid = 0;
        dp->dl_stateid.si_generation = 0;
@@@ -578,7 -580,6 +578,6 @@@ free_session(struct kref *kref
                struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry;
                nfsd4_release_respages(e->ce_respages, e->ce_resused);
        }
-       kfree(ses->se_slots);
        kfree(ses);
  }
  
@@@ -631,20 -632,16 +630,20 @@@ static struct nfs4_client *alloc_client
  static void
  shutdown_callback_client(struct nfs4_client *clp)
  {
 -      struct rpc_clnt *clnt = clp->cl_callback.cb_client;
 +      struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client;
  
        if (clnt) {
                /*
                 * Callback threads take a reference on the client, so there
                 * should be no outstanding callbacks at this point.
                 */
 -              clp->cl_callback.cb_client = NULL;
 +              clp->cl_cb_conn.cb_client = NULL;
                rpc_shutdown_client(clnt);
        }
 +      if (clp->cl_cb_conn.cb_cred) {
 +              put_rpccred(clp->cl_cb_conn.cb_cred);
 +              clp->cl_cb_conn.cb_cred = NULL;
 +      }
  }
  
  static inline void
@@@ -717,7 -714,7 +716,7 @@@ static struct nfs4_client *create_clien
                return NULL;
        memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
        atomic_set(&clp->cl_count, 1);
 -      atomic_set(&clp->cl_callback.cb_set, 0);
 +      atomic_set(&clp->cl_cb_conn.cb_set, 0);
        INIT_LIST_HEAD(&clp->cl_idhash);
        INIT_LIST_HEAD(&clp->cl_strhash);
        INIT_LIST_HEAD(&clp->cl_openowners);
@@@ -969,7 -966,7 +968,7 @@@ parse_ipv4(unsigned int addr_len, char 
  static void
  gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se)
  {
 -      struct nfs4_callback *cb = &clp->cl_callback;
 +      struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
  
        /* Currently, we only support tcp for the callback channel */
        if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3))
@@@ -1689,7 -1686,9 +1688,7 @@@ nfsd4_setclientid_confirm(struct svc_rq
                else {
                        /* XXX: We just turn off callbacks until we can handle
                          * change request correctly. */
 -                      atomic_set(&conf->cl_callback.cb_set, 0);
 -                      gen_confirm(conf);
 -                      nfsd4_remove_clid_dir(unconf);
 +                      atomic_set(&conf->cl_cb_conn.cb_set, 0);
                        expire_client(unconf);
                        status = nfs_ok;
  
@@@ -1883,7 -1882,7 +1882,7 @@@ init_stateid(struct nfs4_stateid *stp, 
        stp->st_stateowner = sop;
        get_nfs4_file(fp);
        stp->st_file = fp;
 -      stp->st_stateid.si_boot = boot_time;
 +      stp->st_stateid.si_boot = get_seconds();
        stp->st_stateid.si_stateownerid = sop->so_id;
        stp->st_stateid.si_fileid = fp->fi_id;
        stp->st_stateid.si_generation = 0;
@@@ -2060,6 -2059,19 +2059,6 @@@ nfs4_file_downgrade(struct file *filp, 
  }
  
  /*
 - * Recall a delegation
 - */
 -static int
 -do_recall(void *__dp)
 -{
 -      struct nfs4_delegation *dp = __dp;
 -
 -      dp->dl_file->fi_had_conflict = true;
 -      nfsd4_cb_recall(dp);
 -      return 0;
 -}
 -
 -/*
   * Spawn a thread to perform a recall on the delegation represented
   * by the lease (file_lock)
   *
  static
  void nfsd_break_deleg_cb(struct file_lock *fl)
  {
 -      struct nfs4_delegation *dp=  (struct nfs4_delegation *)fl->fl_owner;
 -      struct task_struct *t;
 +      struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
  
        dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl);
        if (!dp)
         */
        fl->fl_break_time = 0;
  
 -      t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall");
 -      if (IS_ERR(t)) {
 -              struct nfs4_client *clp = dp->dl_client;
 -
 -              printk(KERN_INFO "NFSD: Callback thread failed for "
 -                      "for client (clientid %08x/%08x)\n",
 -                      clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
 -              put_nfs4_client(dp->dl_client);
 -              nfs4_put_delegation(dp);
 -      }
 +      dp->dl_file->fi_had_conflict = true;
 +      nfsd4_cb_recall(dp);
  }
  
  /*
@@@ -2401,7 -2422,7 +2400,7 @@@ nfs4_open_delegation(struct svc_fh *fh
  {
        struct nfs4_delegation *dp;
        struct nfs4_stateowner *sop = stp->st_stateowner;
 -      struct nfs4_callback *cb = &sop->so_client->cl_callback;
 +      struct nfs4_cb_conn *cb = &sop->so_client->cl_cb_conn;
        struct file_lock fl, *flp = &fl;
        int status, flag = 0;
  
@@@ -2593,7 -2614,7 +2592,7 @@@ nfsd4_renew(struct svc_rqst *rqstp, str
        renew_client(clp);
        status = nfserr_cb_path_down;
        if (!list_empty(&clp->cl_delegations)
 -                      && !atomic_read(&clp->cl_callback.cb_set))
 +                      && !atomic_read(&clp->cl_cb_conn.cb_set))
                goto out;
        status = nfs_ok;
  out:
@@@ -2717,42 -2738,12 +2716,42 @@@ nfs4_check_fh(struct svc_fh *fhp, struc
  static int
  STALE_STATEID(stateid_t *stateid)
  {
 -      if (stateid->si_boot == boot_time)
 -              return 0;
 -      dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
 -              stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
 -              stateid->si_generation);
 -      return 1;
 +      if (time_after((unsigned long)boot_time,
 +                      (unsigned long)stateid->si_boot)) {
 +              dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
 +                      stateid->si_boot, stateid->si_stateownerid,
 +                      stateid->si_fileid, stateid->si_generation);
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +static int
 +EXPIRED_STATEID(stateid_t *stateid)
 +{
 +      if (time_before((unsigned long)boot_time,
 +                      ((unsigned long)stateid->si_boot)) &&
 +          time_before((unsigned long)(stateid->si_boot + lease_time), get_seconds())) {
 +              dprintk("NFSD: expired stateid (%08x/%08x/%08x/%08x)!\n",
 +                      stateid->si_boot, stateid->si_stateownerid,
 +                      stateid->si_fileid, stateid->si_generation);
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +static __be32
 +stateid_error_map(stateid_t *stateid)
 +{
 +      if (STALE_STATEID(stateid))
 +              return nfserr_stale_stateid;
 +      if (EXPIRED_STATEID(stateid))
 +              return nfserr_expired;
 +
 +      dprintk("NFSD: bad stateid (%08x/%08x/%08x/%08x)!\n",
 +              stateid->si_boot, stateid->si_stateownerid,
 +              stateid->si_fileid, stateid->si_generation);
 +      return nfserr_bad_stateid;
  }
  
  static inline int
@@@ -2876,10 -2867,8 +2875,10 @@@ nfs4_preprocess_stateid_op(struct nfsd4
        status = nfserr_bad_stateid;
        if (is_delegation_stateid(stateid)) {
                dp = find_delegation_stateid(ino, stateid);
 -              if (!dp)
 +              if (!dp) {
 +                      status = stateid_error_map(stateid);
                        goto out;
 +              }
                status = check_stateid_generation(stateid, &dp->dl_stateid,
                                                  flags);
                if (status)
                        *filpp = dp->dl_vfs_file;
        } else { /* open or lock stateid */
                stp = find_stateid(stateid, flags);
 -              if (!stp)
 +              if (!stp) {
 +                      status = stateid_error_map(stateid);
                        goto out;
 +              }
                if (nfs4_check_fh(current_fh, stp))
                        goto out;
                if (!stp->st_stateowner->so_confirmed)
@@@ -2969,7 -2956,7 +2968,7 @@@ nfs4_preprocess_seqid_op(struct nfsd4_c
                 */
                sop = search_close_lru(stateid->si_stateownerid, flags);
                if (sop == NULL)
 -                      return nfserr_bad_stateid;
 +                      return stateid_error_map(stateid);
                *sopp = sop;
                goto check_replay;
        }
@@@ -3240,10 -3227,8 +3239,10 @@@ nfsd4_delegreturn(struct svc_rqst *rqst
        if (!is_delegation_stateid(stateid))
                goto out;
        dp = find_delegation_stateid(inode, stateid);
 -      if (!dp)
 +      if (!dp) {
 +              status = stateid_error_map(stateid);
                goto out;
 +      }
        status = check_stateid_generation(stateid, &dp->dl_stateid, flags);
        if (status)
                goto out;
@@@ -3470,7 -3455,7 +3469,7 @@@ alloc_init_lock_stateid(struct nfs4_sta
        stp->st_stateowner = sop;
        get_nfs4_file(fp);
        stp->st_file = fp;
 -      stp->st_stateid.si_boot = boot_time;
 +      stp->st_stateid.si_boot = get_seconds();
        stp->st_stateid.si_stateownerid = sop->so_id;
        stp->st_stateid.si_fileid = fp->fi_id;
        stp->st_stateid.si_generation = 0;
@@@ -4002,7 -3987,6 +4001,7 @@@ nfs4_state_init(void
                INIT_LIST_HEAD(&conf_str_hashtbl[i]);
                INIT_LIST_HEAD(&unconf_str_hashtbl[i]);
                INIT_LIST_HEAD(&unconf_id_hashtbl[i]);
 +              INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
        }
        for (i = 0; i < SESSION_HASH_SIZE; i++)
                INIT_LIST_HEAD(&sessionid_hashtbl[i]);
        INIT_LIST_HEAD(&close_lru);
        INIT_LIST_HEAD(&client_lru);
        INIT_LIST_HEAD(&del_recall_lru);
 -      for (i = 0; i < CLIENT_HASH_SIZE; i++)
 -              INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
        reclaim_str_hashtbl_size = 0;
        return 0;
  }
diff --combined fs/nfsd/nfs4xdr.c
@@@ -83,6 -83,16 +83,6 @@@ check_filename(char *str, int len, __be
        return 0;
  }
  
 -/*
 - * START OF "GENERIC" DECODE ROUTINES.
 - *   These may look a little ugly since they are imported from a "generic"
 - * set of XDR encode/decode routines which are intended to be shared by
 - * all of our NFSv4 implementations (OpenBSD, MacOS X...).
 - *
 - * If the pain of reading these is too great, it should be a straightforward
 - * task to translate them into Linux-specific versions which are more
 - * consistent with the style used in NFSv2/v3...
 - */
  #define DECODE_HEAD                           \
        __be32 *p;                              \
        __be32 status
@@@ -244,8 -254,20 +244,8 @@@ nfsd4_decode_bitmap(struct nfsd4_compou
        DECODE_TAIL;
  }
  
 -static u32 nfsd_attrmask[] = {
 -      NFSD_WRITEABLE_ATTRS_WORD0,
 -      NFSD_WRITEABLE_ATTRS_WORD1,
 -      NFSD_WRITEABLE_ATTRS_WORD2
 -};
 -
 -static u32 nfsd41_ex_attrmask[] = {
 -      NFSD_SUPPATTR_EXCLCREAT_WORD0,
 -      NFSD_SUPPATTR_EXCLCREAT_WORD1,
 -      NFSD_SUPPATTR_EXCLCREAT_WORD2
 -};
 -
  static __be32
 -nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable,
 +nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                   struct iattr *iattr, struct nfs4_acl **acl)
  {
        int expected_len, len = 0;
        if ((status = nfsd4_decode_bitmap(argp, bmval)))
                return status;
  
 -      /*
 -       * According to spec, unsupported attributes return ERR_ATTRNOTSUPP;
 -       * read-only attributes return ERR_INVAL.
 -       */
 -      if ((bmval[0] & ~nfsd_suppattrs0(argp->minorversion)) ||
 -          (bmval[1] & ~nfsd_suppattrs1(argp->minorversion)) ||
 -          (bmval[2] & ~nfsd_suppattrs2(argp->minorversion)))
 -              return nfserr_attrnotsupp;
 -      if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) ||
 -          (bmval[2] & ~writable[2]))
 -              return nfserr_inval;
 -
        READ_BUF(4);
        READ32(expected_len);
  
                        goto xdr_error;
                }
        }
 -      BUG_ON(bmval[2]);       /* no such writeable attr supported yet */
 -      if (len != expected_len)
 +      if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
 +          || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
 +          || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2)
 +              READ_BUF(expected_len - len);
 +      else if (len != expected_len)
                goto xdr_error;
  
        DECODE_TAIL;
@@@ -487,8 -518,8 +487,8 @@@ nfsd4_decode_create(struct nfsd4_compou
        if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))
                return status;
  
 -      status = nfsd4_decode_fattr(argp, create->cr_bmval, nfsd_attrmask,
 -                                  &create->cr_iattr, &create->cr_acl);
 +      status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
 +                                  &create->cr_acl);
        if (status)
                goto out;
  
@@@ -651,7 -682,7 +651,7 @@@ nfsd4_decode_open(struct nfsd4_compound
                case NFS4_CREATE_UNCHECKED:
                case NFS4_CREATE_GUARDED:
                        status = nfsd4_decode_fattr(argp, open->op_bmval,
 -                              nfsd_attrmask, &open->op_iattr, &open->op_acl);
 +                              &open->op_iattr, &open->op_acl);
                        if (status)
                                goto out;
                        break;
                        READ_BUF(8);
                        COPYMEM(open->op_verf.data, 8);
                        status = nfsd4_decode_fattr(argp, open->op_bmval,
 -                              nfsd41_ex_attrmask, &open->op_iattr,
 -                              &open->op_acl);
 +                              &open->op_iattr, &open->op_acl);
                        if (status)
                                goto out;
                        break;
@@@ -861,8 -893,8 +861,8 @@@ nfsd4_decode_setattr(struct nfsd4_compo
        status = nfsd4_decode_stateid(argp, &setattr->sa_stateid);
        if (status)
                return status;
 -      return nfsd4_decode_fattr(argp, setattr->sa_bmval, nfsd_attrmask,
 -                                &setattr->sa_iattr, &setattr->sa_acl);
 +      return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr,
 +                                &setattr->sa_acl);
  }
  
  static __be32
@@@ -1296,64 -1328,64 +1296,64 @@@ static nfsd4_dec nfsd4_dec_ops[] = 
  };
  
  static nfsd4_dec nfsd41_dec_ops[] = {
 -      [OP_ACCESS]             (nfsd4_dec)nfsd4_decode_access,
 -      [OP_CLOSE]              (nfsd4_dec)nfsd4_decode_close,
 -      [OP_COMMIT]             (nfsd4_dec)nfsd4_decode_commit,
 -      [OP_CREATE]             (nfsd4_dec)nfsd4_decode_create,
 -      [OP_DELEGPURGE]         (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_DELEGRETURN]        (nfsd4_dec)nfsd4_decode_delegreturn,
 -      [OP_GETATTR]            (nfsd4_dec)nfsd4_decode_getattr,
 -      [OP_GETFH]              (nfsd4_dec)nfsd4_decode_noop,
 -      [OP_LINK]               (nfsd4_dec)nfsd4_decode_link,
 -      [OP_LOCK]               (nfsd4_dec)nfsd4_decode_lock,
 -      [OP_LOCKT]              (nfsd4_dec)nfsd4_decode_lockt,
 -      [OP_LOCKU]              (nfsd4_dec)nfsd4_decode_locku,
 -      [OP_LOOKUP]             (nfsd4_dec)nfsd4_decode_lookup,
 -      [OP_LOOKUPP]            (nfsd4_dec)nfsd4_decode_noop,
 -      [OP_NVERIFY]            (nfsd4_dec)nfsd4_decode_verify,
 -      [OP_OPEN]               (nfsd4_dec)nfsd4_decode_open,
 -      [OP_OPENATTR]           (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_OPEN_CONFIRM]       (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_OPEN_DOWNGRADE]     (nfsd4_dec)nfsd4_decode_open_downgrade,
 -      [OP_PUTFH]              (nfsd4_dec)nfsd4_decode_putfh,
 -      [OP_PUTPUBFH]           (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_PUTROOTFH]          (nfsd4_dec)nfsd4_decode_noop,
 -      [OP_READ]               (nfsd4_dec)nfsd4_decode_read,
 -      [OP_READDIR]            (nfsd4_dec)nfsd4_decode_readdir,
 -      [OP_READLINK]           (nfsd4_dec)nfsd4_decode_noop,
 -      [OP_REMOVE]             (nfsd4_dec)nfsd4_decode_remove,
 -      [OP_RENAME]             (nfsd4_dec)nfsd4_decode_rename,
 -      [OP_RENEW]              (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_RESTOREFH]          (nfsd4_dec)nfsd4_decode_noop,
 -      [OP_SAVEFH]             (nfsd4_dec)nfsd4_decode_noop,
 -      [OP_SECINFO]            (nfsd4_dec)nfsd4_decode_secinfo,
 -      [OP_SETATTR]            (nfsd4_dec)nfsd4_decode_setattr,
 -      [OP_SETCLIENTID]        (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_SETCLIENTID_CONFIRM](nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_VERIFY]             (nfsd4_dec)nfsd4_decode_verify,
 -      [OP_WRITE]              (nfsd4_dec)nfsd4_decode_write,
 -      [OP_RELEASE_LOCKOWNER]  (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_ACCESS]             (nfsd4_dec)nfsd4_decode_access,
 +      [OP_CLOSE]              (nfsd4_dec)nfsd4_decode_close,
 +      [OP_COMMIT]             (nfsd4_dec)nfsd4_decode_commit,
 +      [OP_CREATE]             (nfsd4_dec)nfsd4_decode_create,
 +      [OP_DELEGPURGE]         (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_DELEGRETURN]        (nfsd4_dec)nfsd4_decode_delegreturn,
 +      [OP_GETATTR]            (nfsd4_dec)nfsd4_decode_getattr,
 +      [OP_GETFH]              (nfsd4_dec)nfsd4_decode_noop,
 +      [OP_LINK]               (nfsd4_dec)nfsd4_decode_link,
 +      [OP_LOCK]               (nfsd4_dec)nfsd4_decode_lock,
 +      [OP_LOCKT]              (nfsd4_dec)nfsd4_decode_lockt,
 +      [OP_LOCKU]              (nfsd4_dec)nfsd4_decode_locku,
 +      [OP_LOOKUP]             (nfsd4_dec)nfsd4_decode_lookup,
 +      [OP_LOOKUPP]            (nfsd4_dec)nfsd4_decode_noop,
 +      [OP_NVERIFY]            (nfsd4_dec)nfsd4_decode_verify,
 +      [OP_OPEN]               (nfsd4_dec)nfsd4_decode_open,
 +      [OP_OPENATTR]           (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_OPEN_CONFIRM]       (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_OPEN_DOWNGRADE]     (nfsd4_dec)nfsd4_decode_open_downgrade,
 +      [OP_PUTFH]              (nfsd4_dec)nfsd4_decode_putfh,
 +      [OP_PUTPUBFH]           (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_PUTROOTFH]          (nfsd4_dec)nfsd4_decode_noop,
 +      [OP_READ]               (nfsd4_dec)nfsd4_decode_read,
 +      [OP_READDIR]            (nfsd4_dec)nfsd4_decode_readdir,
 +      [OP_READLINK]           (nfsd4_dec)nfsd4_decode_noop,
 +      [OP_REMOVE]             (nfsd4_dec)nfsd4_decode_remove,
 +      [OP_RENAME]             (nfsd4_dec)nfsd4_decode_rename,
 +      [OP_RENEW]              (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_RESTOREFH]          (nfsd4_dec)nfsd4_decode_noop,
 +      [OP_SAVEFH]             (nfsd4_dec)nfsd4_decode_noop,
 +      [OP_SECINFO]            (nfsd4_dec)nfsd4_decode_secinfo,
 +      [OP_SETATTR]            (nfsd4_dec)nfsd4_decode_setattr,
 +      [OP_SETCLIENTID]        (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_SETCLIENTID_CONFIRM](nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_VERIFY]             (nfsd4_dec)nfsd4_decode_verify,
 +      [OP_WRITE]              (nfsd4_dec)nfsd4_decode_write,
 +      [OP_RELEASE_LOCKOWNER]  (nfsd4_dec)nfsd4_decode_notsupp,
  
        /* new operations for NFSv4.1 */
 -      [OP_BACKCHANNEL_CTL]    (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_BIND_CONN_TO_SESSION](nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_EXCHANGE_ID]        (nfsd4_dec)nfsd4_decode_exchange_id,
 -      [OP_CREATE_SESSION]     (nfsd4_dec)nfsd4_decode_create_session,
 -      [OP_DESTROY_SESSION]    (nfsd4_dec)nfsd4_decode_destroy_session,
 -      [OP_FREE_STATEID]       (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_GET_DIR_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_GETDEVICEINFO]      (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_GETDEVICELIST]      (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_LAYOUTCOMMIT]       (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_LAYOUTGET]          (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_LAYOUTRETURN]       (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_SECINFO_NO_NAME]    (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_SEQUENCE]           (nfsd4_dec)nfsd4_decode_sequence,
 -      [OP_SET_SSV]            (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_TEST_STATEID]       (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_WANT_DELEGATION]    (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_DESTROY_CLIENTID]   (nfsd4_dec)nfsd4_decode_notsupp,
 -      [OP_RECLAIM_COMPLETE]   (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_BACKCHANNEL_CTL]    (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_BIND_CONN_TO_SESSION](nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_EXCHANGE_ID]        (nfsd4_dec)nfsd4_decode_exchange_id,
 +      [OP_CREATE_SESSION]     (nfsd4_dec)nfsd4_decode_create_session,
 +      [OP_DESTROY_SESSION]    (nfsd4_dec)nfsd4_decode_destroy_session,
 +      [OP_FREE_STATEID]       (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_GET_DIR_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_GETDEVICEINFO]      (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_GETDEVICELIST]      (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_LAYOUTCOMMIT]       (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_LAYOUTGET]          (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_LAYOUTRETURN]       (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_SECINFO_NO_NAME]    (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_SEQUENCE]           (nfsd4_dec)nfsd4_decode_sequence,
 +      [OP_SET_SSV]            (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_TEST_STATEID]       (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_WANT_DELEGATION]    (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_DESTROY_CLIENTID]   (nfsd4_dec)nfsd4_decode_notsupp,
 +      [OP_RECLAIM_COMPLETE]   (nfsd4_dec)nfsd4_decode_notsupp,
  };
  
  struct nfsd4_minorversion_ops {
@@@ -1457,6 -1489,21 +1457,6 @@@ nfsd4_decode_compound(struct nfsd4_comp
  
        DECODE_TAIL;
  }
 -/*
 - * END OF "GENERIC" DECODE ROUTINES.
 - */
 -
 -/*
 - * START OF "GENERIC" ENCODE ROUTINES.
 - *   These may look a little ugly since they are imported from a "generic"
 - * set of XDR encode/decode routines which are intended to be shared by
 - * all of our NFSv4 implementations (OpenBSD, MacOS X...).
 - *
 - * If the pain of reading these is too great, it should be a straightforward
 - * task to translate them into Linux-specific versions which are more
 - * consistent with the style used in NFSv2/v3...
 - */
 -#define ENCODE_HEAD              __be32 *p
  
  #define WRITE32(n)               *p++ = htonl(n)
  #define WRITE64(n)               do {                         \
        memcpy(p, ptr, nbytes);                                 \
        p += XDR_QUADLEN(nbytes);                               \
  }} while (0)
 -#define WRITECINFO(c)         do {                            \
 -      *p++ = htonl(c.atomic);                                 \
 -      *p++ = htonl(c.before_ctime_sec);                               \
 -      *p++ = htonl(c.before_ctime_nsec);                              \
 -      *p++ = htonl(c.after_ctime_sec);                                \
 -      *p++ = htonl(c.after_ctime_nsec);                               \
 -} while (0)
 +
 +static void write32(__be32 **p, u32 n)
 +{
 +      *(*p)++ = n;
 +}
 +
 +static void write64(__be32 **p, u64 n)
 +{
 +      write32(p, (u32)(n >> 32));
 +      write32(p, (u32)n);
 +}
 +
 +static void write_change(__be32 **p, struct kstat *stat, struct inode *inode)
 +{
 +      if (IS_I_VERSION(inode)) {
 +              write64(p, inode->i_version);
 +      } else {
 +              write32(p, stat->ctime.tv_sec);
 +              write32(p, stat->ctime.tv_nsec);
 +      }
 +}
 +
 +static void write_cinfo(__be32 **p, struct nfsd4_change_info *c)
 +{
 +      write32(p, c->atomic);
 +      if (c->change_supported) {
 +              write64(p, c->before_change);
 +              write64(p, c->after_change);
 +      } else {
 +              write32(p, c->before_ctime_sec);
 +              write32(p, c->before_ctime_nsec);
 +              write32(p, c->after_ctime_sec);
 +              write32(p, c->after_ctime_nsec);
 +      }
 +}
  
  #define RESERVE_SPACE(nbytes) do {                            \
        p = resp->p;                                            \
@@@ -1855,9 -1874,16 +1855,9 @@@ nfsd4_encode_fattr(struct svc_fh *fhp, 
                        WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME);
        }
        if (bmval0 & FATTR4_WORD0_CHANGE) {
 -              /*
 -               * Note: This _must_ be consistent with the scheme for writing
 -               * change_info, so any changes made here must be reflected there
 -               * as well.  (See xdr4.h:set_change_info() and the WRITECINFO()
 -               * macro above.)
 -               */
                if ((buflen -= 8) < 0)
                        goto out_resource;
 -              WRITE32(stat.ctime.tv_sec);
 -              WRITE32(stat.ctime.tv_nsec);
 +              write_change(&p, &stat, dentry->d_inode);
        }
        if (bmval0 & FATTR4_WORD0_SIZE) {
                if ((buflen -= 8) < 0)
@@@ -2188,6 -2214,15 +2188,15 @@@ nfsd4_encode_dirent_fattr(struct nfsd4_
        dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
        if (IS_ERR(dentry))
                return nfserrno(PTR_ERR(dentry));
+       if (!dentry->d_inode) {
+               /*
+                * nfsd_buffered_readdir drops the i_mutex between
+                * readdir and calling this callback, leaving a window
+                * where this directory entry could have gone away.
+                */
+               dput(dentry);
+               return nfserr_noent;
+       }
  
        exp_get(exp);
        /*
@@@ -2250,6 -2285,7 +2259,7 @@@ nfsd4_encode_dirent(void *ccdv, const c
        struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
        int buflen;
        __be32 *p = cd->buffer;
+       __be32 *cookiep;
        __be32 nfserr = nfserr_toosmall;
  
        /* In nfsv4, "." and ".." never make it onto the wire.. */
                goto fail;
  
        *p++ = xdr_one;                             /* mark entry present */
-       cd->offset = p;                             /* remember pointer */
+       cookiep = p;
        p = xdr_encode_hyper(p, NFS_OFFSET_MAX);    /* offset of next entry */
        p = xdr_encode_array(p, name, namlen);      /* name length & name */
  
                goto fail;
        case nfserr_dropit:
                goto fail;
+       case nfserr_noent:
+               goto skip_entry;
        default:
                /*
                 * If the client requested the RDATTR_ERROR attribute,
        }
        cd->buflen -= (p - cd->buffer);
        cd->buffer = p;
+       cd->offset = cookiep;
+ skip_entry:
        cd->common.err = nfs_ok;
        return 0;
  fail:
  static void
  nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        RESERVE_SPACE(sizeof(stateid_t));
        WRITE32(sid->si_generation);
  static __be32
  nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (!nfserr) {
                RESERVE_SPACE(8);
@@@ -2346,7 -2386,7 +2360,7 @@@ nfsd4_encode_close(struct nfsd4_compoun
  static __be32
  nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (!nfserr) {
                RESERVE_SPACE(8);
  static __be32
  nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (!nfserr) {
                RESERVE_SPACE(32);
 -              WRITECINFO(create->cr_cinfo);
 +              write_cinfo(&p, &create->cr_cinfo);
                WRITE32(2);
                WRITE32(create->cr_bmval[0]);
                WRITE32(create->cr_bmval[1]);
@@@ -2395,7 -2435,7 +2409,7 @@@ nfsd4_encode_getfh(struct nfsd4_compoun
  {
        struct svc_fh *fhp = *fhpp;
        unsigned int len;
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (!nfserr) {
                len = fhp->fh_handle.fh_size;
  static void
  nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0));
        WRITE64(ld->ld_start);
@@@ -2470,11 -2510,11 +2484,11 @@@ nfsd4_encode_locku(struct nfsd4_compoun
  static __be32
  nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (!nfserr) {
                RESERVE_SPACE(20);
 -              WRITECINFO(link->li_cinfo);
 +              write_cinfo(&p, &link->li_cinfo);
                ADJUST_ARGS();
        }
        return nfserr;
  static __be32
  nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
        ENCODE_SEQID_OP_HEAD;
  
        if (nfserr)
  
        nfsd4_encode_stateid(resp, &open->op_stateid);
        RESERVE_SPACE(40);
 -      WRITECINFO(open->op_cinfo);
 +      write_cinfo(&p, &open->op_cinfo);
        WRITE32(open->op_rflags);
        WRITE32(2);
        WRITE32(open->op_bmval[0]);
@@@ -2579,7 -2619,7 +2593,7 @@@ nfsd4_encode_read(struct nfsd4_compound
        int v, pn;
        unsigned long maxcount; 
        long len;
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (nfserr)
                return nfserr;
@@@ -2641,7 -2681,7 +2655,7 @@@ nfsd4_encode_readlink(struct nfsd4_comp
  {
        int maxcount;
        char *page;
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (nfserr)
                return nfserr;
@@@ -2690,7 -2730,7 +2704,7 @@@ nfsd4_encode_readdir(struct nfsd4_compo
        int maxcount;
        loff_t offset;
        __be32 *page, *savep, *tailbase;
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (nfserr)
                return nfserr;
@@@ -2766,11 -2806,11 +2780,11 @@@ err_no_verf
  static __be32
  nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (!nfserr) {
                RESERVE_SPACE(20);
 -              WRITECINFO(remove->rm_cinfo);
 +              write_cinfo(&p, &remove->rm_cinfo);
                ADJUST_ARGS();
        }
        return nfserr;
  static __be32
  nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (!nfserr) {
                RESERVE_SPACE(40);
 -              WRITECINFO(rename->rn_sinfo);
 -              WRITECINFO(rename->rn_tinfo);
 +              write_cinfo(&p, &rename->rn_sinfo);
 +              write_cinfo(&p, &rename->rn_tinfo);
                ADJUST_ARGS();
        }
        return nfserr;
@@@ -2799,7 -2839,7 +2813,7 @@@ nfsd4_encode_secinfo(struct nfsd4_compo
        u32 nflavs;
        struct exp_flavor_info *flavs;
        struct exp_flavor_info def_flavs[2];
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (nfserr)
                goto out;
@@@ -2864,7 -2904,7 +2878,7 @@@ out
  static __be32
  nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        RESERVE_SPACE(12);
        if (nfserr) {
  static __be32
  nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (!nfserr) {
                RESERVE_SPACE(8 + sizeof(nfs4_verifier));
  static __be32
  nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (!nfserr) {
                RESERVE_SPACE(16);
@@@ -2920,7 -2960,7 +2934,7 @@@ static __be3
  nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr,
                         struct nfsd4_exchange_id *exid)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
        char *major_id;
        char *server_scope;
        int major_id_sz;
@@@ -2975,7 -3015,7 +2989,7 @@@ static __be3
  nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr,
                            struct nfsd4_create_session *sess)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (nfserr)
                return nfserr;
@@@ -3031,7 -3071,7 +3045,7 @@@ __be3
  nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
                      struct nfsd4_sequence *seq)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        if (nfserr)
                return nfserr;
@@@ -3179,7 -3219,7 +3193,7 @@@ voi
  nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
  {
        __be32 *statp;
 -      ENCODE_HEAD;
 +      __be32 *p;
  
        RESERVE_SPACE(8);
        WRITE32(op->opnum);
@@@ -3213,7 -3253,7 +3227,7 @@@ status
  void
  nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
  {
 -      ENCODE_HEAD;
 +      __be32 *p;
        struct nfs4_replay *rp = op->replay;
  
        BUG_ON(!rp);
        ADJUST_ARGS();
  }
  
 -/*
 - * END OF "GENERIC" ENCODE ROUTINES.
 - */
 -
  int
  nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
  {
diff --combined include/linux/fs.h
@@@ -1108,7 -1108,6 +1108,7 @@@ extern void locks_copy_lock(struct file
  extern void __locks_copy_lock(struct file_lock *, const struct file_lock *);
  extern void locks_remove_posix(struct file *, fl_owner_t);
  extern void locks_remove_flock(struct file *);
 +extern void locks_release_private(struct file_lock *);
  extern void posix_test_lock(struct file *, struct file_lock *);
  extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
  extern int posix_lock_file_wait(struct file *, struct file_lock *);
@@@ -1776,6 -1775,7 +1776,7 @@@ void kill_block_super(struct super_bloc
  void kill_anon_super(struct super_block *sb);
  void kill_litter_super(struct super_block *sb);
  void deactivate_super(struct super_block *sb);
+ void deactivate_locked_super(struct super_block *sb);
  int set_anon_super(struct super_block *s, void *data);
  struct super_block *sget(struct file_system_type *type,
                        int (*test)(struct super_block *,void *),
@@@ -2118,7 -2118,7 +2119,7 @@@ extern struct file *create_write_pipe(i
  extern void free_write_pipe(struct file *);
  
  extern struct file *do_filp_open(int dfd, const char *pathname,
-               int open_flag, int mode);
+               int open_flag, int mode, int acc_mode);
  extern int may_open(struct path *, int, int);
  
  extern int kernel_read(struct file *, unsigned long, char *, unsigned long);
@@@ -2368,6 -2368,7 +2369,7 @@@ extern void file_update_time(struct fil
  
  extern int generic_show_options(struct seq_file *m, struct vfsmount *mnt);
  extern void save_mount_options(struct super_block *sb, char *options);
+ extern void replace_mount_options(struct super_block *sb, char *options);
  
  static inline ino_t parent_ino(struct dentry *dentry)
  {
diff --combined net/sunrpc/svcsock.c
@@@ -240,76 -240,42 +240,76 @@@ out
  /*
   * Report socket names for nfsdfs
   */
 -static int one_sock_name(char *buf, struct svc_sock *svsk)
 +static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining)
  {
 +      const struct sock *sk = svsk->sk_sk;
 +      const char *proto_name = sk->sk_protocol == IPPROTO_UDP ?
 +                                                      "udp" : "tcp";
        int len;
  
 -      switch(svsk->sk_sk->sk_family) {
 -      case AF_INET:
 -              len = sprintf(buf, "ipv4 %s %pI4 %d\n",
 -                            svsk->sk_sk->sk_protocol == IPPROTO_UDP ?
 -                            "udp" : "tcp",
 -                            &inet_sk(svsk->sk_sk)->rcv_saddr,
 -                            inet_sk(svsk->sk_sk)->num);
 +      switch (sk->sk_family) {
 +      case PF_INET:
 +              len = snprintf(buf, remaining, "ipv4 %s %pI4 %d\n",
 +                              proto_name,
 +                              &inet_sk(sk)->rcv_saddr,
 +                              inet_sk(sk)->num);
 +              break;
 +      case PF_INET6:
 +              len = snprintf(buf, remaining, "ipv6 %s %pI6 %d\n",
 +                              proto_name,
 +                              &inet6_sk(sk)->rcv_saddr,
 +                              inet_sk(sk)->num);
                break;
        default:
 -              len = sprintf(buf, "*unknown-%d*\n",
 -                             svsk->sk_sk->sk_family);
 +              len = snprintf(buf, remaining, "*unknown-%d*\n",
 +                              sk->sk_family);
 +      }
 +
 +      if (len >= remaining) {
 +              *buf = '\0';
 +              return -ENAMETOOLONG;
        }
        return len;
  }
  
 -int
 -svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
 +/**
 + * svc_sock_names - construct a list of listener names in a string
 + * @serv: pointer to RPC service
 + * @buf: pointer to a buffer to fill in with socket names
 + * @buflen: size of the buffer to be filled
 + * @toclose: pointer to '\0'-terminated C string containing the name
 + *            of a listener to be closed
 + *
 + * Fills in @buf with a '\n'-separated list of names of listener
 + * sockets.  If @toclose is not NULL, the socket named by @toclose
 + * is closed, and is not included in the output list.
 + *
 + * Returns positive length of the socket name string, or a negative
 + * errno value on error.
 + */
 +int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen,
 +                 const char *toclose)
  {
        struct svc_sock *svsk, *closesk = NULL;
        int len = 0;
  
        if (!serv)
                return 0;
 +
        spin_lock_bh(&serv->sv_lock);
        list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) {
 -              int onelen = one_sock_name(buf+len, svsk);
 -              if (toclose && strcmp(toclose, buf+len) == 0)
 +              int onelen = svc_one_sock_name(svsk, buf + len, buflen - len);
 +              if (onelen < 0) {
 +                      len = onelen;
 +                      break;
 +              }
 +              if (toclose && strcmp(toclose, buf + len) == 0)
                        closesk = svsk;
                else
                        len += onelen;
        }
        spin_unlock_bh(&serv->sv_lock);
 +
        if (closesk)
                /* Should unregister with portmap, but you cannot
                 * unregister just one protocol...
@@@ -379,6 -345,7 +379,7 @@@ static void svc_sock_setbufsize(struct 
        lock_sock(sock->sk);
        sock->sk->sk_sndbuf = snd * 2;
        sock->sk->sk_rcvbuf = rcv * 2;
+       sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK;
        release_sock(sock->sk);
  #endif
  }
@@@ -460,14 -427,13 +461,14 @@@ static int svc_udp_recvfrom(struct svc_
                long            all[SVC_PKTINFO_SPACE / sizeof(long)];
        } buffer;
        struct cmsghdr *cmh = &buffer.hdr;
 -      int             err, len;
        struct msghdr msg = {
                .msg_name = svc_addr(rqstp),
                .msg_control = cmh,
                .msg_controllen = sizeof(buffer),
                .msg_flags = MSG_DONTWAIT,
        };
 +      size_t len;
 +      int err;
  
        if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
            /* udp sockets need large rcvbuf as all pending
                return -EAGAIN;
        }
        len = svc_addr_len(svc_addr(rqstp));
 -      if (len < 0)
 -              return len;
 +      if (len == 0)
 +              return -EAFNOSUPPORT;
        rqstp->rq_addrlen = len;
        if (skb->tstamp.tv64 == 0) {
                skb->tstamp = ktime_get_real();
@@@ -831,6 -797,23 +832,23 @@@ static int svc_tcp_recvfrom(struct svc_
                test_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags),
                test_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags));
  
+       if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
+               /* sndbuf needs to have room for one request
+                * per thread, otherwise we can stall even when the
+                * network isn't a bottleneck.
+                *
+                * We count all threads rather than threads in a
+                * particular pool, which provides an upper bound
+                * on the number of threads which will access the socket.
+                *
+                * rcvbuf just needs to be able to hold a few requests.
+                * Normally they will be removed from the queue
+                * as soon a a complete request arrives.
+                */
+               svc_sock_setbufsize(svsk->sk_sock,
+                                   (serv->sv_nrthreads+3) * serv->sv_max_mesg,
+                                   3 * serv->sv_max_mesg);
        clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
  
        /* Receive data. If we haven't got the record length yet, get
@@@ -1078,6 -1061,15 +1096,15 @@@ static void svc_tcp_init(struct svc_soc
  
                tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
  
+               /* initialise setting must have enough space to
+                * receive and respond to one request.
+                * svc_tcp_recvfrom will re-adjust if necessary
+                */
+               svc_sock_setbufsize(svsk->sk_sock,
+                                   3 * svsk->sk_xprt.xpt_server->sv_max_mesg,
+                                   3 * svsk->sk_xprt.xpt_server->sv_max_mesg);
+               set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
                set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
                if (sk->sk_state != TCP_ESTABLISHED)
                        set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
@@@ -1147,14 -1139,8 +1174,8 @@@ static struct svc_sock *svc_setup_socke
        /* Initialize the socket */
        if (sock->type == SOCK_DGRAM)
                svc_udp_init(svsk, serv);
-       else {
-               /* initialise setting must have enough space to
-                * receive and respond to one request.
-                */
-               svc_sock_setbufsize(svsk->sk_sock, 4 * serv->sv_max_mesg,
-                                       4 * serv->sv_max_mesg);
+       else
                svc_tcp_init(svsk, serv);
-       }
  
        dprintk("svc: svc_setup_socket created %p (inet %p)\n",
                                svsk, svsk->sk_sk);
        return svsk;
  }
  
 -int svc_addsock(struct svc_serv *serv,
 -              int fd,
 -              char *name_return)
 +/**
 + * svc_addsock - add a listener socket to an RPC service
 + * @serv: pointer to RPC service to which to add a new listener
 + * @fd: file descriptor of the new listener
 + * @name_return: pointer to buffer to fill in with name of listener
 + * @len: size of the buffer
 + *
 + * Fills in socket name and returns positive length of name if successful.
 + * Name is terminated with '\n'.  On error, returns a negative errno
 + * value.
 + */
 +int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
 +              const size_t len)
  {
        int err = 0;
        struct socket *so = sockfd_lookup(fd, &err);
                sockfd_put(so);
                return err;
        }
 -      return one_sock_name(name_return, svsk);
 +      return svc_one_sock_name(svsk, name_return, len);
  }
  EXPORT_SYMBOL_GPL(svc_addsock);