aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-04-09 16:12:31 -0400
committerDavid Howells <dhowells@redhat.com>2018-04-09 16:12:31 -0400
commit5cf9dd55a0ec26428f2824aadd16bfa305a5b603 (patch)
tree4a782bb849b5eefc8ef797bf4c68515e84d35ed4
parent17814aef57fc0b80ac2a4a7a639db358b75cb6b9 (diff)
afs: Prospectively look up extra files when doing a single lookup
When afs_lookup() is called, prospectively look up the next 50 uncached fids also from that same directory and cache the results, rather than just looking up the one file requested. This allows us to use the FS.InlineBulkStatus RPC op to increase efficiency by fetching up to 50 file statuses at a time. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--fs/afs/afs.h21
-rw-r--r--fs/afs/afs_fs.h2
-rw-r--r--fs/afs/callback.c8
-rw-r--r--fs/afs/cmservice.c12
-rw-r--r--fs/afs/dir.c288
-rw-r--r--fs/afs/fsclient.c272
-rw-r--r--fs/afs/internal.h10
-rw-r--r--include/trace/events/afs.h2
8 files changed, 552 insertions, 63 deletions
diff --git a/fs/afs/afs.h b/fs/afs/afs.h
index b94d0edc2b78..a670bca6d3ba 100644
--- a/fs/afs/afs.h
+++ b/fs/afs/afs.h
@@ -67,10 +67,14 @@ typedef enum {
67} afs_callback_type_t; 67} afs_callback_type_t;
68 68
69struct afs_callback { 69struct afs_callback {
70 struct afs_fid fid; /* file identifier */ 70 unsigned version; /* Callback version */
71 unsigned version; /* callback version */ 71 unsigned expiry; /* Time at which expires */
72 unsigned expiry; /* time at which expires */ 72 afs_callback_type_t type; /* Type of callback */
73 afs_callback_type_t type; /* type of callback */ 73};
74
75struct afs_callback_break {
76 struct afs_fid fid; /* File identifier */
77 struct afs_callback cb; /* Callback details */
74}; 78};
75 79
76#define AFSCBMAX 50 /* maximum callbacks transferred per bulk op */ 80#define AFSCBMAX 50 /* maximum callbacks transferred per bulk op */
@@ -123,21 +127,22 @@ typedef u32 afs_access_t;
123 * AFS file status information 127 * AFS file status information
124 */ 128 */
125struct afs_file_status { 129struct afs_file_status {
130 u64 size; /* file size */
131 afs_dataversion_t data_version; /* current data version */
132 time_t mtime_client; /* last time client changed data */
133 time_t mtime_server; /* last time server changed data */
126 unsigned if_version; /* interface version */ 134 unsigned if_version; /* interface version */
127#define AFS_FSTATUS_VERSION 1 135#define AFS_FSTATUS_VERSION 1
136 unsigned abort_code; /* Abort if bulk-fetching this failed */
128 137
129 afs_file_type_t type; /* file type */ 138 afs_file_type_t type; /* file type */
130 unsigned nlink; /* link count */ 139 unsigned nlink; /* link count */
131 u64 size; /* file size */
132 afs_dataversion_t data_version; /* current data version */
133 u32 author; /* author ID */ 140 u32 author; /* author ID */
134 kuid_t owner; /* owner ID */ 141 kuid_t owner; /* owner ID */
135 kgid_t group; /* group ID */ 142 kgid_t group; /* group ID */
136 afs_access_t caller_access; /* access rights for authenticated caller */ 143 afs_access_t caller_access; /* access rights for authenticated caller */
137 afs_access_t anon_access; /* access rights for unauthenticated caller */ 144 afs_access_t anon_access; /* access rights for unauthenticated caller */
138 umode_t mode; /* UNIX mode */ 145 umode_t mode; /* UNIX mode */
139 time_t mtime_client; /* last time client changed data */
140 time_t mtime_server; /* last time server changed data */
141 s32 lock_count; /* file lock count (0=UNLK -1=WRLCK +ve=#RDLCK */ 146 s32 lock_count; /* file lock count (0=UNLK -1=WRLCK +ve=#RDLCK */
142}; 147};
143 148
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h
index d47b6d01e4c0..ddfa88a7a9c0 100644
--- a/fs/afs/afs_fs.h
+++ b/fs/afs/afs_fs.h
@@ -31,10 +31,12 @@ enum AFS_FS_Operations {
31 FSGETVOLUMEINFO = 148, /* AFS Get information about a volume */ 31 FSGETVOLUMEINFO = 148, /* AFS Get information about a volume */
32 FSGETVOLUMESTATUS = 149, /* AFS Get volume status information */ 32 FSGETVOLUMESTATUS = 149, /* AFS Get volume status information */
33 FSGETROOTVOLUME = 151, /* AFS Get root volume name */ 33 FSGETROOTVOLUME = 151, /* AFS Get root volume name */
34 FSBULKSTATUS = 155, /* AFS Fetch multiple file statuses */
34 FSSETLOCK = 156, /* AFS Request a file lock */ 35 FSSETLOCK = 156, /* AFS Request a file lock */
35 FSEXTENDLOCK = 157, /* AFS Extend a file lock */ 36 FSEXTENDLOCK = 157, /* AFS Extend a file lock */
36 FSRELEASELOCK = 158, /* AFS Release a file lock */ 37 FSRELEASELOCK = 158, /* AFS Release a file lock */
37 FSLOOKUP = 161, /* AFS lookup file in directory */ 38 FSLOOKUP = 161, /* AFS lookup file in directory */
39 FSINLINEBULKSTATUS = 65536, /* AFS Fetch multiple file statuses with inline errors */
38 FSFETCHDATA64 = 65537, /* AFS Fetch file data */ 40 FSFETCHDATA64 = 65537, /* AFS Fetch file data */
39 FSSTOREDATA64 = 65538, /* AFS Store file data */ 41 FSSTOREDATA64 = 65538, /* AFS Store file data */
40 FSGIVEUPALLCALLBACKS = 65539, /* AFS Give up all outstanding callbacks on a server */ 42 FSGIVEUPALLCALLBACKS = 65539, /* AFS Give up all outstanding callbacks on a server */
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index bf082c719645..6049ca837498 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -187,7 +187,7 @@ static void afs_break_one_callback(struct afs_server *server,
187 * allow the fileserver to break callback promises 187 * allow the fileserver to break callback promises
188 */ 188 */
189void afs_break_callbacks(struct afs_server *server, size_t count, 189void afs_break_callbacks(struct afs_server *server, size_t count,
190 struct afs_callback callbacks[]) 190 struct afs_callback_break *callbacks)
191{ 191{
192 _enter("%p,%zu,", server, count); 192 _enter("%p,%zu,", server, count);
193 193
@@ -199,9 +199,9 @@ void afs_break_callbacks(struct afs_server *server, size_t count,
199 callbacks->fid.vid, 199 callbacks->fid.vid,
200 callbacks->fid.vnode, 200 callbacks->fid.vnode,
201 callbacks->fid.unique, 201 callbacks->fid.unique,
202 callbacks->version, 202 callbacks->cb.version,
203 callbacks->expiry, 203 callbacks->cb.expiry,
204 callbacks->type 204 callbacks->cb.type
205 ); 205 );
206 afs_break_one_callback(server, &callbacks->fid); 206 afs_break_one_callback(server, &callbacks->fid);
207 } 207 }
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index 83ff283979a4..fa07f83e9f29 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -178,8 +178,8 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
178 */ 178 */
179static int afs_deliver_cb_callback(struct afs_call *call) 179static int afs_deliver_cb_callback(struct afs_call *call)
180{ 180{
181 struct afs_callback_break *cb;
181 struct sockaddr_rxrpc srx; 182 struct sockaddr_rxrpc srx;
182 struct afs_callback *cb;
183 struct afs_server *server; 183 struct afs_server *server;
184 __be32 *bp; 184 __be32 *bp;
185 int ret, loop; 185 int ret, loop;
@@ -218,7 +218,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
218 218
219 _debug("unmarshall FID array"); 219 _debug("unmarshall FID array");
220 call->request = kcalloc(call->count, 220 call->request = kcalloc(call->count,
221 sizeof(struct afs_callback), 221 sizeof(struct afs_callback_break),
222 GFP_KERNEL); 222 GFP_KERNEL);
223 if (!call->request) 223 if (!call->request)
224 return -ENOMEM; 224 return -ENOMEM;
@@ -229,7 +229,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
229 cb->fid.vid = ntohl(*bp++); 229 cb->fid.vid = ntohl(*bp++);
230 cb->fid.vnode = ntohl(*bp++); 230 cb->fid.vnode = ntohl(*bp++);
231 cb->fid.unique = ntohl(*bp++); 231 cb->fid.unique = ntohl(*bp++);
232 cb->type = AFSCM_CB_UNTYPED; 232 cb->cb.type = AFSCM_CB_UNTYPED;
233 } 233 }
234 234
235 call->offset = 0; 235 call->offset = 0;
@@ -260,9 +260,9 @@ static int afs_deliver_cb_callback(struct afs_call *call)
260 cb = call->request; 260 cb = call->request;
261 bp = call->buffer; 261 bp = call->buffer;
262 for (loop = call->count2; loop > 0; loop--, cb++) { 262 for (loop = call->count2; loop > 0; loop--, cb++) {
263 cb->version = ntohl(*bp++); 263 cb->cb.version = ntohl(*bp++);
264 cb->expiry = ntohl(*bp++); 264 cb->cb.expiry = ntohl(*bp++);
265 cb->type = ntohl(*bp++); 265 cb->cb.type = ntohl(*bp++);
266 } 266 }
267 267
268 call->offset = 0; 268 call->offset = 0;
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index ba2b458b36d1..27c5231e89e7 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -29,8 +29,10 @@ static int afs_readdir(struct file *file, struct dir_context *ctx);
29static int afs_d_revalidate(struct dentry *dentry, unsigned int flags); 29static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
30static int afs_d_delete(const struct dentry *dentry); 30static int afs_d_delete(const struct dentry *dentry);
31static void afs_d_release(struct dentry *dentry); 31static void afs_d_release(struct dentry *dentry);
32static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen, 32static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen,
33 loff_t fpos, u64 ino, unsigned dtype); 33 loff_t fpos, u64 ino, unsigned dtype);
34static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen,
35 loff_t fpos, u64 ino, unsigned dtype);
34static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, 36static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
35 bool excl); 37 bool excl);
36static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); 38static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
@@ -134,11 +136,22 @@ struct afs_dir_page {
134 union afs_dir_block blocks[PAGE_SIZE / sizeof(union afs_dir_block)]; 136 union afs_dir_block blocks[PAGE_SIZE / sizeof(union afs_dir_block)];
135}; 137};
136 138
139struct afs_lookup_one_cookie {
140 struct dir_context ctx;
141 struct qstr name;
142 bool found;
143 struct afs_fid fid;
144};
145
137struct afs_lookup_cookie { 146struct afs_lookup_cookie {
138 struct dir_context ctx; 147 struct dir_context ctx;
139 struct afs_fid fid; 148 struct qstr name;
140 struct qstr name; 149 bool found;
141 int found; 150 bool one_only;
151 unsigned short nr_fids;
152 struct afs_file_status *statuses;
153 struct afs_callback *callbacks;
154 struct afs_fid fids[50];
142}; 155};
143 156
144/* 157/*
@@ -330,7 +343,8 @@ static int afs_dir_iterate_block(struct dir_context *ctx,
330 /* found the next entry */ 343 /* found the next entry */
331 if (!dir_emit(ctx, dire->u.name, nlen, 344 if (!dir_emit(ctx, dire->u.name, nlen,
332 ntohl(dire->u.vnode), 345 ntohl(dire->u.vnode),
333 ctx->actor == afs_lookup_filldir ? 346 (ctx->actor == afs_lookup_filldir ||
347 ctx->actor == afs_lookup_one_filldir)?
334 ntohl(dire->u.unique) : DT_UNKNOWN)) { 348 ntohl(dire->u.unique) : DT_UNKNOWN)) {
335 _leave(" = 0 [full]"); 349 _leave(" = 0 [full]");
336 return 0; 350 return 0;
@@ -414,15 +428,15 @@ static int afs_readdir(struct file *file, struct dir_context *ctx)
414} 428}
415 429
416/* 430/*
417 * search the directory for a name 431 * Search the directory for a single name
418 * - if afs_dir_iterate_block() spots this function, it'll pass the FID 432 * - if afs_dir_iterate_block() spots this function, it'll pass the FID
419 * uniquifier through dtype 433 * uniquifier through dtype
420 */ 434 */
421static int afs_lookup_filldir(struct dir_context *ctx, const char *name, 435static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name,
422 int nlen, loff_t fpos, u64 ino, unsigned dtype) 436 int nlen, loff_t fpos, u64 ino, unsigned dtype)
423{ 437{
424 struct afs_lookup_cookie *cookie = 438 struct afs_lookup_one_cookie *cookie =
425 container_of(ctx, struct afs_lookup_cookie, ctx); 439 container_of(ctx, struct afs_lookup_one_cookie, ctx);
426 440
427 _enter("{%s,%u},%s,%u,,%llu,%u", 441 _enter("{%s,%u},%s,%u,,%llu,%u",
428 cookie->name.name, cookie->name.len, name, nlen, 442 cookie->name.name, cookie->name.len, name, nlen,
@@ -447,15 +461,15 @@ static int afs_lookup_filldir(struct dir_context *ctx, const char *name,
447} 461}
448 462
449/* 463/*
450 * do a lookup in a directory 464 * Do a lookup of a single name in a directory
451 * - just returns the FID the dentry name maps to if found 465 * - just returns the FID the dentry name maps to if found
452 */ 466 */
453static int afs_do_lookup(struct inode *dir, struct dentry *dentry, 467static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry,
454 struct afs_fid *fid, struct key *key) 468 struct afs_fid *fid, struct key *key)
455{ 469{
456 struct afs_super_info *as = dir->i_sb->s_fs_info; 470 struct afs_super_info *as = dir->i_sb->s_fs_info;
457 struct afs_lookup_cookie cookie = { 471 struct afs_lookup_one_cookie cookie = {
458 .ctx.actor = afs_lookup_filldir, 472 .ctx.actor = afs_lookup_one_filldir,
459 .name = dentry->d_name, 473 .name = dentry->d_name,
460 .fid.vid = as->volume->vid 474 .fid.vid = as->volume->vid
461 }; 475 };
@@ -482,6 +496,212 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
482} 496}
483 497
484/* 498/*
499 * search the directory for a name
500 * - if afs_dir_iterate_block() spots this function, it'll pass the FID
501 * uniquifier through dtype
502 */
503static int afs_lookup_filldir(struct dir_context *ctx, const char *name,
504 int nlen, loff_t fpos, u64 ino, unsigned dtype)
505{
506 struct afs_lookup_cookie *cookie =
507 container_of(ctx, struct afs_lookup_cookie, ctx);
508 int ret;
509
510 _enter("{%s,%u},%s,%u,,%llu,%u",
511 cookie->name.name, cookie->name.len, name, nlen,
512 (unsigned long long) ino, dtype);
513
514 /* insanity checks first */
515 BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
516 BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
517
518 if (cookie->found) {
519 if (cookie->nr_fids < 50) {
520 cookie->fids[cookie->nr_fids].vnode = ino;
521 cookie->fids[cookie->nr_fids].unique = dtype;
522 cookie->nr_fids++;
523 }
524 } else if (cookie->name.len == nlen &&
525 memcmp(cookie->name.name, name, nlen) == 0) {
526 cookie->fids[0].vnode = ino;
527 cookie->fids[0].unique = dtype;
528 cookie->found = 1;
529 if (cookie->one_only)
530 return -1;
531 }
532
533 ret = cookie->nr_fids >= 50 ? -1 : 0;
534 _leave(" = %d", ret);
535 return ret;
536}
537
538/*
539 * Do a lookup in a directory. We make use of bulk lookup to query a slew of
540 * files in one go and create inodes for them. The inode of the file we were
541 * asked for is returned.
542 */
543static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
544 struct key *key)
545{
546 struct afs_lookup_cookie *cookie;
547 struct afs_cb_interest *cbi = NULL;
548 struct afs_super_info *as = dir->i_sb->s_fs_info;
549 struct afs_iget_data data;
550 struct afs_fs_cursor fc;
551 struct afs_vnode *dvnode = AFS_FS_I(dir);
552 struct inode *inode = NULL;
553 int ret, i;
554
555 _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
556
557 cookie = kzalloc(sizeof(struct afs_lookup_cookie), GFP_KERNEL);
558 if (!cookie)
559 return ERR_PTR(-ENOMEM);
560
561 cookie->ctx.actor = afs_lookup_filldir;
562 cookie->name = dentry->d_name;
563 cookie->nr_fids = 1; /* slot 0 is saved for the fid we actually want */
564
565 read_seqlock_excl(&dvnode->cb_lock);
566 if (dvnode->cb_interest &&
567 dvnode->cb_interest->server &&
568 test_bit(AFS_SERVER_FL_NO_IBULK, &dvnode->cb_interest->server->flags))
569 cookie->one_only = true;
570 read_sequnlock_excl(&dvnode->cb_lock);
571
572 for (i = 0; i < 50; i++)
573 cookie->fids[i].vid = as->volume->vid;
574
575 /* search the directory */
576 ret = afs_dir_iterate(dir, &cookie->ctx, key);
577 if (ret < 0) {
578 inode = ERR_PTR(ret);
579 goto out;
580 }
581
582 inode = ERR_PTR(-ENOENT);
583 if (!cookie->found)
584 goto out;
585
586 /* Check to see if we already have an inode for the primary fid. */
587 data.volume = dvnode->volume;
588 data.fid = cookie->fids[0];
589 inode = ilookup5(dir->i_sb, cookie->fids[0].vnode, afs_iget5_test, &data);
590 if (inode)
591 goto out;
592
593 /* Need space for examining all the selected files */
594 inode = ERR_PTR(-ENOMEM);
595 cookie->statuses = kcalloc(cookie->nr_fids, sizeof(struct afs_file_status),
596 GFP_KERNEL);
597 if (!cookie->statuses)
598 goto out;
599
600 cookie->callbacks = kcalloc(cookie->nr_fids, sizeof(struct afs_callback),
601 GFP_KERNEL);
602 if (!cookie->callbacks)
603 goto out_s;
604
605 /* Try FS.InlineBulkStatus first. Abort codes for the individual
606 * lookups contained therein are stored in the reply without aborting
607 * the whole operation.
608 */
609 if (cookie->one_only)
610 goto no_inline_bulk_status;
611
612 inode = ERR_PTR(-ERESTARTSYS);
613 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
614 while (afs_select_fileserver(&fc)) {
615 if (test_bit(AFS_SERVER_FL_NO_IBULK,
616 &fc.cbi->server->flags)) {
617 fc.ac.abort_code = RX_INVALID_OPERATION;
618 fc.ac.error = -ECONNABORTED;
619 break;
620 }
621 afs_fs_inline_bulk_status(&fc,
622 afs_v2net(dvnode),
623 cookie->fids,
624 cookie->statuses,
625 cookie->callbacks,
626 cookie->nr_fids, NULL);
627 }
628
629 if (fc.ac.error == 0)
630 cbi = afs_get_cb_interest(fc.cbi);
631 if (fc.ac.abort_code == RX_INVALID_OPERATION)
632 set_bit(AFS_SERVER_FL_NO_IBULK, &fc.cbi->server->flags);
633 inode = ERR_PTR(afs_end_vnode_operation(&fc));
634 }
635
636 if (!IS_ERR(inode))
637 goto success;
638 if (fc.ac.abort_code != RX_INVALID_OPERATION)
639 goto out_c;
640
641no_inline_bulk_status:
642 /* We could try FS.BulkStatus next, but this aborts the entire op if
643 * any of the lookups fails - so, for the moment, revert to
644 * FS.FetchStatus for just the primary fid.
645 */
646 cookie->nr_fids = 1;
647 inode = ERR_PTR(-ERESTARTSYS);
648 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
649 while (afs_select_fileserver(&fc)) {
650 afs_fs_fetch_status(&fc,
651 afs_v2net(dvnode),
652 cookie->fids,
653 cookie->statuses,
654 cookie->callbacks,
655 NULL);
656 }
657
658 if (fc.ac.error == 0)
659 cbi = afs_get_cb_interest(fc.cbi);
660 inode = ERR_PTR(afs_end_vnode_operation(&fc));
661 }
662
663 if (IS_ERR(inode))
664 goto out_c;
665
666 for (i = 0; i < cookie->nr_fids; i++)
667 cookie->statuses[i].abort_code = 0;
668
669success:
670 /* Turn all the files into inodes and save the first one - which is the
671 * one we actually want.
672 */
673 if (cookie->statuses[0].abort_code != 0)
674 inode = ERR_PTR(afs_abort_to_error(cookie->statuses[0].abort_code));
675
676 for (i = 0; i < cookie->nr_fids; i++) {
677 struct inode *ti;
678
679 if (cookie->statuses[i].abort_code != 0)
680 continue;
681
682 ti = afs_iget(dir->i_sb, key, &cookie->fids[i],
683 &cookie->statuses[i],
684 &cookie->callbacks[i],
685 cbi);
686 if (i == 0) {
687 inode = ti;
688 } else {
689 if (!IS_ERR(ti))
690 iput(ti);
691 }
692 }
693
694out_c:
695 afs_put_cb_interest(afs_v2net(dvnode), cbi);
696 kfree(cookie->callbacks);
697out_s:
698 kfree(cookie->statuses);
699out:
700 kfree(cookie);
701 return inode;
702}
703
704/*
485 * Probe to see if a cell may exist. This prevents positive dentries from 705 * Probe to see if a cell may exist. This prevents positive dentries from
486 * being created unnecessarily. 706 * being created unnecessarily.
487 */ 707 */
@@ -516,8 +736,7 @@ static int afs_probe_cell_name(struct dentry *dentry)
516 * Try to auto mount the mountpoint with pseudo directory, if the autocell 736 * Try to auto mount the mountpoint with pseudo directory, if the autocell
517 * operation is setted. 737 * operation is setted.
518 */ 738 */
519static struct inode *afs_try_auto_mntpt(struct dentry *dentry, 739static struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir)
520 struct inode *dir, struct afs_fid *fid)
521{ 740{
522 struct afs_vnode *vnode = AFS_FS_I(dir); 741 struct afs_vnode *vnode = AFS_FS_I(dir);
523 struct inode *inode; 742 struct inode *inode;
@@ -539,7 +758,6 @@ static struct inode *afs_try_auto_mntpt(struct dentry *dentry,
539 goto out; 758 goto out;
540 } 759 }
541 760
542 *fid = AFS_FS_I(inode)->fid;
543 _leave("= %p", inode); 761 _leave("= %p", inode);
544 return inode; 762 return inode;
545 763
@@ -554,16 +772,13 @@ out:
554static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, 772static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
555 unsigned int flags) 773 unsigned int flags)
556{ 774{
557 struct afs_vnode *vnode; 775 struct afs_vnode *dvnode = AFS_FS_I(dir);
558 struct afs_fid fid;
559 struct inode *inode; 776 struct inode *inode;
560 struct key *key; 777 struct key *key;
561 int ret; 778 int ret;
562 779
563 vnode = AFS_FS_I(dir);
564
565 _enter("{%x:%u},%p{%pd},", 780 _enter("{%x:%u},%p{%pd},",
566 vnode->fid.vid, vnode->fid.vnode, dentry, dentry); 781 dvnode->fid.vid, dvnode->fid.vnode, dentry, dentry);
567 782
568 ASSERTCMP(d_inode(dentry), ==, NULL); 783 ASSERTCMP(d_inode(dentry), ==, NULL);
569 784
@@ -572,28 +787,29 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
572 return ERR_PTR(-ENAMETOOLONG); 787 return ERR_PTR(-ENAMETOOLONG);
573 } 788 }
574 789
575 if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 790 if (test_bit(AFS_VNODE_DELETED, &dvnode->flags)) {
576 _leave(" = -ESTALE"); 791 _leave(" = -ESTALE");
577 return ERR_PTR(-ESTALE); 792 return ERR_PTR(-ESTALE);
578 } 793 }
579 794
580 key = afs_request_key(vnode->volume->cell); 795 key = afs_request_key(dvnode->volume->cell);
581 if (IS_ERR(key)) { 796 if (IS_ERR(key)) {
582 _leave(" = %ld [key]", PTR_ERR(key)); 797 _leave(" = %ld [key]", PTR_ERR(key));
583 return ERR_CAST(key); 798 return ERR_CAST(key);
584 } 799 }
585 800
586 ret = afs_validate(vnode, key); 801 ret = afs_validate(dvnode, key);
587 if (ret < 0) { 802 if (ret < 0) {
588 key_put(key); 803 key_put(key);
589 _leave(" = %d [val]", ret); 804 _leave(" = %d [val]", ret);
590 return ERR_PTR(ret); 805 return ERR_PTR(ret);
591 } 806 }
592 807
593 ret = afs_do_lookup(dir, dentry, &fid, key); 808 inode = afs_do_lookup(dir, dentry, key);
594 if (ret < 0) { 809 if (IS_ERR(inode)) {
810 ret = PTR_ERR(inode);
595 if (ret == -ENOENT) { 811 if (ret == -ENOENT) {
596 inode = afs_try_auto_mntpt(dentry, dir, &fid); 812 inode = afs_try_auto_mntpt(dentry, dir);
597 if (!IS_ERR(inode)) { 813 if (!IS_ERR(inode)) {
598 key_put(key); 814 key_put(key);
599 goto success; 815 goto success;
@@ -611,10 +827,9 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
611 _leave(" = %d [do]", ret); 827 _leave(" = %d [do]", ret);
612 return ERR_PTR(ret); 828 return ERR_PTR(ret);
613 } 829 }
614 dentry->d_fsdata = (void *)(unsigned long) vnode->status.data_version; 830 dentry->d_fsdata = (void *)(unsigned long)dvnode->status.data_version;
615 831
616 /* instantiate the dentry */ 832 /* instantiate the dentry */
617 inode = afs_iget(dir->i_sb, key, &fid, NULL, NULL, NULL);
618 key_put(key); 833 key_put(key);
619 if (IS_ERR(inode)) { 834 if (IS_ERR(inode)) {
620 _leave(" = %ld", PTR_ERR(inode)); 835 _leave(" = %ld", PTR_ERR(inode));
@@ -623,9 +838,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
623 838
624success: 839success:
625 d_add(dentry, inode); 840 d_add(dentry, inode);
626 _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%u }", 841 _leave(" = 0 { ino=%lu v=%u }",
627 fid.vnode,
628 fid.unique,
629 d_inode(dentry)->i_ino, 842 d_inode(dentry)->i_ino,
630 d_inode(dentry)->i_generation); 843 d_inode(dentry)->i_generation);
631 844
@@ -639,7 +852,6 @@ static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentr
639 unsigned int flags) 852 unsigned int flags)
640{ 853{
641 struct afs_vnode *vnode; 854 struct afs_vnode *vnode;
642 struct afs_fid fid;
643 struct inode *inode; 855 struct inode *inode;
644 int ret; 856 int ret;
645 857
@@ -654,7 +866,7 @@ static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentr
654 return ERR_PTR(-ENAMETOOLONG); 866 return ERR_PTR(-ENAMETOOLONG);
655 } 867 }
656 868
657 inode = afs_try_auto_mntpt(dentry, dir, &fid); 869 inode = afs_try_auto_mntpt(dentry, dir);
658 if (IS_ERR(inode)) { 870 if (IS_ERR(inode)) {
659 ret = PTR_ERR(inode); 871 ret = PTR_ERR(inode);
660 if (ret == -ENOENT) { 872 if (ret == -ENOENT) {
@@ -736,7 +948,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
736 _debug("dir modified"); 948 _debug("dir modified");
737 949
738 /* search the directory for this vnode */ 950 /* search the directory for this vnode */
739 ret = afs_do_lookup(&dir->vfs_inode, dentry, &fid, key); 951 ret = afs_do_lookup_one(&dir->vfs_inode, dentry, &fid, key);
740 switch (ret) { 952 switch (ret) {
741 case 0: 953 case 0:
742 /* the filename maps to something */ 954 /* the filename maps to something */
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 88ec38c2d83c..75554ee98d02 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -94,7 +94,7 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
94 data_version |= (u64) ntohl(*bp++) << 32; 94 data_version |= (u64) ntohl(*bp++) << 32;
95 EXTRACT(status->lock_count); 95 EXTRACT(status->lock_count);
96 size |= (u64) ntohl(*bp++) << 32; 96 size |= (u64) ntohl(*bp++) << 32;
97 bp++; /* spare 4 */ 97 EXTRACT(status->abort_code); /* spare 4 */
98 *_bp = bp; 98 *_bp = bp;
99 99
100 if (size != status->size) { 100 if (size != status->size) {
@@ -274,7 +274,7 @@ static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
274/* 274/*
275 * deliver reply data to an FS.FetchStatus 275 * deliver reply data to an FS.FetchStatus
276 */ 276 */
277static int afs_deliver_fs_fetch_status(struct afs_call *call) 277static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call)
278{ 278{
279 struct afs_vnode *vnode = call->reply[0]; 279 struct afs_vnode *vnode = call->reply[0];
280 const __be32 *bp; 280 const __be32 *bp;
@@ -300,10 +300,10 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call)
300/* 300/*
301 * FS.FetchStatus operation type 301 * FS.FetchStatus operation type
302 */ 302 */
303static const struct afs_call_type afs_RXFSFetchStatus = { 303static const struct afs_call_type afs_RXFSFetchStatus_vnode = {
304 .name = "FS.FetchStatus", 304 .name = "FS.FetchStatus(vnode)",
305 .op = afs_FS_FetchStatus, 305 .op = afs_FS_FetchStatus,
306 .deliver = afs_deliver_fs_fetch_status, 306 .deliver = afs_deliver_fs_fetch_status_vnode,
307 .destructor = afs_flat_call_destructor, 307 .destructor = afs_flat_call_destructor,
308}; 308};
309 309
@@ -320,7 +320,8 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy
320 _enter(",%x,{%x:%u},,", 320 _enter(",%x,{%x:%u},,",
321 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); 321 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
322 322
323 call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); 323 call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus_vnode,
324 16, (21 + 3 + 6) * 4);
324 if (!call) { 325 if (!call) {
325 fc->ac.error = -ENOMEM; 326 fc->ac.error = -ENOMEM;
326 return -ENOMEM; 327 return -ENOMEM;
@@ -1947,3 +1948,262 @@ int afs_fs_get_capabilities(struct afs_net *net,
1947 trace_afs_make_fs_call(call, NULL); 1948 trace_afs_make_fs_call(call, NULL);
1948 return afs_make_call(ac, call, GFP_NOFS, false); 1949 return afs_make_call(ac, call, GFP_NOFS, false);
1949} 1950}
1951
1952/*
1953 * Deliver reply data to an FS.FetchStatus with no vnode.
1954 */
1955static int afs_deliver_fs_fetch_status(struct afs_call *call)
1956{
1957 struct afs_file_status *status = call->reply[1];
1958 struct afs_callback *callback = call->reply[2];
1959 struct afs_volsync *volsync = call->reply[3];
1960 struct afs_vnode *vnode = call->reply[0];
1961 const __be32 *bp;
1962 int ret;
1963
1964 ret = afs_transfer_reply(call);
1965 if (ret < 0)
1966 return ret;
1967
1968 _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
1969
1970 /* unmarshall the reply once we've received all of it */
1971 bp = call->buffer;
1972 xdr_decode_AFSFetchStatus(&bp, status, vnode, NULL);
1973 callback[call->count].version = ntohl(bp[0]);
1974 callback[call->count].expiry = ntohl(bp[1]);
1975 callback[call->count].type = ntohl(bp[2]);
1976 if (vnode)
1977 xdr_decode_AFSCallBack(call, vnode, &bp);
1978 else
1979 bp += 3;
1980 if (volsync)
1981 xdr_decode_AFSVolSync(&bp, volsync);
1982
1983 _leave(" = 0 [done]");
1984 return 0;
1985}
1986
1987/*
1988 * FS.FetchStatus operation type
1989 */
1990static const struct afs_call_type afs_RXFSFetchStatus = {
1991 .name = "FS.FetchStatus",
1992 .op = afs_FS_FetchStatus,
1993 .deliver = afs_deliver_fs_fetch_status,
1994 .destructor = afs_flat_call_destructor,
1995};
1996
1997/*
1998 * Fetch the status information for a fid without needing a vnode handle.
1999 */
2000int afs_fs_fetch_status(struct afs_fs_cursor *fc,
2001 struct afs_net *net,
2002 struct afs_fid *fid,
2003 struct afs_file_status *status,
2004 struct afs_callback *callback,
2005 struct afs_volsync *volsync)
2006{
2007 struct afs_call *call;
2008 __be32 *bp;
2009
2010 _enter(",%x,{%x:%u},,",
2011 key_serial(fc->key), fid->vid, fid->vnode);
2012
2013 call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
2014 if (!call) {
2015 fc->ac.error = -ENOMEM;
2016 return -ENOMEM;
2017 }
2018
2019 call->key = fc->key;
2020 call->reply[0] = NULL; /* vnode for fid[0] */
2021 call->reply[1] = status;
2022 call->reply[2] = callback;
2023 call->reply[3] = volsync;
2024
2025 /* marshall the parameters */
2026 bp = call->request;
2027 bp[0] = htonl(FSFETCHSTATUS);
2028 bp[1] = htonl(fid->vid);
2029 bp[2] = htonl(fid->vnode);
2030 bp[3] = htonl(fid->unique);
2031
2032 call->cb_break = fc->cb_break;
2033 afs_use_fs_server(call, fc->cbi);
2034 trace_afs_make_fs_call(call, fid);
2035 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
2036}
2037
2038/*
2039 * Deliver reply data to an FS.InlineBulkStatus call
2040 */
2041static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
2042{
2043 struct afs_file_status *statuses;
2044 struct afs_callback *callbacks;
2045 struct afs_vnode *vnode = call->reply[0];
2046 const __be32 *bp;
2047 u32 tmp;
2048 int ret;
2049
2050 _enter("{%u}", call->unmarshall);
2051
2052 switch (call->unmarshall) {
2053 case 0:
2054 call->offset = 0;
2055 call->unmarshall++;
2056
2057 /* Extract the file status count and array in two steps */
2058 case 1:
2059 _debug("extract status count");
2060 ret = afs_extract_data(call, &call->tmp, 4, true);
2061 if (ret < 0)
2062 return ret;
2063
2064 tmp = ntohl(call->tmp);
2065 _debug("status count: %u/%u", tmp, call->count2);
2066 if (tmp != call->count2)
2067 return -EBADMSG;
2068
2069 call->count = 0;
2070 call->unmarshall++;
2071 more_counts:
2072 call->offset = 0;
2073
2074 case 2:
2075 _debug("extract status array %u", call->count);
2076 ret = afs_extract_data(call, call->buffer, 21 * 4, true);
2077 if (ret < 0)
2078 return ret;
2079
2080 bp = call->buffer;
2081 statuses = call->reply[1];
2082 xdr_decode_AFSFetchStatus(&bp, &statuses[call->count],
2083 call->count == 0 ? vnode : NULL,
2084 NULL);
2085
2086 call->count++;
2087 if (call->count < call->count2)
2088 goto more_counts;
2089
2090 call->count = 0;
2091 call->unmarshall++;
2092 call->offset = 0;
2093
2094 /* Extract the callback count and array in two steps */
2095 case 3:
2096 _debug("extract CB count");
2097 ret = afs_extract_data(call, &call->tmp, 4, true);
2098 if (ret < 0)
2099 return ret;
2100
2101 tmp = ntohl(call->tmp);
2102 _debug("CB count: %u", tmp);
2103 if (tmp != call->count2)
2104 return -EBADMSG;
2105 call->count = 0;
2106 call->unmarshall++;
2107 more_cbs:
2108 call->offset = 0;
2109
2110 case 4:
2111 _debug("extract CB array");
2112 ret = afs_extract_data(call, call->buffer, 3 * 4, true);
2113 if (ret < 0)
2114 return ret;
2115
2116 _debug("unmarshall CB array");
2117 bp = call->buffer;
2118 callbacks = call->reply[2];
2119 callbacks[call->count].version = ntohl(bp[0]);
2120 callbacks[call->count].expiry = ntohl(bp[1]);
2121 callbacks[call->count].type = ntohl(bp[2]);
2122 statuses = call->reply[1];
2123 if (call->count == 0 && vnode && statuses[0].abort_code == 0)
2124 xdr_decode_AFSCallBack(call, vnode, &bp);
2125 call->count++;
2126 if (call->count < call->count2)
2127 goto more_cbs;
2128
2129 call->offset = 0;
2130 call->unmarshall++;
2131
2132 case 5:
2133 ret = afs_extract_data(call, call->buffer, 6 * 4, false);
2134 if (ret < 0)
2135 return ret;
2136
2137 bp = call->buffer;
2138 if (call->reply[3])
2139 xdr_decode_AFSVolSync(&bp, call->reply[3]);
2140
2141 call->offset = 0;
2142 call->unmarshall++;
2143
2144 case 6:
2145 break;
2146 }
2147
2148 _leave(" = 0 [done]");
2149 return 0;
2150}
2151
2152/*
2153 * FS.InlineBulkStatus operation type
2154 */
2155static const struct afs_call_type afs_RXFSInlineBulkStatus = {
2156 .name = "FS.InlineBulkStatus",
2157 .op = afs_FS_InlineBulkStatus,
2158 .deliver = afs_deliver_fs_inline_bulk_status,
2159 .destructor = afs_flat_call_destructor,
2160};
2161
2162/*
2163 * Fetch the status information for up to 50 files
2164 */
2165int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
2166 struct afs_net *net,
2167 struct afs_fid *fids,
2168 struct afs_file_status *statuses,
2169 struct afs_callback *callbacks,
2170 unsigned int nr_fids,
2171 struct afs_volsync *volsync)
2172{
2173 struct afs_call *call;
2174 __be32 *bp;
2175 int i;
2176
2177 _enter(",%x,{%x:%u},%u",
2178 key_serial(fc->key), fids[0].vid, fids[1].vnode, nr_fids);
2179
2180 call = afs_alloc_flat_call(net, &afs_RXFSInlineBulkStatus,
2181 (2 + nr_fids * 3) * 4,
2182 21 * 4);
2183 if (!call) {
2184 fc->ac.error = -ENOMEM;
2185 return -ENOMEM;
2186 }
2187
2188 call->key = fc->key;
2189 call->reply[0] = NULL; /* vnode for fid[0] */
2190 call->reply[1] = statuses;
2191 call->reply[2] = callbacks;
2192 call->reply[3] = volsync;
2193 call->count2 = nr_fids;
2194
2195 /* marshall the parameters */
2196 bp = call->request;
2197 *bp++ = htonl(FSINLINEBULKSTATUS);
2198 *bp++ = htonl(nr_fids);
2199 for (i = 0; i < nr_fids; i++) {
2200 *bp++ = htonl(fids[i].vid);
2201 *bp++ = htonl(fids[i].vnode);
2202 *bp++ = htonl(fids[i].unique);
2203 }
2204
2205 call->cb_break = fc->cb_break;
2206 afs_use_fs_server(call, fc->cbi);
2207 trace_afs_make_fs_call(call, &fids[0]);
2208 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
2209}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 135192b7dc04..55b07e818400 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -363,6 +363,7 @@ struct afs_server {
363#define AFS_SERVER_FL_UPDATING 4 363#define AFS_SERVER_FL_UPDATING 4
364#define AFS_SERVER_FL_PROBED 5 /* The fileserver has been probed */ 364#define AFS_SERVER_FL_PROBED 5 /* The fileserver has been probed */
365#define AFS_SERVER_FL_PROBING 6 /* Fileserver is being probed */ 365#define AFS_SERVER_FL_PROBING 6 /* Fileserver is being probed */
366#define AFS_SERVER_FL_NO_IBULK 7 /* Fileserver doesn't support FS.InlineBulkStatus */
366 atomic_t usage; 367 atomic_t usage;
367 u32 addr_version; /* Address list version */ 368 u32 addr_version; /* Address list version */
368 369
@@ -611,7 +612,7 @@ extern struct fscache_cookie_def afs_vnode_cache_index_def;
611 */ 612 */
612extern void afs_init_callback_state(struct afs_server *); 613extern void afs_init_callback_state(struct afs_server *);
613extern void afs_break_callback(struct afs_vnode *); 614extern void afs_break_callback(struct afs_vnode *);
614extern void afs_break_callbacks(struct afs_server *, size_t,struct afs_callback[]); 615extern void afs_break_callbacks(struct afs_server *, size_t, struct afs_callback_break*);
615 616
616extern int afs_register_server_cb_interest(struct afs_vnode *, struct afs_server_entry *); 617extern int afs_register_server_cb_interest(struct afs_vnode *, struct afs_server_entry *);
617extern void afs_put_cb_interest(struct afs_net *, struct afs_cb_interest *); 618extern void afs_put_cb_interest(struct afs_net *, struct afs_cb_interest *);
@@ -702,6 +703,13 @@ extern int afs_fs_give_up_all_callbacks(struct afs_net *, struct afs_server *,
702 struct afs_addr_cursor *, struct key *); 703 struct afs_addr_cursor *, struct key *);
703extern int afs_fs_get_capabilities(struct afs_net *, struct afs_server *, 704extern int afs_fs_get_capabilities(struct afs_net *, struct afs_server *,
704 struct afs_addr_cursor *, struct key *); 705 struct afs_addr_cursor *, struct key *);
706extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
707 struct afs_fid *, struct afs_file_status *,
708 struct afs_callback *, unsigned int,
709 struct afs_volsync *);
710extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
711 struct afs_fid *, struct afs_file_status *,
712 struct afs_callback *, struct afs_volsync *);
705 713
706/* 714/*
707 * inode.c 715 * inode.c
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
index 63815f66b274..0419b7e1e968 100644
--- a/include/trace/events/afs.h
+++ b/include/trace/events/afs.h
@@ -49,6 +49,7 @@ enum afs_fs_operation {
49 afs_FS_ExtendLock = 157, /* AFS Extend a file lock */ 49 afs_FS_ExtendLock = 157, /* AFS Extend a file lock */
50 afs_FS_ReleaseLock = 158, /* AFS Release a file lock */ 50 afs_FS_ReleaseLock = 158, /* AFS Release a file lock */
51 afs_FS_Lookup = 161, /* AFS lookup file in directory */ 51 afs_FS_Lookup = 161, /* AFS lookup file in directory */
52 afs_FS_InlineBulkStatus = 65536, /* AFS Fetch multiple file statuses with errors */
52 afs_FS_FetchData64 = 65537, /* AFS Fetch file data */ 53 afs_FS_FetchData64 = 65537, /* AFS Fetch file data */
53 afs_FS_StoreData64 = 65538, /* AFS Store file data */ 54 afs_FS_StoreData64 = 65538, /* AFS Store file data */
54 afs_FS_GiveUpAllCallBacks = 65539, /* AFS Give up all our callbacks on a server */ 55 afs_FS_GiveUpAllCallBacks = 65539, /* AFS Give up all our callbacks on a server */
@@ -93,6 +94,7 @@ enum afs_vl_operation {
93 EM(afs_FS_ExtendLock, "FS.ExtendLock") \ 94 EM(afs_FS_ExtendLock, "FS.ExtendLock") \
94 EM(afs_FS_ReleaseLock, "FS.ReleaseLock") \ 95 EM(afs_FS_ReleaseLock, "FS.ReleaseLock") \
95 EM(afs_FS_Lookup, "FS.Lookup") \ 96 EM(afs_FS_Lookup, "FS.Lookup") \
97 EM(afs_FS_InlineBulkStatus, "FS.InlineBulkStatus") \
96 EM(afs_FS_FetchData64, "FS.FetchData64") \ 98 EM(afs_FS_FetchData64, "FS.FetchData64") \
97 EM(afs_FS_StoreData64, "FS.StoreData64") \ 99 EM(afs_FS_StoreData64, "FS.StoreData64") \
98 EM(afs_FS_GiveUpAllCallBacks, "FS.GiveUpAllCallBacks") \ 100 EM(afs_FS_GiveUpAllCallBacks, "FS.GiveUpAllCallBacks") \