aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2007-05-10 06:15:21 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-10 12:26:52 -0400
commitb9b1f8d5930a813879278d0cbfc8c658d6a038dc (patch)
tree1879e0e70ce946e3519a205698f4dd1b34a3a7ea
parent218e180e7ea5334e1f94121940ba82cd1f0f4e58 (diff)
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. [akpm@linux-foundation.org: fix right shift count >= width of type] Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/afs/afs_fs.h2
-rw-r--r--fs/afs/fsclient.c217
-rw-r--r--fs/afs/write.c14
3 files changed, 216 insertions, 17 deletions
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h
index 2198006d2d03..d963ef4daee8 100644
--- a/fs/afs/afs_fs.h
+++ b/fs/afs/afs_fs.h
@@ -31,6 +31,8 @@ enum AFS_FS_Operations {
31 FSGETVOLUMEINFO = 148, /* AFS Get root volume information */ 31 FSGETVOLUMEINFO = 148, /* AFS Get root volume information */
32 FSGETROOTVOLUME = 151, /* AFS Get root volume name */ 32 FSGETROOTVOLUME = 151, /* AFS Get root volume name */
33 FSLOOKUP = 161, /* AFS lookup file in directory */ 33 FSLOOKUP = 161, /* AFS lookup file in directory */
34 FSFETCHDATA64 = 65537, /* AFS Fetch file data */
35 FSSTOREDATA64 = 65538, /* AFS Store file data */
34}; 36};
35 37
36enum AFS_FS_Errors { 38enum AFS_FS_Errors {
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 025b1903d9e1..56cc0efa2a0c 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -293,9 +293,33 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
293 case 0: 293 case 0:
294 call->offset = 0; 294 call->offset = 0;
295 call->unmarshall++; 295 call->unmarshall++;
296 if (call->operation_ID != FSFETCHDATA64) {
297 call->unmarshall++;
298 goto no_msw;
299 }
296 300
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) */
298 case 1: 304 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:
299 _debug("extract data length"); 323 _debug("extract data length");
300 ret = afs_extract_data(call, skb, last, &call->tmp, 4); 324 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
301 switch (ret) { 325 switch (ret) {
@@ -312,7 +336,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
312 call->unmarshall++; 336 call->unmarshall++;
313 337
314 /* extract the returned data */ 338 /* extract the returned data */
315 case 2: 339 case 3:
316 _debug("extract data"); 340 _debug("extract data");
317 if (call->count > 0) { 341 if (call->count > 0) {
318 page = call->reply3; 342 page = call->reply3;
@@ -331,7 +355,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
331 call->unmarshall++; 355 call->unmarshall++;
332 356
333 /* extract the metadata */ 357 /* extract the metadata */
334 case 3: 358 case 4:
335 ret = afs_extract_data(call, skb, last, call->buffer, 359 ret = afs_extract_data(call, skb, last, call->buffer,
336 (21 + 3 + 6) * 4); 360 (21 + 3 + 6) * 4);
337 switch (ret) { 361 switch (ret) {
@@ -349,7 +373,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
349 call->offset = 0; 373 call->offset = 0;
350 call->unmarshall++; 374 call->unmarshall++;
351 375
352 case 4: 376 case 5:
353 _debug("trailer"); 377 _debug("trailer");
354 if (skb->len != 0) 378 if (skb->len != 0)
355 return -EBADMSG; 379 return -EBADMSG;
@@ -381,6 +405,56 @@ static const struct afs_call_type afs_RXFSFetchData = {
381 .destructor = afs_flat_call_destructor, 405 .destructor = afs_flat_call_destructor,
382}; 406};
383 407
408static 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 */
418static 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
384/* 458/*
385 * fetch data from a file 459 * fetch data from a file
386 */ 460 */
@@ -394,6 +468,10 @@ int afs_fs_fetch_data(struct afs_server *server,
394 struct afs_call *call; 468 struct afs_call *call;
395 __be32 *bp; 469 __be32 *bp;
396 470
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
397 _enter(""); 475 _enter("");
398 476
399 call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); 477 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,
406 call->reply3 = buffer; 484 call->reply3 = buffer;
407 call->service_id = FS_SERVICE; 485 call->service_id = FS_SERVICE;
408 call->port = htons(AFS_FS_PORT); 486 call->port = htons(AFS_FS_PORT);
487 call->operation_ID = FSFETCHDATA;
409 488
410 /* marshall the parameters */ 489 /* marshall the parameters */
411 bp = call->request; 490 bp = call->request;
@@ -1032,6 +1111,73 @@ static const struct afs_call_type afs_RXFSStoreData = {
1032 .destructor = afs_flat_call_destructor, 1111 .destructor = afs_flat_call_destructor,
1033}; 1112};
1034 1113
1114static 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 */
1124static 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
1035/* 1181/*
1036 * store a set of pages 1182 * store a set of pages
1037 */ 1183 */
@@ -1062,7 +1208,9 @@ int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
1062 (unsigned long long) size, (unsigned long long) pos, 1208 (unsigned long long) size, (unsigned long long) pos,
1063 (unsigned long long) i_size); 1209 (unsigned long long) i_size);
1064 1210
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);
1066 1214
1067 call = afs_alloc_flat_call(&afs_RXFSStoreData, 1215 call = afs_alloc_flat_call(&afs_RXFSStoreData,
1068 (4 + 6 + 3) * 4, 1216 (4 + 6 + 3) * 4,
@@ -1158,6 +1306,61 @@ static const struct afs_call_type afs_RXFSStoreData_as_Status = {
1158 .destructor = afs_flat_call_destructor, 1306 .destructor = afs_flat_call_destructor,
1159}; 1307};
1160 1308
1309static 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 */
1320static 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
1161/* 1364/*
1162 * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus 1365 * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
1163 * so as to alter the file size also 1366 * 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,
1173 key_serial(key), vnode->fid.vid, vnode->fid.vnode); 1376 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1174 1377
1175 ASSERT(attr->ia_valid & ATTR_SIZE); 1378 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);
1177 1382
1178 call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status, 1383 call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
1179 (4 + 6 + 3) * 4, 1384 (4 + 6 + 3) * 4,
diff --git a/fs/afs/write.c b/fs/afs/write.c
index 83ff29262816..aa03d43984b3 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -122,7 +122,7 @@ static int afs_prepare_page(struct afs_vnode *vnode, struct page *page,
122 if (offset == 0 && to == PAGE_SIZE) 122 if (offset == 0 && to == PAGE_SIZE)
123 return 0; 123 return 0;
124 124
125 p = kmap(page); 125 p = kmap_atomic(page, KM_USER0);
126 126
127 i_size = i_size_read(&vnode->vfs_inode); 127 i_size = i_size_read(&vnode->vfs_inode);
128 pos = (loff_t) page->index << PAGE_SHIFT; 128 pos = (loff_t) page->index << PAGE_SHIFT;
@@ -133,7 +133,7 @@ static int afs_prepare_page(struct afs_vnode *vnode, struct page *page,
133 memset(p, 0, offset); 133 memset(p, 0, offset);
134 if (to < PAGE_SIZE) 134 if (to < PAGE_SIZE)
135 memset(p + to, 0, PAGE_SIZE - to); 135 memset(p + to, 0, PAGE_SIZE - to);
136 kunmap(page); 136 kunmap_atomic(p, KM_USER0);
137 return 0; 137 return 0;
138 } 138 }
139 139
@@ -152,7 +152,7 @@ static int afs_prepare_page(struct afs_vnode *vnode, struct page *page,
152 memset(p + eof, 0, PAGE_SIZE - eof); 152 memset(p + eof, 0, PAGE_SIZE - eof);
153 } 153 }
154 154
155 kunmap(p); 155 kunmap_atomic(p, KM_USER0);
156 156
157 ret = 0; 157 ret = 0;
158 if (offset > 0 || eof > to) { 158 if (offset > 0 || eof > to) {
@@ -489,14 +489,6 @@ int afs_writepage(struct page *page, struct writeback_control *wbc)
489 489
490 _enter("{%lx},", page->index); 490 _enter("{%lx},", page->index);
491 491
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
500 wb = (struct afs_writeback *) page_private(page); 492 wb = (struct afs_writeback *) page_private(page);
501 ASSERT(wb != NULL); 493 ASSERT(wb != NULL);
502 494