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()
Unified · Split
| @@ -424,12 +424,17 @@ static int xdr_decode(nfs_readdir_descriptor_t *desc, · 423 unmodified lines | ||
| 424 | 424 | static |
| 425 | 425 | int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) |
| 426 | 426 | { |
| 427 | + struct inode *inode; | |
| 427 | 428 | struct nfs_inode *nfsi; |
| 428 | 429 | |
| 429 | 430 | if (d_really_is_negative(dentry)) |
| 430 | 431 | return 0; |
| 431 | 432 | |
| 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); | |
| 433 | 438 | if (entry->fattr->fileid == nfsi->fileid) |
| 434 | 439 | return 1; |
| 435 | 440 | if (nfs_compare_fh(entry->fh, &nfsi->fh) == 0) |
| @@ -1363,7 +1368,6 @@ EXPORT_SYMBOL_GPL(nfs_dentry_operations); · 927 unmodified lines | ||
| 1363 | 1368 | struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) |
| 1364 | 1369 | { |
| 1365 | 1370 | struct dentry *res; |
| 1366 | − struct dentry *parent; | |
| 1367 | 1371 | struct inode *inode = NULL; |
| 1368 | 1372 | struct nfs_fh *fhandle = NULL; |
| 1369 | 1373 | struct nfs_fattr *fattr = NULL; |
| @@ -1393,7 +1397,6 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in · 23 unmodified lines | ||
| 1393 | 1397 | if (IS_ERR(label)) |
| 1394 | 1398 | goto out; |
| 1395 | 1399 | |
| 1396 | − parent = dentry->d_parent; | |
| 1397 | 1400 | /* Protect against concurrent sillydeletes */ |
| 1398 | 1401 | trace_nfs_lookup_enter(dir, dentry, flags); |
| 1399 | 1402 | 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, · 136 unmodified lines | ||
| 1536 | 1539 | err = PTR_ERR(inode); |
| 1537 | 1540 | trace_nfs_atomic_open_exit(dir, ctx, open_flags, err); |
| 1538 | 1541 | put_nfs_open_context(ctx); |
| 1542 | + d_drop(dentry); | |
| 1539 | 1543 | switch (err) { |
| 1540 | 1544 | case -ENOENT: |
| 1541 | − d_drop(dentry); | |
| 1542 | 1545 | d_add(dentry, NULL); |
| 1543 | 1546 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
| 1544 | 1547 | break; |
| @@ -353,10 +353,12 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq) · 352 unmodified lines | ||
| 353 | 353 | |
| 354 | 354 | result = wait_for_completion_killable(&dreq->completion); |
| 355 | 355 | |
| 356 | + if (!result) { | |
| 357 | + result = dreq->count; | |
| 358 | + WARN_ON_ONCE(dreq->count < 0); | |
| 359 | + } | |
| 356 | 360 | if (!result) |
| 357 | 361 | result = dreq->error; |
| 358 | − if (!result) | |
| 359 | − result = dreq->count; | |
| 360 | 362 | |
| 361 | 363 | out: |
| 362 | 364 | return (ssize_t) result; |
| @@ -386,8 +388,10 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq, bool write) · 23 unmodified lines | ||
| 386 | 388 | |
| 387 | 389 | if (dreq->iocb) { |
| 388 | 390 | long res = (long) dreq->error; |
| 389 | − if (!res) | |
| 391 | + if (dreq->count != 0) { | |
| 390 | 392 | res = (long) dreq->count; |
| 393 | + WARN_ON_ONCE(dreq->count < 0); | |
| 394 | + } | |
| 391 | 395 | dreq->iocb->ki_complete(dreq->iocb, res, 0); |
| 392 | 396 | } |
| 393 | 397 | |
| @@ -282,6 +282,7 @@ nfs_init_locked(struct inode *inode, void *opaque) · 281 unmodified lines | ||
| 282 | 282 | struct nfs_fattr *fattr = desc->fattr; |
| 283 | 283 | |
| 284 | 284 | set_nfs_fileid(inode, fattr->fileid); |
| 285 | + inode->i_mode = fattr->mode; | |
| 285 | 286 | nfs_copy_fh(NFS_FH(inode), desc->fh); |
| 286 | 287 | return 0; |
| 287 | 288 | } |
| @@ -2882,12 +2882,11 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) · 2881 unmodified lines | ||
| 2882 | 2882 | call_close |= is_wronly; |
| 2883 | 2883 | else if (is_wronly) |
| 2884 | 2884 | calldata->arg.fmode |= FMODE_WRITE; |
| 2885 | + if (calldata->arg.fmode != (FMODE_READ|FMODE_WRITE)) | |
| 2886 | + call_close |= is_rdwr; | |
| 2885 | 2887 | } else if (is_rdwr) |
| 2886 | 2888 | calldata->arg.fmode |= FMODE_READ|FMODE_WRITE; |
| 2887 | 2889 | |
| 2888 | − if (calldata->arg.fmode == 0) | |
| 2889 | − call_close |= is_rdwr; | |
| 2890 | − | |
| 2891 | 2890 | if (!nfs4_valid_open_stateid(state)) |
| 2892 | 2891 | call_close = 0; |
| 2893 | 2892 | spin_unlock(&state->owner->so_lock); |
| @@ -7924,8 +7923,8 @@ nfs4_layoutget_handle_exception(struct rpc_task *task, · 5030 unmodified lines | ||
| 7924 | 7923 | break; |
| 7925 | 7924 | } |
| 7926 | 7925 | 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)) { | |
| 7929 | 7928 | LIST_HEAD(head); |
| 7930 | 7929 | |
| 7931 | 7930 | /* |
| @@ -7936,10 +7935,10 @@ nfs4_layoutget_handle_exception(struct rpc_task *task, · 4 unmodified lines | ||
| 7936 | 7935 | pnfs_mark_matching_lsegs_invalid(lo, &head, NULL, 0); |
| 7937 | 7936 | spin_unlock(&inode->i_lock); |
| 7938 | 7937 | pnfs_free_lseg_list(&head); |
| 7938 | + status = -EAGAIN; | |
| 7939 | + goto out; | |
| 7939 | 7940 | } else |
| 7940 | 7941 | spin_unlock(&inode->i_lock); |
| 7941 | − status = -EAGAIN; | |
| 7942 | − goto out; | |
| 7943 | 7942 | } |
| 7944 | 7943 | |
| 7945 | 7944 | status = nfs4_handle_exception(server, status, exception); |
| @@ -8036,7 +8035,10 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout, gfp_t gfp_flags) · 90 unmodified lines | ||
| 8036 | 8035 | .flags = RPC_TASK_ASYNC, |
| 8037 | 8036 | }; |
| 8038 | 8037 | 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 | + }; | |
| 8040 | 8042 | int status = 0; |
| 8041 | 8043 | |
| 8042 | 8044 | dprintk("--> %s\n", __func__); |
| @@ -1488,9 +1488,9 @@ restart: · 1487 unmodified lines | ||
| 1488 | 1488 | } |
| 1489 | 1489 | spin_unlock(&state->state_lock); |
| 1490 | 1490 | } |
| 1491 | − nfs4_put_open_state(state); | |
| 1492 | 1491 | clear_bit(NFS_STATE_RECLAIM_NOGRACE, |
| 1493 | 1492 | &state->flags); |
| 1493 | + nfs4_put_open_state(state); | |
| 1494 | 1494 | spin_lock(&sp->so_lock); |
| 1495 | 1495 | goto restart; |
| 1496 | 1496 | } |
| @@ -361,8 +361,10 @@ pnfs_layout_remove_lseg(struct pnfs_layout_hdr *lo, · 360 unmodified lines | ||
| 361 | 361 | list_del_init(&lseg->pls_list); |
| 362 | 362 | /* Matched by pnfs_get_layout_hdr in pnfs_layout_insert_lseg */ |
| 363 | 363 | 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); | |
| 365 | 366 | clear_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags); |
| 367 | + } | |
| 366 | 368 | rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq); |
| 367 | 369 | } |
| 368 | 370 | |
| @@ -1290,6 +1292,7 @@ alloc_init_layout_hdr(struct inode *ino, · 921 unmodified lines | ||
| 1290 | 1292 | INIT_LIST_HEAD(&lo->plh_bulk_destroy); |
| 1291 | 1293 | lo->plh_inode = ino; |
| 1292 | 1294 | lo->plh_lc_cred = get_rpccred(ctx->cred); |
| 1295 | + lo->plh_flags |= 1 << NFS_LAYOUT_INVALID_STID; | |
| 1293 | 1296 | return lo; |
| 1294 | 1297 | } |
| 1295 | 1298 | |
| @@ -1297,6 +1300,8 @@ static struct pnfs_layout_hdr * · 1 unmodified line | ||
| 1297 | 1300 | pnfs_find_alloc_layout(struct inode *ino, |
| 1298 | 1301 | struct nfs_open_context *ctx, |
| 1299 | 1302 | gfp_t gfp_flags) |
| 1303 | + __releases(&ino->i_lock) | |
| 1304 | + __acquires(&ino->i_lock) | |
| 1300 | 1305 | { |
| 1301 | 1306 | struct nfs_inode *nfsi = NFS_I(ino); |
| 1302 | 1307 | struct pnfs_layout_hdr *new = NULL; |
| @@ -1565,8 +1570,7 @@ lookup_again: · 262 unmodified lines | ||
| 1565 | 1570 | * stateid, or it has been invalidated, then we must use the open |
| 1566 | 1571 | * stateid. |
| 1567 | 1572 | */ |
| 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)) { | |
| 1570 | 1574 | |
| 1571 | 1575 | /* |
| 1572 | 1576 | * The first layoutget for the file. Need to serialize per |
| @@ -247,7 +247,11 @@ void pnfs_fetch_commit_bucket_list(struct list_head *pages, · 246 unmodified lines | ||
| 247 | 247 | } |
| 248 | 248 | |
| 249 | 249 | /* 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 | + */ | |
| 251 | 255 | static bool |
| 252 | 256 | pnfs_generic_commit_cancel_empty_pagelist(struct list_head *pages, |
| 253 | 257 | struct nfs_commit_data *data, |
| @@ -256,7 +260,11 @@ pnfs_generic_commit_cancel_empty_pagelist(struct list_head *pages, · 2 unmodified lines | ||
| 256 | 260 | if (list_empty(pages)) { |
| 257 | 261 | if (atomic_dec_and_test(&cinfo->mds->rpcs_out)) |
| 258 | 262 | 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); | |
| 260 | 268 | return true; |
| 261 | 269 | } |
| 262 | 270 | |
| @@ -367,13 +367,13 @@ readpage_async_filler(void *data, struct page *page) · 366 unmodified lines | ||
| 367 | 367 | nfs_list_remove_request(new); |
| 368 | 368 | nfs_readpage_release(new); |
| 369 | 369 | error = desc->pgio->pg_error; |
| 370 | − goto out_unlock; | |
| 370 | + goto out; | |
| 371 | 371 | } |
| 372 | 372 | return 0; |
| 373 | 373 | out_error: |
| 374 | 374 | error = PTR_ERR(new); |
| 375 | −out_unlock: | |
| 376 | 375 | unlock_page(page); |
| 376 | +out: | |
| 377 | 377 | return error; |
| 378 | 378 | } |
| 379 | 379 | |