diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/file-item.c | 2 | ||||
-rw-r--r-- | fs/ceph/caps.c | 2 | ||||
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.c | 2 | ||||
-rw-r--r-- | fs/nfs/blocklayout/rpc_pipefs.c | 14 | ||||
-rw-r--r-- | fs/nfs/delegation.c | 25 | ||||
-rw-r--r-- | fs/nfs/delegation.h | 1 | ||||
-rw-r--r-- | fs/nfs/dir.c | 1 | ||||
-rw-r--r-- | fs/nfs/direct.c | 1 | ||||
-rw-r--r-- | fs/nfs/filelayout/filelayout.c | 3 | ||||
-rw-r--r-- | fs/nfs/inode.c | 2 | ||||
-rw-r--r-- | fs/nfs/netns.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 95 | ||||
-rw-r--r-- | fs/nfs/write.c | 2 | ||||
-rw-r--r-- | fs/notify/fsnotify.c | 36 | ||||
-rw-r--r-- | fs/notify/fsnotify.h | 4 | ||||
-rw-r--r-- | fs/notify/inode_mark.c | 8 | ||||
-rw-r--r-- | fs/notify/mark.c | 36 | ||||
-rw-r--r-- | fs/notify/vfsmount_mark.c | 8 | ||||
-rw-r--r-- | fs/ocfs2/cluster/tcp.c | 2 | ||||
-rw-r--r-- | fs/overlayfs/readdir.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_util.c | 72 | ||||
-rw-r--r-- | fs/xfs/xfs_itable.c | 250 | ||||
-rw-r--r-- | fs/xfs/xfs_itable.h | 16 |
23 files changed, 296 insertions, 289 deletions
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 783a94355efd..84a2d1868271 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -413,7 +413,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | |||
413 | ret = 0; | 413 | ret = 0; |
414 | fail: | 414 | fail: |
415 | while (ret < 0 && !list_empty(&tmplist)) { | 415 | while (ret < 0 && !list_empty(&tmplist)) { |
416 | sums = list_entry(&tmplist, struct btrfs_ordered_sum, list); | 416 | sums = list_entry(tmplist.next, struct btrfs_ordered_sum, list); |
417 | list_del(&sums->list); | 417 | list_del(&sums->list); |
418 | kfree(sums); | 418 | kfree(sums); |
419 | } | 419 | } |
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 659f2ea9e6f7..cefca661464b 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -2638,7 +2638,7 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid, | |||
2638 | 2638 | ||
2639 | for (i = 0; i < CEPH_CAP_BITS; i++) | 2639 | for (i = 0; i < CEPH_CAP_BITS; i++) |
2640 | if ((dirty & (1 << i)) && | 2640 | if ((dirty & (1 << i)) && |
2641 | flush_tid == ci->i_cap_flush_tid[i]) | 2641 | (u16)flush_tid == ci->i_cap_flush_tid[i]) |
2642 | cleaned |= 1 << i; | 2642 | cleaned |= 1 << i; |
2643 | 2643 | ||
2644 | dout("handle_cap_flush_ack inode %p mds%d seq %d on %s cleaned %s," | 2644 | dout("handle_cap_flush_ack inode %p mds%d seq %d on %s cleaned %s," |
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 5228f201d3d5..4f46f7a05289 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
@@ -378,7 +378,7 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) | |||
378 | loff_t offset = header->args.offset; | 378 | loff_t offset = header->args.offset; |
379 | size_t count = header->args.count; | 379 | size_t count = header->args.count; |
380 | struct page **pages = header->args.pages; | 380 | struct page **pages = header->args.pages; |
381 | int pg_index = pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT; | 381 | int pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT; |
382 | unsigned int pg_len; | 382 | unsigned int pg_len; |
383 | struct blk_plug plug; | 383 | struct blk_plug plug; |
384 | int i; | 384 | int i; |
diff --git a/fs/nfs/blocklayout/rpc_pipefs.c b/fs/nfs/blocklayout/rpc_pipefs.c index e966c023b1b7..acbf9ca4018c 100644 --- a/fs/nfs/blocklayout/rpc_pipefs.c +++ b/fs/nfs/blocklayout/rpc_pipefs.c | |||
@@ -65,17 +65,18 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, | |||
65 | 65 | ||
66 | dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); | 66 | dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); |
67 | 67 | ||
68 | mutex_lock(&nn->bl_mutex); | ||
68 | bl_pipe_msg.bl_wq = &nn->bl_wq; | 69 | bl_pipe_msg.bl_wq = &nn->bl_wq; |
69 | 70 | ||
70 | b->simple.len += 4; /* single volume */ | 71 | b->simple.len += 4; /* single volume */ |
71 | if (b->simple.len > PAGE_SIZE) | 72 | if (b->simple.len > PAGE_SIZE) |
72 | return -EIO; | 73 | goto out_unlock; |
73 | 74 | ||
74 | memset(msg, 0, sizeof(*msg)); | 75 | memset(msg, 0, sizeof(*msg)); |
75 | msg->len = sizeof(*bl_msg) + b->simple.len; | 76 | msg->len = sizeof(*bl_msg) + b->simple.len; |
76 | msg->data = kzalloc(msg->len, gfp_mask); | 77 | msg->data = kzalloc(msg->len, gfp_mask); |
77 | if (!msg->data) | 78 | if (!msg->data) |
78 | goto out; | 79 | goto out_free_data; |
79 | 80 | ||
80 | bl_msg = msg->data; | 81 | bl_msg = msg->data; |
81 | bl_msg->type = BL_DEVICE_MOUNT, | 82 | bl_msg->type = BL_DEVICE_MOUNT, |
@@ -87,7 +88,7 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, | |||
87 | rc = rpc_queue_upcall(nn->bl_device_pipe, msg); | 88 | rc = rpc_queue_upcall(nn->bl_device_pipe, msg); |
88 | if (rc < 0) { | 89 | if (rc < 0) { |
89 | remove_wait_queue(&nn->bl_wq, &wq); | 90 | remove_wait_queue(&nn->bl_wq, &wq); |
90 | goto out; | 91 | goto out_free_data; |
91 | } | 92 | } |
92 | 93 | ||
93 | set_current_state(TASK_UNINTERRUPTIBLE); | 94 | set_current_state(TASK_UNINTERRUPTIBLE); |
@@ -97,12 +98,14 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, | |||
97 | if (reply->status != BL_DEVICE_REQUEST_PROC) { | 98 | if (reply->status != BL_DEVICE_REQUEST_PROC) { |
98 | printk(KERN_WARNING "%s failed to decode device: %d\n", | 99 | printk(KERN_WARNING "%s failed to decode device: %d\n", |
99 | __func__, reply->status); | 100 | __func__, reply->status); |
100 | goto out; | 101 | goto out_free_data; |
101 | } | 102 | } |
102 | 103 | ||
103 | dev = MKDEV(reply->major, reply->minor); | 104 | dev = MKDEV(reply->major, reply->minor); |
104 | out: | 105 | out_free_data: |
105 | kfree(msg->data); | 106 | kfree(msg->data); |
107 | out_unlock: | ||
108 | mutex_unlock(&nn->bl_mutex); | ||
106 | return dev; | 109 | return dev; |
107 | } | 110 | } |
108 | 111 | ||
@@ -232,6 +235,7 @@ static int nfs4blocklayout_net_init(struct net *net) | |||
232 | struct nfs_net *nn = net_generic(net, nfs_net_id); | 235 | struct nfs_net *nn = net_generic(net, nfs_net_id); |
233 | struct dentry *dentry; | 236 | struct dentry *dentry; |
234 | 237 | ||
238 | mutex_init(&nn->bl_mutex); | ||
235 | init_waitqueue_head(&nn->bl_wq); | 239 | init_waitqueue_head(&nn->bl_wq); |
236 | nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); | 240 | nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); |
237 | if (IS_ERR(nn->bl_device_pipe)) | 241 | if (IS_ERR(nn->bl_device_pipe)) |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 5853f53db732..7f3f60641344 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -125,6 +125,8 @@ again: | |||
125 | continue; | 125 | continue; |
126 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | 126 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) |
127 | continue; | 127 | continue; |
128 | if (!nfs4_valid_open_stateid(state)) | ||
129 | continue; | ||
128 | if (!nfs4_stateid_match(&state->stateid, stateid)) | 130 | if (!nfs4_stateid_match(&state->stateid, stateid)) |
129 | continue; | 131 | continue; |
130 | get_nfs_open_context(ctx); | 132 | get_nfs_open_context(ctx); |
@@ -193,7 +195,11 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation * | |||
193 | { | 195 | { |
194 | int res = 0; | 196 | int res = 0; |
195 | 197 | ||
196 | res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync); | 198 | if (!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) |
199 | res = nfs4_proc_delegreturn(inode, | ||
200 | delegation->cred, | ||
201 | &delegation->stateid, | ||
202 | issync); | ||
197 | nfs_free_delegation(delegation); | 203 | nfs_free_delegation(delegation); |
198 | return res; | 204 | return res; |
199 | } | 205 | } |
@@ -380,11 +386,13 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation | |||
380 | { | 386 | { |
381 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 387 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
382 | struct nfs_inode *nfsi = NFS_I(inode); | 388 | struct nfs_inode *nfsi = NFS_I(inode); |
383 | int err; | 389 | int err = 0; |
384 | 390 | ||
385 | if (delegation == NULL) | 391 | if (delegation == NULL) |
386 | return 0; | 392 | return 0; |
387 | do { | 393 | do { |
394 | if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) | ||
395 | break; | ||
388 | err = nfs_delegation_claim_opens(inode, &delegation->stateid); | 396 | err = nfs_delegation_claim_opens(inode, &delegation->stateid); |
389 | if (!issync || err != -EAGAIN) | 397 | if (!issync || err != -EAGAIN) |
390 | break; | 398 | break; |
@@ -605,10 +613,23 @@ static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *cl | |||
605 | rcu_read_unlock(); | 613 | rcu_read_unlock(); |
606 | } | 614 | } |
607 | 615 | ||
616 | static void nfs_revoke_delegation(struct inode *inode) | ||
617 | { | ||
618 | struct nfs_delegation *delegation; | ||
619 | rcu_read_lock(); | ||
620 | delegation = rcu_dereference(NFS_I(inode)->delegation); | ||
621 | if (delegation != NULL) { | ||
622 | set_bit(NFS_DELEGATION_REVOKED, &delegation->flags); | ||
623 | nfs_mark_return_delegation(NFS_SERVER(inode), delegation); | ||
624 | } | ||
625 | rcu_read_unlock(); | ||
626 | } | ||
627 | |||
608 | void nfs_remove_bad_delegation(struct inode *inode) | 628 | void nfs_remove_bad_delegation(struct inode *inode) |
609 | { | 629 | { |
610 | struct nfs_delegation *delegation; | 630 | struct nfs_delegation *delegation; |
611 | 631 | ||
632 | nfs_revoke_delegation(inode); | ||
612 | delegation = nfs_inode_detach_delegation(inode); | 633 | delegation = nfs_inode_detach_delegation(inode); |
613 | if (delegation) { | 634 | if (delegation) { |
614 | nfs_inode_find_state_and_recover(inode, &delegation->stateid); | 635 | nfs_inode_find_state_and_recover(inode, &delegation->stateid); |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 5c1cce39297f..e3c20a3ccc93 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -31,6 +31,7 @@ enum { | |||
31 | NFS_DELEGATION_RETURN_IF_CLOSED, | 31 | NFS_DELEGATION_RETURN_IF_CLOSED, |
32 | NFS_DELEGATION_REFERENCED, | 32 | NFS_DELEGATION_REFERENCED, |
33 | NFS_DELEGATION_RETURNING, | 33 | NFS_DELEGATION_RETURNING, |
34 | NFS_DELEGATION_REVOKED, | ||
34 | }; | 35 | }; |
35 | 36 | ||
36 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 37 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 06e8cfcbb670..6e62155abf26 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1527,6 +1527,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, | |||
1527 | case -ENOENT: | 1527 | case -ENOENT: |
1528 | d_drop(dentry); | 1528 | d_drop(dentry); |
1529 | d_add(dentry, NULL); | 1529 | d_add(dentry, NULL); |
1530 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
1530 | break; | 1531 | break; |
1531 | case -EISDIR: | 1532 | case -EISDIR: |
1532 | case -ENOTDIR: | 1533 | case -ENOTDIR: |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 20cffc830468..10bf07280f4a 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -266,6 +266,7 @@ static void nfs_direct_req_free(struct kref *kref) | |||
266 | { | 266 | { |
267 | struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); | 267 | struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); |
268 | 268 | ||
269 | nfs_free_pnfs_ds_cinfo(&dreq->ds_cinfo); | ||
269 | if (dreq->l_ctx != NULL) | 270 | if (dreq->l_ctx != NULL) |
270 | nfs_put_lock_context(dreq->l_ctx); | 271 | nfs_put_lock_context(dreq->l_ctx); |
271 | if (dreq->ctx != NULL) | 272 | if (dreq->ctx != NULL) |
diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c index 46fab1cb455a..7afb52f6a25a 100644 --- a/fs/nfs/filelayout/filelayout.c +++ b/fs/nfs/filelayout/filelayout.c | |||
@@ -145,9 +145,6 @@ static int filelayout_async_handle_error(struct rpc_task *task, | |||
145 | case -NFS4ERR_DELEG_REVOKED: | 145 | case -NFS4ERR_DELEG_REVOKED: |
146 | case -NFS4ERR_ADMIN_REVOKED: | 146 | case -NFS4ERR_ADMIN_REVOKED: |
147 | case -NFS4ERR_BAD_STATEID: | 147 | case -NFS4ERR_BAD_STATEID: |
148 | if (state == NULL) | ||
149 | break; | ||
150 | nfs_remove_bad_delegation(state->inode); | ||
151 | case -NFS4ERR_OPENMODE: | 148 | case -NFS4ERR_OPENMODE: |
152 | if (state == NULL) | 149 | if (state == NULL) |
153 | break; | 150 | break; |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6388a59f2add..00689a8a85e4 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -626,7 +626,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
626 | { | 626 | { |
627 | struct inode *inode = dentry->d_inode; | 627 | struct inode *inode = dentry->d_inode; |
628 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; | 628 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; |
629 | int err; | 629 | int err = 0; |
630 | 630 | ||
631 | trace_nfs_getattr_enter(inode); | 631 | trace_nfs_getattr_enter(inode); |
632 | /* Flush out writes to the server in order to update c/mtime. */ | 632 | /* Flush out writes to the server in order to update c/mtime. */ |
diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h index ef221fb8a183..f0e06e4acbef 100644 --- a/fs/nfs/netns.h +++ b/fs/nfs/netns.h | |||
@@ -19,6 +19,7 @@ struct nfs_net { | |||
19 | struct rpc_pipe *bl_device_pipe; | 19 | struct rpc_pipe *bl_device_pipe; |
20 | struct bl_dev_msg bl_mount_reply; | 20 | struct bl_dev_msg bl_mount_reply; |
21 | wait_queue_head_t bl_wq; | 21 | wait_queue_head_t bl_wq; |
22 | struct mutex bl_mutex; | ||
22 | struct list_head nfs_client_list; | 23 | struct list_head nfs_client_list; |
23 | struct list_head nfs_volume_list; | 24 | struct list_head nfs_volume_list; |
24 | #if IS_ENABLED(CONFIG_NFS_V4) | 25 | #if IS_ENABLED(CONFIG_NFS_V4) |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 405bd95c1f58..69dc20a743f9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -370,11 +370,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc | |||
370 | case -NFS4ERR_DELEG_REVOKED: | 370 | case -NFS4ERR_DELEG_REVOKED: |
371 | case -NFS4ERR_ADMIN_REVOKED: | 371 | case -NFS4ERR_ADMIN_REVOKED: |
372 | case -NFS4ERR_BAD_STATEID: | 372 | case -NFS4ERR_BAD_STATEID: |
373 | if (inode != NULL && nfs4_have_delegation(inode, FMODE_READ)) { | ||
374 | nfs_remove_bad_delegation(inode); | ||
375 | exception->retry = 1; | ||
376 | break; | ||
377 | } | ||
378 | if (state == NULL) | 373 | if (state == NULL) |
379 | break; | 374 | break; |
380 | ret = nfs4_schedule_stateid_recovery(server, state); | 375 | ret = nfs4_schedule_stateid_recovery(server, state); |
@@ -1654,7 +1649,7 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct | |||
1654 | nfs_inode_find_state_and_recover(state->inode, | 1649 | nfs_inode_find_state_and_recover(state->inode, |
1655 | stateid); | 1650 | stateid); |
1656 | nfs4_schedule_stateid_recovery(server, state); | 1651 | nfs4_schedule_stateid_recovery(server, state); |
1657 | return 0; | 1652 | return -EAGAIN; |
1658 | case -NFS4ERR_DELAY: | 1653 | case -NFS4ERR_DELAY: |
1659 | case -NFS4ERR_GRACE: | 1654 | case -NFS4ERR_GRACE: |
1660 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 1655 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
@@ -2109,46 +2104,60 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
2109 | return ret; | 2104 | return ret; |
2110 | } | 2105 | } |
2111 | 2106 | ||
2107 | static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state) | ||
2108 | { | ||
2109 | nfs_remove_bad_delegation(state->inode); | ||
2110 | write_seqlock(&state->seqlock); | ||
2111 | nfs4_stateid_copy(&state->stateid, &state->open_stateid); | ||
2112 | write_sequnlock(&state->seqlock); | ||
2113 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
2114 | } | ||
2115 | |||
2116 | static void nfs40_clear_delegation_stateid(struct nfs4_state *state) | ||
2117 | { | ||
2118 | if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL) | ||
2119 | nfs_finish_clear_delegation_stateid(state); | ||
2120 | } | ||
2121 | |||
2122 | static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) | ||
2123 | { | ||
2124 | /* NFSv4.0 doesn't allow for delegation recovery on open expire */ | ||
2125 | nfs40_clear_delegation_stateid(state); | ||
2126 | return nfs4_open_expired(sp, state); | ||
2127 | } | ||
2128 | |||
2112 | #if defined(CONFIG_NFS_V4_1) | 2129 | #if defined(CONFIG_NFS_V4_1) |
2113 | static void nfs41_clear_delegation_stateid(struct nfs4_state *state) | 2130 | static void nfs41_check_delegation_stateid(struct nfs4_state *state) |
2114 | { | 2131 | { |
2115 | struct nfs_server *server = NFS_SERVER(state->inode); | 2132 | struct nfs_server *server = NFS_SERVER(state->inode); |
2116 | nfs4_stateid *stateid = &state->stateid; | 2133 | nfs4_stateid stateid; |
2117 | struct nfs_delegation *delegation; | 2134 | struct nfs_delegation *delegation; |
2118 | struct rpc_cred *cred = NULL; | 2135 | struct rpc_cred *cred; |
2119 | int status = -NFS4ERR_BAD_STATEID; | 2136 | int status; |
2120 | |||
2121 | /* If a state reset has been done, test_stateid is unneeded */ | ||
2122 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | ||
2123 | return; | ||
2124 | 2137 | ||
2125 | /* Get the delegation credential for use by test/free_stateid */ | 2138 | /* Get the delegation credential for use by test/free_stateid */ |
2126 | rcu_read_lock(); | 2139 | rcu_read_lock(); |
2127 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); | 2140 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); |
2128 | if (delegation != NULL && | 2141 | if (delegation == NULL) { |
2129 | nfs4_stateid_match(&delegation->stateid, stateid)) { | ||
2130 | cred = get_rpccred(delegation->cred); | ||
2131 | rcu_read_unlock(); | ||
2132 | status = nfs41_test_stateid(server, stateid, cred); | ||
2133 | trace_nfs4_test_delegation_stateid(state, NULL, status); | ||
2134 | } else | ||
2135 | rcu_read_unlock(); | 2142 | rcu_read_unlock(); |
2143 | return; | ||
2144 | } | ||
2145 | |||
2146 | nfs4_stateid_copy(&stateid, &delegation->stateid); | ||
2147 | cred = get_rpccred(delegation->cred); | ||
2148 | rcu_read_unlock(); | ||
2149 | status = nfs41_test_stateid(server, &stateid, cred); | ||
2150 | trace_nfs4_test_delegation_stateid(state, NULL, status); | ||
2136 | 2151 | ||
2137 | if (status != NFS_OK) { | 2152 | if (status != NFS_OK) { |
2138 | /* Free the stateid unless the server explicitly | 2153 | /* Free the stateid unless the server explicitly |
2139 | * informs us the stateid is unrecognized. */ | 2154 | * informs us the stateid is unrecognized. */ |
2140 | if (status != -NFS4ERR_BAD_STATEID) | 2155 | if (status != -NFS4ERR_BAD_STATEID) |
2141 | nfs41_free_stateid(server, stateid, cred); | 2156 | nfs41_free_stateid(server, &stateid, cred); |
2142 | nfs_remove_bad_delegation(state->inode); | 2157 | nfs_finish_clear_delegation_stateid(state); |
2143 | |||
2144 | write_seqlock(&state->seqlock); | ||
2145 | nfs4_stateid_copy(&state->stateid, &state->open_stateid); | ||
2146 | write_sequnlock(&state->seqlock); | ||
2147 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
2148 | } | 2158 | } |
2149 | 2159 | ||
2150 | if (cred != NULL) | 2160 | put_rpccred(cred); |
2151 | put_rpccred(cred); | ||
2152 | } | 2161 | } |
2153 | 2162 | ||
2154 | /** | 2163 | /** |
@@ -2192,7 +2201,7 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
2192 | { | 2201 | { |
2193 | int status; | 2202 | int status; |
2194 | 2203 | ||
2195 | nfs41_clear_delegation_stateid(state); | 2204 | nfs41_check_delegation_stateid(state); |
2196 | status = nfs41_check_open_stateid(state); | 2205 | status = nfs41_check_open_stateid(state); |
2197 | if (status != NFS_OK) | 2206 | if (status != NFS_OK) |
2198 | status = nfs4_open_expired(sp, state); | 2207 | status = nfs4_open_expired(sp, state); |
@@ -2231,19 +2240,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, | |||
2231 | seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); | 2240 | seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); |
2232 | 2241 | ||
2233 | ret = _nfs4_proc_open(opendata); | 2242 | ret = _nfs4_proc_open(opendata); |
2234 | if (ret != 0) { | 2243 | if (ret != 0) |
2235 | if (ret == -ENOENT) { | ||
2236 | dentry = opendata->dentry; | ||
2237 | if (dentry->d_inode) | ||
2238 | d_delete(dentry); | ||
2239 | else if (d_unhashed(dentry)) | ||
2240 | d_add(dentry, NULL); | ||
2241 | |||
2242 | nfs_set_verifier(dentry, | ||
2243 | nfs_save_change_attribute(opendata->dir->d_inode)); | ||
2244 | } | ||
2245 | goto out; | 2244 | goto out; |
2246 | } | ||
2247 | 2245 | ||
2248 | state = nfs4_opendata_to_nfs4_state(opendata); | 2246 | state = nfs4_opendata_to_nfs4_state(opendata); |
2249 | ret = PTR_ERR(state); | 2247 | ret = PTR_ERR(state); |
@@ -4841,9 +4839,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
4841 | case -NFS4ERR_DELEG_REVOKED: | 4839 | case -NFS4ERR_DELEG_REVOKED: |
4842 | case -NFS4ERR_ADMIN_REVOKED: | 4840 | case -NFS4ERR_ADMIN_REVOKED: |
4843 | case -NFS4ERR_BAD_STATEID: | 4841 | case -NFS4ERR_BAD_STATEID: |
4844 | if (state == NULL) | ||
4845 | break; | ||
4846 | nfs_remove_bad_delegation(state->inode); | ||
4847 | case -NFS4ERR_OPENMODE: | 4842 | case -NFS4ERR_OPENMODE: |
4848 | if (state == NULL) | 4843 | if (state == NULL) |
4849 | break; | 4844 | break; |
@@ -8341,7 +8336,7 @@ static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { | |||
8341 | static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { | 8336 | static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { |
8342 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | 8337 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, |
8343 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 8338 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
8344 | .recover_open = nfs4_open_expired, | 8339 | .recover_open = nfs40_open_expired, |
8345 | .recover_lock = nfs4_lock_expired, | 8340 | .recover_lock = nfs4_lock_expired, |
8346 | .establish_clid = nfs4_init_clientid, | 8341 | .establish_clid = nfs4_init_clientid, |
8347 | }; | 8342 | }; |
@@ -8408,8 +8403,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { | |||
8408 | | NFS_CAP_CHANGE_ATTR | 8403 | | NFS_CAP_CHANGE_ATTR |
8409 | | NFS_CAP_POSIX_LOCK | 8404 | | NFS_CAP_POSIX_LOCK |
8410 | | NFS_CAP_STATEID_NFSV41 | 8405 | | NFS_CAP_STATEID_NFSV41 |
8411 | | NFS_CAP_ATOMIC_OPEN_V1 | 8406 | | NFS_CAP_ATOMIC_OPEN_V1, |
8412 | | NFS_CAP_SEEK, | ||
8413 | .init_client = nfs41_init_client, | 8407 | .init_client = nfs41_init_client, |
8414 | .shutdown_client = nfs41_shutdown_client, | 8408 | .shutdown_client = nfs41_shutdown_client, |
8415 | .match_stateid = nfs41_match_stateid, | 8409 | .match_stateid = nfs41_match_stateid, |
@@ -8431,7 +8425,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { | |||
8431 | | NFS_CAP_CHANGE_ATTR | 8425 | | NFS_CAP_CHANGE_ATTR |
8432 | | NFS_CAP_POSIX_LOCK | 8426 | | NFS_CAP_POSIX_LOCK |
8433 | | NFS_CAP_STATEID_NFSV41 | 8427 | | NFS_CAP_STATEID_NFSV41 |
8434 | | NFS_CAP_ATOMIC_OPEN_V1, | 8428 | | NFS_CAP_ATOMIC_OPEN_V1 |
8429 | | NFS_CAP_SEEK, | ||
8435 | .init_client = nfs41_init_client, | 8430 | .init_client = nfs41_init_client, |
8436 | .shutdown_client = nfs41_shutdown_client, | 8431 | .shutdown_client = nfs41_shutdown_client, |
8437 | .match_stateid = nfs41_match_stateid, | 8432 | .match_stateid = nfs41_match_stateid, |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 12493846a2d3..f83b02dc9166 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -715,8 +715,6 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
715 | 715 | ||
716 | if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) | 716 | if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) |
717 | nfs_release_request(req); | 717 | nfs_release_request(req); |
718 | else | ||
719 | WARN_ON_ONCE(1); | ||
720 | } | 718 | } |
721 | 719 | ||
722 | static void | 720 | static void |
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 9d3e9c50066a..89326acd4561 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c | |||
@@ -229,8 +229,16 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, | |||
229 | &fsnotify_mark_srcu); | 229 | &fsnotify_mark_srcu); |
230 | } | 230 | } |
231 | 231 | ||
232 | /* | ||
233 | * We need to merge inode & vfsmount mark lists so that inode mark | ||
234 | * ignore masks are properly reflected for mount mark notifications. | ||
235 | * That's why this traversal is so complicated... | ||
236 | */ | ||
232 | while (inode_node || vfsmount_node) { | 237 | while (inode_node || vfsmount_node) { |
233 | inode_group = vfsmount_group = NULL; | 238 | inode_group = NULL; |
239 | inode_mark = NULL; | ||
240 | vfsmount_group = NULL; | ||
241 | vfsmount_mark = NULL; | ||
234 | 242 | ||
235 | if (inode_node) { | 243 | if (inode_node) { |
236 | inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu), | 244 | inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu), |
@@ -244,21 +252,19 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, | |||
244 | vfsmount_group = vfsmount_mark->group; | 252 | vfsmount_group = vfsmount_mark->group; |
245 | } | 253 | } |
246 | 254 | ||
247 | if (inode_group > vfsmount_group) { | 255 | if (inode_group && vfsmount_group) { |
248 | /* handle inode */ | 256 | int cmp = fsnotify_compare_groups(inode_group, |
249 | ret = send_to_group(to_tell, inode_mark, NULL, mask, | 257 | vfsmount_group); |
250 | data, data_is, cookie, file_name); | 258 | if (cmp > 0) { |
251 | /* we didn't use the vfsmount_mark */ | 259 | inode_group = NULL; |
252 | vfsmount_group = NULL; | 260 | inode_mark = NULL; |
253 | } else if (vfsmount_group > inode_group) { | 261 | } else if (cmp < 0) { |
254 | ret = send_to_group(to_tell, NULL, vfsmount_mark, mask, | 262 | vfsmount_group = NULL; |
255 | data, data_is, cookie, file_name); | 263 | vfsmount_mark = NULL; |
256 | inode_group = NULL; | 264 | } |
257 | } else { | ||
258 | ret = send_to_group(to_tell, inode_mark, vfsmount_mark, | ||
259 | mask, data, data_is, cookie, | ||
260 | file_name); | ||
261 | } | 265 | } |
266 | ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask, | ||
267 | data, data_is, cookie, file_name); | ||
262 | 268 | ||
263 | if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS)) | 269 | if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS)) |
264 | goto out; | 270 | goto out; |
diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h index 9c0898c4cfe1..3b68b0ae0a97 100644 --- a/fs/notify/fsnotify.h +++ b/fs/notify/fsnotify.h | |||
@@ -12,6 +12,10 @@ extern void fsnotify_flush_notify(struct fsnotify_group *group); | |||
12 | /* protects reads of inode and vfsmount marks list */ | 12 | /* protects reads of inode and vfsmount marks list */ |
13 | extern struct srcu_struct fsnotify_mark_srcu; | 13 | extern struct srcu_struct fsnotify_mark_srcu; |
14 | 14 | ||
15 | /* compare two groups for sorting of marks lists */ | ||
16 | extern int fsnotify_compare_groups(struct fsnotify_group *a, | ||
17 | struct fsnotify_group *b); | ||
18 | |||
15 | extern void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *fsn_mark, | 19 | extern void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *fsn_mark, |
16 | __u32 mask); | 20 | __u32 mask); |
17 | /* add a mark to an inode */ | 21 | /* add a mark to an inode */ |
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index e8497144b323..dfbf5447eea4 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c | |||
@@ -194,6 +194,7 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | |||
194 | { | 194 | { |
195 | struct fsnotify_mark *lmark, *last = NULL; | 195 | struct fsnotify_mark *lmark, *last = NULL; |
196 | int ret = 0; | 196 | int ret = 0; |
197 | int cmp; | ||
197 | 198 | ||
198 | mark->flags |= FSNOTIFY_MARK_FLAG_INODE; | 199 | mark->flags |= FSNOTIFY_MARK_FLAG_INODE; |
199 | 200 | ||
@@ -219,11 +220,8 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | |||
219 | goto out; | 220 | goto out; |
220 | } | 221 | } |
221 | 222 | ||
222 | if (mark->group->priority < lmark->group->priority) | 223 | cmp = fsnotify_compare_groups(lmark->group, mark->group); |
223 | continue; | 224 | if (cmp < 0) |
224 | |||
225 | if ((mark->group->priority == lmark->group->priority) && | ||
226 | (mark->group < lmark->group)) | ||
227 | continue; | 225 | continue; |
228 | 226 | ||
229 | hlist_add_before_rcu(&mark->i.i_list, &lmark->i.i_list); | 227 | hlist_add_before_rcu(&mark->i.i_list, &lmark->i.i_list); |
diff --git a/fs/notify/mark.c b/fs/notify/mark.c index d90deaa08e78..34c38fabf514 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c | |||
@@ -210,6 +210,42 @@ void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mas | |||
210 | } | 210 | } |
211 | 211 | ||
212 | /* | 212 | /* |
213 | * Sorting function for lists of fsnotify marks. | ||
214 | * | ||
215 | * Fanotify supports different notification classes (reflected as priority of | ||
216 | * notification group). Events shall be passed to notification groups in | ||
217 | * decreasing priority order. To achieve this marks in notification lists for | ||
218 | * inodes and vfsmounts are sorted so that priorities of corresponding groups | ||
219 | * are descending. | ||
220 | * | ||
221 | * Furthermore correct handling of the ignore mask requires processing inode | ||
222 | * and vfsmount marks of each group together. Using the group address as | ||
223 | * further sort criterion provides a unique sorting order and thus we can | ||
224 | * merge inode and vfsmount lists of marks in linear time and find groups | ||
225 | * present in both lists. | ||
226 | * | ||
227 | * A return value of 1 signifies that b has priority over a. | ||
228 | * A return value of 0 signifies that the two marks have to be handled together. | ||
229 | * A return value of -1 signifies that a has priority over b. | ||
230 | */ | ||
231 | int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b) | ||
232 | { | ||
233 | if (a == b) | ||
234 | return 0; | ||
235 | if (!a) | ||
236 | return 1; | ||
237 | if (!b) | ||
238 | return -1; | ||
239 | if (a->priority < b->priority) | ||
240 | return 1; | ||
241 | if (a->priority > b->priority) | ||
242 | return -1; | ||
243 | if (a < b) | ||
244 | return 1; | ||
245 | return -1; | ||
246 | } | ||
247 | |||
248 | /* | ||
213 | * Attach an initialized mark to a given group and fs object. | 249 | * Attach an initialized mark to a given group and fs object. |
214 | * These marks may be used for the fsnotify backend to determine which | 250 | * These marks may be used for the fsnotify backend to determine which |
215 | * event types should be delivered to which group. | 251 | * event types should be delivered to which group. |
diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c index ac851e8376b1..faefa72a11eb 100644 --- a/fs/notify/vfsmount_mark.c +++ b/fs/notify/vfsmount_mark.c | |||
@@ -153,6 +153,7 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | |||
153 | struct mount *m = real_mount(mnt); | 153 | struct mount *m = real_mount(mnt); |
154 | struct fsnotify_mark *lmark, *last = NULL; | 154 | struct fsnotify_mark *lmark, *last = NULL; |
155 | int ret = 0; | 155 | int ret = 0; |
156 | int cmp; | ||
156 | 157 | ||
157 | mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; | 158 | mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; |
158 | 159 | ||
@@ -178,11 +179,8 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | |||
178 | goto out; | 179 | goto out; |
179 | } | 180 | } |
180 | 181 | ||
181 | if (mark->group->priority < lmark->group->priority) | 182 | cmp = fsnotify_compare_groups(lmark->group, mark->group); |
182 | continue; | 183 | if (cmp < 0) |
183 | |||
184 | if ((mark->group->priority == lmark->group->priority) && | ||
185 | (mark->group < lmark->group)) | ||
186 | continue; | 184 | continue; |
187 | 185 | ||
188 | hlist_add_before_rcu(&mark->m.m_list, &lmark->m.m_list); | 186 | hlist_add_before_rcu(&mark->m.m_list, &lmark->m.m_list); |
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index 97de0fbd9f78..a96044004064 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c | |||
@@ -925,7 +925,7 @@ static int o2net_send_tcp_msg(struct socket *sock, struct kvec *vec, | |||
925 | size_t veclen, size_t total) | 925 | size_t veclen, size_t total) |
926 | { | 926 | { |
927 | int ret; | 927 | int ret; |
928 | struct msghdr msg; | 928 | struct msghdr msg = {.msg_flags = 0,}; |
929 | 929 | ||
930 | if (sock == NULL) { | 930 | if (sock == NULL) { |
931 | ret = -EINVAL; | 931 | ret = -EINVAL; |
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 4e9d7c1fea52..2a7ef4f8e2a6 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c | |||
@@ -168,7 +168,7 @@ static void ovl_cache_put(struct ovl_dir_file *od, struct dentry *dentry) | |||
168 | { | 168 | { |
169 | struct ovl_dir_cache *cache = od->cache; | 169 | struct ovl_dir_cache *cache = od->cache; |
170 | 170 | ||
171 | list_del(&od->cursor.l_node); | 171 | list_del_init(&od->cursor.l_node); |
172 | WARN_ON(cache->refcount <= 0); | 172 | WARN_ON(cache->refcount <= 0); |
173 | cache->refcount--; | 173 | cache->refcount--; |
174 | if (!cache->refcount) { | 174 | if (!cache->refcount) { |
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index 92e8f99a5857..281002689d64 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c | |||
@@ -1338,7 +1338,10 @@ xfs_free_file_space( | |||
1338 | goto out; | 1338 | goto out; |
1339 | } | 1339 | } |
1340 | 1340 | ||
1341 | 1341 | /* | |
1342 | * Preallocate and zero a range of a file. This mechanism has the allocation | ||
1343 | * semantics of fallocate and in addition converts data in the range to zeroes. | ||
1344 | */ | ||
1342 | int | 1345 | int |
1343 | xfs_zero_file_space( | 1346 | xfs_zero_file_space( |
1344 | struct xfs_inode *ip, | 1347 | struct xfs_inode *ip, |
@@ -1346,65 +1349,30 @@ xfs_zero_file_space( | |||
1346 | xfs_off_t len) | 1349 | xfs_off_t len) |
1347 | { | 1350 | { |
1348 | struct xfs_mount *mp = ip->i_mount; | 1351 | struct xfs_mount *mp = ip->i_mount; |
1349 | uint granularity; | 1352 | uint blksize; |
1350 | xfs_off_t start_boundary; | ||
1351 | xfs_off_t end_boundary; | ||
1352 | int error; | 1353 | int error; |
1353 | 1354 | ||
1354 | trace_xfs_zero_file_space(ip); | 1355 | trace_xfs_zero_file_space(ip); |
1355 | 1356 | ||
1356 | granularity = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE); | 1357 | blksize = 1 << mp->m_sb.sb_blocklog; |
1357 | 1358 | ||
1358 | /* | 1359 | /* |
1359 | * Round the range of extents we are going to convert inwards. If the | 1360 | * Punch a hole and prealloc the range. We use hole punch rather than |
1360 | * offset is aligned, then it doesn't get changed so we zero from the | 1361 | * unwritten extent conversion for two reasons: |
1361 | * start of the block offset points to. | 1362 | * |
1363 | * 1.) Hole punch handles partial block zeroing for us. | ||
1364 | * | ||
1365 | * 2.) If prealloc returns ENOSPC, the file range is still zero-valued | ||
1366 | * by virtue of the hole punch. | ||
1362 | */ | 1367 | */ |
1363 | start_boundary = round_up(offset, granularity); | 1368 | error = xfs_free_file_space(ip, offset, len); |
1364 | end_boundary = round_down(offset + len, granularity); | 1369 | if (error) |
1365 | 1370 | goto out; | |
1366 | ASSERT(start_boundary >= offset); | ||
1367 | ASSERT(end_boundary <= offset + len); | ||
1368 | |||
1369 | if (start_boundary < end_boundary - 1) { | ||
1370 | /* | ||
1371 | * Writeback the range to ensure any inode size updates due to | ||
1372 | * appending writes make it to disk (otherwise we could just | ||
1373 | * punch out the delalloc blocks). | ||
1374 | */ | ||
1375 | error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, | ||
1376 | start_boundary, end_boundary - 1); | ||
1377 | if (error) | ||
1378 | goto out; | ||
1379 | truncate_pagecache_range(VFS_I(ip), start_boundary, | ||
1380 | end_boundary - 1); | ||
1381 | |||
1382 | /* convert the blocks */ | ||
1383 | error = xfs_alloc_file_space(ip, start_boundary, | ||
1384 | end_boundary - start_boundary - 1, | ||
1385 | XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT); | ||
1386 | if (error) | ||
1387 | goto out; | ||
1388 | |||
1389 | /* We've handled the interior of the range, now for the edges */ | ||
1390 | if (start_boundary != offset) { | ||
1391 | error = xfs_iozero(ip, offset, start_boundary - offset); | ||
1392 | if (error) | ||
1393 | goto out; | ||
1394 | } | ||
1395 | |||
1396 | if (end_boundary != offset + len) | ||
1397 | error = xfs_iozero(ip, end_boundary, | ||
1398 | offset + len - end_boundary); | ||
1399 | |||
1400 | } else { | ||
1401 | /* | ||
1402 | * It's either a sub-granularity range or the range spanned lies | ||
1403 | * partially across two adjacent blocks. | ||
1404 | */ | ||
1405 | error = xfs_iozero(ip, offset, len); | ||
1406 | } | ||
1407 | 1371 | ||
1372 | error = xfs_alloc_file_space(ip, round_down(offset, blksize), | ||
1373 | round_up(offset + len, blksize) - | ||
1374 | round_down(offset, blksize), | ||
1375 | XFS_BMAPI_PREALLOC); | ||
1408 | out: | 1376 | out: |
1409 | return error; | 1377 | return error; |
1410 | 1378 | ||
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index f1deb961a296..894924a5129b 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c | |||
@@ -236,8 +236,10 @@ xfs_bulkstat_grab_ichunk( | |||
236 | XFS_WANT_CORRUPTED_RETURN(stat == 1); | 236 | XFS_WANT_CORRUPTED_RETURN(stat == 1); |
237 | 237 | ||
238 | /* Check if the record contains the inode in request */ | 238 | /* Check if the record contains the inode in request */ |
239 | if (irec->ir_startino + XFS_INODES_PER_CHUNK <= agino) | 239 | if (irec->ir_startino + XFS_INODES_PER_CHUNK <= agino) { |
240 | return -EINVAL; | 240 | *icount = 0; |
241 | return 0; | ||
242 | } | ||
241 | 243 | ||
242 | idx = agino - irec->ir_startino + 1; | 244 | idx = agino - irec->ir_startino + 1; |
243 | if (idx < XFS_INODES_PER_CHUNK && | 245 | if (idx < XFS_INODES_PER_CHUNK && |
@@ -262,75 +264,76 @@ xfs_bulkstat_grab_ichunk( | |||
262 | 264 | ||
263 | #define XFS_BULKSTAT_UBLEFT(ubleft) ((ubleft) >= statstruct_size) | 265 | #define XFS_BULKSTAT_UBLEFT(ubleft) ((ubleft) >= statstruct_size) |
264 | 266 | ||
267 | struct xfs_bulkstat_agichunk { | ||
268 | char __user **ac_ubuffer;/* pointer into user's buffer */ | ||
269 | int ac_ubleft; /* bytes left in user's buffer */ | ||
270 | int ac_ubelem; /* spaces used in user's buffer */ | ||
271 | }; | ||
272 | |||
265 | /* | 273 | /* |
266 | * Process inodes in chunk with a pointer to a formatter function | 274 | * Process inodes in chunk with a pointer to a formatter function |
267 | * that will iget the inode and fill in the appropriate structure. | 275 | * that will iget the inode and fill in the appropriate structure. |
268 | */ | 276 | */ |
269 | int | 277 | static int |
270 | xfs_bulkstat_ag_ichunk( | 278 | xfs_bulkstat_ag_ichunk( |
271 | struct xfs_mount *mp, | 279 | struct xfs_mount *mp, |
272 | xfs_agnumber_t agno, | 280 | xfs_agnumber_t agno, |
273 | struct xfs_inobt_rec_incore *irbp, | 281 | struct xfs_inobt_rec_incore *irbp, |
274 | bulkstat_one_pf formatter, | 282 | bulkstat_one_pf formatter, |
275 | size_t statstruct_size, | 283 | size_t statstruct_size, |
276 | struct xfs_bulkstat_agichunk *acp) | 284 | struct xfs_bulkstat_agichunk *acp, |
285 | xfs_agino_t *last_agino) | ||
277 | { | 286 | { |
278 | xfs_ino_t lastino = acp->ac_lastino; | ||
279 | char __user **ubufp = acp->ac_ubuffer; | 287 | char __user **ubufp = acp->ac_ubuffer; |
280 | int ubleft = acp->ac_ubleft; | 288 | int chunkidx; |
281 | int ubelem = acp->ac_ubelem; | ||
282 | int chunkidx, clustidx; | ||
283 | int error = 0; | 289 | int error = 0; |
284 | xfs_agino_t agino; | 290 | xfs_agino_t agino = irbp->ir_startino; |
285 | 291 | ||
286 | for (agino = irbp->ir_startino, chunkidx = clustidx = 0; | 292 | for (chunkidx = 0; chunkidx < XFS_INODES_PER_CHUNK; |
287 | XFS_BULKSTAT_UBLEFT(ubleft) && | 293 | chunkidx++, agino++) { |
288 | irbp->ir_freecount < XFS_INODES_PER_CHUNK; | 294 | int fmterror; |
289 | chunkidx++, clustidx++, agino++) { | ||
290 | int fmterror; /* bulkstat formatter result */ | ||
291 | int ubused; | 295 | int ubused; |
292 | xfs_ino_t ino = XFS_AGINO_TO_INO(mp, agno, agino); | ||
293 | 296 | ||
294 | ASSERT(chunkidx < XFS_INODES_PER_CHUNK); | 297 | /* inode won't fit in buffer, we are done */ |
298 | if (acp->ac_ubleft < statstruct_size) | ||
299 | break; | ||
295 | 300 | ||
296 | /* Skip if this inode is free */ | 301 | /* Skip if this inode is free */ |
297 | if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) { | 302 | if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) |
298 | lastino = ino; | ||
299 | continue; | 303 | continue; |
300 | } | ||
301 | |||
302 | /* | ||
303 | * Count used inodes as free so we can tell when the | ||
304 | * chunk is used up. | ||
305 | */ | ||
306 | irbp->ir_freecount++; | ||
307 | 304 | ||
308 | /* Get the inode and fill in a single buffer */ | 305 | /* Get the inode and fill in a single buffer */ |
309 | ubused = statstruct_size; | 306 | ubused = statstruct_size; |
310 | error = formatter(mp, ino, *ubufp, ubleft, &ubused, &fmterror); | 307 | error = formatter(mp, XFS_AGINO_TO_INO(mp, agno, agino), |
311 | if (fmterror == BULKSTAT_RV_NOTHING) { | 308 | *ubufp, acp->ac_ubleft, &ubused, &fmterror); |
312 | if (error && error != -ENOENT && error != -EINVAL) { | 309 | |
313 | ubleft = 0; | 310 | if (fmterror == BULKSTAT_RV_GIVEUP || |
314 | break; | 311 | (error && error != -ENOENT && error != -EINVAL)) { |
315 | } | 312 | acp->ac_ubleft = 0; |
316 | lastino = ino; | ||
317 | continue; | ||
318 | } | ||
319 | if (fmterror == BULKSTAT_RV_GIVEUP) { | ||
320 | ubleft = 0; | ||
321 | ASSERT(error); | 313 | ASSERT(error); |
322 | break; | 314 | break; |
323 | } | 315 | } |
324 | if (*ubufp) | 316 | |
325 | *ubufp += ubused; | 317 | /* be careful not to leak error if at end of chunk */ |
326 | ubleft -= ubused; | 318 | if (fmterror == BULKSTAT_RV_NOTHING || error) { |
327 | ubelem++; | 319 | error = 0; |
328 | lastino = ino; | 320 | continue; |
321 | } | ||
322 | |||
323 | *ubufp += ubused; | ||
324 | acp->ac_ubleft -= ubused; | ||
325 | acp->ac_ubelem++; | ||
329 | } | 326 | } |
330 | 327 | ||
331 | acp->ac_lastino = lastino; | 328 | /* |
332 | acp->ac_ubleft = ubleft; | 329 | * Post-update *last_agino. At this point, agino will always point one |
333 | acp->ac_ubelem = ubelem; | 330 | * inode past the last inode we processed successfully. Hence we |
331 | * substract that inode when setting the *last_agino cursor so that we | ||
332 | * return the correct cookie to userspace. On the next bulkstat call, | ||
333 | * the inode under the lastino cookie will be skipped as we have already | ||
334 | * processed it here. | ||
335 | */ | ||
336 | *last_agino = agino - 1; | ||
334 | 337 | ||
335 | return error; | 338 | return error; |
336 | } | 339 | } |
@@ -353,45 +356,33 @@ xfs_bulkstat( | |||
353 | xfs_agino_t agino; /* inode # in allocation group */ | 356 | xfs_agino_t agino; /* inode # in allocation group */ |
354 | xfs_agnumber_t agno; /* allocation group number */ | 357 | xfs_agnumber_t agno; /* allocation group number */ |
355 | xfs_btree_cur_t *cur; /* btree cursor for ialloc btree */ | 358 | xfs_btree_cur_t *cur; /* btree cursor for ialloc btree */ |
356 | int end_of_ag; /* set if we've seen the ag end */ | ||
357 | int error; /* error code */ | ||
358 | int fmterror;/* bulkstat formatter result */ | ||
359 | int i; /* loop index */ | ||
360 | int icount; /* count of inodes good in irbuf */ | ||
361 | size_t irbsize; /* size of irec buffer in bytes */ | 359 | size_t irbsize; /* size of irec buffer in bytes */ |
362 | xfs_ino_t ino; /* inode number (filesystem) */ | ||
363 | xfs_inobt_rec_incore_t *irbp; /* current irec buffer pointer */ | ||
364 | xfs_inobt_rec_incore_t *irbuf; /* start of irec buffer */ | 360 | xfs_inobt_rec_incore_t *irbuf; /* start of irec buffer */ |
365 | xfs_inobt_rec_incore_t *irbufend; /* end of good irec buffer entries */ | ||
366 | xfs_ino_t lastino; /* last inode number returned */ | ||
367 | int nirbuf; /* size of irbuf */ | 361 | int nirbuf; /* size of irbuf */ |
368 | int rval; /* return value error code */ | ||
369 | int tmp; /* result value from btree calls */ | ||
370 | int ubcount; /* size of user's buffer */ | 362 | int ubcount; /* size of user's buffer */ |
371 | int ubleft; /* bytes left in user's buffer */ | 363 | struct xfs_bulkstat_agichunk ac; |
372 | char __user *ubufp; /* pointer into user's buffer */ | 364 | int error = 0; |
373 | int ubelem; /* spaces used in user's buffer */ | ||
374 | 365 | ||
375 | /* | 366 | /* |
376 | * Get the last inode value, see if there's nothing to do. | 367 | * Get the last inode value, see if there's nothing to do. |
377 | */ | 368 | */ |
378 | ino = (xfs_ino_t)*lastinop; | 369 | agno = XFS_INO_TO_AGNO(mp, *lastinop); |
379 | lastino = ino; | 370 | agino = XFS_INO_TO_AGINO(mp, *lastinop); |
380 | agno = XFS_INO_TO_AGNO(mp, ino); | ||
381 | agino = XFS_INO_TO_AGINO(mp, ino); | ||
382 | if (agno >= mp->m_sb.sb_agcount || | 371 | if (agno >= mp->m_sb.sb_agcount || |
383 | ino != XFS_AGINO_TO_INO(mp, agno, agino)) { | 372 | *lastinop != XFS_AGINO_TO_INO(mp, agno, agino)) { |
384 | *done = 1; | 373 | *done = 1; |
385 | *ubcountp = 0; | 374 | *ubcountp = 0; |
386 | return 0; | 375 | return 0; |
387 | } | 376 | } |
388 | 377 | ||
389 | ubcount = *ubcountp; /* statstruct's */ | 378 | ubcount = *ubcountp; /* statstruct's */ |
390 | ubleft = ubcount * statstruct_size; /* bytes */ | 379 | ac.ac_ubuffer = &ubuffer; |
391 | *ubcountp = ubelem = 0; | 380 | ac.ac_ubleft = ubcount * statstruct_size; /* bytes */; |
381 | ac.ac_ubelem = 0; | ||
382 | |||
383 | *ubcountp = 0; | ||
392 | *done = 0; | 384 | *done = 0; |
393 | fmterror = 0; | 385 | |
394 | ubufp = ubuffer; | ||
395 | irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4); | 386 | irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4); |
396 | if (!irbuf) | 387 | if (!irbuf) |
397 | return -ENOMEM; | 388 | return -ENOMEM; |
@@ -402,9 +393,13 @@ xfs_bulkstat( | |||
402 | * Loop over the allocation groups, starting from the last | 393 | * Loop over the allocation groups, starting from the last |
403 | * inode returned; 0 means start of the allocation group. | 394 | * inode returned; 0 means start of the allocation group. |
404 | */ | 395 | */ |
405 | rval = 0; | 396 | while (agno < mp->m_sb.sb_agcount) { |
406 | while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) { | 397 | struct xfs_inobt_rec_incore *irbp = irbuf; |
407 | cond_resched(); | 398 | struct xfs_inobt_rec_incore *irbufend = irbuf + nirbuf; |
399 | bool end_of_ag = false; | ||
400 | int icount = 0; | ||
401 | int stat; | ||
402 | |||
408 | error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); | 403 | error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); |
409 | if (error) | 404 | if (error) |
410 | break; | 405 | break; |
@@ -414,10 +409,6 @@ xfs_bulkstat( | |||
414 | */ | 409 | */ |
415 | cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno, | 410 | cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno, |
416 | XFS_BTNUM_INO); | 411 | XFS_BTNUM_INO); |
417 | irbp = irbuf; | ||
418 | irbufend = irbuf + nirbuf; | ||
419 | end_of_ag = 0; | ||
420 | icount = 0; | ||
421 | if (agino > 0) { | 412 | if (agino > 0) { |
422 | /* | 413 | /* |
423 | * In the middle of an allocation group, we need to get | 414 | * In the middle of an allocation group, we need to get |
@@ -427,22 +418,23 @@ xfs_bulkstat( | |||
427 | 418 | ||
428 | error = xfs_bulkstat_grab_ichunk(cur, agino, &icount, &r); | 419 | error = xfs_bulkstat_grab_ichunk(cur, agino, &icount, &r); |
429 | if (error) | 420 | if (error) |
430 | break; | 421 | goto del_cursor; |
431 | if (icount) { | 422 | if (icount) { |
432 | irbp->ir_startino = r.ir_startino; | 423 | irbp->ir_startino = r.ir_startino; |
433 | irbp->ir_freecount = r.ir_freecount; | 424 | irbp->ir_freecount = r.ir_freecount; |
434 | irbp->ir_free = r.ir_free; | 425 | irbp->ir_free = r.ir_free; |
435 | irbp++; | 426 | irbp++; |
436 | agino = r.ir_startino + XFS_INODES_PER_CHUNK; | ||
437 | } | 427 | } |
438 | /* Increment to the next record */ | 428 | /* Increment to the next record */ |
439 | error = xfs_btree_increment(cur, 0, &tmp); | 429 | error = xfs_btree_increment(cur, 0, &stat); |
440 | } else { | 430 | } else { |
441 | /* Start of ag. Lookup the first inode chunk */ | 431 | /* Start of ag. Lookup the first inode chunk */ |
442 | error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &tmp); | 432 | error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &stat); |
433 | } | ||
434 | if (error || stat == 0) { | ||
435 | end_of_ag = true; | ||
436 | goto del_cursor; | ||
443 | } | 437 | } |
444 | if (error) | ||
445 | break; | ||
446 | 438 | ||
447 | /* | 439 | /* |
448 | * Loop through inode btree records in this ag, | 440 | * Loop through inode btree records in this ag, |
@@ -451,10 +443,10 @@ xfs_bulkstat( | |||
451 | while (irbp < irbufend && icount < ubcount) { | 443 | while (irbp < irbufend && icount < ubcount) { |
452 | struct xfs_inobt_rec_incore r; | 444 | struct xfs_inobt_rec_incore r; |
453 | 445 | ||
454 | error = xfs_inobt_get_rec(cur, &r, &i); | 446 | error = xfs_inobt_get_rec(cur, &r, &stat); |
455 | if (error || i == 0) { | 447 | if (error || stat == 0) { |
456 | end_of_ag = 1; | 448 | end_of_ag = true; |
457 | break; | 449 | goto del_cursor; |
458 | } | 450 | } |
459 | 451 | ||
460 | /* | 452 | /* |
@@ -469,77 +461,79 @@ xfs_bulkstat( | |||
469 | irbp++; | 461 | irbp++; |
470 | icount += XFS_INODES_PER_CHUNK - r.ir_freecount; | 462 | icount += XFS_INODES_PER_CHUNK - r.ir_freecount; |
471 | } | 463 | } |
472 | /* | 464 | error = xfs_btree_increment(cur, 0, &stat); |
473 | * Set agino to after this chunk and bump the cursor. | 465 | if (error || stat == 0) { |
474 | */ | 466 | end_of_ag = true; |
475 | agino = r.ir_startino + XFS_INODES_PER_CHUNK; | 467 | goto del_cursor; |
476 | error = xfs_btree_increment(cur, 0, &tmp); | 468 | } |
477 | cond_resched(); | 469 | cond_resched(); |
478 | } | 470 | } |
471 | |||
479 | /* | 472 | /* |
480 | * Drop the btree buffers and the agi buffer. | 473 | * Drop the btree buffers and the agi buffer as we can't hold any |
481 | * We can't hold any of the locks these represent | 474 | * of the locks these represent when calling iget. If there is a |
482 | * when calling iget. | 475 | * pending error, then we are done. |
483 | */ | 476 | */ |
477 | del_cursor: | ||
484 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); | 478 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); |
485 | xfs_buf_relse(agbp); | 479 | xfs_buf_relse(agbp); |
480 | if (error) | ||
481 | break; | ||
486 | /* | 482 | /* |
487 | * Now format all the good inodes into the user's buffer. | 483 | * Now format all the good inodes into the user's buffer. The |
484 | * call to xfs_bulkstat_ag_ichunk() sets up the agino pointer | ||
485 | * for the next loop iteration. | ||
488 | */ | 486 | */ |
489 | irbufend = irbp; | 487 | irbufend = irbp; |
490 | for (irbp = irbuf; | 488 | for (irbp = irbuf; |
491 | irbp < irbufend && XFS_BULKSTAT_UBLEFT(ubleft); irbp++) { | 489 | irbp < irbufend && ac.ac_ubleft >= statstruct_size; |
492 | struct xfs_bulkstat_agichunk ac; | 490 | irbp++) { |
493 | |||
494 | ac.ac_lastino = lastino; | ||
495 | ac.ac_ubuffer = &ubuffer; | ||
496 | ac.ac_ubleft = ubleft; | ||
497 | ac.ac_ubelem = ubelem; | ||
498 | error = xfs_bulkstat_ag_ichunk(mp, agno, irbp, | 491 | error = xfs_bulkstat_ag_ichunk(mp, agno, irbp, |
499 | formatter, statstruct_size, &ac); | 492 | formatter, statstruct_size, &ac, |
493 | &agino); | ||
500 | if (error) | 494 | if (error) |
501 | rval = error; | 495 | break; |
502 | |||
503 | lastino = ac.ac_lastino; | ||
504 | ubleft = ac.ac_ubleft; | ||
505 | ubelem = ac.ac_ubelem; | ||
506 | 496 | ||
507 | cond_resched(); | 497 | cond_resched(); |
508 | } | 498 | } |
499 | |||
509 | /* | 500 | /* |
510 | * Set up for the next loop iteration. | 501 | * If we've run out of space or had a formatting error, we |
502 | * are now done | ||
511 | */ | 503 | */ |
512 | if (XFS_BULKSTAT_UBLEFT(ubleft)) { | 504 | if (ac.ac_ubleft < statstruct_size || error) |
513 | if (end_of_ag) { | ||
514 | agno++; | ||
515 | agino = 0; | ||
516 | } else | ||
517 | agino = XFS_INO_TO_AGINO(mp, lastino); | ||
518 | } else | ||
519 | break; | 505 | break; |
506 | |||
507 | if (end_of_ag) { | ||
508 | agno++; | ||
509 | agino = 0; | ||
510 | } | ||
520 | } | 511 | } |
521 | /* | 512 | /* |
522 | * Done, we're either out of filesystem or space to put the data. | 513 | * Done, we're either out of filesystem or space to put the data. |
523 | */ | 514 | */ |
524 | kmem_free(irbuf); | 515 | kmem_free(irbuf); |
525 | *ubcountp = ubelem; | 516 | *ubcountp = ac.ac_ubelem; |
517 | |||
526 | /* | 518 | /* |
527 | * Found some inodes, return them now and return the error next time. | 519 | * We found some inodes, so clear the error status and return them. |
520 | * The lastino pointer will point directly at the inode that triggered | ||
521 | * any error that occurred, so on the next call the error will be | ||
522 | * triggered again and propagated to userspace as there will be no | ||
523 | * formatted inodes in the buffer. | ||
528 | */ | 524 | */ |
529 | if (ubelem) | 525 | if (ac.ac_ubelem) |
530 | rval = 0; | 526 | error = 0; |
531 | if (agno >= mp->m_sb.sb_agcount) { | 527 | |
532 | /* | 528 | /* |
533 | * If we ran out of filesystem, mark lastino as off | 529 | * If we ran out of filesystem, lastino will point off the end of |
534 | * the end of the filesystem, so the next call | 530 | * the filesystem so the next call will return immediately. |
535 | * will return immediately. | 531 | */ |
536 | */ | 532 | *lastinop = XFS_AGINO_TO_INO(mp, agno, agino); |
537 | *lastinop = (xfs_ino_t)XFS_AGINO_TO_INO(mp, agno, 0); | 533 | if (agno >= mp->m_sb.sb_agcount) |
538 | *done = 1; | 534 | *done = 1; |
539 | } else | ||
540 | *lastinop = (xfs_ino_t)lastino; | ||
541 | 535 | ||
542 | return rval; | 536 | return error; |
543 | } | 537 | } |
544 | 538 | ||
545 | int | 539 | int |
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h index aaed08022eb9..6ea8b3912fa4 100644 --- a/fs/xfs/xfs_itable.h +++ b/fs/xfs/xfs_itable.h | |||
@@ -30,22 +30,6 @@ typedef int (*bulkstat_one_pf)(struct xfs_mount *mp, | |||
30 | int *ubused, | 30 | int *ubused, |
31 | int *stat); | 31 | int *stat); |
32 | 32 | ||
33 | struct xfs_bulkstat_agichunk { | ||
34 | xfs_ino_t ac_lastino; /* last inode returned */ | ||
35 | char __user **ac_ubuffer;/* pointer into user's buffer */ | ||
36 | int ac_ubleft; /* bytes left in user's buffer */ | ||
37 | int ac_ubelem; /* spaces used in user's buffer */ | ||
38 | }; | ||
39 | |||
40 | int | ||
41 | xfs_bulkstat_ag_ichunk( | ||
42 | struct xfs_mount *mp, | ||
43 | xfs_agnumber_t agno, | ||
44 | struct xfs_inobt_rec_incore *irbp, | ||
45 | bulkstat_one_pf formatter, | ||
46 | size_t statstruct_size, | ||
47 | struct xfs_bulkstat_agichunk *acp); | ||
48 | |||
49 | /* | 33 | /* |
50 | * Values for stat return value. | 34 | * Values for stat return value. |
51 | */ | 35 | */ |