NFSv4: Remove requirement for machine creds for the "renew" operation
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 3 Jan 2006 08:55:25 +0000 (09:55 +0100)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 6 Jan 2006 19:58:47 +0000 (14:58 -0500)
 In RFC3530, the RENEW operation is allowed to use either

 the same principal, RPC security flavour and (if RPCSEC_GSS), the same
  mechanism and service that was used for SETCLIENTID_CONFIRM

 OR

 Any principal, RPC security flavour and service combination that
 currently has an OPEN file on the server.

 Choose the latter since that doesn't require us to keep credentials for
 the same principal for the entire duration of the mount.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4renewd.c
fs/nfs/nfs4state.c

index 75fe646c28ab63906c9fd376458dae41627a3bef..4a9c53e0793c95e49f7010db5663ab1d5ef74731 100644 (file)
@@ -213,8 +213,8 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t);
 extern int nfs4_map_errors(int err);
 extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short);
 extern int nfs4_proc_setclientid_confirm(struct nfs4_client *);
-extern int nfs4_proc_async_renew(struct nfs4_client *);
-extern int nfs4_proc_renew(struct nfs4_client *);
+extern int nfs4_proc_async_renew(struct nfs4_client *, struct rpc_cred *);
+extern int nfs4_proc_renew(struct nfs4_client *, struct rpc_cred *);
 extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
 extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
 extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
@@ -240,6 +240,7 @@ extern struct nfs4_client *nfs4_get_client(struct in_addr *);
 extern void nfs4_put_client(struct nfs4_client *clp);
 extern int nfs4_init_client(struct nfs4_client *clp);
 extern struct nfs4_client *nfs4_find_client(struct in_addr *);
+struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp);
 extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *);
 
 extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
index cc33a1c32cfba19183f960404675ad42be073f46..e384019312914b5ad25dcfcd038e65a85b10e8d8 100644 (file)
@@ -850,9 +850,14 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred
        int open_flags = flags & (FMODE_READ|FMODE_WRITE);
        int err;
 
+       err = -ENOMEM;
+       if (!(sp = nfs4_get_state_owner(server, cred))) {
+               dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__);
+               return err;
+       }
        err = nfs4_recover_expired_lease(server);
        if (err != 0)
-               return err;
+               goto out_put_state_owner;
        /* Protect against reboot recovery - NOTE ORDER! */
        down_read(&clp->cl_sem);
        /* Protect against delegation recall */
@@ -862,10 +867,6 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred
        if (delegation == NULL || (delegation->type & open_flags) != open_flags)
                goto out_err;
        err = -ENOMEM;
-       if (!(sp = nfs4_get_state_owner(server, cred))) {
-               dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__);
-               goto out_err;
-       }
        state = nfs4_get_open_state(inode, sp);
        if (state == NULL)
                goto out_err;
@@ -877,13 +878,13 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred
                spin_unlock(&inode->i_lock);
                goto out_ok;
        } else if (state->state != 0)
-               goto out_err;
+               goto out_put_open_state;
 
        lock_kernel();
        err = _nfs4_do_access(inode, cred, open_flags);
        unlock_kernel();
        if (err != 0)
-               goto out_err;
+               goto out_put_open_state;
        set_bit(NFS_DELEGATED_STATE, &state->flags);
        update_open_stateid(state, &delegation->stateid, open_flags);
 out_ok:
@@ -891,17 +892,16 @@ out_ok:
        up_read(&nfsi->rwsem);
        up_read(&clp->cl_sem);
        *res = state;
-       return 0; 
+       return 0;
+out_put_open_state:
+       nfs4_put_open_state(state);
 out_err:
-       if (sp != NULL) {
-               if (state != NULL)
-                       nfs4_put_open_state(state);
-               nfs4_put_state_owner(sp);
-       }
        up_read(&nfsi->rwsem);
        up_read(&clp->cl_sem);
        if (err != -EACCES)
                nfs_inode_return_delegation(inode);
