Skip to content

Commit 7c9d845

Browse files
author
Trond Myklebust
committed
NFSv4/pNFS: Fix another issue with a list iterator pointing to the head
In nfs4_callback_devicenotify(), if we don't find a matching entry for the deviceid, we're left with a pointer to 'struct nfs_server' that actually points to the list of super blocks associated with our struct nfs_client. Furthermore, even if we have a valid pointer, nothing pins the super block, and so the struct nfs_server could end up getting freed while we're using it. Since all we want is a pointer to the struct pnfs_layoutdriver_type, let's skip all the iteration over super blocks, and just use APIs to find the layout driver directly. Reported-by: Xiaomeng Tong <xiam0nd.tong@gmail.com> Fixes: 1be5683 ("pnfs: CB_NOTIFY_DEVICEID") Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
1 parent d02d81e commit 7c9d845

File tree

3 files changed

+22
-18
lines changed

3 files changed

+22
-18
lines changed

fs/nfs/callback_proc.c

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -358,36 +358,27 @@ __be32 nfs4_callback_devicenotify(void *argp, void *resp,
358358
struct cb_process_state *cps)
359359
{
360360
struct cb_devicenotifyargs *args = argp;
361+
const struct pnfs_layoutdriver_type *ld = NULL;
361362
uint32_t i;
362363
__be32 res = 0;
363-
struct nfs_client *clp = cps->clp;
364-
struct nfs_server *server = NULL;
365364

366-
if (!clp) {
365+
if (!cps->clp) {
367366
res = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION);
368367
goto out;
369368
}
370369

371370
for (i = 0; i < args->ndevs; i++) {
372371
struct cb_devicenotifyitem *dev = &args->devs[i];
373372

374-
if (!server ||
375-
server->pnfs_curr_ld->id != dev->cbd_layout_type) {
376-
rcu_read_lock();
377-
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
378-
if (server->pnfs_curr_ld &&
379-
server->pnfs_curr_ld->id == dev->cbd_layout_type) {
380-
rcu_read_unlock();
381-
goto found;
382-
}
383-
rcu_read_unlock();
384-
continue;
373+
if (!ld || ld->id != dev->cbd_layout_type) {
374+
pnfs_put_layoutdriver(ld);
375+
ld = pnfs_find_layoutdriver(dev->cbd_layout_type);
376+
if (!ld)
377+
continue;
385378
}
386-
387-
found:
388-
nfs4_delete_deviceid(server->pnfs_curr_ld, clp, &dev->cbd_dev_id);
379+
nfs4_delete_deviceid(ld, cps->clp, &dev->cbd_dev_id);
389380
}
390-
381+
pnfs_put_layoutdriver(ld);
391382
out:
392383
kfree(args->devs);
393384
return res;

fs/nfs/pnfs.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,17 @@ find_pnfs_driver(u32 id)
9292
return local;
9393
}
9494

95+
const struct pnfs_layoutdriver_type *pnfs_find_layoutdriver(u32 id)
96+
{
97+
return find_pnfs_driver(id);
98+
}
99+
100+
void pnfs_put_layoutdriver(const struct pnfs_layoutdriver_type *ld)
101+
{
102+
if (ld)
103+
module_put(ld->owner);
104+
}
105+
95106
void
96107
unset_pnfs_layoutdriver(struct nfs_server *nfss)
97108
{

fs/nfs/pnfs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ struct pnfs_devicelist {
234234

235235
extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *);
236236
extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *);
237+
extern const struct pnfs_layoutdriver_type *pnfs_find_layoutdriver(u32 id);
238+
extern void pnfs_put_layoutdriver(const struct pnfs_layoutdriver_type *ld);
237239

238240
/* nfs4proc.c */
239241
extern size_t max_response_pages(struct nfs_server *server);

0 commit comments

Comments
 (0)