Skip to content

Commit 77e82fb

Browse files
neilbrownAnna Schumaker
authored andcommitted
nfs_localio: always hold nfsd net ref with nfsd_file ref
Having separate nfsd_file_put and nfsd_file_put_local in struct nfsd_localio_operations doesn't make much sense. The difference is that nfsd_file_put doesn't drop a reference to the nfs_net which is what keeps nfsd from shutting down. Currently, if nfsd tries to shutdown it will invalidate the files stored in the list from the nfs_uuid and this will drop all references to the nfsd net that the client holds. But the client could still hold some references to nfsd_files for active IO. So nfsd might think is has completely shut down local IO, but hasn't and has no way to wait for those active IO requests to complete. So this patch changes nfsd_file_get to nfsd_file_get_local and has it increase the ref count on the nfsd net and it replaces all calls to ->nfsd_put_file to ->nfsd_put_file_local. It also changes ->nfsd_open_local_fh to return with the refcount on the net elevated precisely when a valid nfsd_file is returned. This means that whenever the client holds a valid nfsd_file, there will be an associated count on the nfsd net, and so the count can only reach zero when all nfsd_files have been returned. nfs_local_file_put() is changed to call nfs_to_nfsd_file_put_local() instead of replacing calls to one with calls to the other because this will help a later patch which changes nfs_to_nfsd_file_put_local() to take an __rcu pointer while nfs_local_file_put() doesn't. Fixes: 86e0041 ("nfs: cache all open LOCALIO nfsd_file(s) in client") Signed-off-by: NeilBrown <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent ed9be31 commit 77e82fb

File tree

6 files changed

+34
-9
lines changed

6 files changed

+34
-9
lines changed

fs/nfs/localio.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,12 @@ EXPORT_SYMBOL_GPL(nfs_local_probe_async);
211211

212212
static inline struct nfsd_file *nfs_local_file_get(struct nfsd_file *nf)
213213
{
214-
return nfs_to->nfsd_file_get(nf);
214+
return nfs_to->nfsd_file_get_local(nf);
215215
}
216216

217217
static inline void nfs_local_file_put(struct nfsd_file *nf)
218218
{
219-
nfs_to->nfsd_file_put(nf);
219+
nfs_to_nfsd_file_put_local(nf);
220220
}
221221

222222
/*

fs/nfs_common/nfslocalio.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,8 @@ struct nfsd_file *nfs_open_local_fh(nfs_uuid_t *uuid,
262262
/* We have an implied reference to net thanks to nfsd_net_try_get */
263263
localio = nfs_to->nfsd_open_local_fh(net, uuid->dom, rpc_clnt,
264264
cred, nfs_fh, fmode);
265-
if (IS_ERR(localio))
266-
nfs_to_nfsd_net_put(net);
267-
else
265+
nfs_to_nfsd_net_put(net);
266+
if (!IS_ERR(localio))
268267
nfs_uuid_add_file(uuid, nfl);
269268

270269
return localio;

fs/nfsd/filecache.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,27 @@ nfsd_file_put_local(struct nfsd_file *nf)
386386
return net;
387387
}
388388

389+
/**
390+
* nfsd_file_get_local - get nfsd_file reference and reference to net
391+
* @nf: nfsd_file of which to put the reference
392+
*
393+
* Get reference to both the nfsd_file and nf->nf_net.
394+
*/
395+
struct nfsd_file *
396+
nfsd_file_get_local(struct nfsd_file *nf)
397+
{
398+
struct net *net = nf->nf_net;
399+
400+
if (nfsd_net_try_get(net)) {
401+
nf = nfsd_file_get(nf);
402+
if (!nf)
403+
nfsd_net_put(net);
404+
} else {
405+
nf = NULL;
406+
}
407+
return nf;
408+
}
409+
389410
/**
390411
* nfsd_file_file - get the backing file of an nfsd_file
391412
* @nf: nfsd_file of which to access the backing file.

fs/nfsd/filecache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ int nfsd_file_cache_start_net(struct net *net);
6363
void nfsd_file_cache_shutdown_net(struct net *net);
6464
void nfsd_file_put(struct nfsd_file *nf);
6565
struct net *nfsd_file_put_local(struct nfsd_file *nf);
66+
struct nfsd_file *nfsd_file_get_local(struct nfsd_file *nf);
6667
struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
6768
struct file *nfsd_file_file(struct nfsd_file *nf);
6869
void nfsd_file_close_inode_sync(struct inode *inode);

fs/nfsd/localio.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ static const struct nfsd_localio_operations nfsd_localio_ops = {
2929
.nfsd_net_put = nfsd_net_put,
3030
.nfsd_open_local_fh = nfsd_open_local_fh,
3131
.nfsd_file_put_local = nfsd_file_put_local,
32-
.nfsd_file_get = nfsd_file_get,
33-
.nfsd_file_put = nfsd_file_put,
32+
.nfsd_file_get_local = nfsd_file_get_local,
3433
.nfsd_file_file = nfsd_file_file,
3534
};
3635

@@ -71,6 +70,9 @@ nfsd_open_local_fh(struct net *net, struct auth_domain *dom,
7170
if (nfs_fh->size > NFS4_FHSIZE)
7271
return ERR_PTR(-EINVAL);
7372

73+
if (!nfsd_net_try_get(net))
74+
return ERR_PTR(-ENXIO);
75+
7476
/* nfs_fh -> svc_fh */
7577
fh_init(&fh, NFS4_FHSIZE);
7678
fh.fh_handle.fh_size = nfs_fh->size;
@@ -92,6 +94,9 @@ nfsd_open_local_fh(struct net *net, struct auth_domain *dom,
9294
if (rq_cred.cr_group_info)
9395
put_group_info(rq_cred.cr_group_info);
9496

97+
if (IS_ERR(localio))
98+
nfsd_net_put(net);
99+
95100
return localio;
96101
}
97102
EXPORT_SYMBOL_GPL(nfsd_open_local_fh);

include/linux/nfslocalio.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ struct nfsd_localio_operations {
6666
const struct nfs_fh *,
6767
const fmode_t);
6868
struct net *(*nfsd_file_put_local)(struct nfsd_file *);
69-
struct nfsd_file *(*nfsd_file_get)(struct nfsd_file *);
70-
void (*nfsd_file_put)(struct nfsd_file *);
69+
struct nfsd_file *(*nfsd_file_get_local)(struct nfsd_file *);
7170
struct file *(*nfsd_file_file)(struct nfsd_file *);
7271
} ____cacheline_aligned;
7372

0 commit comments

Comments
 (0)