Merge branch 'for-3.15' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 9 Apr 2014 01:28:14 +0000 (18:28 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 9 Apr 2014 01:28:14 +0000 (18:28 -0700)
Pull nfsd updates from Bruce Fields:
 "Highlights:
   - server-side nfs/rdma fixes from Jeff Layton and Tom Tucker
   - xdr fixes (a larger xdr rewrite has been posted but I decided it
     would be better to queue it up for 3.16).
   - miscellaneous fixes and cleanup from all over (thanks especially to
     Kinglong Mee)"

* 'for-3.15' of git://linux-nfs.org/~bfields/linux: (36 commits)
  nfsd4: don't create unnecessary mask acl
  nfsd: revert v2 half of "nfsd: don't return high mode bits"
  nfsd4: fix memory leak in nfsd4_encode_fattr()
  nfsd: check passed socket's net matches NFSd superblock's one
  SUNRPC: Clear xpt_bc_xprt if xs_setup_bc_tcp failed
  NFSD/SUNRPC: Check rpc_xprt out of xs_setup_bc_tcp
  SUNRPC: New helper for creating client with rpc_xprt
  NFSD: Free backchannel xprt in bc_destroy
  NFSD: Clear wcc data between compound ops
  nfsd: Don't return NFS4ERR_STALE_STATEID for NFSv4.1+
  nfsd4: fix nfs4err_resource in 4.1 case
  nfsd4: fix setclientid encode size
  nfsd4: remove redundant check from nfsd4_check_resp_size
  nfsd4: use more generous NFS4_ACL_MAX
  nfsd4: minor nfsd4_replay_cache_entry cleanup
  nfsd4: nfsd4_replay_cache_entry should be static
  nfsd4: update comments with obsolete function name
  rpc: Allow xdr_buf_subsegment to operate in-place
  NFSD: Using free_conn free connection
  SUNRPC: fix memory leak of peer addresses in XPRT
  ...

1  2 
fs/nfsd/vfs.c
net/sunrpc/clnt.c
net/sunrpc/xprtsock.c

diff --combined fs/nfsd/vfs.c
index 915808b36df76142634478b02832c90676202275,4d8dcd62481e1e682f1774eb0b19070eabc3a0a3..16f0673a423c0884772cb2fffbfcf96b86cc3e65
@@@ -404,6 -404,7 +404,7 @@@ nfsd_setattr(struct svc_rqst *rqstp, st
        umode_t         ftype = 0;
        __be32          err;
        int             host_err;
+       bool            get_write_count;
        int             size_change = 0;
  
        if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
        if (iap->ia_valid & ATTR_SIZE)
                ftype = S_IFREG;
  
+       /* Callers that do fh_verify should do the fh_want_write: */
+       get_write_count = !fhp->fh_dentry;
        /* Get inode */
        err = fh_verify(rqstp, fhp, ftype, accmode);
        if (err)
                goto out;
+       if (get_write_count) {
+               host_err = fh_want_write(fhp);
+               if (host_err)
+                       return nfserrno(host_err);
+       }
  
        dentry = fhp->fh_dentry;
        inode = dentry->d_inode;
@@@ -1694,7 -1703,7 +1703,7 @@@ nfsd_rename(struct svc_rqst *rqstp, str
        if (ffhp->fh_export->ex_path.dentry != tfhp->fh_export->ex_path.dentry)
                goto out_dput_new;
  
 -      host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL);
 +      host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL, 0);
        if (!host_err) {
                host_err = commit_metadata(tfhp);
                if (!host_err)
        dput(odentry);
   out_nfserr:
        err = nfserrno(host_err);
-       /* we cannot reply on fh_unlock on the two filehandles,
+       /*
+        * We cannot rely on fh_unlock on the two filehandles,
         * as that would do the wrong thing if the two directories
-        * were the same, so again we do it by hand
+        * were the same, so again we do it by hand.
         */
        fill_post_wcc(ffhp);
        fill_post_wcc(tfhp);
diff --combined net/sunrpc/clnt.c
index f400445d1a44317ea6d9300f600c43c3bfb1e74f,3c9a0f02374d4f98b907282bfedac3cb5bdf8b96..2e6ab10734f6869af45a422bad6253e9de5cd580
@@@ -438,6 -438,38 +438,38 @@@ out_no_rpciod
        return ERR_PTR(err);
  }
  
+ struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
+                                       struct rpc_xprt *xprt)
+ {
+       struct rpc_clnt *clnt = NULL;
+       clnt = rpc_new_client(args, xprt, NULL);
+       if (IS_ERR(clnt))
+               return clnt;
+       if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
+               int err = rpc_ping(clnt);
+               if (err != 0) {
+                       rpc_shutdown_client(clnt);
+                       return ERR_PTR(err);
+               }
+       }
+       clnt->cl_softrtry = 1;
+       if (args->flags & RPC_CLNT_CREATE_HARDRTRY)
+               clnt->cl_softrtry = 0;
+       if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
+               clnt->cl_autobind = 1;
+       if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
+               clnt->cl_discrtry = 1;
+       if (!(args->flags & RPC_CLNT_CREATE_QUIET))
+               clnt->cl_chatty = 1;
+       return clnt;
+ }
+ EXPORT_SYMBOL_GPL(rpc_create_xprt);
  /**
   * rpc_create - create an RPC client and transport with one call
   * @args: rpc_clnt create argument structure
  struct rpc_clnt *rpc_create(struct rpc_create_args *args)
  {
        struct rpc_xprt *xprt;
-       struct rpc_clnt *clnt;
        struct xprt_create xprtargs = {
                .net = args->net,
                .ident = args->protocol,
        if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
                xprt->resvport = 0;
  
-       clnt = rpc_new_client(args, xprt, NULL);
-       if (IS_ERR(clnt))
-               return clnt;
-       if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
-               int err = rpc_ping(clnt);
-               if (err != 0) {
-                       rpc_shutdown_client(clnt);
-                       return ERR_PTR(err);
-               }
-       }
-       clnt->cl_softrtry = 1;
-       if (args->flags & RPC_CLNT_CREATE_HARDRTRY)
-               clnt->cl_softrtry = 0;
-       if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
-               clnt->cl_autobind = 1;
-       if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
-               clnt->cl_discrtry = 1;
-       if (!(args->flags & RPC_CLNT_CREATE_QUIET))
-               clnt->cl_chatty = 1;
-       return clnt;
+       return rpc_create_xprt(args, xprt);
  }
  EXPORT_SYMBOL_GPL(rpc_create);
  
@@@ -1363,7 -1371,6 +1371,7 @@@ rpc_restart_call_prepare(struct rpc_tas
        if (RPC_ASSASSINATED(task))
                return 0;
        task->tk_action = call_start;
 +      task->tk_status = 0;
        if (task->tk_ops->rpc_call_prepare != NULL)
                task->tk_action = rpc_prepare_task;
        return 1;
@@@ -1380,7 -1387,6 +1388,7 @@@ rpc_restart_call(struct rpc_task *task
        if (RPC_ASSASSINATED(task))
                return 0;
        task->tk_action = call_start;
 +      task->tk_status = 0;
        return 1;
  }
  EXPORT_SYMBOL_GPL(rpc_restart_call);
@@@ -1730,7 -1736,9 +1738,7 @@@ call_bind_status(struct rpc_task *task
        case -EPROTONOSUPPORT:
                dprintk("RPC: %5u remote rpcbind version unavailable, retrying\n",
                                task->tk_pid);
 -              task->tk_status = 0;
 -              task->tk_action = call_bind;
 -              return;
 +              goto retry_timeout;
        case -ECONNREFUSED:             /* connection problems */
        case -ECONNRESET:
        case -ECONNABORTED:
        return;
  
  retry_timeout:
 +      task->tk_status = 0;
        task->tk_action = call_timeout;
  }
  
