8000 Merge tag 'nfs-for-4.7-2' of git://git.linux-nfs.org/projects/anna/li… · bsd-unix/linux@e7bdea7 · GitHub
[go: up one dir, main page]

Skip to content

Commit e7bdea7

Browse files
committed
Merge tag 'nfs-for-4.7-2' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client bugfixes from Anna Schumaker: "Stable bugfixes: - Fix _cancel_empty_pagelist - Fix a double page unlock - Make nfs_atomic_open() call d_drop() on all ->open_context() errors. - Fix another OPEN_DOWNGRADE bug Other bugfixes: - Ensure we handle delegation errors in nfs4_proc_layoutget() - Layout stateids start out as being invalid - Add sparse lock annotations for pnfs_find_alloc_layout - Handle bad delegation stateids in nfs4_layoutget_handle_exception - Fix up O_DIRECT results - Fix potential use after free of state in nfs4_do_reclaim. - Mark the layout stateid invalid when all segments are removed - Don't let readdirplus revalidate an inode that was marked as stale - Fix potential race in nfs_fhget() - Fix an unused variable warning" * tag 'nfs-for-4.7-2' of git://git.linux-nfs.org/projects/anna/linux-nfs: NFS: Fix another OPEN_DOWNGRADE bug make nfs_atomic_open() call d_drop() on all ->open_context() errors. NFS: Fix an unused variable warning NFS: Fix potential race in nfs_fhget() NFS: Don't let readdirplus revalidate an inode that was marked as stale NFSv4.1/pnfs: Mark the layout stateid invalid when all segments are removed NFS: Fix a double page unlock pnfs_nfs: fix _cancel_empty_pagelist nfs4: Fix potential use after free of state in nfs4_do_reclaim. NFS: Fix up O_DIRECT results NFS/pnfs: handle bad delegation stateids in nfs4_layoutget_handle_exception NFSv4.1/pnfs: Add sparse lock annotations for pnfs_find_alloc_layout NFSv4.1/pnfs: Layout stateids start out as being invalid NFSv4.1/pnfs: Ensure we handle delegation errors in nfs4_proc_layoutget()
2 parents 89a82a9 + e547f26 commit e7bdea7

File tree

8 files changed

+45
-23
lines changed

8 files changed

+45
-23
lines changed

