diff options
author | David Howells <dhowells@redhat.com> | 2019-05-09 11:17:05 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-05-16 11:25:21 -0400 |
commit | 87182759cd6f94875d6aaaac74eaa52aa6aa6f98 (patch) | |
tree | 3a143ae4a411fd26b1d98bffff3f66770e027901 | |
parent | ffba718e935402e7f42b8cd5d1e00e4a3907d361 (diff) |
afs: Fix order-1 allocation in afs_do_lookup()
afs_do_lookup() will do an order-1 allocation to allocate status records if
there are more than 39 vnodes to stat.
Fix this by allocating an array of {status,callback} records for each vnode
we want to examine using vmalloc() if larger than a page.
This not only gets rid of the order-1 allocation, but makes it easier to
grow beyond 50 records for YFS servers. It also allows us to move to
{status,callback} tuples for other calls too and makes it easier to lock
across the application of the status and the callback to the vnode.
Fixes: 5cf9dd55a0ec ("afs: Prospectively look up extra files when doing a single lookup")
Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r-- | fs/afs/afs.h | 6 | ||||
-rw-r--r-- | fs/afs/dir.c | 37 | ||||
-rw-r--r-- | fs/afs/fsclient.c | 21 | ||||
-rw-r--r-- | fs/afs/internal.h | 11 | ||||
-rw-r--r-- | fs/afs/yfsclient.c | 20 |
5 files changed, 45 insertions, 50 deletions
diff --git a/fs/afs/afs.h b/fs/afs/afs.h index 74913c707bba..8fa0dffff1cc 100644 --- a/fs/afs/afs.h +++ b/fs/afs/afs.h | |||
@@ -147,6 +147,12 @@ struct afs_file_status { | |||
147 | u32 abort_code; /* Abort if bulk-fetching this failed */ | 147 | u32 abort_code; /* Abort if bulk-fetching this failed */ |
148 | }; | 148 | }; |
149 | 149 | ||
150 | struct afs_status_cb { | ||
151 | struct afs_file_status status; | ||
152 | struct afs_callback callback; | ||
153 | bool have_cb; /* True if cb record was retrieved */ | ||
154 | }; | ||
155 | |||
150 | /* | 156 | /* |
151 | * AFS file status change request | 157 | * AFS file status change request |
152 | */ | 158 | */ |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index c15550310f62..0f14bcfe233d 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -102,8 +102,7 @@ struct afs_lookup_cookie { | |||
102 | bool found; | 102 | bool found; |
103 | bool one_only; | 103 | bool one_only; |
104 | unsigned short nr_fids; | 104 | unsigned short nr_fids; |
105 | struct afs_file_status *statuses; | 105 | struct afs_status_cb *statuses; |
106 | struct afs_callback *callbacks; | ||
107 | struct afs_fid fids[50]; | 106 | struct afs_fid fids[50]; |
108 | }; | 107 | }; |
109 | 108 | ||
@@ -640,6 +639,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, | |||
640 | struct afs_lookup_cookie *cookie; | 639 | struct afs_lookup_cookie *cookie; |
641 | struct afs_cb_interest *cbi = NULL; | 640 | struct afs_cb_interest *cbi = NULL; |
642 | struct afs_super_info *as = dir->i_sb->s_fs_info; | 641 | struct afs_super_info *as = dir->i_sb->s_fs_info; |
642 | struct afs_status_cb *scb; | ||
643 | struct afs_iget_data data; | 643 | struct afs_iget_data data; |
644 | struct afs_fs_cursor fc; | 644 | struct afs_fs_cursor fc; |
645 | struct afs_vnode *dvnode = AFS_FS_I(dir); | 645 | struct afs_vnode *dvnode = AFS_FS_I(dir); |
@@ -686,16 +686,11 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, | |||
686 | 686 | ||
687 | /* Need space for examining all the selected files */ | 687 | /* Need space for examining all the selected files */ |
688 | inode = ERR_PTR(-ENOMEM); | 688 | inode = ERR_PTR(-ENOMEM); |
689 | cookie->statuses = kcalloc(cookie->nr_fids, sizeof(struct afs_file_status), | 689 | cookie->statuses = kvcalloc(cookie->nr_fids, sizeof(struct afs_status_cb), |
690 | GFP_KERNEL); | 690 | GFP_KERNEL); |
691 | if (!cookie->statuses) | 691 | if (!cookie->statuses) |
692 | goto out; | 692 | goto out; |
693 | 693 | ||
694 | cookie->callbacks = kcalloc(cookie->nr_fids, sizeof(struct afs_callback), | ||
695 | GFP_KERNEL); | ||
696 | if (!cookie->callbacks) | ||
697 | goto out_s; | ||
698 | |||
699 | /* Try FS.InlineBulkStatus first. Abort codes for the individual | 694 | /* Try FS.InlineBulkStatus first. Abort codes for the individual |
700 | * lookups contained therein are stored in the reply without aborting | 695 | * lookups contained therein are stored in the reply without aborting |
701 | * the whole operation. | 696 | * the whole operation. |
@@ -716,7 +711,6 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, | |||
716 | afs_v2net(dvnode), | 711 | afs_v2net(dvnode), |
717 | cookie->fids, | 712 | cookie->fids, |
718 | cookie->statuses, | 713 | cookie->statuses, |
719 | cookie->callbacks, | ||
720 | cookie->nr_fids, NULL); | 714 | cookie->nr_fids, NULL); |
721 | } | 715 | } |
722 | 716 | ||
@@ -741,11 +735,12 @@ no_inline_bulk_status: | |||
741 | inode = ERR_PTR(-ERESTARTSYS); | 735 | inode = ERR_PTR(-ERESTARTSYS); |
742 | if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { | 736 | if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { |
743 | while (afs_select_fileserver(&fc)) { | 737 | while (afs_select_fileserver(&fc)) { |
738 | scb = &cookie->statuses[0]; | ||
744 | afs_fs_fetch_status(&fc, | 739 | afs_fs_fetch_status(&fc, |
745 | afs_v2net(dvnode), | 740 | afs_v2net(dvnode), |
746 | cookie->fids, | 741 | cookie->fids, |
747 | cookie->statuses, | 742 | &scb->status, |
748 | cookie->callbacks, | 743 | &scb->callback, |
749 | NULL); | 744 | NULL); |
750 | } | 745 | } |
751 | 746 | ||
@@ -758,24 +753,26 @@ no_inline_bulk_status: | |||
758 | goto out_c; | 753 | goto out_c; |
759 | 754 | ||
760 | for (i = 0; i < cookie->nr_fids; i++) | 755 | for (i = 0; i < cookie->nr_fids; i++) |
761 | cookie->statuses[i].abort_code = 0; | 756 | cookie->statuses[i].status.abort_code = 0; |
762 | 757 | ||
763 | success: | 758 | success: |
764 | /* Turn all the files into inodes and save the first one - which is the | 759 | /* Turn all the files into inodes and save the first one - which is the |
765 | * one we actually want. | 760 | * one we actually want. |
766 | */ | 761 | */ |
767 | if (cookie->statuses[0].abort_code != 0) | 762 | scb = &cookie->statuses[0]; |
768 | inode = ERR_PTR(afs_abort_to_error(cookie->statuses[0].abort_code)); | 763 | if (scb->status.abort_code != 0) |
764 | inode = ERR_PTR(afs_abort_to_error(scb->status.abort_code)); | ||
769 | 765 | ||
770 | for (i = 0; i < cookie->nr_fids; i++) { | 766 | for (i = 0; i < cookie->nr_fids; i++) { |
767 | struct afs_status_cb *scb = &cookie->statuses[i]; | ||
771 | struct inode *ti; | 768 | struct inode *ti; |
772 | 769 | ||
773 | if (cookie->statuses[i].abort_code != 0) | 770 | if (scb->status.abort_code != 0) |
774 | continue; | 771 | continue; |
775 | 772 | ||
776 | ti = afs_iget(dir->i_sb, key, &cookie->fids[i], | 773 | ti = afs_iget(dir->i_sb, key, &cookie->fids[i], |
777 | &cookie->statuses[i], | 774 | &scb->status, |
778 | &cookie->callbacks[i], | 775 | &scb->callback, |
779 | cbi, dvnode); | 776 | cbi, dvnode); |
780 | if (i == 0) { | 777 | if (i == 0) { |
781 | inode = ti; | 778 | inode = ti; |
@@ -787,9 +784,7 @@ success: | |||
787 | 784 | ||
788 | out_c: | 785 | out_c: |
789 | afs_put_cb_interest(afs_v2net(dvnode), cbi); | 786 | afs_put_cb_interest(afs_v2net(dvnode), cbi); |
790 | kfree(cookie->callbacks); | 787 | kvfree(cookie->statuses); |
791 | out_s: | ||
792 | kfree(cookie->statuses); | ||
793 | out: | 788 | out: |
794 | kfree(cookie); | 789 | kfree(cookie); |
795 | return inode; | 790 | return inode; |
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 16bcc578e3b2..eeba2a359fb4 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c | |||
@@ -2209,8 +2209,7 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc, | |||
2209 | */ | 2209 | */ |
2210 | static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) | 2210 | static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) |
2211 | { | 2211 | { |
2212 | struct afs_file_status *statuses; | 2212 | struct afs_status_cb *scb; |
2213 | struct afs_callback *callbacks; | ||
2214 | const __be32 *bp; | 2213 | const __be32 *bp; |
2215 | u32 tmp; | 2214 | u32 tmp; |
2216 | int ret; | 2215 | int ret; |
@@ -2249,8 +2248,8 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) | |||
2249 | return ret; | 2248 | return ret; |
2250 | 2249 | ||
2251 | bp = call->buffer; | 2250 | bp = call->buffer; |
2252 | statuses = call->out_extra_status; | 2251 | scb = &call->out_scb[call->count]; |
2253 | ret = afs_decode_status(call, &bp, &statuses[call->count], | 2252 | ret = afs_decode_status(call, &bp, &scb->status, |
2254 | NULL, NULL, NULL); | 2253 | NULL, NULL, NULL); |
2255 | if (ret < 0) | 2254 | if (ret < 0) |
2256 | return ret; | 2255 | return ret; |
@@ -2290,9 +2289,9 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) | |||
2290 | 2289 | ||
2291 | _debug("unmarshall CB array"); | 2290 | _debug("unmarshall CB array"); |
2292 | bp = call->buffer; | 2291 | bp = call->buffer; |
2293 | callbacks = call->out_cb; | 2292 | scb = &call->out_scb[call->count]; |
2294 | xdr_decode_AFSCallBack_raw(call, &callbacks[call->count], &bp); | 2293 | xdr_decode_AFSCallBack_raw(call, &scb->callback, &bp); |
2295 | statuses = call->out_extra_status; | 2294 | scb->have_cb = true; |
2296 | call->count++; | 2295 | call->count++; |
2297 | if (call->count < call->count2) | 2296 | if (call->count < call->count2) |
2298 | goto more_cbs; | 2297 | goto more_cbs; |
@@ -2335,8 +2334,7 @@ static const struct afs_call_type afs_RXFSInlineBulkStatus = { | |||
2335 | int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, | 2334 | int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, |
2336 | struct afs_net *net, | 2335 | struct afs_net *net, |
2337 | struct afs_fid *fids, | 2336 | struct afs_fid *fids, |
2338 | struct afs_file_status *statuses, | 2337 | struct afs_status_cb *statuses, |
2339 | struct afs_callback *callbacks, | ||
2340 | unsigned int nr_fids, | 2338 | unsigned int nr_fids, |
2341 | struct afs_volsync *volsync) | 2339 | struct afs_volsync *volsync) |
2342 | { | 2340 | { |
@@ -2345,7 +2343,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, | |||
2345 | int i; | 2343 | int i; |
2346 | 2344 | ||
2347 | if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) | 2345 | if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) |
2348 | return yfs_fs_inline_bulk_status(fc, net, fids, statuses, callbacks, | 2346 | return yfs_fs_inline_bulk_status(fc, net, fids, statuses, |
2349 | nr_fids, volsync); | 2347 | nr_fids, volsync); |
2350 | 2348 | ||
2351 | _enter(",%x,{%llx:%llu},%u", | 2349 | _enter(",%x,{%llx:%llu},%u", |
@@ -2360,8 +2358,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, | |||
2360 | } | 2358 | } |
2361 | 2359 | ||
2362 | call->key = fc->key; | 2360 | call->key = fc->key; |
2363 | call->out_extra_status = statuses; | 2361 | call->out_scb = statuses; |
2364 | call->out_cb = callbacks; | ||
2365 | call->out_volsync = volsync; | 2362 | call->out_volsync = volsync; |
2366 | call->count2 = nr_fids; | 2363 | call->count2 = nr_fids; |
2367 | call->want_reply_time = true; | 2364 | call->want_reply_time = true; |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 705833eb2d45..2a100be91721 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -137,6 +137,7 @@ struct afs_call { | |||
137 | struct afs_file_status *out_vnode_status; | 137 | struct afs_file_status *out_vnode_status; |
138 | struct afs_file_status *out_extra_status; | 138 | struct afs_file_status *out_extra_status; |
139 | struct afs_callback *out_cb; | 139 | struct afs_callback *out_cb; |
140 | struct afs_status_cb *out_scb; | ||
140 | struct yfs_acl *out_yacl; | 141 | struct yfs_acl *out_yacl; |
141 | struct afs_volsync *out_volsync; | 142 | struct afs_volsync *out_volsync; |
142 | struct afs_volume_status *out_volstatus; | 143 | struct afs_volume_status *out_volstatus; |
@@ -991,9 +992,8 @@ extern struct afs_call *afs_fs_get_capabilities(struct afs_net *, struct afs_ser | |||
991 | struct afs_addr_cursor *, struct key *, | 992 | struct afs_addr_cursor *, struct key *, |
992 | unsigned int); | 993 | unsigned int); |
993 | extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, | 994 | extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, |
994 | struct afs_fid *, struct afs_file_status *, | 995 | struct afs_fid *, struct afs_status_cb *, |
995 | struct afs_callback *, unsigned int, | 996 | unsigned int, struct afs_volsync *); |
996 | struct afs_volsync *); | ||
997 | extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *, | 997 | extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *, |
998 | struct afs_fid *, struct afs_file_status *, | 998 | struct afs_fid *, struct afs_file_status *, |
999 | struct afs_callback *, struct afs_volsync *); | 999 | struct afs_callback *, struct afs_volsync *); |
@@ -1393,9 +1393,8 @@ extern int yfs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *, | |||
1393 | struct afs_fid *, struct afs_file_status *, | 1393 | struct afs_fid *, struct afs_file_status *, |
1394 | struct afs_callback *, struct afs_volsync *); | 1394 | struct afs_callback *, struct afs_volsync *); |
1395 | extern int yfs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, | 1395 | extern int yfs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, |
1396 | struct afs_fid *, struct afs_file_status *, | 1396 | struct afs_fid *, struct afs_status_cb *, |
1397 | struct afs_callback *, unsigned int, | 1397 | unsigned int, struct afs_volsync *); |
1398 | struct afs_volsync *); | ||
1399 | 1398 | ||
1400 | struct yfs_acl { | 1399 | struct yfs_acl { |
1401 | struct afs_acl *acl; /* Dir/file/symlink ACL */ | 1400 | struct afs_acl *acl; /* Dir/file/symlink ACL */ |
diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index a815d22f62f1..1f1ccf7b7822 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c | |||
@@ -338,7 +338,7 @@ static void xdr_decode_YFSCallBack(struct afs_call *call, | |||
338 | struct afs_callback cb; | 338 | struct afs_callback cb; |
339 | 339 | ||
340 | xdr_decode_YFSCallBack_raw(call, &cb, _bp); | 340 | xdr_decode_YFSCallBack_raw(call, &cb, _bp); |
341 | 341 | ||
342 | write_seqlock(&vnode->cb_lock); | 342 | write_seqlock(&vnode->cb_lock); |
343 | 343 | ||
344 | if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) { | 344 | if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) { |
@@ -2032,8 +2032,7 @@ int yfs_fs_fetch_status(struct afs_fs_cursor *fc, | |||
2032 | */ | 2032 | */ |
2033 | static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) | 2033 | static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) |
2034 | { | 2034 | { |
2035 | struct afs_file_status *statuses; | 2035 | struct afs_status_cb *scb; |
2036 | struct afs_callback *callbacks; | ||
2037 | const __be32 *bp; | 2036 | const __be32 *bp; |
2038 | u32 tmp; | 2037 | u32 tmp; |
2039 | int ret; | 2038 | int ret; |
@@ -2072,8 +2071,8 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) | |||
2072 | return ret; | 2071 | return ret; |
2073 | 2072 | ||
2074 | bp = call->buffer; | 2073 | bp = call->buffer; |
2075 | statuses = call->out_extra_status; | 2074 | scb = &call->out_scb[call->count]; |
2076 | ret = yfs_decode_status(call, &bp, &statuses[call->count], | 2075 | ret = yfs_decode_status(call, &bp, &scb->status, |
2077 | NULL, NULL, NULL); | 2076 | NULL, NULL, NULL); |
2078 | if (ret < 0) | 2077 | if (ret < 0) |
2079 | return ret; | 2078 | return ret; |
@@ -2113,8 +2112,9 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) | |||
2113 | 2112 | ||
2114 | _debug("unmarshall CB array"); | 2113 | _debug("unmarshall CB array"); |
2115 | bp = call->buffer; | 2114 | bp = call->buffer; |
2116 | callbacks = call->out_cb; | 2115 | scb = &call->out_scb[call->count]; |
2117 | xdr_decode_YFSCallBack_raw(call, &callbacks[call->count], &bp); | 2116 | xdr_decode_YFSCallBack_raw(call, &scb->callback, &bp); |
2117 | scb->have_cb = true; | ||
2118 | call->count++; | 2118 | call->count++; |
2119 | if (call->count < call->count2) | 2119 | if (call->count < call->count2) |
2120 | goto more_cbs; | 2120 | goto more_cbs; |
@@ -2158,8 +2158,7 @@ static const struct afs_call_type yfs_RXYFSInlineBulkStatus = { | |||
2158 | int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc, | 2158 | int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc, |
2159 | struct afs_net *net, | 2159 | struct afs_net *net, |
2160 | struct afs_fid *fids, | 2160 | struct afs_fid *fids, |
2161 | struct afs_file_status *statuses, | 2161 | struct afs_status_cb *statuses, |
2162 | struct afs_callback *callbacks, | ||
2163 | unsigned int nr_fids, | 2162 | unsigned int nr_fids, |
2164 | struct afs_volsync *volsync) | 2163 | struct afs_volsync *volsync) |
2165 | { | 2164 | { |
@@ -2182,8 +2181,7 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc, | |||
2182 | } | 2181 | } |
2183 | 2182 | ||
2184 | call->key = fc->key; | 2183 | call->key = fc->key; |
2185 | call->out_extra_status = statuses; | 2184 | call->out_scb = statuses; |
2186 | call->out_cb = callbacks; | ||
2187 | call->out_volsync = volsync; | 2185 | call->out_volsync = volsync; |
2188 | call->count2 = nr_fids; | 2186 | call->count2 = nr_fids; |
2189 | 2187 | ||