Skip to content

Commit 3fbd67a

Browse files
Trond MyklebustTrond Myklebust
authored andcommitted
NFSv4: Iterate through all nfs_clients when the server recalls a delegation
The same delegation may have been handed out to more than one nfs_client. Ensure that if a recall occurs, we return all instances. Signed-off-by: Trond Myklebust <[email protected]>
1 parent 57bfa89 commit 3fbd67a

File tree

3 files changed

+58
-17
lines changed

3 files changed

+58
-17
lines changed

fs/nfs/callback_proc.c

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -75,23 +75,28 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
7575
dprintk("NFS: RECALL callback request from %s\n",
7676
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
7777

78-
inode = nfs_delegation_find_inode(clp, &args->fh);
79-
if (inode == NULL)
80-
goto out_putclient;
81-
/* Set up a helper thread to actually return the delegation */
82-
switch(nfs_async_inode_return_delegation(inode, &args->stateid)) {
83-
case 0:
84-
res = 0;
85-
break;
86-
case -ENOENT:
87-
res = htonl(NFS4ERR_BAD_STATEID);
88-
break;
89-
default:
90-
res = htonl(NFS4ERR_RESOURCE);
91-
}
92-
iput(inode);
93-
out_putclient:
94-
nfs_put_client(clp);
78+
do {
79+
struct nfs_client *prev = clp;
80+
81+
inode = nfs_delegation_find_inode(clp, &args->fh);
82+
if (inode != NULL) {
83+
/* Set up a helper thread to actually return the delegation */
84+
switch(nfs_async_inode_return_delegation(inode, &args->stateid)) {
85+
case 0:
86+
res = 0;
87+
break;
88+
case -ENOENT:
89+
if (res != 0)
90+
res = htonl(NFS4ERR_BAD_STATEID);
91+
break;
92+
default:
93+
res = htonl(NFS4ERR_RESOURCE);
94+
}
95+
iput(inode);
96+
}
97+
clp = nfs_find_client_next(prev);
98+
nfs_put_client(prev);
99+
} while (clp != NULL);
95100
out:
96101
dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
97102
return res;

fs/nfs/client.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,41 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion)
275275
return NULL;
276276
}
277277

278+
/*
279+
* Find a client by IP address and protocol version
280+
* - returns NULL if no such client
281+
*/
282+
struct nfs_client *nfs_find_client_next(struct nfs_client *clp)
283+
{
284+
struct sockaddr *sap = (struct sockaddr *)&clp->cl_addr;
285+
u32 nfsvers = clp->rpc_ops->version;
286+
287+
spin_lock(&nfs_client_lock);
288+
list_for_each_entry_continue(clp, &nfs_client_list, cl_share_link) {
289+
struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
290+
291+
/* Don't match clients that failed to initialise properly */
292+
if (clp->cl_cons_state != NFS_CS_READY)
293+
continue;
294+
295+
/* Different NFS versions cannot share the same nfs_client */
296+
if (clp->rpc_ops->version != nfsvers)
297+
continue;
298+
299+
if (sap->sa_family != clap->sa_family)
300+
continue;
301+
/* Match only the IP address, not the port number */
302+
if (!nfs_sockaddr_match_ipaddr(sap, clap))
303+
continue;
304+
305+
atomic_inc(&clp->cl_count);
306+
spin_unlock(&nfs_client_lock);
307+
return clp;
308+
}
309+
spin_unlock(&nfs_client_lock);
310+
return NULL;
311+
}
312+
278313
/*
279314
* Find an nfs_client on the list that matches the initialisation data
280315
* that is supplied.

fs/nfs/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ extern struct rpc_program nfs_program;
6464

6565
extern void nfs_put_client(struct nfs_client *);
6666
extern struct nfs_client *nfs_find_client(const struct sockaddr *, u32);
67+
extern struct nfs_client *nfs_find_client_next(struct nfs_client *);
6768
extern struct nfs_server *nfs_create_server(
6869
const struct nfs_parsed_mount_data *,
6970
struct nfs_fh *);

0 commit comments

Comments
 (0)