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: 5cf9dd55a0 ("afs: Prospectively look up extra files when doing a single lookup")
Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
@@ -147,6 +147,12 @@ struct afs_file_status {
|
|||||||
u32 abort_code; /* Abort if bulk-fetching this failed */
|
u32 abort_code; /* Abort if bulk-fetching this failed */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct afs_status_cb {
|
||||||
|
struct afs_file_status status;
|
||||||
|
struct afs_callback callback;
|
||||||
|
bool have_cb; /* True if cb record was retrieved */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AFS file status change request
|
* AFS file status change request
|
||||||
*/
|
*/
|
||||||
|
|||||||
+16
-21
@@ -102,8 +102,7 @@ struct afs_lookup_cookie {
|
|||||||
bool found;
|
bool found;
|
||||||
bool one_only;
|
bool one_only;
|
||||||
unsigned short nr_fids;
|
unsigned short nr_fids;
|
||||||
struct afs_file_status *statuses;
|
struct afs_status_cb *statuses;
|
||||||
struct afs_callback *callbacks;
|
|
||||||
struct afs_fid fids[50];
|
struct afs_fid fids[50];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -640,6 +639,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
|
|||||||
struct afs_lookup_cookie *cookie;
|
struct afs_lookup_cookie *cookie;
|
||||||
struct afs_cb_interest *cbi = NULL;
|
struct afs_cb_interest *cbi = NULL;
|
||||||
struct afs_super_info *as = dir->i_sb->s_fs_info;
|
struct afs_super_info *as = dir->i_sb->s_fs_info;
|
||||||
|
struct afs_status_cb *scb;
|
||||||
struct afs_iget_data data;
|
struct afs_iget_data data;
|
||||||
struct afs_fs_cursor fc;
|
struct afs_fs_cursor fc;
|
||||||
struct afs_vnode *dvnode = AFS_FS_I(dir);
|
struct afs_vnode *dvnode = AFS_FS_I(dir);
|
||||||
@@ -686,16 +686,11 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
|
|||||||
|
|
||||||
/* Need space for examining all the selected files */
|
/* Need space for examining all the selected files */
|
||||||
inode = ERR_PTR(-ENOMEM);
|
inode = ERR_PTR(-ENOMEM);
|
||||||
cookie->statuses = kcalloc(cookie->nr_fids, sizeof(struct afs_file_status),
|
cookie->statuses = kvcalloc(cookie->nr_fids, sizeof(struct afs_status_cb),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!cookie->statuses)
|
if (!cookie->statuses)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
cookie->callbacks = kcalloc(cookie->nr_fids, sizeof(struct afs_callback),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!cookie->callbacks)
|
|
||||||
goto out_s;
|
|
||||||
|
|
||||||
/* Try FS.InlineBulkStatus first. Abort codes for the individual
|
/* Try FS.InlineBulkStatus first. Abort codes for the individual
|
||||||
* lookups contained therein are stored in the reply without aborting
|
* lookups contained therein are stored in the reply without aborting
|
||||||
* the whole operation.
|
* the whole operation.
|
||||||
@@ -716,7 +711,6 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
|
|||||||
afs_v2net(dvnode),
|
afs_v2net(dvnode),
|
||||||
cookie->fids,
|
cookie->fids,
|
||||||
cookie->statuses,
|
cookie->statuses,
|
||||||
cookie->callbacks,
|
|
||||||
cookie->nr_fids, NULL);
|
cookie->nr_fids, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,11 +735,12 @@ no_inline_bulk_status:
|
|||||||
inode = ERR_PTR(-ERESTARTSYS);
|
inode = ERR_PTR(-ERESTARTSYS);
|
||||||
if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
|
if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
|
||||||
while (afs_select_fileserver(&fc)) {
|
while (afs_select_fileserver(&fc)) {
|
||||||
|
scb = &cookie->statuses[0];
|
||||||
afs_fs_fetch_status(&fc,
|
afs_fs_fetch_status(&fc,
|
||||||
afs_v2net(dvnode),
|
afs_v2net(dvnode),
|
||||||
cookie->fids,
|
cookie->fids,
|
||||||
cookie->statuses,
|
&scb->status,
|
||||||
cookie->callbacks,
|
&scb->callback,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -758,24 +753,26 @@ no_inline_bulk_status:
|
|||||||
goto out_c;
|
goto out_c;
|
||||||
|
|
||||||
for (i = 0; i < cookie->nr_fids; i++)
|
for (i = 0; i < cookie->nr_fids; i++)
|
||||||
cookie->statuses[i].abort_code = 0;
|
cookie->statuses[i].status.abort_code = 0;
|
||||||
|
|
||||||
success:
|
success:
|
||||||
/* Turn all the files into inodes and save the first one - which is the
|
/* Turn all the files into inodes and save the first one - which is the
|
||||||
* one we actually want.
|
* one we actually want.
|
||||||
*/
|
*/
|
||||||
if (cookie->statuses[0].abort_code != 0)
|
scb = &cookie->statuses[0];
|
||||||
inode = ERR_PTR(afs_abort_to_error(cookie->statuses[0].abort_code));
|
if (scb->status.abort_code != 0)
|
||||||
|
inode = ERR_PTR(afs_abort_to_error(scb->status.abort_code));
|
||||||
|
|
||||||
for (i = 0; i < cookie->nr_fids; i++) {
|
for (i = 0; i < cookie->nr_fids; i++) {
|
||||||
|
struct afs_status_cb *scb = &cookie->statuses[i];
|
||||||
struct inode *ti;
|
struct inode *ti;
|
||||||
|
|
||||||
if (cookie->statuses[i].abort_code != 0)
|
if (scb->status.abort_code != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ti = afs_iget(dir->i_sb, key, &cookie->fids[i],
|
ti = afs_iget(dir->i_sb, key, &cookie->fids[i],
|
||||||
&cookie->statuses[i],
|
&scb->status,
|
||||||
&cookie->callbacks[i],
|
&scb->callback,
|
||||||
cbi, dvnode);
|
cbi, dvnode);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
inode = ti;
|
inode = ti;
|
||||||
@@ -787,9 +784,7 @@ success:
|
|||||||
|
|
||||||
out_c:
|
out_c:
|
||||||
afs_put_cb_interest(afs_v2net(dvnode), cbi);
|
afs_put_cb_interest(afs_v2net(dvnode), cbi);
|
||||||
kfree(cookie->callbacks);
|
kvfree(cookie->statuses);
|
||||||
out_s:
|
|
||||||
kfree(cookie->statuses);
|
|
||||||
out:
|
out:
|
||||||
kfree(cookie);
|
kfree(cookie);
|
||||||
return inode;
|
return inode;
|
||||||
|
|||||||
+9
-12
@@ -2209,8 +2209,7 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc,
|
|||||||
*/
|
*/
|
||||||
static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
||||||
{
|
{
|
||||||
struct afs_file_status *statuses;
|
struct afs_status_cb *scb;
|
||||||
struct afs_callback *callbacks;
|
|
||||||
const __be32 *bp;
|
const __be32 *bp;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -2249,8 +2248,8 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
bp = call->buffer;
|
bp = call->buffer;
|
||||||
statuses = call->out_extra_status;
|
scb = &call->out_scb[call->count];
|
||||||
ret = afs_decode_status(call, &bp, &statuses[call->count],
|
ret = afs_decode_status(call, &bp, &scb->status,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -2290,9 +2289,9 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
|||||||
|
|
||||||
_debug("unmarshall CB array");
|
_debug("unmarshall CB array");
|
||||||
bp = call->buffer;
|
bp = call->buffer;
|
||||||
callbacks = call->out_cb;
|
scb = &call->out_scb[call->count];
|
||||||
xdr_decode_AFSCallBack_raw(call, &callbacks[call->count], &bp);
|
xdr_decode_AFSCallBack_raw(call, &scb->callback, &bp);
|
||||||
statuses = call->out_extra_status;
|
scb->have_cb = true;
|
||||||
call->count++;
|
call->count++;
|
||||||
if (call->count < call->count2)
|
if (call->count < call->count2)
|
||||||
goto more_cbs;
|
goto more_cbs;
|
||||||
@@ -2335,8 +2334,7 @@ static const struct afs_call_type afs_RXFSInlineBulkStatus = {
|
|||||||
int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
|
int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
|
||||||
struct afs_net *net,
|
struct afs_net *net,
|
||||||
struct afs_fid *fids,
|
struct afs_fid *fids,
|
||||||
struct afs_file_status *statuses,
|
struct afs_status_cb *statuses,
|
||||||
struct afs_callback *callbacks,
|
|
||||||
unsigned int nr_fids,
|
unsigned int nr_fids,
|
||||||
struct afs_volsync *volsync)
|
struct afs_volsync *volsync)
|
||||||
{
|
{
|
||||||
@@ -2345,7 +2343,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
|
if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
|
||||||
return yfs_fs_inline_bulk_status(fc, net, fids, statuses, callbacks,
|
return yfs_fs_inline_bulk_status(fc, net, fids, statuses,
|
||||||
nr_fids, volsync);
|
nr_fids, volsync);
|
||||||
|
|
||||||
_enter(",%x,{%llx:%llu},%u",
|
_enter(",%x,{%llx:%llu},%u",
|
||||||
@@ -2360,8 +2358,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
call->key = fc->key;
|
call->key = fc->key;
|
||||||
call->out_extra_status = statuses;
|
call->out_scb = statuses;
|
||||||
call->out_cb = callbacks;
|
|
||||||
call->out_volsync = volsync;
|
call->out_volsync = volsync;
|
||||||
call->count2 = nr_fids;
|
call->count2 = nr_fids;
|
||||||
call->want_reply_time = true;
|
call->want_reply_time = true;
|
||||||
|
|||||||
+5
-6
@@ -137,6 +137,7 @@ struct afs_call {
|
|||||||
struct afs_file_status *out_vnode_status;
|
struct afs_file_status *out_vnode_status;
|
||||||
struct afs_file_status *out_extra_status;
|
struct afs_file_status *out_extra_status;
|
||||||
struct afs_callback *out_cb;
|
struct afs_callback *out_cb;
|
||||||
|
struct afs_status_cb *out_scb;
|
||||||
struct yfs_acl *out_yacl;
|
struct yfs_acl *out_yacl;
|
||||||
struct afs_volsync *out_volsync;
|
struct afs_volsync *out_volsync;
|
||||||
struct afs_volume_status *out_volstatus;
|
struct afs_volume_status *out_volstatus;
|
||||||
@@ -991,9 +992,8 @@ extern struct afs_call *afs_fs_get_capabilities(struct afs_net *, struct afs_ser
|
|||||||
struct afs_addr_cursor *, struct key *,
|
struct afs_addr_cursor *, struct key *,
|
||||||
unsigned int);
|
unsigned int);
|
||||||
extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
|
extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
|
||||||
struct afs_fid *, struct afs_file_status *,
|
struct afs_fid *, struct afs_status_cb *,
|
||||||
struct afs_callback *, unsigned int,
|
unsigned int, struct afs_volsync *);
|
||||||
struct afs_volsync *);
|
|
||||||
extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
|
extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
|
||||||
struct afs_fid *, struct afs_file_status *,
|
struct afs_fid *, struct afs_file_status *,
|
||||||
struct afs_callback *, struct afs_volsync *);
|
struct afs_callback *, struct afs_volsync *);
|
||||||
@@ -1393,9 +1393,8 @@ extern int yfs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
|
|||||||
struct afs_fid *, struct afs_file_status *,
|
struct afs_fid *, struct afs_file_status *,
|
||||||
struct afs_callback *, struct afs_volsync *);
|
struct afs_callback *, struct afs_volsync *);
|
||||||
extern int yfs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
|
extern int yfs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
|
||||||
struct afs_fid *, struct afs_file_status *,
|
struct afs_fid *, struct afs_status_cb *,
|
||||||
struct afs_callback *, unsigned int,
|
unsigned int, struct afs_volsync *);
|
||||||
struct afs_volsync *);
|
|
||||||
|
|
||||||
struct yfs_acl {
|
struct yfs_acl {
|
||||||
struct afs_acl *acl; /* Dir/file/symlink ACL */
|
struct afs_acl *acl; /* Dir/file/symlink ACL */
|
||||||
|
|||||||
+9
-11
@@ -338,7 +338,7 @@ static void xdr_decode_YFSCallBack(struct afs_call *call,
|
|||||||
struct afs_callback cb;
|
struct afs_callback cb;
|
||||||
|
|
||||||
xdr_decode_YFSCallBack_raw(call, &cb, _bp);
|
xdr_decode_YFSCallBack_raw(call, &cb, _bp);
|
||||||
|
|
||||||
write_seqlock(&vnode->cb_lock);
|
write_seqlock(&vnode->cb_lock);
|
||||||
|
|
||||||
if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) {
|
if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) {
|
||||||
@@ -2032,8 +2032,7 @@ int yfs_fs_fetch_status(struct afs_fs_cursor *fc,
|
|||||||
*/
|
*/
|
||||||
static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
||||||
{
|
{
|
||||||
struct afs_file_status *statuses;
|
struct afs_status_cb *scb;
|
||||||
struct afs_callback *callbacks;
|
|
||||||
const __be32 *bp;
|
const __be32 *bp;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -2072,8 +2071,8 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
bp = call->buffer;
|
bp = call->buffer;
|
||||||
statuses = call->out_extra_status;
|
scb = &call->out_scb[call->count];
|
||||||
ret = yfs_decode_status(call, &bp, &statuses[call->count],
|
ret = yfs_decode_status(call, &bp, &scb->status,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -2113,8 +2112,9 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
|||||||
|
|
||||||
_debug("unmarshall CB array");
|
_debug("unmarshall CB array");
|
||||||
bp = call->buffer;
|
bp = call->buffer;
|
||||||
callbacks = call->out_cb;
|
scb = &call->out_scb[call->count];
|
||||||
xdr_decode_YFSCallBack_raw(call, &callbacks[call->count], &bp);
|
xdr_decode_YFSCallBack_raw(call, &scb->callback, &bp);
|
||||||
|
scb->have_cb = true;
|
||||||
call->count++;
|
call->count++;
|
||||||
if (call->count < call->count2)
|
if (call->count < call->count2)
|
||||||
goto more_cbs;
|
goto more_cbs;
|
||||||
@@ -2158,8 +2158,7 @@ static const struct afs_call_type yfs_RXYFSInlineBulkStatus = {
|
|||||||
int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
|
int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
|
||||||
struct afs_net *net,
|
struct afs_net *net,
|
||||||
struct afs_fid *fids,
|
struct afs_fid *fids,
|
||||||
struct afs_file_status *statuses,
|
struct afs_status_cb *statuses,
|
||||||
struct afs_callback *callbacks,
|
|
||||||
unsigned int nr_fids,
|
unsigned int nr_fids,
|
||||||
struct afs_volsync *volsync)
|
struct afs_volsync *volsync)
|
||||||
{
|
{
|
||||||
@@ -2182,8 +2181,7 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
call->key = fc->key;
|
call->key = fc->key;
|
||||||
call->out_extra_status = statuses;
|
call->out_scb = statuses;
|
||||||
call->out_cb = callbacks;
|
|
||||||
call->out_volsync = volsync;
|
call->out_volsync = volsync;
|
||||||
call->count2 = nr_fids;
|
call->count2 = nr_fids;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user