@@@ -1799,19 -1806,21 +1807,19 @@@ call_connect_status(struct rpc_task *ta
        trace_rpc_connect_status(task, status);
        task->tk_status = 0;
        switch (status) {
 -              /* if soft mounted, test if we've timed out */
 -      case -ETIMEDOUT:
 -              task->tk_action = call_timeout;
 -              return;
        case -ECONNREFUSED:
        case -ECONNRESET:
        case -ECONNABORTED:
        case -ENETUNREACH:
        case -EHOSTUNREACH:
 -              /* retry with existing socket, after a delay */
 -              rpc_delay(task, 3*HZ);
                if (RPC_IS_SOFTCONN(task))
                        break;
 +              /* retry with existing socket, after a delay */
 +              rpc_delay(task, 3*HZ);
        case -EAGAIN:
 -              task->tk_action = call_bind;
 +              /* Check for timeouts before looping back to call_bind */
 +      case -ETIMEDOUT:
 +              task->tk_action = call_timeout;
                return;
        case 0:
                clnt->cl_stats->netreconn++;
@@@ -2006,10 -2015,6 +2014,10 @@@ call_status(struct rpc_task *task
        case -EHOSTDOWN:
        case -EHOSTUNREACH:
        case -ENETUNREACH:
 +              if (RPC_IS_SOFTCONN(task)) {
 +                      rpc_exit(task, status);
 +                      break;
 +              }
                /*
                 * Delay any retries for 3 seconds, then handle as if it
                 * were a timeout.
diff --combined net/sunrpc/xprtsock.c
index 966763d735e9f34164a32d85b15ae9d8c0081f1a,3e251b81d26aeed03d293dc67865e091f6e93174..6735e1d1e9bb4dcf6c550c20e622bbeb43dc335c
@@@ -510,7 -510,6 +510,7 @@@ static int xs_nospace(struct rpc_task *
        struct rpc_rqst *req = task->tk_rqstp;
        struct rpc_xprt *xprt = req->rq_xprt;
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
 +      struct sock *sk = transport->inet;
        int ret = -EAGAIN;
  
        dprintk("RPC: %5u xmit incomplete (%u left of %u)\n",
                         * window size
                         */
                        set_bit(SOCK_NOSPACE, &transport->sock->flags);
 -                      transport->inet->sk_write_pending++;
 +                      sk->sk_write_pending++;
                        /* ...and wait for more buffer space */
                        xprt_wait_for_buffer_space(task, xs_nospace_callback);
                }
        }
  
        spin_unlock_bh(&xprt->transport_lock);
 +
 +      /* Race breaker in case memory is freed before above code is called */
 +      sk->sk_write_space(sk);
        return ret;
  }
  