fs/nfs/dir.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -424,12 +424,17 @@ static int xdr_decode(nfs_readdir_descriptor_t *desc,
424424
static
425425
int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
426426
{
427+
struct inode *inode;
427428
struct nfs_inode *nfsi;
428429

429430
if (d_really_is_negative(dentry))
430431
return 0;
431432

432-
nfsi = NFS_I(d_inode(dentry));
433+
inode = d_inode(dentry);
434+
if (is_bad_inode(inode) || NFS_STALE(inode))
435+
return 0;
436+
437+
nfsi = NFS_I(inode);
433438
if (entry->fattr->fileid == nfsi->fileid)
434439
return 1;
435440
if (nfs_compare_fh(entry->fh, &nfsi->fh) == 0)
@@ -1363,7 +1368,6 @@ EXPORT_SYMBOL_GPL(nfs_dentry_operations);
13631368
struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
13641369
{
13651370
struct dentry *res;
1366-
struct dentry *parent;
13671371
struct inode *inode = NULL;
13681372
struct nfs_fh *fhandle = NULL;
13691373
struct nfs_fattr *fattr = NULL;
@@ -1393,7 +1397,6 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
13931397
if (IS_ERR(label))
13941398
goto out;
13951399

1396-
parent = dentry->d_parent;
13971400
/* Protect against concurrent sillydeletes */
13981401
trace_nfs_lookup_enter(dir, dentry, flags);
13991402
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
@@ -1536,9 +1539,9 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
15361539
err = PTR_ERR(inode);
15371540
trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
15381541
put_nfs_open_context(ctx);
1542+
d_drop(dentry);
15391543
switch (err) {
15401544
case -ENOENT:
1541-
d_drop(dentry);
15421545
d_add(dentry, NULL);
15431546
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
15441547
break;

fs/nfs/direct.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,12 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq)
353353

354354
result = wait_for_completion_killable(&dreq->completion);
355355

356+
if (!result) {
357+
result = dreq->count;
358+
WARN_ON_ONCE(dreq->count < 0);
359+
}
356360
if (!result)
357361
result = dreq->error;
358-
if (!result)
359-
result = dreq->count;
360362

361363
out:
362364
return (ssize_t) result;
@@ -386,8 +388,10 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq, bool write)
386388

387389
if (dreq->iocb) {
388390
long res = (long) dreq->error;
389-
if (!res)
391+
if (dreq->count != 0) {
390392
res = (long) dreq->count;
393+
WARN_ON_ONCE(dreq->count < 0);
394+
}
391395
dreq->iocb->ki_complete(dreq->iocb, res, 0);
392396
}
393397

fs/nfs/inode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ nfs_init_locked(struct inode *inode, void *opaque)
282282
struct nfs_fattr *fattr = desc->fattr;
283283

284284
set_nfs_fileid(inode, fattr->fileid);
285+
inode->i_mode = fattr->mode;
285286
nfs_copy_fh(NFS_FH(inode), desc->fh);
286287
return 0;
287288
}

fs/nfs/nfs4proc.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2882,12 +2882,11 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
28822882
call_close |= is_wronly;
28832883
else if (is_wronly)
28842884
calldata->arg.fmode |= FMODE_WRITE;
2885+
if (calldata->arg.fmode != (FMODE_READ|FMODE_WRITE))
2886+
call_close |= is_rdwr;
28852887
} else if (is_rdwr)
28862888
calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
28872889

2888-
if (calldata->arg.fmode == 0)
2889-
call_close |= is_rdwr;
2890-
28912890
if (!nfs4_valid_open_stateid(state))
28922891
call_close = 0;
28932892
spin_unlock(&state->owner->so_lock);
@@ -7924,8 +7923,8 @@ nfs4_layoutget_handle_exception(struct rpc_task *task,
79247923
break;
79257924
}
79267925
lo = NFS_I(inode)->layout;
7927-
if (lo && nfs4_stateid_match(&lgp->args.stateid,
7928-
&lo->plh_stateid)) {
7926+
if (lo && !test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) &&
7927+
nfs4_stateid_match_other(&lgp->args.stateid, &lo->plh_stateid)) {
79297928
LIST_HEAD(head);
79307929

79317930
/*
@@ -7936,10 +7935,10 @@ nfs4_layoutget_handle_exception(struct rpc_task *task,
79367935
pnfs_mark_matching_lsegs_invalid(lo, &head, NULL, 0);
79377936
spin_unlock(&inode->i_lock);
79387937
pnfs_free_lseg_list(&head);
7938+
status = -EAGAIN;
7939+
goto out;
79397940
} else
79407941
spin_unlock(&inode->i_lock);
7941-
status = -EAGAIN;
7942-
goto out;
79437942
}
79447943

79457944
status = nfs4_handle_exception(server, status, exception);
@@ -8036,7 +8035,10 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout, gfp_t gfp_flags)
80368035
.flags = RPC_TASK_ASYNC,
80378036
};
80388037
struct pnfs_layout_segment *lseg = NULL;
8039-
struct nfs4_exception exception = { .timeout = *timeout };
8038+
struct nfs4_exception exception = {
8039+
.inode = inode,
8040+
.timeout = *timeout,
8041+
};
80408042
int status = 0;
80418043

80428044
dprintk("--> %s\n", __func__);

fs/nfs/nfs4state.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1488,9 +1488,9 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
14881488
}
14891489
spin_unlock(&state->state_lock);
14901490
}
1491-
nfs4_put_open_state(state);
14921491
clear_bit(NFS_STATE_RECLAIM_NOGRACE,
14931492
&state->flags);
1493+
nfs4_put_open_state(state);
14941494
spin_lock(&sp->so_lock);
14951495
goto restart;
14961496
}

fs/nfs/pnfs.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,10 @@ pnfs_layout_remove_lseg(struct pnfs_layout_hdr *lo,
361361
list_del_init(&lseg->pls_list);
362362
/* Matched by pnfs_get_layout_hdr in pnfs_layout_insert_lseg */
363363
atomic_dec(&lo->plh_refcount);
364-
if (list_empty(&lo->plh_segs))
364+
if (list_empty(&lo->plh_segs)) {
365+
set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
365366
clear_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags);
367+
}
366368
rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq);
367369
}
368370

