Skip to content

Commit b9b1f8d

Browse files
dhowellsLinus Torvalds
authored andcommitted
AFS: write support fixes
AFS write support fixes: (1) Support large files using the 64-bit file access operations if available on the server. (2) Use kmap_atomic() rather than kmap() in afs_prepare_page(). (3) Don't do stuff in afs_writepage() that's done by the caller. [[email protected]: fix right shift count >= width of type] Signed-off-by: David Howells <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 218e180 commit b9b1f8d

File tree

3 files changed

+216
-17
lines changed

3 files changed

+216
-17
lines changed

fs/afs/afs_fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ enum AFS_FS_Operations {
3131
FSGETVOLUMEINFO = 148, /* AFS Get root volume information */
3232
FSGETROOTVOLUME = 151, /* AFS Get root volume name */
3333
FSLOOKUP = 161, /* AFS lookup file in directory */
34+
FSFETCHDATA64 = 65537, /* AFS Fetch file data */
35+
FSSTOREDATA64 = 65538, /* AFS Store file data */
3436
};
3537

3638
enum AFS_FS_Errors {

fs/afs/fsclient.c

Lines changed: 211 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,33 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
293293
case 0:
294294
call->offset = 0;
295295
call->unmarshall++;
296+
if (call->operation_ID != FSFETCHDATA64) {
297+
call->unmarshall++;
298+
goto no_msw;
299+
}
296300

297-
/* extract the returned data length */
301+
/* extract the upper part of the returned data length of an
302+
* FSFETCHDATA64 op (which should always be 0 using this
303+
* client) */
298304
case 1:
305+
_debug("extract data length (MSW)");
306+
ret = afs_extract_data(call, skb, last, &call->tmp, 4);
307+
switch (ret) {
308+
case 0: break;
309+
case -EAGAIN: return 0;
310+
default: return ret;
311+
}
312+
313+
call->count = ntohl(call->tmp);
314+
_debug("DATA length MSW: %u", call->count);
315+
if (call->count > 0)
316+
return -EBADMSG;
317+
call->offset = 0;
318+
call->unmarshall++;
319+
320+
no_msw:
321+
/* extract the returned data length */
322+
case 2:
299323
_debug("extract data length");
300324
ret = afs_extract_data(call, skb, last, &call->tmp, 4);
301325
switch (ret) {
@@ -312,7 +336,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
312336
call->unmarshall++;
313337

314338
/* extract the returned data */
315-
case 2:
339+
case 3:
316340
_debug("extract data");
317341
if (call->count > 0) {
318342
page = call->reply3;
@@ -331,7 +355,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
331355
call->unmarshall++;
332356

333357
/* extract the metadata */
334-
case 3:
358+
case 4:
335359
ret = afs_extract_data(call, skb, last, call->buffer,
336360
(21 + 3 + 6) * 4);
337361
switch (ret) {
@@ -349,7 +373,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
349373
call->offset = 0;
350374
call->unmarshall++;
351375

352-
case 4:
376+
case 5:
353377
_debug("trailer");
354378
if (skb->len != 0)
355379
return -EBADMSG;
@@ -381,6 +405,56 @@ static const struct afs_call_type afs_RXFSFetchData = {
381405
.destructor = afs_flat_call_destructor,
382406
};
383407

408+
static const struct afs_call_type afs_RXFSFetchData64 = {
409+
.name = "FS.FetchData64",
410+
.deliver = afs_deliver_fs_fetch_data,
411+
.abort_to_error = afs_abort_to_error,
412+
.destructor = afs_flat_call_destructor,
413+
};
414+
415+
/*
416+
* fetch data from a very large file
417+
*/
418+
static int afs_fs_fetch_data64(struct afs_server *server,
419+
struct key *key,
420+
struct afs_vnode *vnode,
421+
off_t offset, size_t length,
422+
struct page *buffer,
423+
const struct afs_wait_mode *wait_mode)
424+
{
425+
struct afs_call *call;
426+
__be32 *bp;
427+
428+
_enter("");
429+
430+
ASSERTCMP(length, <, ULONG_MAX);
431+
432+
call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
433+
if (!call)
434+
return -ENOMEM;
435+
436+
call->key = key;
437+
call->reply = vnode;
438+
call->reply2 = NULL; /* volsync */
439+
call->reply3 = buffer;
440+
call->service_id = FS_SERVICE;
441+
call->port = htons(AFS_FS_PORT);
442+
call->operation_ID = FSFETCHDATA64;
443+
444+
/* marshall the parameters */
445+
bp = call->request;
446+
bp[0] = htonl(FSFETCHDATA64);
447+
bp[1] = htonl(vnode->fid.vid);
448+
bp[2] = htonl(vnode->fid.vnode);
449+
bp[3] = htonl(vnode->fid.unique);
450+
bp[4] = htonl(upper_32_bits(offset));
451+
bp[5] = htonl((u32) offset);
452+
bp[6] = 0;
453+
bp[7] = htonl((u32) length);
454+
455+
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
456+
}
457+
384458
/*
385459
* fetch data from a file
386460
*/
@@ -394,6 +468,10 @@ int afs_fs_fetch_data(struct afs_server *server,
394468
struct afs_call *call;
395469
__be32 *bp;
396470

471+
if (upper_32_bits(offset) || upper_32_bits(offset + length))
472+
return afs_fs_fetch_data64(server, key, vnode, offset, length,
473+
buffer, wait_mode);
474+
397475
_enter("");
398476

399477
call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
@@ -406,6 +484,7 @@ int afs_fs_fetch_data(struct afs_server *server,
406484
call->reply3 = buffer;
407485
call->service_id = FS_SERVICE;
408486
call->port = htons(AFS_FS_PORT);
487+
call->operation_ID = FSFETCHDATA;
409488

410489
/* marshall the parameters */
411490
bp = call->request;
@@ -1032,6 +1111,73 @@ static const struct afs_call_type afs_RXFSStoreData = {
10321111
.destructor = afs_flat_call_destructor,
10331112
};
10341113

1114+
static const struct afs_call_type afs_RXFSStoreData64 = {
1115+
.name = "FS.StoreData64",
1116+
.deliver = afs_deliver_fs_store_data,
1117+
.abort_to_error = afs_abort_to_error,
1118+
.destructor = afs_flat_call_destructor,
1119+
};
1120+
1121+
/*
1122+
* store a set of pages to a very large file
1123+
*/
1124+
static int afs_fs_store_data64(struct afs_server *server,
1125+
struct afs_writeback *wb,
1126+
pgoff_t first, pgoff_t last,
1127+
unsigned offset, unsigned to,
1128+
loff_t size, loff_t pos, loff_t i_size,
1129+
const struct afs_wait_mode *wait_mode)
1130+
{
1131+
struct afs_vnode *vnode = wb->vnode;
1132+
struct afs_call *call;
1133+
__be32 *bp;
1134+
1135+
_enter(",%x,{%x:%u},,",
1136+
key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
1137+
1138+
call = afs_alloc_flat_call(&afs_RXFSStoreData64,
1139+
(4 + 6 + 3 * 2) * 4,
1140+
(21 + 6) * 4);
1141+
if (!call)
1142+
return -ENOMEM;
1143+
1144+
call->wb = wb;
1145+
call->key = wb->key;
1146+
call->reply = vnode;
1147+
call->service_id = FS_SERVICE;
1148+
call->port = htons(AFS_FS_PORT);
1149+
call->mapping = vnode->vfs_inode.i_mapping;
1150+
call->first = first;
1151+
call->last = last;
1152+
call->first_offset = offset;
1153+
call->last_to = to;
1154+
call->send_pages = true;
1155+
call->store_version = vnode->status.data_version + 1;
1156+
1157+
/* marshall the parameters */
1158+
bp = call->request;
1159+
*bp++ = htonl(FSSTOREDATA64);
1160+
*bp++ = htonl(vnode->fid.vid);
1161+
*bp++ = htonl(vnode->fid.vnode);
1162+
*bp++ = htonl(vnode->fid.unique);
1163+
1164+
*bp++ = 0; /* mask */
1165+
*bp++ = 0; /* mtime */
1166+
*bp++ = 0; /* owner */
1167+
*bp++ = 0; /* group */
1168+
*bp++ = 0; /* unix mode */
1169+
*bp++ = 0; /* segment size */
1170+
1171+
*bp++ = htonl(pos >> 32);
1172+
*bp++ = htonl((u32) pos);
1173+
*bp++ = htonl(size >> 32);
1174+
*bp++ = htonl((u32) size);
1175+
*bp++ = htonl(i_size >> 32);
1176+
*bp++ = htonl((u32) i_size);
1177+
1178+
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1179+
}
1180+
10351181
/*
10361182
* store a set of pages
10371183
*/
@@ -1062,7 +1208,9 @@ int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
10621208
(unsigned long long) size, (unsigned long long) pos,
10631209
(unsigned long long) i_size);
10641210

1065-
BUG_ON(i_size > 0xffffffff); // TODO: use 64-bit store
1211+
if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
1212+
return afs_fs_store_data64(server, wb, first, last, offset, to,
1213+
size, pos, i_size, wait_mode);
10661214

10671215
call = afs_alloc_flat_call(&afs_RXFSStoreData,
10681216
(4 + 6 + 3) * 4,
@@ -1158,6 +1306,61 @@ static const struct afs_call_type afs_RXFSStoreData_as_Status = {
11581306
.destructor = afs_flat_call_destructor,
11591307
};
11601308

1309+
static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1310+
.name = "FS.StoreData64",
1311+
.deliver = afs_deliver_fs_store_status,
1312+
.abort_to_error = afs_abort_to_error,
1313+
.destructor = afs_flat_call_destructor,
1314+
};
1315+
1316+
/*
1317+
* set the attributes on a very large file, using FS.StoreData rather than
1318+
* FS.StoreStatus so as to alter the file size also
1319+
*/
1320+
static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,
1321+
struct afs_vnode *vnode, struct iattr *attr,
1322+
const struct afs_wait_mode *wait_mode)
1323+
{
1324+
struct afs_call *call;
1325+
__be32 *bp;
1326+
1327+
_enter(",%x,{%x:%u},,",
1328+
key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1329+
1330+
ASSERT(attr->ia_valid & ATTR_SIZE);
1331+
1332+
call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status,
1333+
(4 + 6 + 3 * 2) * 4,
1334+
(21 + 6) * 4);
1335+
if (!call)
1336+
return -ENOMEM;
1337+
1338+
call->key = key;
1339+
call->reply = vnode;
1340+
call->service_id = FS_SERVICE;
1341+
call->port = htons(AFS_FS_PORT);
1342+
call->store_version = vnode->status.data_version + 1;
1343+
call->operation_ID = FSSTOREDATA;
1344+
1345+
/* marshall the parameters */
1346+
bp = call->request;
1347+
*bp++ = htonl(FSSTOREDATA64);
1348+
*bp++ = htonl(vnode->fid.vid);
1349+
*bp++ = htonl(vnode->fid.vnode);
1350+
*bp++ = htonl(vnode->fid.unique);
1351+
1352+
xdr_encode_AFS_StoreStatus(&bp, attr);
1353+
1354+
*bp++ = 0; /* position of start of write */
1355+
*bp++ = 0;
1356+
*bp++ = 0; /* size of write */
1357+
*bp++ = 0;
1358+
*bp++ = htonl(attr->ia_size >> 32); /* new file length */
1359+
*bp++ = htonl((u32) attr->ia_size);
1360+
1361+
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1362+
}
1363+
11611364
/*
11621365
* set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
11631366
* so as to alter the file size also
@@ -1173,7 +1376,9 @@ static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
11731376
key_serial(key), vnode->fid.vid, vnode->fid.vnode);
11741377

11751378
ASSERT(attr->ia_valid & ATTR_SIZE);
1176-
ASSERTCMP(attr->ia_size, <=, 0xffffffff); // TODO: use 64-bit store
1379+
if (attr->ia_size >> 32)
1380+
return afs_fs_setattr_size64(server, key, vnode, attr,
1381+
wait_mode);
11771382

11781383
call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
11791384
(4 + 6 + 3) * 4,

fs/afs/write.c

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ static int afs_prepare_page(struct afs_vnode *vnode, struct page *page,
122122
if (offset == 0 && to == PAGE_SIZE)
123123
return 0;
124124

125-
p = kmap(page);
125+
p = kmap_atomic(page, KM_USER0);
126126

127127
i_size = i_size_read(&vnode->vfs_inode);
128128
pos = (loff_t) page->index << PAGE_SHIFT;
@@ -133,7 +133,7 @@ static int afs_prepare_page(struct afs_vnode *vnode, struct page *page,
133133
memset(p, 0, offset);
134134
if (to < PAGE_SIZE)
135135
memset(p + to, 0, PAGE_SIZE - to);
136-
kunmap(page);
136+
kunmap_atomic(p, KM_USER0);
137137
return 0;
138138
}
139139

@@ -152,7 +152,7 @@ static int afs_prepare_page(struct afs_vnode *vnode, struct page *page,
152152
memset(p + eof, 0, PAGE_SIZE - eof);
153153
}
154154

155-
kunmap(p);
155+
kunmap_atomic(p, KM_USER0);
156156

157157
ret = 0;
158158
if (offset > 0 || eof > to) {
@@ -489,14 +489,6 @@ int afs_writepage(struct page *page, struct writeback_control *wbc)
489489

490490
_enter("{%lx},", page->index);
491491

492-
if (wbc->sync_mode != WB_SYNC_NONE)
493-
wait_on_page_writeback(page);
494-
495-
if (PageWriteback(page) || !PageDirty(page)) {
496-
unlock_page(page);
497-
return 0;
498-
}
499-
500492
wb = (struct afs_writeback *) page_private(page);
501493
ASSERT(wb != NULL);
502494

0 commit comments

Comments
 (0)