From: Lev Solomonov <solo@xxxxxxxxxx> when pNFS layout state allocation code was originally introduced in 54655510b8c2a04ddbadd532f3d639b9277aa288, get_new_stid() used to do idr preallocation in-situ. however, this preallocation was subsequently factored out upstream in 996e09385c364f97a89648b401409521e2a3a094 into nfs4_alloc_stid(). this lead to pNFS code occasionally failing to obtain an ID from stateids idr in alloc_init_layout_state(), resulting in BUG_ON-s akin to: kernel BUG at fs/nfsd/nfs4state.c:273! invalid opcode: 0000 [#1] SMP CPU 0 <snip> Process nfsd (pid: 9969, threadinfo ffff88003a96a000, task ffff880038b30000) <snip> Call Trace: [<ffffffffa0105006>] nfs4_process_layout_stateid+0xea/0x1d8 [nfsd] [<ffffffff814ccd53>] ? _raw_spin_unlock+0x28/0x3b [<ffffffffa0105ccf>] nfs4_pnfs_get_layout+0x1a0/0x742 [nfsd] [<ffffffff8108c6bc>] ? trace_hardirqs_on_caller+0x121/0x158 [<ffffffffa00f3b3c>] nfsd4_encode_layoutget+0xd7/0x18e [nfsd] [<ffffffffa00fa4a7>] nfsd4_encode_operation+0x57/0x7a [nfsd] [<ffffffffa00f0c6b>] nfsd4_proc_compound+0x39d/0x484 [nfsd] [<ffffffffa00e389c>] nfsd_dispatch+0xe7/0x1cc [nfsd] [<ffffffffa0073045>] svc_process_common+0x2d4/0x4d5 [sunrpc] [<ffffffffa0073458>] svc_process+0x10f/0x12d [sunrpc] [<ffffffffa00e3143>] nfsd+0x104/0x15e [nfsd] [<ffffffffa00e303f>] ? nfsd_get_default_max_blksize+0x3f/0x3f [nfsd] [<ffffffff8105cf3f>] kthread+0xaf/0xb7 [<ffffffff8108c6bc>] ? trace_hardirqs_on_caller+0x121/0x158 [<ffffffff814d4ff4>] kernel_thread_helper+0x4/0x10 [<ffffffff810673e3>] ? finish_task_switch+0x4a/0xd0 [<ffffffff814cd134>] ? retint_restore_args+0x13/0x13 [<ffffffff8105ce90>] ? __init_kthread_worker+0x5a/0x5a [<ffffffff814d4ff0>] ? gs_change+0x13/0x13 <snip> RIP [<ffffffffa00fc0f3>] nfsd4_init_stid+0x3c/0x64 [nfsd] this patch makes layout handling code pass through the same state allocation code as the rest of nfs4. this required a small rearrangement of struct nfs4_layout_state fields due to the peculiar way the upstream nfs4 code handles state allocations ("nfs4_alloc_stid" may be a bit of a misnomer since it allocates more than just state *id*). Signed-off-by: Lev Solomonov <solo@xxxxxxxxxx> Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxx> --- fs/nfsd/nfs4pnfsd.c | 2 +- fs/nfsd/nfs4state.c | 2 +- fs/nfsd/pnfsd.h | 7 ++++++- fs/nfsd/state.h | 1 + 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4pnfsd.c b/fs/nfsd/nfs4pnfsd.c index 11bccdf..509b260 100644 --- a/fs/nfsd/nfs4pnfsd.c +++ b/fs/nfsd/nfs4pnfsd.c @@ -152,7 +152,7 @@ void pnfs_clear_device_notify(struct nfs4_client *clp) { struct nfs4_layout_state *new; - new = kmem_cache_alloc(layout_state_slab, GFP_KERNEL); + new = layoutstateid(nfs4_alloc_stid(clp, layout_state_slab)); if (!new) return new; kref_init(&new->ls_ref); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e5d4bc4..b884281 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -302,7 +302,7 @@ void nfsd4_init_stid(struct nfs4_stid *stid, struct nfs4_client *cl, unsigned ch s->si_generation = 0; } -static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab) +struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab) { struct idr *stateids = &cl->cl_stateids; diff --git a/fs/nfsd/pnfsd.h b/fs/nfsd/pnfsd.h index e960fd3..35859ff 100644 --- a/fs/nfsd/pnfsd.h +++ b/fs/nfsd/pnfsd.h @@ -42,8 +42,8 @@ /* outstanding layout stateid */ struct nfs4_layout_state { + struct nfs4_stid ls_stid; /* must be first field */ struct kref ls_ref; - struct nfs4_stid ls_stid; struct list_head ls_perfile; bool ls_roc; }; @@ -134,6 +134,11 @@ int nfsd_device_notify_cb(struct super_block *, void pnfs_set_device_notify(clientid_t *, unsigned int types); void pnfs_clear_device_notify(struct nfs4_client *); +static inline struct nfs4_layout_state *layoutstateid(struct nfs4_stid *s) +{ + return container_of(s, struct nfs4_layout_state, ls_stid); +} + #if defined(CONFIG_PNFSD_LOCAL_EXPORT) extern struct sockaddr_storage pnfsd_lexp_addr; extern size_t pnfs_lexp_addr_len; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index c1eb396..b3af6bc 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -507,6 +507,7 @@ extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, extern void put_nfs4_file(struct nfs4_file *); extern void get_nfs4_file(struct nfs4_file *); extern struct nfs4_client *find_confirmed_client(clientid_t *); +extern struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab); extern void nfsd4_init_stid(struct nfs4_stid *, struct nfs4_client *, unsigned char type); extern void nfsd4_unhash_stid(struct nfs4_stid *); extern struct nfs4_stid *find_stateid(struct nfs4_client *, stateid_t *); -- 1.7.11.2 -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html