Skip to content

Commit e609571

Browse files
committed
Merge tag 'nfs-for-5.11-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client fixes from Trond Myklebust: "Highlights include: - Fix parsing of link-local IPv6 addresses - Fix confusing logging of mount errors that was introduced by the fsopen() patchset. - Fix a tracing use after free in _nfs4_do_setlk() - Layout return-on-close fixes when called from nfs4_evict_inode() - Layout segments were being leaked in pnfs_generic_clear_request_commit() - Don't leak DS commits in pnfs_generic_retry_commit() - Fix an Oopsable use-after-free when nfs_delegation_find_inode_server() calls iput() on an inode after the super block has gone away" * tag 'nfs-for-5.11-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFS: nfs_igrab_and_active must first reference the superblock NFS: nfs_delegation_find_inode_server must first reference the superblock NFS/pNFS: Fix a leak of the layout 'plh_outstanding' counter NFS/pNFS: Don't leak DS commits in pnfs_generic_retry_commit() NFS/pNFS: Don't call pnfs_free_bucket_lseg() before removing the request pNFS: Stricter ordering of layoutget and layoutreturn pNFS: Clean up pnfs_layoutreturn_free_lsegs() pNFS: We want return-on-close to complete when evicting the inode pNFS: Mark layout for return if return-on-close was not sent net: sunrpc: interpret the return value of kstrtou32 correctly NFS: Adjust fs_context error logging NFS4: Fix use-after-free in trace_event_raw_event_nfs4_set_lock
2 parents ea49c88 + 896567e commit e609571

File tree

8 files changed

+99
-82
lines changed

8 files changed

+99
-82
lines changed

fs/nfs/delegation.c

+7-5
Original file line numberDiff line numberDiff line change
@@ -1011,22 +1011,24 @@ nfs_delegation_find_inode_server(struct nfs_server *server,
10111011
const struct nfs_fh *fhandle)
10121012
{
10131013
struct nfs_delegation *delegation;
1014-
struct inode *freeme, *res = NULL;
1014+
struct super_block *freeme = NULL;
1015+
struct inode *res = NULL;
10151016

10161017
list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
10171018
spin_lock(&delegation->lock);
10181019
if (delegation->inode != NULL &&
10191020
!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) &&
10201021
nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
1021-
freeme = igrab(delegation->inode);
1022-
if (freeme && nfs_sb_active(freeme->i_sb))
1023-
res = freeme;
1022+
if (nfs_sb_active(server->super)) {
1023+
freeme = server->super;
1024+
res = igrab(delegation->inode);
1025+
}
10241026
spin_unlock(&delegation->lock);
10251027
if (res != NULL)
10261028
return res;
10271029
if (freeme) {
10281030
rcu_read_unlock();
1029-
iput(freeme);
1031+
nfs_sb_deactive(freeme);
10301032
rcu_read_lock();
10311033
}
10321034
return ERR_PTR(-EAGAIN);

fs/nfs/internal.h

+30-8
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,29 @@ struct nfs_fs_context {
136136
} clone_data;
137137
};
138138