@@@ -909,6 -905,12 +909,12 @@@ static void xs_tcp_close(struct rpc_xpr
                xs_tcp_shutdown(xprt);
  }
  
+ static void xs_xprt_free(struct rpc_xprt *xprt)
+ {
+       xs_free_peer_addresses(xprt);
+       xprt_free(xprt);
+ }
  /**
   * xs_destroy - prepare to shutdown a transport
   * @xprt: doomed transport
@@@ -919,8 -921,7 +925,7 @@@ static void xs_destroy(struct rpc_xprt 
        dprintk("RPC:       xs_destroy xprt %p\n", xprt);
  
        xs_close(xprt);
-       xs_free_peer_addresses(xprt);
-       xprt_free(xprt);
+       xs_xprt_free(xprt);
        module_put(THIS_MODULE);
  }
  
@@@ -1306,29 -1307,41 +1311,29 @@@ static inline int xs_tcp_read_reply(str
   * If we're unable to obtain the rpc_rqst we schedule the closing of the
   * connection and return -1.
   */
 -static inline int xs_tcp_read_callback(struct rpc_xprt *xprt,
 +static int xs_tcp_read_callback(struct rpc_xprt *xprt,
                                       struct xdr_skb_reader *desc)
  {
        struct sock_xprt *transport =
                                container_of(xprt, struct sock_xprt, xprt);
        struct rpc_rqst *req;
  
 -      req = xprt_alloc_bc_request(xprt);
 +      /* Look up and lock the request corresponding to the given XID */
 +      spin_lock(&xprt->transport_lock);
 +      req = xprt_lookup_bc_request(xprt, transport->tcp_xid);
        if (req == NULL) {
 +              spin_unlock(&xprt->transport_lock);
                printk(KERN_WARNING "Callback slot table overflowed\n");
                xprt_force_disconnect(xprt);
                return -1;
        }
  
 -      req->rq_xid = transport->tcp_xid;
        dprintk("RPC:       read callback  XID %08x\n", ntohl(req->rq_xid));
        xs_tcp_read_common(xprt, desc, req);
  
 -      if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) {
 -              struct svc_serv *bc_serv = xprt->bc_serv;
 -
 -              /*
 -               * Add callback request to callback list.  The callback
 -               * service sleeps on the sv_cb_waitq waiting for new
 -               * requests.  Wake it up after adding enqueing the
 -               * request.
 -               */
 -              dprintk("RPC:       add callback request to list\n");
 -              spin_lock(&bc_serv->sv_cb_lock);
 -              list_add(&req->rq_bc_list, &bc_serv->sv_cb_list);
 -              spin_unlock(&bc_serv->sv_cb_lock);
 -              wake_up(&bc_serv->sv_cb_waitq);
 -      }
 -
 -      req->rq_private_buf.len = transport->tcp_copied;
 +      if (!(transport->tcp_flags & TCP_RCV_COPY_DATA))
 +              xprt_complete_bc_request(req, transport->tcp_copied);
 +      spin_unlock(&xprt->transport_lock);
  
        return 0;
  }
