Skip to content

Commit 196ee9c

Browse files
committed
afs: Make afs_fs_fetch_data() take a list of pages
Make afs_fs_fetch_data() take a list of pages for bulk data transfer. This will allow afs_readpages() to be made more efficient. Signed-off-by: David Howells <[email protected]>
1 parent c1878f7 commit 196ee9c

File tree

5 files changed

+145
-55
lines changed

5 files changed

+145
-55
lines changed

fs/afs/file.c

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,21 @@ int afs_release(struct inode *inode, struct file *file)
101101
return 0;
102102
}
103103

104+
/*
105+
* Dispose of a ref to a read record.
106+
*/
107+
void afs_put_read(struct afs_read *req)
108+
{
109+
int i;
110+
111+
if (atomic_dec_and_test(&req->usage)) {
112+
for (i = 0; i < req->nr_pages; i++)
113+
if (req->pages[i])
114+
put_page(req->pages[i]);
115+
kfree(req);
116+
}
117+
}
118+
104119
#ifdef CONFIG_AFS_FSCACHE
105120
/*
106121
* deal with notification that a page was read from the cache
@@ -126,9 +141,8 @@ int afs_page_filler(void *data, struct page *page)
126141
{
127142
struct inode *inode = page->mapping->host;
128143
struct afs_vnode *vnode = AFS_FS_I(inode);
144+
struct afs_read *req;
129145
struct key *key = data;
130-
size_t len;
131-
off_t offset;
132146
int ret;
133147

134148
_enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
@@ -164,12 +178,23 @@ int afs_page_filler(void *data, struct page *page)
164178
_debug("cache said ENOBUFS");
165179
default:
166180
go_on:
167-
offset = page->index << PAGE_SHIFT;
168-
len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE);
181+
req = kzalloc(sizeof(struct afs_read) + sizeof(struct page *),
182+
GFP_KERNEL);
183+
if (!req)
184+
goto enomem;
185+
186+
atomic_set(&req->usage, 1);
187+
req->pos = (loff_t)page->index << PAGE_SHIFT;
188+
req->len = min_t(size_t, i_size_read(inode) - req->pos,
189+
PAGE_SIZE);
190+
req->nr_pages = 1;
191+
req->pages[0] = page;
192+
get_page(page);
169193

170194
/* read the contents of the file from the server into the
171195
* page */
172-
ret = afs_vnode_fetch_data(vnode, key, offset, len, page);
196+
ret = afs_vnode_fetch_data(vnode, key, req);
197+
afs_put_read(req);
173198
if (ret < 0) {
174199
if (ret == -ENOENT) {
175200
_debug("got NOENT from server"
@@ -201,6 +226,8 @@ int afs_page_filler(void *data, struct page *page)
201226
_leave(" = 0");
202227
return 0;
203228

229+
enomem:
230+
ret = -ENOMEM;
204231
error:
205232
SetPageError(page);
206233
unlock_page(page);

fs/afs/fsclient.c

Lines changed: 76 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -309,15 +309,19 @@ int afs_fs_fetch_file_status(struct afs_server *server,
309309
static int afs_deliver_fs_fetch_data(struct afs_call *call)
310310
{
311311
struct afs_vnode *vnode = call->reply;
312+
struct afs_read *req = call->reply3;
312313
const __be32 *bp;
313-
struct page *page;
314+
unsigned int size;
314315
void *buffer;
315316
int ret;
316317

317-
_enter("{%u}", call->unmarshall);
318+
_enter("{%u,%zu/%u;%u/%llu}",
319+
call->unmarshall, call->offset, call->count,
320+
req->remain, req->actual_len);
318321

319322
switch (call->unmarshall) {
320323
case 0:
324+
req->actual_len = 0;
321325
call->offset = 0;
322326
call->unmarshall++;
323327
if (call->operation_ID != FSFETCHDATA64) {
@@ -334,10 +338,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
334338
if (ret < 0)
335339
return ret;
336340

337-
call->count = ntohl(call->tmp);
338-
_debug("DATA length MSW: %u", call->count);
339-
if (call->count > 0)
340-
return -EBADMSG;
341+
req->actual_len = ntohl(call->tmp);
342+
req->actual_len <<= 32;
341343
call->offset = 0;
342344
call->unmarshall++;
343345

@@ -349,26 +351,52 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
349351
if (ret < 0)
350352
return ret;
351353

352-
call->count = ntohl(call->tmp);
353-
_debug("DATA length: %u", call->count);
354-
if (call->count > PAGE_SIZE)
354+
req->actual_len |= ntohl(call->tmp);
355+
_debug("DATA length: %llu", req->actual_len);
356+
/* Check that the server didn't want to send us extra. We
357+
* might want to just discard instead, but that requires
358+
* cooperation from AF_RXRPC.
359+
*/
360+
if (req->actual_len > req->len)
355361
return -EBADMSG;
356-
call->offset = 0;
362+
363+
req->remain = req->actual_len;
364+
call->offset = req->pos & (PAGE_SIZE - 1);
365+
req->index = 0;
366+
if (req->actual_len == 0)
367+
goto no_more_data;
357368
call->unmarshall++;
358369

370+
begin_page:
371+
if (req->remain > PAGE_SIZE - call->offset)
372+
size = PAGE_SIZE - call->offset;
373+
else
374+
size = req->remain;
375+
call->count = call->offset + size;
376+
ASSERTCMP(call->count, <=, PAGE_SIZE);
377+
req->remain -= size;
378+
359379
/* extract the returned data */
360380
case 3:
361-
_debug("extract data");
362-
if (call->count > 0) {
363-
page = call->reply3;
364-
buffer = kmap(page);
365-
ret = afs_extract_data(call, buffer,
366-
call->count, true);
367-
kunmap(page);
368-
if (ret < 0)
369-
return ret;
381+
_debug("extract data %u/%llu %zu/%u",
382+
req->remain, req->actual_len, call->offset, call->count);
383+
384+
buffer = kmap(req->pages[req->index]);
385+
ret = afs_extract_data(call, buffer, call->count, true);
386+
kunmap(req->pages[req->index]);
387+
if (ret < 0)
388+
return ret;
389+
if (call->offset == PAGE_SIZE) {
390+
if (req->page_done)
391+
req->page_done(call, req);
392+
if (req->remain > 0) {
393+
req->index++;
394+
call->offset = 0;
395+
goto begin_page;
396+
}
370397
}
371398

399+
no_more_data:
372400
call->offset = 0;
373401
call->unmarshall++;
374402

@@ -393,32 +421,40 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
393421
}
394422

395423
if (call->count < PAGE_SIZE) {
396-
_debug("clear");
397-
page = call->reply3;
398-
buffer = kmap(page);
424+
buffer = kmap(req->pages[req->index]);
399425
memset(buffer + call->count, 0, PAGE_SIZE - call->count);
400-
kunmap(page);
426+
kunmap(req->pages[req->index]);
427+
if (req->page_done)
428+
req->page_done(call, req);
401429
}
402430

403431
_leave(" = 0 [done]");
404432
return 0;
405433
}
406434

435+
static void afs_fetch_data_destructor(struct afs_call *call)
436+
{
437+
struct afs_read *req = call->reply3;
438+
439+
afs_put_read(req);
440+
afs_flat_call_destructor(call);
441+
}
442+
407443
/*
408444
* FS.FetchData operation type
409445
*/
410446
static const struct afs_call_type afs_RXFSFetchData = {
411447
.name = "FS.FetchData",
412448
.deliver = afs_deliver_fs_fetch_data,
413449
.abort_to_error = afs_abort_to_error,
414-
.destructor = afs_flat_call_destructor,
450+
.destructor = afs_fetch_data_destructor,
415451
};
416452

417453
static const struct afs_call_type afs_RXFSFetchData64 = {
418454
.name = "FS.FetchData64",
419455
.deliver = afs_deliver_fs_fetch_data,
420456
.abort_to_error = afs_abort_to_error,
421-
.destructor = afs_flat_call_destructor,
457+
.destructor = afs_fetch_data_destructor,
422458
};
423459

424460
/*
@@ -427,25 +463,22 @@ static const struct afs_call_type afs_RXFSFetchData64 = {
427463
static int afs_fs_fetch_data64(struct afs_server *server,
428464
struct key *key,
429465
struct afs_vnode *vnode,
430-
off_t offset, size_t length,
431-
struct page *buffer,
466+
struct afs_read *req,
432467
const struct afs_wait_mode *wait_mode)
433468
{
434469
struct afs_call *call;
435470
__be32 *bp;
436471

437472
_enter("");
438473

439-
ASSERTCMP(length, <, ULONG_MAX);
440-
441474
call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
442475
if (!call)
443476
return -ENOMEM;
444477

445478
call->key = key;
446479
call->reply = vnode;
447480
call->reply2 = NULL; /* volsync */
448-
call->reply3 = buffer;
481+
call->reply3 = req;
449482
call->service_id = FS_SERVICE;
450483
call->port = htons(AFS_FS_PORT);
451484
call->operation_ID = FSFETCHDATA64;
@@ -456,11 +489,12 @@ static int afs_fs_fetch_data64(struct afs_server *server,
456489
bp[1] = htonl(vnode->fid.vid);
457490
bp[2] = htonl(vnode->fid.vnode);
458491
bp[3] = htonl(vnode->fid.unique);
459-
bp[4] = htonl(upper_32_bits(offset));
460-
bp[5] = htonl((u32) offset);
492+
bp[4] = htonl(upper_32_bits(req->pos));
493+
bp[5] = htonl(lower_32_bits(req->pos));
461494
bp[6] = 0;
462-
bp[7] = htonl((u32) length);
495+
bp[7] = htonl(lower_32_bits(req->len));
463496

497+
atomic_inc(&req->usage);
464498
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
465499
}
466500

@@ -470,16 +504,16 @@ static int afs_fs_fetch_data64(struct afs_server *server,
470504
int afs_fs_fetch_data(struct afs_server *server,
471505
struct key *key,
472506
struct afs_vnode *vnode,
473-
off_t offset, size_t length,
474-
struct page *buffer,
507+
struct afs_read *req,
475508
const struct afs_wait_mode *wait_mode)
476509
{
477510
struct afs_call *call;
478511
__be32 *bp;
479512

480-
if (upper_32_bits(offset) || upper_32_bits(offset + length))
481-
return afs_fs_fetch_data64(server, key, vnode, offset, length,
482-
buffer, wait_mode);
513+
if (upper_32_bits(req->pos) ||
514+
upper_32_bits(req->len) ||
515+
upper_32_bits(req->pos + req->len))
516+
return afs_fs_fetch_data64(server, key, vnode, req, wait_mode);
483517

484518
_enter("");
485519

@@ -490,7 +524,7 @@ int afs_fs_fetch_data(struct afs_server *server,
490524
call->key = key;
491525
call->reply = vnode;
492526
call->reply2 = NULL; /* volsync */
493-
call->reply3 = buffer;
527+
call->reply3 = req;
494528
call->service_id = FS_SERVICE;
495529
call->port = htons(AFS_FS_PORT);
496530
call->operation_ID = FSFETCHDATA;
@@ -501,9 +535,10 @@ int afs_fs_fetch_data(struct afs_server *server,
501535
bp[1] = htonl(vnode->fid.vid);
502536
bp[2] = htonl(vnode->fid.vnode);
503537
bp[3] = htonl(vnode->fid.unique);
504-
bp[4] = htonl(offset);
505-
bp[5] = htonl(length);
538+
bp[4] = htonl(lower_32_bits(req->pos));
539+
bp[5] = htonl(lower_32_bits(req->len));
506540

541+
atomic_inc(&req->usage);
507542
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
508543
}
509544

fs/afs/internal.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,22 @@ struct afs_call_type {
133133
void (*destructor)(struct afs_call *call);
134134
};
135135

136+
/*
137+
* Record of an outstanding read operation on a vnode.
138+
*/
139+
struct afs_read {
140+
loff_t pos; /* Where to start reading */
141+
loff_t len; /* How much to read */
142+
loff_t actual_len; /* How much we're actually getting */
143+
atomic_t usage;
144+
unsigned int remain; /* Amount remaining */
145+
unsigned int index; /* Which page we're reading into */
146+
unsigned int pg_offset; /* Offset in page we're at */
147+
unsigned int nr_pages;
148+
void (*page_done)(struct afs_call *, struct afs_read *);
149+
struct page *pages[];
150+
};
151+
136152
/*
137153
* record of an outstanding writeback on a vnode
138154
*/
@@ -494,6 +510,7 @@ extern const struct file_operations afs_file_operations;
494510
extern int afs_open(struct inode *, struct file *);
495511
extern int afs_release(struct inode *, struct file *);
496512
extern int afs_page_filler(void *, struct page *);
513+
extern void afs_put_read(struct afs_read *);
497514

498515
/*
499516
* flock.c
@@ -513,7 +530,7 @@ extern int afs_fs_fetch_file_status(struct afs_server *, struct key *,
513530
extern int afs_fs_give_up_callbacks(struct afs_server *,
514531
const struct afs_wait_mode *);
515532
extern int afs_fs_fetch_data(struct afs_server *, struct key *,
516-
struct afs_vnode *, off_t, size_t, struct page *,
533+
struct afs_vnode *, struct afs_read *,
517534
const struct afs_wait_mode *);
518535
extern int afs_fs_create(struct afs_server *, struct key *,
519536
struct afs_vnode *, const char *, umode_t,
@@ -699,7 +716,7 @@ extern void afs_vnode_finalise_status_update(struct afs_vnode *,
699716
extern int afs_vnode_fetch_status(struct afs_vnode *, struct afs_vnode *,
700717
struct key *);
701718
extern int afs_vnode_fetch_data(struct afs_vnode *, struct key *,
702-
off_t, size_t, struct page *);
719+
struct afs_read *);
703720
extern int afs_vnode_create(struct afs_vnode *, struct key *, const char *,
704721
umode_t, struct afs_fid *, struct afs_file_status *,
705722
struct afs_callback *, struct afs_server **);

fs/afs/vnode.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ int afs_vnode_fetch_status(struct afs_vnode *vnode,
393393
* - TODO implement caching
394394
*/
395395
int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key,
396-
off_t offset, size_t length, struct page *page)
396+
struct afs_read *desc)
397397
{
398398
struct afs_server *server;
399399
int ret;
@@ -420,8 +420,8 @@ int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key,
420420

421421
_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
422422

423-
ret = afs_fs_fetch_data(server, key, vnode, offset, length,
424-
page, &afs_sync_call);
423+
ret = afs_fs_fetch_data(server, key, vnode, desc,
424+
&afs_sync_call);
425425

426426
} while (!afs_volume_release_fileserver(vnode, server, ret));
427427

0 commit comments

Comments
 (0)