diff options
| -rw-r--r-- | fs/afs/afs_fs.h | 2 | ||||
| -rw-r--r-- | fs/afs/fsclient.c | 217 | ||||
| -rw-r--r-- | fs/afs/write.c | 14 |
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 | ||
| 36 | enum AFS_FS_Errors { | 38 | enum 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 | ||
| 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 | |||
| 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 | ||
| 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 | |||
| 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 | ||
| 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 | |||
| 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 | ||