@@ -1290,13 +1292,16 @@ alloc_init_layout_hdr(struct inode *ino,
12901292
INIT_LIST_HEAD(&lo->plh_bulk_destroy);
12911293
lo->plh_inode = ino;
12921294
lo->plh_lc_cred = get_rpccred(ctx->cred);
1295+
lo->plh_flags |= 1 << NFS_LAYOUT_INVALID_STID;
12931296
return lo;
12941297
}
12951298

12961299
static struct pnfs_layout_hdr *
12971300
pnfs_find_alloc_layout(struct inode *ino,
12981301
struct nfs_open_context *ctx,
12991302
gfp_t gfp_flags)
1303+
__releases(&ino->i_lock)
1304+
__acquires(&ino->i_lock)
13001305
{
13011306
struct nfs_inode *nfsi = NFS_I(ino);
13021307
struct pnfs_layout_hdr *new = NULL;
@@ -1565,8 +1570,7 @@ pnfs_update_layout(struct inode *ino,
15651570
* stateid, or it has been invalidated, then we must use the open
15661571
* stateid.
15671572
*/
1568-
if (lo->plh_stateid.seqid == 0 ||
1569-
test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) {
1573+
if (test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) {
15701574

15711575
/*
15721576
* The first layoutget for the file. Need to serialize per

fs/nfs/pnfs_nfs.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,11 @@ void pnfs_fetch_commit_bucket_list(struct list_head *pages,
247247
}
248248

249249
/* Helper function for pnfs_generic_commit_pagelist to catch an empty
250-
* page list. This can happen when two commits race. */
250+
* page list. This can happen when two commits race.
251+
*
252+
* This must be called instead of nfs_init_commit - call one or the other, but
253+
* not both!
254+
*/
251255
static bool
252256
pnfs_generic_commit_cancel_empty_pagelist(struct list_head *pages,
253257
struct nfs_commit_data *data,
@@ -256,7 +260,11 @@ pnfs_generic_commit_cancel_empty_pagelist(struct list_head *pages,
256260
if (list_empty(pages)) {
257261
if (atomic_dec_and_test(&cinfo->mds->rpcs_out))
258262
wake_up_atomic_t(&cinfo->mds->rpcs_out);
259-
nfs_commitdata_release(data);
263+
/* don't call nfs_commitdata_release - it tries to put
264+
* the open_context which is not acquired until nfs_init_commit
265+
* which has not been called on @data */
266+
WARN_ON_ONCE(data->context);
267+
nfs_commit_free(data);
260268
return true;
261269
}
262270

fs/nfs/read.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,13 +367,13 @@ readpage_async_filler(void *data, struct page *page)
367367
nfs_list_remove_request(new);
368368
nfs_readpage_release(new);
369369
error = desc->pgio->pg_error;
370-
goto out_unlock;
370+
goto out;
371371
}
372372
return 0;
373373
out_error:
374374
error = PTR_ERR(new);
375-
out_unlock:
376375
unlock_page(page);
376+
out:
377377
return error;
378378
}
379379

0 commit comments

Comments
 (0)
0