139-
#define nfs_errorf(fc, fmt, ...) errorf(fc, fmt, ## __VA_ARGS__)
140-
#define nfs_invalf(fc, fmt, ...) invalf(fc, fmt, ## __VA_ARGS__)
141-
#define nfs_warnf(fc, fmt, ...) warnf(fc, fmt, ## __VA_ARGS__)
139+
#define nfs_errorf(fc, fmt, ...) ((fc)->log.log ? \
140+
errorf(fc, fmt, ## __VA_ARGS__) : \
141+
({ dprintk(fmt "\n", ## __VA_ARGS__); }))
142+
143+
#define nfs_ferrorf(fc, fac, fmt, ...) ((fc)->log.log ? \
144+
errorf(fc, fmt, ## __VA_ARGS__) : \
145+
({ dfprintk(fac, fmt "\n", ## __VA_ARGS__); }))
146+
147+
#define nfs_invalf(fc, fmt, ...) ((fc)->log.log ? \
148+
invalf(fc, fmt, ## __VA_ARGS__) : \
149+
({ dprintk(fmt "\n", ## __VA_ARGS__); -EINVAL; }))
150+
151+
#define nfs_finvalf(fc, fac, fmt, ...) ((fc)->log.log ? \
152+
invalf(fc, fmt, ## __VA_ARGS__) : \
153+
({ dfprintk(fac, fmt "\n", ## __VA_ARGS__); -EINVAL; }))
154+
155+
#define nfs_warnf(fc, fmt, ...) ((fc)->log.log ? \
156+
warnf(fc, fmt, ## __VA_ARGS__) : \
157+
({ dprintk(fmt "\n", ## __VA_ARGS__); }))
158+
159+
#define nfs_fwarnf(fc, fac, fmt, ...) ((fc)->log.log ? \
160+
warnf(fc, fmt, ## __VA_ARGS__) : \
161+
({ dfprintk(fac, fmt "\n", ## __VA_ARGS__); }))
142162

143163
static inline struct nfs_fs_context *nfs_fc2context(const struct fs_context *fc)
144164
{
@@ -579,12 +599,14 @@ extern void nfs4_test_session_trunk(struct rpc_clnt *clnt,
579599

580600
static inline struct inode *nfs_igrab_and_active(struct inode *inode)
581601
{
582-
inode = igrab(inode);
583-
if (inode != NULL && !nfs_sb_active(inode->i_sb)) {
584-
iput(inode);
585-
inode = NULL;
602+
struct super_block *sb = inode->i_sb;
603+
604+
if (sb && nfs_sb_active(sb)) {
605+
if (igrab(inode))
606+
return inode;
607+
nfs_sb_deactive(sb);
586608
}
587-
return inode;
609+
return NULL;
588610
}
589611

590612
static inline void nfs_iput_and_deactive(struct inode *inode)

fs/nfs/nfs4proc.c

+11-17
Original file line numberDiff line numberDiff line change
@@ -3536,10 +3536,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
35363536
trace_nfs4_close(state, &calldata->arg, &calldata->res, task->tk_status);
35373537

35383538
/* Handle Layoutreturn errors */
3539-
if (pnfs_roc_done(task, calldata->inode,
3540-
&calldata->arg.lr_args,
3541-
&calldata->res.lr_res,
3542-
&calldata->res.lr_ret) == -EAGAIN)
3539+
if (pnfs_roc_done(task, &calldata->arg.lr_args, &calldata->res.lr_res,
3540+
&calldata->res.lr_ret) == -EAGAIN)
35433541
goto out_restart;
35443542

35453543
/* hmm. we are done with the inode, and in the process of freeing
@@ -6384,10 +6382,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
63846382
trace_nfs4_delegreturn_exit(&data->args, &data->res, task->tk_status);
63856383

63866384
/* Handle Layoutreturn errors */
6387-
if (pnfs_roc_done(task, data->inode,
6388-
&data->args.lr_args,
6389-
&data->res.lr_res,
6390-
&data->res.lr_ret) == -EAGAIN)
6385+
if (pnfs_roc_done(task, &data->args.lr_args, &data->res.lr_res,
6386+
&data->res.lr_ret) == -EAGAIN)
63916387
goto out_restart;
63926388

63936389
switch (task->tk_status) {
@@ -6441,10 +6437,10 @@ static void nfs4_delegreturn_release(void *calldata)
64416437
struct nfs4_delegreturndata *data = calldata;
64426438
struct inode *inode = data->inode;
64436439

6440+
if (data->lr.roc)
6441+
pnfs_roc_release(&data->lr.arg, &data->lr.res,
6442+
data->res.lr_ret);
64446443
if (inode) {
6445-
if (data->lr.roc)
6446-
pnfs_roc_release(&data->lr.arg, &data->lr.res,
6447-
data->res.lr_ret);
64486444
nfs_post_op_update_inode_force_wcc(inode, &data->fattr);
64496445
nfs_iput_and_deactive(inode);
64506446
}
@@ -6520,16 +6516,14 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred,
65206516
nfs_fattr_init(data->res.fattr);
65216517
data->timestamp = jiffies;
65226518
data->rpc_status = 0;
6523-
data->lr.roc = pnfs_roc(inode, &data->lr.arg, &data->lr.res, cred);
65246519
data->inode = nfs_igrab_and_active(inode);
6525-
if (data->inode) {
6520+
if (data->inode || issync) {
6521+
data->lr.roc = pnfs_roc(inode, &data->lr.arg, &data->lr.res,
6522+
cred);
65266523
if (data->lr.roc) {
65276524
data->args.lr_args = &data->lr.arg;
65286525
data->res.lr_res = &data->lr.res;
65296526
}
6530-
} else if (data->lr.roc) {
6531-
pnfs_roc_release(&data->lr.arg, &data->lr.res, 0);
6532-
data->lr.roc = false;
65336527
}
65346528

65356529
task_setup_data.callback_data = data;
@@ -7111,9 +7105,9 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
71117105
data->arg.new_lock_owner, ret);
71127106
} else
71137107
data->cancelled = true;
7108+
trace_nfs4_set_lock(fl, state, &data->res.stateid, cmd, ret);
71147109
rpc_put_task(task);
71157110
dprintk("%s: done, ret = %d!\n", __func__, ret);
7116-
trace_nfs4_set_lock(fl, state, &data->res.stateid, cmd, ret);
71177111
return ret;
71187112
}
71197113

fs/nfs/nfs4super.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ int nfs4_try_get_tree(struct fs_context *fc)
227227
fc, ctx->nfs_server.hostname,
228228
ctx->nfs_server.export_path);
229229
if (err) {
230-
nfs_errorf(fc, "NFS4: Couldn't follow remote path");
230+
nfs_ferrorf(fc, MOUNT, "NFS4: Couldn't follow remote path");
231231
dfprintk(MOUNT, "<-- nfs4_try_get_tree() = %d [error]\n", err);
232232
} else {
233233
dfprintk(MOUNT, "<-- nfs4_try_get_tree() = 0\n");
@@ -250,7 +250,7 @@ int nfs4_get_referral_tree(struct fs_context *fc)
250250
fc, ctx->nfs_server.hostname,
251251
ctx->nfs_server.export_path);
252252
if (err) {
253-
nfs_errorf(fc, "NFS4: Couldn't follow remote path");
253+
nfs_ferrorf(fc, MOUNT, "NFS4: Couldn't follow remote path");
254254
dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = %d [error]\n", err);
255255
} else {
256256
dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = 0\n");

fs/nfs/pnfs.c

+35-32
Original file line numberDiff line numberDiff line change
@@ -1152,7 +1152,7 @@ void pnfs_layoutreturn_free_lsegs(struct pnfs_layout_hdr *lo,
11521152
LIST_HEAD(freeme);
11531153

11541154
spin_lock(&inode->i_lock);
1155-
if (!pnfs_layout_is_valid(lo) || !arg_stateid ||
1155+
if (!pnfs_layout_is_valid(lo) ||
11561156
!nfs4_stateid_match_other(&lo->plh_stateid, arg_stateid))
11571157
goto out_unlock;
11581158
if (stateid) {
@@ -1509,10 +1509,8 @@ bool pnfs_roc(struct inode *ino,
15091509
return false;
15101510
}
15111511

1512-
int pnfs_roc_done(struct rpc_task *task, struct inode *inode,
1513-
struct nfs4_layoutreturn_args **argpp,
1514-
struct nfs4_layoutreturn_res **respp,
1515-
int *ret)
1512+
int pnfs_roc_done(struct rpc_task *task, struct nfs4_layoutreturn_args **argpp,
1513+
struct nfs4_layoutreturn_res **respp, int *ret)
15161514
{
15171515
struct nfs4_layoutreturn_args *arg = *argpp;
15181516
int retval = -EAGAIN;
@@ -1545,7 +1543,7 @@ int pnfs_roc_done(struct rpc_task *task, struct inode *inode,
15451543
return 0;
15461544
case -NFS4ERR_OLD_STATEID:
15471545
if (!nfs4_layout_refresh_old_stateid(&arg->stateid,
1548-
&arg->range, inode))
1546+
&arg->range, arg->inode))
15491547
break;
15501548
*ret = -NFS4ERR_NOMATCHING_LAYOUT;
15511549
return -EAGAIN;
@@ -1560,23 +1558,28 @@ void pnfs_roc_release(struct nfs4_layoutreturn_args *args,
15601558
int ret)
15611559
{
15621560
struct pnfs_layout_hdr *lo = args->layout;
1563-
const nfs4_stateid *arg_stateid = NULL;
1561+
struct inode *inode = args->inode;
15641562
const nfs4_stateid *res_stateid = NULL;
15651563
struct nfs4_xdr_opaque_data *ld_private = args->ld_private;
15661564

15671565
switch (ret) {
15681566
case -NFS4ERR_NOMATCHING_LAYOUT:
1567+
spin_lock(&inode->i_lock);
1568+
if (pnfs_layout_is_valid(lo) &&
1569+
nfs4_stateid_match_other(&args->stateid, &lo->plh_stateid))
1570+
pnfs_set_plh_return_info(lo, args->range.iomode, 0);
1571+
pnfs_clear_layoutreturn_waitbit(lo);
1572+
spin_unlock(&inode->i_lock);
15691573
break;
15701574
case 0:
15711575
if (res->lrs_present)
15721576
res_stateid = &res->stateid;
15731577
fallthrough;
15741578
default:
1575-
arg_stateid = &args->stateid;
1579+
pnfs_layoutreturn_free_lsegs(lo, &args->stateid, &args->range,
1580+
res_stateid);
15761581
}
15771582
trace_nfs4_layoutreturn_on_close(args->inode, &args->stateid, ret);
1578-
pnfs_layoutreturn_free_lsegs(lo, arg_stateid, &args->range,
1579-
res_stateid);
15801583
if (ld_private && ld_private->ops && ld_private->ops->free)
15811584
ld_private->ops->free(ld_private);
15821585
pnfs_put_layout_hdr(lo);
@@ -2015,6 +2018,27 @@ pnfs_update_layout(struct inode *ino,
20152018
goto lookup_again;
20162019
}
20172020

2021+
/*
2022+
* Because we free lsegs when sending LAYOUTRETURN, we need to wait
2023+
* for LAYOUTRETURN.
2024+
*/
2025+
if (test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) {
2026+
spin_unlock(&ino->i_lock);
2027+
dprintk("%s wait for layoutreturn\n", __func__);
2028+
lseg = ERR_PTR(pnfs_prepare_to_retry_layoutget(lo));
2029+
if (!IS_ERR(lseg)) {
2030+
pnfs_put_layout_hdr(lo);
2031+
dprintk("%s retrying\n", __func__);
2032+
trace_pnfs_update_layout(ino, pos, count, iomode, lo,
2033+
lseg,
2034+
PNFS_UPDATE_LAYOUT_RETRY);
2035+
goto lookup_again;
2036+
}
2037+
trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
2038+
PNFS_UPDATE_LAYOUT_RETURN);
2039+
goto out_put_layout_hdr;
2040+
}
2041+
20182042
lseg = pnfs_find_lseg(lo, &arg, strict_iomode);
20192043
if (lseg) {
20202044
trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
@@ -2067,28 +2091,6 @@ pnfs_update_layout(struct inode *ino,
20672091
nfs4_stateid_copy(&stateid, &lo->plh_stateid);
20682092
}
20692093

2070-
/*
2071-
* Because we free lsegs before sending LAYOUTRETURN, we need to wait
2072-
* for LAYOUTRETURN even if first is true.
2073-
*/
2074-
if (test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) {
2075-
spin_unlock(&ino->i_lock);
2076-
dprintk("%s wait for layoutreturn\n", __func__);
2077-
lseg = ERR_PTR(pnfs_prepare_to_retry_layoutget(lo));
2078-
if (!IS_ERR(lseg)) {
2079-
if (first)
2080-
pnfs_clear_first_layoutget(lo);
2081-
pnfs_put_layout_hdr(lo);
2082-
dprintk("%s retrying\n", __func__);
2083-
trace_pnfs_update_layout(ino, pos, count, iomode, lo,
2084-
lseg, PNFS_UPDATE_LAYOUT_RETRY);
2085-
goto lookup_again;
2086-
}
2087-
trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
2088-
PNFS_UPDATE_LAYOUT_RETURN);
2089-
goto out_put_layout_hdr;
2090-
}
2091-
20922094
if (pnfs_layoutgets_blocked(lo)) {
20932095
trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
20942096
PNFS_UPDATE_LAYOUT_BLOCKED);
@@ -2242,6 +2244,7 @@ static void _lgopen_prepare_attached(struct nfs4_opendata *data,
22422244
&rng, GFP_KERNEL);
22432245
if (!lgp) {
22442246
pnfs_clear_first_layoutget(lo);
2247+
nfs_layoutget_end(lo);
22452248
pnfs_put_layout_hdr(lo);
22462249
return;
22472250
}

fs/nfs/pnfs.h

+3-5
Original file line numberDiff line numberDiff line change
@@ -297,10 +297,8 @@ bool pnfs_roc(struct inode *ino,
297297
struct nfs4_layoutreturn_args *args,
298298
struct nfs4_layoutreturn_res *res,
299299
const struct cred *cred);
300-
int pnfs_roc_done(struct rpc_task *task, struct inode *inode,
301-
struct nfs4_layoutreturn_args **argpp,
302-
struct nfs4_layoutreturn_res **respp,
303-
int *ret);
300+
int pnfs_roc_done(struct rpc_task *task, struct nfs4_layoutreturn_args **argpp,
301+
struct nfs4_layoutreturn_res **respp, int *ret);
304302
void pnfs_roc_release(struct nfs4_layoutreturn_args *args,
305303
struct nfs4_layoutreturn_res *res,
306304
int ret);
@@ -772,7 +770,7 @@ pnfs_roc(struct inode *ino,
772770
}
773771

774772
static inline int
775-
pnfs_roc_done(struct rpc_task *task, struct inode *inode,
773+
pnfs_roc_done(struct rpc_task *task,
776774
struct nfs4_layoutreturn_args **argpp,
777775
struct nfs4_layoutreturn_res **respp,
778776
int *ret)

fs/nfs/pnfs_nfs.c

+10-12
Original file line numberDiff line numberDiff line change
@@ -78,22 +78,18 @@ void
7878
pnfs_generic_clear_request_commit(struct nfs_page *req,
7979
struct nfs_commit_info *cinfo)
8080
{
81-
struct pnfs_layout_segment *freeme = NULL;
81+
struct pnfs_commit_bucket *bucket = NULL;
8282

8383
if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags))
8484
goto out;
8585
cinfo->ds->nwritten--;
86-
if (list_is_singular(&req->wb_list)) {
87-
struct pnfs_commit_bucket *bucket;
88-
86+
if (list_is_singular(&req->wb_list))
8987
bucket = list_first_entry(&req->wb_list,
90-
struct pnfs_commit_bucket,
91-
written);
92-
freeme = pnfs_free_bucket_lseg(bucket);
93-
}
88+
struct pnfs_commit_bucket, written);
9489
out:
9590
nfs_request_remove_commit_list(req, cinfo);
96-
pnfs_put_lseg(freeme);
91+
if (bucket)
92+
pnfs_put_lseg(pnfs_free_bucket_lseg(bucket));
9793
}
9894
EXPORT_SYMBOL_GPL(pnfs_generic_clear_request_commit);
9995

@@ -407,12 +403,16 @@ pnfs_bucket_get_committing(struct list_head *head,
407403
struct pnfs_commit_bucket *bucket,
408404
struct nfs_commit_info *cinfo)
409405
{
406+
struct pnfs_layout_segment *lseg;
410407
struct list_head *pos;
411408

412409
list_for_each(pos, &bucket->committing)
413410
cinfo->ds->ncommitting--;
414411
list_splice_init(&bucket->committing, head);
415-
return pnfs_free_bucket_lseg(bucket);
412+
lseg = pnfs_free_bucket_lseg(bucket);
413+
if (!lseg)
414+
lseg = pnfs_get_lseg(bucket->lseg);
415+
return lseg;
416416
}
417417

418418
static struct nfs_commit_data *
@@ -424,8 +424,6 @@ pnfs_bucket_fetch_commitdata(struct pnfs_commit_bucket *bucket,
424424
if (!data)
425425
return NULL;
426426
data->lseg = pnfs_bucket_get_committing(&data->pages, bucket, cinfo);
427-
if (!data->lseg)
428-
data->lseg = pnfs_get_lseg(bucket->lseg);
429427
return data;
430428
}
431429

net/sunrpc/addr.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ static int rpc_parse_scope_id(struct net *net, const char *buf,
185185
scope_id = dev->ifindex;
186186
dev_put(dev);
187187
} else {
188-
if (kstrtou32(p, 10, &scope_id) == 0) {
188+
if (kstrtou32(p, 10, &scope_id) != 0) {
189189
kfree(p);
190190
return 0;
191191
}

0 commit comments

Comments
 (0)