@@@ -2532,6 -2545,10 +2537,10 @@@ static void bc_close(struct rpc_xprt *x
  
  static void bc_destroy(struct rpc_xprt *xprt)
  {
+       dprintk("RPC:       bc_destroy xprt %p\n", xprt);
+       xs_xprt_free(xprt);
+       module_put(THIS_MODULE);
  }
  
  static struct rpc_xprt_ops xs_local_ops = {
@@@ -2732,7 -2749,7 +2741,7 @@@ static struct rpc_xprt *xs_setup_local(
                return xprt;
        ret = ERR_PTR(-EINVAL);
  out_err:
-       xprt_free(xprt);
+       xs_xprt_free(xprt);
        return ret;
  }
  
@@@ -2810,7 -2827,7 +2819,7 @@@ static struct rpc_xprt *xs_setup_udp(st
                return xprt;
        ret = ERR_PTR(-EINVAL);
  out_err:
-       xprt_free(xprt);
+       xs_xprt_free(xprt);
        return ret;
  }
  
@@@ -2885,12 -2902,11 +2894,11 @@@ static struct rpc_xprt *xs_setup_tcp(st
                                xprt->address_strings[RPC_DISPLAY_ADDR],
                                xprt->address_strings[RPC_DISPLAY_PROTO]);
  
        if (try_module_get(THIS_MODULE))
                return xprt;
        ret = ERR_PTR(-EINVAL);
  out_err:
-       xprt_free(xprt);
+       xs_xprt_free(xprt);
        return ret;
  }
  
@@@ -2907,15 -2923,6 +2915,6 @@@ static struct rpc_xprt *xs_setup_bc_tcp
        struct svc_sock *bc_sock;
        struct rpc_xprt *ret;
  
-       if (args->bc_xprt->xpt_bc_xprt) {
-               /*
-                * This server connection already has a backchannel
-                * transport; we can't create a new one, as we wouldn't
-                * be able to match replies based on xid any more.  So,
-                * reuse the already-existing one:
-                */
-                return args->bc_xprt->xpt_bc_xprt;
-       }
        xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries,
                        xprt_tcp_slot_table_entries);
        if (IS_ERR(xprt))
         */
        xprt_set_connected(xprt);
  
        if (try_module_get(THIS_MODULE))
                return xprt;
+       args->bc_xprt->xpt_bc_xprt = NULL;
        xprt_put(xprt);
        ret = ERR_PTR(-EINVAL);
  out_err:
-       xprt_free(xprt);
+       xs_xprt_free(xprt);
        return ret;
  }