+out_put_state_owner:
+       nfs4_put_state_owner(sp);
        return err;
 }
 
@@ -941,7 +941,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
        }
        status = nfs4_recover_expired_lease(server);
        if (status != 0)
-               goto out_err;
+               goto err_put_state_owner;
        down_read(&clp->cl_sem);
        status = -ENOMEM;
        opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr);
@@ -2518,26 +2518,24 @@ static const struct rpc_call_ops nfs4_renew_ops = {
        .rpc_call_done = nfs4_renew_done,
 };
 
-int
-nfs4_proc_async_renew(struct nfs4_client *clp)
+int nfs4_proc_async_renew(struct nfs4_client *clp, struct rpc_cred *cred)
 {
        struct rpc_message msg = {
                .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
                .rpc_argp       = clp,
-               .rpc_cred       = clp->cl_cred,
+               .rpc_cred       = cred,
        };
 
        return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT,
                        &nfs4_renew_ops, (void *)jiffies);
 }
 
-int
-nfs4_proc_renew(struct nfs4_client *clp)
+int nfs4_proc_renew(struct nfs4_client *clp, struct rpc_cred *cred)
 {
        struct rpc_message msg = {
                .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
                .rpc_argp       = clp,
-               .rpc_cred       = clp->cl_cred,
+               .rpc_cred       = cred,
        };
        unsigned long now = jiffies;
        int status;
index f62c2f7a4ffbda8717d037a57f5f3b17cfbbd6c5..5d764d8e6d8ac5ab6eff0efd86b03a55a8c1a16d 100644 (file)
@@ -62,6 +62,7 @@ void
 nfs4_renew_state(void *data)
 {
        struct nfs4_client *clp = (struct nfs4_client *)data;
+       struct rpc_cred *cred;
        long lease, timeout;
        unsigned long last, now;
 
@@ -77,7 +78,8 @@ nfs4_renew_state(void *data)
        timeout = (2 * lease) / 3 + (long)last - (long)now;
        /* Are we close to a lease timeout? */
        if (time_after(now, last + lease/3)) {
-               if (list_empty(&clp->cl_state_owners)) {
+               cred = nfs4_get_renew_cred(clp);
+               if (cred == NULL) {
                        set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
                        spin_unlock(&clp->cl_lock);
                        nfs_expire_all_delegations(clp);
@@ -85,7 +87,8 @@ nfs4_renew_state(void *data)
                }
                spin_unlock(&clp->cl_lock);
                /* Queue an asynchronous RENEW. */
-               nfs4_proc_async_renew(clp);
+               nfs4_proc_async_renew(clp, cred);
+               put_rpccred(cred);
                timeout = (2 * lease) / 3;
                spin_lock(&clp->cl_lock);
        } else
index f2148376f1a72c254e9f576f8a3820084431b5bc..18f6ed1a0b5405c1e0d3ee8b609d758e595233bc 100644 (file)
@@ -232,6 +232,20 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred)
        return sp;
 }
 
+struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp)
+{
+       struct nfs4_state_owner *sp;
+       struct rpc_cred *cred = NULL;
+
+       list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
+               if (list_empty(&sp->so_states))
+                       continue;
+               cred = get_rpccred(sp->so_cred);
+               break;
+       }
+       return cred;
+}
+
 static struct nfs4_state_owner *
 nfs4_find_state_owner(struct nfs4_client *clp, struct rpc_cred *cred)
 {
@@ -899,7 +913,7 @@ static int reclaimer(void *ptr)
        if (list_empty(&clp->cl_superblocks))
                goto out;
 restart_loop:
-       status = nfs4_proc_renew(clp);
+       status = nfs4_proc_renew(clp, clp->cl_cred);
        switch (status) {
                case 0:
                case -NFS4ERR_CB_PATH_DOWN: