diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/callback.c | 26 | ||||
-rw-r--r-- | fs/nfs/client.c | 15 | ||||
-rw-r--r-- | fs/nfs/file.c | 49 | ||||
-rw-r--r-- | fs/nfs/inode.c | 92 | ||||
-rw-r--r-- | fs/nfs/internal.h | 6 | ||||
-rw-r--r-- | fs/nfs/mount_clnt.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 40 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 86 | ||||
-rw-r--r-- | fs/nfs/write.c | 91 |
9 files changed, 316 insertions, 93 deletions
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 7f604c7941fb..293fa0528a6e 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -43,21 +43,29 @@ static struct svc_program nfs4_callback_program; | |||
43 | unsigned int nfs_callback_set_tcpport; | 43 | unsigned int nfs_callback_set_tcpport; |
44 | unsigned short nfs_callback_tcpport; | 44 | unsigned short nfs_callback_tcpport; |
45 | unsigned short nfs_callback_tcpport6; | 45 | unsigned short nfs_callback_tcpport6; |
46 | static const int nfs_set_port_min = 0; | 46 | #define NFS_CALLBACK_MAXPORTNR (65535U) |
47 | static const int nfs_set_port_max = 65535; | ||
48 | 47 | ||
49 | static int param_set_port(const char *val, struct kernel_param *kp) | 48 | static int param_set_portnr(const char *val, struct kernel_param *kp) |
50 | { | 49 | { |
51 | char *endp; | 50 | unsigned long num; |
52 | int num = simple_strtol(val, &endp, 0); | 51 | int ret; |
53 | if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max) | 52 | |
53 | if (!val) | ||
54 | return -EINVAL; | ||
55 | ret = strict_strtoul(val, 0, &num); | ||
56 | if (ret == -EINVAL || num > NFS_CALLBACK_MAXPORTNR) | ||
54 | return -EINVAL; | 57 | return -EINVAL; |
55 | *((int *)kp->arg) = num; | 58 | *((unsigned int *)kp->arg) = num; |
56 | return 0; | 59 | return 0; |
57 | } | 60 | } |
58 | 61 | ||
59 | module_param_call(callback_tcpport, param_set_port, param_get_int, | 62 | static int param_get_portnr(char *buffer, struct kernel_param *kp) |
60 | &nfs_callback_set_tcpport, 0644); | 63 | { |
64 | return param_get_uint(buffer, kp); | ||
65 | } | ||
66 | #define param_check_portnr(name, p) __param_check(name, p, unsigned int); | ||
67 | |||
68 | module_param_named(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644); | ||
61 | 69 | ||
62 | /* | 70 | /* |
63 | * This is the NFSv4 callback kernel thread. | 71 | * This is the NFSv4 callback kernel thread. |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 8d25ccb2d51d..d36925f9b952 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -809,6 +809,9 @@ static int nfs_init_server(struct nfs_server *server, | |||
809 | /* Initialise the client representation from the mount data */ | 809 | /* Initialise the client representation from the mount data */ |
810 | server->flags = data->flags; | 810 | server->flags = data->flags; |
811 | server->options = data->options; | 811 | server->options = data->options; |
812 | server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID| | ||
813 | NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP| | ||
814 | NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME; | ||
812 | 815 | ||
813 | if (data->rsize) | 816 | if (data->rsize) |
814 | server->rsize = nfs_block_size(data->rsize, NULL); | 817 | server->rsize = nfs_block_size(data->rsize, NULL); |
@@ -1074,10 +1077,6 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
1074 | (unsigned long long) server->fsid.major, | 1077 | (unsigned long long) server->fsid.major, |
1075 | (unsigned long long) server->fsid.minor); | 1078 | (unsigned long long) server->fsid.minor); |
1076 | 1079 | ||
1077 | BUG_ON(!server->nfs_client); | ||
1078 | BUG_ON(!server->nfs_client->rpc_ops); | ||
1079 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
1080 | |||
1081 | spin_lock(&nfs_client_lock); | 1080 | spin_lock(&nfs_client_lock); |
1082 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | 1081 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); |
1083 | list_add_tail(&server->master_link, &nfs_volume_list); | 1082 | list_add_tail(&server->master_link, &nfs_volume_list); |
@@ -1274,7 +1273,7 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1274 | 1273 | ||
1275 | /* Initialise the client representation from the mount data */ | 1274 | /* Initialise the client representation from the mount data */ |
1276 | server->flags = data->flags; | 1275 | server->flags = data->flags; |
1277 | server->caps |= NFS_CAP_ATOMIC_OPEN; | 1276 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR; |
1278 | server->options = data->options; | 1277 | server->options = data->options; |
1279 | 1278 | ||
1280 | /* Get a client record */ | 1279 | /* Get a client record */ |
@@ -1359,10 +1358,6 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
1359 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) | 1358 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) |
1360 | server->namelen = NFS4_MAXNAMLEN; | 1359 | server->namelen = NFS4_MAXNAMLEN; |
1361 | 1360 | ||
1362 | BUG_ON(!server->nfs_client); | ||
1363 | BUG_ON(!server->nfs_client->rpc_ops); | ||
1364 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
1365 | |||
1366 | spin_lock(&nfs_client_lock); | 1361 | spin_lock(&nfs_client_lock); |
1367 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | 1362 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); |
1368 | list_add_tail(&server->master_link, &nfs_volume_list); | 1363 | list_add_tail(&server->master_link, &nfs_volume_list); |
@@ -1400,7 +1395,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1400 | 1395 | ||
1401 | /* Initialise the client representation from the parent server */ | 1396 | /* Initialise the client representation from the parent server */ |
1402 | nfs_server_copy_userdata(server, parent_server); | 1397 | nfs_server_copy_userdata(server, parent_server); |
1403 | server->caps |= NFS_CAP_ATOMIC_OPEN; | 1398 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR; |
1404 | 1399 | ||
1405 | /* Get a client representation. | 1400 | /* Get a client representation. |
1406 | * Note: NFSv4 always uses TCP, */ | 1401 | * Note: NFSv4 always uses TCP, */ |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 05062329b678..5021b75d2d1e 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -328,6 +328,42 @@ nfs_file_fsync(struct file *file, struct dentry *dentry, int datasync) | |||
328 | } | 328 | } |
329 | 329 | ||
330 | /* | 330 | /* |
331 | * Decide whether a read/modify/write cycle may be more efficient | ||
332 | * then a modify/write/read cycle when writing to a page in the | ||
333 | * page cache. | ||
334 | * | ||
335 | * The modify/write/read cycle may occur if a page is read before | ||
336 | * being completely filled by the writer. In this situation, the | ||
337 | * page must be completely written to stable storage on the server | ||
338 | * before it can be refilled by reading in the page from the server. | ||
339 | * This can lead to expensive, small, FILE_SYNC mode writes being | ||
340 | * done. | ||
341 | * | ||
342 | * It may be more efficient to read the page first if the file is | ||
343 | * open for reading in addition to writing, the page is not marked | ||
344 | * as Uptodate, it is not dirty or waiting to be committed, | ||
345 | * indicating that it was previously allocated and then modified, | ||
346 | * that there were valid bytes of data in that range of the file, | ||
347 | * and that the new data won't completely replace the old data in | ||
348 | * that range of the file. | ||
349 | */ | ||
350 | static int nfs_want_read_modify_write(struct file *file, struct page *page, | ||
351 | loff_t pos, unsigned len) | ||
352 | { | ||
353 | unsigned int pglen = nfs_page_length(page); | ||
354 | unsigned int offset = pos & (PAGE_CACHE_SIZE - 1); | ||
355 | unsigned int end = offset + len; | ||
356 | |||
357 | if ((file->f_mode & FMODE_READ) && /* open for read? */ | ||
358 | !PageUptodate(page) && /* Uptodate? */ | ||
359 | !PagePrivate(page) && /* i/o request already? */ | ||
360 | pglen && /* valid bytes of file? */ | ||
361 | (end < pglen || offset)) /* replace all valid bytes? */ | ||
362 | return 1; | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | /* | ||
331 | * This does the "real" work of the write. We must allocate and lock the | 367 | * This does the "real" work of the write. We must allocate and lock the |
332 | * page to be sent back to the generic routine, which then copies the | 368 | * page to be sent back to the generic routine, which then copies the |
333 | * data from user space. | 369 | * data from user space. |
@@ -340,15 +376,16 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, | |||
340 | struct page **pagep, void **fsdata) | 376 | struct page **pagep, void **fsdata) |
341 | { | 377 | { |
342 | int ret; | 378 | int ret; |
343 | pgoff_t index; | 379 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
344 | struct page *page; | 380 | struct page *page; |
345 | index = pos >> PAGE_CACHE_SHIFT; | 381 | int once_thru = 0; |
346 | 382 | ||
347 | dfprintk(PAGECACHE, "NFS: write_begin(%s/%s(%ld), %u@%lld)\n", | 383 | dfprintk(PAGECACHE, "NFS: write_begin(%s/%s(%ld), %u@%lld)\n", |
348 | file->f_path.dentry->d_parent->d_name.name, | 384 | file->f_path.dentry->d_parent->d_name.name, |
349 | file->f_path.dentry->d_name.name, | 385 | file->f_path.dentry->d_name.name, |
350 | mapping->host->i_ino, len, (long long) pos); | 386 | mapping->host->i_ino, len, (long long) pos); |
351 | 387 | ||
388 | start: | ||
352 | /* | 389 | /* |
353 | * Prevent starvation issues if someone is doing a consistency | 390 | * Prevent starvation issues if someone is doing a consistency |
354 | * sync-to-disk | 391 | * sync-to-disk |
@@ -367,6 +404,13 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, | |||
367 | if (ret) { | 404 | if (ret) { |
368 | unlock_page(page); | 405 | unlock_page(page); |
369 | page_cache_release(page); | 406 | page_cache_release(page); |
407 | } else if (!once_thru && | ||
408 | nfs_want_read_modify_write(file, page, pos, len)) { | ||
409 | once_thru = 1; | ||
410 | ret = nfs_readpage(file, page); | ||
411 | page_cache_release(page); | ||
412 | if (!ret) | ||
413 | goto start; | ||
370 | } | 414 | } |
371 | return ret; | 415 | return ret; |
372 | } | 416 | } |
@@ -479,6 +523,7 @@ const struct address_space_operations nfs_file_aops = { | |||
479 | .invalidatepage = nfs_invalidate_page, | 523 | .invalidatepage = nfs_invalidate_page, |
480 | .releasepage = nfs_release_page, | 524 | .releasepage = nfs_release_page, |
481 | .direct_IO = nfs_direct_IO, | 525 | .direct_IO = nfs_direct_IO, |
526 | .migratepage = nfs_migrate_page, | ||
482 | .launder_page = nfs_launder_page, | 527 | .launder_page = nfs_launder_page, |
483 | }; | 528 | }; |
484 | 529 | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index bd7938eda6a8..fe5a8b45d867 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -286,6 +286,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
286 | /* We can't support update_atime(), since the server will reset it */ | 286 | /* We can't support update_atime(), since the server will reset it */ |
287 | inode->i_flags |= S_NOATIME|S_NOCMTIME; | 287 | inode->i_flags |= S_NOATIME|S_NOCMTIME; |
288 | inode->i_mode = fattr->mode; | 288 | inode->i_mode = fattr->mode; |
289 | if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0 | ||
290 | && nfs_server_capable(inode, NFS_CAP_MODE)) | ||
291 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
292 | | NFS_INO_INVALID_ACCESS | ||
293 | | NFS_INO_INVALID_ACL; | ||
289 | /* Why so? Because we want revalidate for devices/FIFOs, and | 294 | /* Why so? Because we want revalidate for devices/FIFOs, and |
290 | * that's precisely what we have in nfs_file_inode_operations. | 295 | * that's precisely what we have in nfs_file_inode_operations. |
291 | */ | 296 | */ |
@@ -330,20 +335,46 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
330 | nfsi->attr_gencount = fattr->gencount; | 335 | nfsi->attr_gencount = fattr->gencount; |
331 | if (fattr->valid & NFS_ATTR_FATTR_ATIME) | 336 | if (fattr->valid & NFS_ATTR_FATTR_ATIME) |
332 | inode->i_atime = fattr->atime; | 337 | inode->i_atime = fattr->atime; |
338 | else if (nfs_server_capable(inode, NFS_CAP_ATIME)) | ||
339 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | ||
333 | if (fattr->valid & NFS_ATTR_FATTR_MTIME) | 340 | if (fattr->valid & NFS_ATTR_FATTR_MTIME) |
334 | inode->i_mtime = fattr->mtime; | 341 | inode->i_mtime = fattr->mtime; |
342 | else if (nfs_server_capable(inode, NFS_CAP_MTIME)) | ||
343 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
344 | | NFS_INO_INVALID_DATA; | ||
335 | if (fattr->valid & NFS_ATTR_FATTR_CTIME) | 345 | if (fattr->valid & NFS_ATTR_FATTR_CTIME) |
336 | inode->i_ctime = fattr->ctime; | 346 | inode->i_ctime = fattr->ctime; |
347 | else if (nfs_server_capable(inode, NFS_CAP_CTIME)) | ||
348 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
349 | | NFS_INO_INVALID_ACCESS | ||
350 | | NFS_INO_INVALID_ACL; | ||
337 | if (fattr->valid & NFS_ATTR_FATTR_CHANGE) | 351 | if (fattr->valid & NFS_ATTR_FATTR_CHANGE) |
338 | nfsi->change_attr = fattr->change_attr; | 352 | nfsi->change_attr = fattr->change_attr; |
353 | else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR)) | ||
354 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
355 | | NFS_INO_INVALID_DATA; | ||
339 | if (fattr->valid & NFS_ATTR_FATTR_SIZE) | 356 | if (fattr->valid & NFS_ATTR_FATTR_SIZE) |
340 | inode->i_size = nfs_size_to_loff_t(fattr->size); | 357 | inode->i_size = nfs_size_to_loff_t(fattr->size); |
358 | else | ||
359 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
360 | | NFS_INO_INVALID_DATA | ||
361 | | NFS_INO_REVAL_PAGECACHE; | ||
341 | if (fattr->valid & NFS_ATTR_FATTR_NLINK) | 362 | if (fattr->valid & NFS_ATTR_FATTR_NLINK) |
342 | inode->i_nlink = fattr->nlink; | 363 | inode->i_nlink = fattr->nlink; |
364 | else if (nfs_server_capable(inode, NFS_CAP_NLINK)) | ||
365 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | ||
343 | if (fattr->valid & NFS_ATTR_FATTR_OWNER) | 366 | if (fattr->valid & NFS_ATTR_FATTR_OWNER) |
344 | inode->i_uid = fattr->uid; | 367 | inode->i_uid = fattr->uid; |
368 | else if (nfs_server_capable(inode, NFS_CAP_OWNER)) | ||
369 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
370 | | NFS_INO_INVALID_ACCESS | ||
371 | | NFS_INO_INVALID_ACL; | ||
345 | if (fattr->valid & NFS_ATTR_FATTR_GROUP) | 372 | if (fattr->valid & NFS_ATTR_FATTR_GROUP) |
346 | inode->i_gid = fattr->gid; | 373 | inode->i_gid = fattr->gid; |
374 | else if (nfs_server_capable(inode, NFS_CAP_OWNER_GROUP)) | ||
375 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
376 | | NFS_INO_INVALID_ACCESS | ||
377 | | NFS_INO_INVALID_ACL; | ||
347 | if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) | 378 | if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) |
348 | inode->i_blocks = fattr->du.nfs2.blocks; | 379 | inode->i_blocks = fattr->du.nfs2.blocks; |
349 | if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { | 380 | if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { |
@@ -1145,6 +1176,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1145 | loff_t cur_isize, new_isize; | 1176 | loff_t cur_isize, new_isize; |
1146 | unsigned long invalid = 0; | 1177 | unsigned long invalid = 0; |
1147 | unsigned long now = jiffies; | 1178 | unsigned long now = jiffies; |
1179 | unsigned long save_cache_validity; | ||
1148 | 1180 | ||
1149 | dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", | 1181 | dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", |
1150 | __func__, inode->i_sb->s_id, inode->i_ino, | 1182 | __func__, inode->i_sb->s_id, inode->i_ino, |
@@ -1171,10 +1203,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1171 | */ | 1203 | */ |
1172 | nfsi->read_cache_jiffies = fattr->time_start; | 1204 | nfsi->read_cache_jiffies = fattr->time_start; |
1173 | 1205 | ||
1174 | if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) || (fattr->valid & (NFS_ATTR_FATTR_MTIME|NFS_ATTR_FATTR_CTIME))) | 1206 | save_cache_validity = nfsi->cache_validity; |
1175 | nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR | 1207 | nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR |
1176 | | NFS_INO_INVALID_ATIME | 1208 | | NFS_INO_INVALID_ATIME |
1177 | | NFS_INO_REVAL_PAGECACHE); | 1209 | | NFS_INO_REVAL_FORCED |
1210 | | NFS_INO_REVAL_PAGECACHE); | ||
1178 | 1211 | ||
1179 | /* Do atomic weak cache consistency updates */ | 1212 | /* Do atomic weak cache consistency updates */ |
1180 | nfs_wcc_update_inode(inode, fattr); | 1213 | nfs_wcc_update_inode(inode, fattr); |
@@ -1189,7 +1222,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1189 | nfs_force_lookup_revalidate(inode); | 1222 | nfs_force_lookup_revalidate(inode); |
1190 | nfsi->change_attr = fattr->change_attr; | 1223 | nfsi->change_attr = fattr->change_attr; |
1191 | } | 1224 | } |
1192 | } | 1225 | } else if (server->caps & NFS_CAP_CHANGE_ATTR) |
1226 | invalid |= save_cache_validity; | ||
1193 | 1227 | ||
1194 | if (fattr->valid & NFS_ATTR_FATTR_MTIME) { | 1228 | if (fattr->valid & NFS_ATTR_FATTR_MTIME) { |
1195 | /* NFSv2/v3: Check if the mtime agrees */ | 1229 | /* NFSv2/v3: Check if the mtime agrees */ |
@@ -1201,7 +1235,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1201 | nfs_force_lookup_revalidate(inode); | 1235 | nfs_force_lookup_revalidate(inode); |
1202 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); | 1236 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); |
1203 | } | 1237 | } |
1204 | } | 1238 | } else if (server->caps & NFS_CAP_MTIME) |
1239 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
1240 | | NFS_INO_INVALID_DATA | ||
1241 | | NFS_INO_REVAL_PAGECACHE | ||
1242 | | NFS_INO_REVAL_FORCED); | ||
1243 | |||
1205 | if (fattr->valid & NFS_ATTR_FATTR_CTIME) { | 1244 | if (fattr->valid & NFS_ATTR_FATTR_CTIME) { |
1206 | /* If ctime has changed we should definitely clear access+acl caches */ | 1245 | /* If ctime has changed we should definitely clear access+acl caches */ |
1207 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { | 1246 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { |
@@ -1215,7 +1254,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1215 | } | 1254 | } |
1216 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); | 1255 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); |
1217 | } | 1256 | } |
1218 | } | 1257 | } else if (server->caps & NFS_CAP_CTIME) |
1258 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
1259 | | NFS_INO_INVALID_ACCESS | ||
1260 | | NFS_INO_INVALID_ACL | ||
1261 | | NFS_INO_REVAL_FORCED); | ||
1219 | 1262 | ||
1220 | /* Check if our cached file size is stale */ | 1263 | /* Check if our cached file size is stale */ |
1221 | if (fattr->valid & NFS_ATTR_FATTR_SIZE) { | 1264 | if (fattr->valid & NFS_ATTR_FATTR_SIZE) { |
@@ -1231,30 +1274,50 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1231 | dprintk("NFS: isize change on server for file %s/%ld\n", | 1274 | dprintk("NFS: isize change on server for file %s/%ld\n", |
1232 | inode->i_sb->s_id, inode->i_ino); | 1275 | inode->i_sb->s_id, inode->i_ino); |
1233 | } | 1276 | } |
1234 | } | 1277 | } else |
1278 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
1279 | | NFS_INO_REVAL_PAGECACHE | ||
1280 | | NFS_INO_REVAL_FORCED); | ||
1235 | 1281 | ||
1236 | 1282 | ||
1237 | if (fattr->valid & NFS_ATTR_FATTR_ATIME) | 1283 | if (fattr->valid & NFS_ATTR_FATTR_ATIME) |
1238 | memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); | 1284 | memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); |
1285 | else if (server->caps & NFS_CAP_ATIME) | ||
1286 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATIME | ||
1287 | | NFS_INO_REVAL_FORCED); | ||
1239 | 1288 | ||
1240 | if (fattr->valid & NFS_ATTR_FATTR_MODE) { | 1289 | if (fattr->valid & NFS_ATTR_FATTR_MODE) { |
1241 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { | 1290 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { |
1242 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1291 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1243 | inode->i_mode = fattr->mode; | 1292 | inode->i_mode = fattr->mode; |
1244 | } | 1293 | } |
1245 | } | 1294 | } else if (server->caps & NFS_CAP_MODE) |
1295 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
1296 | | NFS_INO_INVALID_ACCESS | ||
1297 | | NFS_INO_INVALID_ACL | ||
1298 | | NFS_INO_REVAL_FORCED); | ||
1299 | |||
1246 | if (fattr->valid & NFS_ATTR_FATTR_OWNER) { | 1300 | if (fattr->valid & NFS_ATTR_FATTR_OWNER) { |
1247 | if (inode->i_uid != fattr->uid) { | 1301 | if (inode->i_uid != fattr->uid) { |
1248 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1302 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1249 | inode->i_uid = fattr->uid; | 1303 | inode->i_uid = fattr->uid; |
1250 | } | 1304 | } |
1251 | } | 1305 | } else if (server->caps & NFS_CAP_OWNER) |
1306 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
1307 | | NFS_INO_INVALID_ACCESS | ||
1308 | | NFS_INO_INVALID_ACL | ||
1309 | | NFS_INO_REVAL_FORCED); | ||
1310 | |||
1252 | if (fattr->valid & NFS_ATTR_FATTR_GROUP) { | 1311 | if (fattr->valid & NFS_ATTR_FATTR_GROUP) { |
1253 | if (inode->i_gid != fattr->gid) { | 1312 | if (inode->i_gid != fattr->gid) { |
1254 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1313 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1255 | inode->i_gid = fattr->gid; | 1314 | inode->i_gid = fattr->gid; |
1256 | } | 1315 | } |
1257 | } | 1316 | } else if (server->caps & NFS_CAP_OWNER_GROUP) |
1317 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
1318 | | NFS_INO_INVALID_ACCESS | ||
1319 | | NFS_INO_INVALID_ACL | ||
1320 | | NFS_INO_REVAL_FORCED); | ||
1258 | 1321 | ||
1259 | if (fattr->valid & NFS_ATTR_FATTR_NLINK) { | 1322 | if (fattr->valid & NFS_ATTR_FATTR_NLINK) { |
1260 | if (inode->i_nlink != fattr->nlink) { | 1323 | if (inode->i_nlink != fattr->nlink) { |
@@ -1263,7 +1326,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1263 | invalid |= NFS_INO_INVALID_DATA; | 1326 | invalid |= NFS_INO_INVALID_DATA; |
1264 | inode->i_nlink = fattr->nlink; | 1327 | inode->i_nlink = fattr->nlink; |
1265 | } | 1328 | } |
1266 | } | 1329 | } else if (server->caps & NFS_CAP_NLINK) |
1330 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
1331 | | NFS_INO_REVAL_FORCED); | ||
1267 | 1332 | ||
1268 | if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { | 1333 | if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { |
1269 | /* | 1334 | /* |
@@ -1293,9 +1358,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1293 | || S_ISLNK(inode->i_mode))) | 1358 | || S_ISLNK(inode->i_mode))) |
1294 | invalid &= ~NFS_INO_INVALID_DATA; | 1359 | invalid &= ~NFS_INO_INVALID_DATA; |
1295 | if (!nfs_have_delegation(inode, FMODE_READ) || | 1360 | if (!nfs_have_delegation(inode, FMODE_READ) || |
1296 | (nfsi->cache_validity & NFS_INO_REVAL_FORCED)) | 1361 | (save_cache_validity & NFS_INO_REVAL_FORCED)) |
1297 | nfsi->cache_validity |= invalid; | 1362 | nfsi->cache_validity |= invalid; |
1298 | nfsi->cache_validity &= ~NFS_INO_REVAL_FORCED; | ||
1299 | 1363 | ||
1300 | return 0; | 1364 | return 0; |
1301 | out_changed: | 1365 | out_changed: |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index c2f171a3d70e..2e485677019c 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -248,6 +248,12 @@ extern void nfs_read_prepare(struct rpc_task *task, void *calldata); | |||
248 | 248 | ||
249 | /* write.c */ | 249 | /* write.c */ |
250 | extern void nfs_write_prepare(struct rpc_task *task, void *calldata); | 250 | extern void nfs_write_prepare(struct rpc_task *task, void *calldata); |
251 | #ifdef CONFIG_MIGRATION | ||
252 | extern int nfs_migrate_page(struct address_space *, | ||
253 | struct page *, struct page *); | ||
254 | #else | ||
255 | #define nfs_migrate_page NULL | ||
256 | #endif | ||
251 | 257 | ||
252 | /* nfs4proc.c */ | 258 | /* nfs4proc.c */ |
253 | extern int _nfs4_call_sync(struct nfs_server *server, | 259 | extern int _nfs4_call_sync(struct nfs_server *server, |
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 72dd8b6ccafa..0adefc40cc89 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -323,7 +323,7 @@ static int decode_status(struct xdr_stream *xdr, struct mountres *res) | |||
323 | return -EIO; | 323 | return -EIO; |
324 | status = ntohl(*p); | 324 | status = ntohl(*p); |
325 | 325 | ||
326 | for (i = 0; i <= ARRAY_SIZE(mnt_errtbl); i++) { | 326 | for (i = 0; i < ARRAY_SIZE(mnt_errtbl); i++) { |
327 | if (mnt_errtbl[i].status == status) { | 327 | if (mnt_errtbl[i].status == status) { |
328 | res->errno = mnt_errtbl[i].errno; | 328 | res->errno = mnt_errtbl[i].errno; |
329 | return 0; | 329 | return 0; |
@@ -374,7 +374,7 @@ static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res) | |||
374 | return -EIO; | 374 | return -EIO; |
375 | status = ntohl(*p); | 375 | status = ntohl(*p); |
376 | 376 | ||
377 | for (i = 0; i <= ARRAY_SIZE(mnt3_errtbl); i++) { | 377 | for (i = 0; i < ARRAY_SIZE(mnt3_errtbl); i++) { |
378 | if (mnt3_errtbl[i].status == status) { | 378 | if (mnt3_errtbl[i].status == status) { |
379 | res->errno = mnt3_errtbl[i].errno; | 379 | res->errno = mnt3_errtbl[i].errno; |
380 | return 0; | 380 | return 0; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6917311f201c..be6544aef41f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -61,6 +61,8 @@ | |||
61 | #define NFS4_POLL_RETRY_MIN (HZ/10) | 61 | #define NFS4_POLL_RETRY_MIN (HZ/10) |
62 | #define NFS4_POLL_RETRY_MAX (15*HZ) | 62 | #define NFS4_POLL_RETRY_MAX (15*HZ) |
63 | 63 | ||
64 | #define NFS4_MAX_LOOP_ON_RECOVER (10) | ||
65 | |||
64 | struct nfs4_opendata; | 66 | struct nfs4_opendata; |
65 | static int _nfs4_proc_open(struct nfs4_opendata *data); | 67 | static int _nfs4_proc_open(struct nfs4_opendata *data); |
66 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 68 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
@@ -426,17 +428,19 @@ out: | |||
426 | static int nfs4_recover_session(struct nfs4_session *session) | 428 | static int nfs4_recover_session(struct nfs4_session *session) |
427 | { | 429 | { |
428 | struct nfs_client *clp = session->clp; | 430 | struct nfs_client *clp = session->clp; |
431 | unsigned int loop; | ||
429 | int ret; | 432 | int ret; |
430 | 433 | ||
431 | for (;;) { | 434 | for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) { |
432 | ret = nfs4_wait_clnt_recover(clp); | 435 | ret = nfs4_wait_clnt_recover(clp); |
433 | if (ret != 0) | 436 | if (ret != 0) |
434 | return ret; | 437 | break; |
435 | if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | 438 | if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) |
436 | break; | 439 | break; |
437 | nfs4_schedule_state_manager(clp); | 440 | nfs4_schedule_state_manager(clp); |
441 | ret = -EIO; | ||
438 | } | 442 | } |
439 | return 0; | 443 | return ret; |
440 | } | 444 | } |
441 | 445 | ||
442 | static int nfs41_setup_sequence(struct nfs4_session *session, | 446 | static int nfs41_setup_sequence(struct nfs4_session *session, |
@@ -1444,18 +1448,20 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
1444 | static int nfs4_recover_expired_lease(struct nfs_server *server) | 1448 | static int nfs4_recover_expired_lease(struct nfs_server *server) |
1445 | { | 1449 | { |
1446 | struct nfs_client *clp = server->nfs_client; | 1450 | struct nfs_client *clp = server->nfs_client; |
1451 | unsigned int loop; | ||
1447 | int ret; | 1452 | int ret; |
1448 | 1453 | ||
1449 | for (;;) { | 1454 | for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) { |
1450 | ret = nfs4_wait_clnt_recover(clp); | 1455 | ret = nfs4_wait_clnt_recover(clp); |
1451 | if (ret != 0) | 1456 | if (ret != 0) |
1452 | return ret; | 1457 | break; |
1453 | if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) && | 1458 | if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) && |
1454 | !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state)) | 1459 | !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state)) |
1455 | break; | 1460 | break; |
1456 | nfs4_schedule_state_recovery(clp); | 1461 | nfs4_schedule_state_recovery(clp); |
1462 | ret = -EIO; | ||
1457 | } | 1463 | } |
1458 | return 0; | 1464 | return ret; |
1459 | } | 1465 | } |
1460 | 1466 | ||
1461 | /* | 1467 | /* |
@@ -1997,12 +2003,34 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
1997 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 2003 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1998 | if (status == 0) { | 2004 | if (status == 0) { |
1999 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); | 2005 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); |
2006 | server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS| | ||
2007 | NFS_CAP_SYMLINKS|NFS_CAP_FILEID| | ||
2008 | NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER| | ||
2009 | NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME| | ||
2010 | NFS_CAP_CTIME|NFS_CAP_MTIME); | ||
2000 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) | 2011 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) |
2001 | server->caps |= NFS_CAP_ACLS; | 2012 | server->caps |= NFS_CAP_ACLS; |
2002 | if (res.has_links != 0) | 2013 | if (res.has_links != 0) |
2003 | server->caps |= NFS_CAP_HARDLINKS; | 2014 | server->caps |= NFS_CAP_HARDLINKS; |
2004 | if (res.has_symlinks != 0) | 2015 | if (res.has_symlinks != 0) |
2005 | server->caps |= NFS_CAP_SYMLINKS; | 2016 | server->caps |= NFS_CAP_SYMLINKS; |
2017 | if (res.attr_bitmask[0] & FATTR4_WORD0_FILEID) | ||
2018 | server->caps |= NFS_CAP_FILEID; | ||
2019 | if (res.attr_bitmask[1] & FATTR4_WORD1_MODE) | ||
2020 | server->caps |= NFS_CAP_MODE; | ||
2021 | if (res.attr_bitmask[1] & FATTR4_WORD1_NUMLINKS) | ||
2022 | server->caps |= NFS_CAP_NLINK; | ||
2023 | if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER) | ||
2024 | server->caps |= NFS_CAP_OWNER; | ||
2025 | if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER_GROUP) | ||
2026 | server->caps |= NFS_CAP_OWNER_GROUP; | ||
2027 | if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_ACCESS) | ||
2028 | server->caps |= NFS_CAP_ATIME; | ||
2029 | if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_METADATA) | ||
2030 | server->caps |= NFS_CAP_CTIME; | ||
2031 | if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY) | ||
2032 | server->caps |= NFS_CAP_MTIME; | ||
2033 | |||
2006 | memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask)); | 2034 | memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask)); |
2007 | server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; | 2035 | server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; |
2008 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | 2036 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 617273e7d47f..e65cc2e650c8 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -3075,7 +3075,8 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t | |||
3075 | return ret; | 3075 | return ret; |
3076 | } | 3076 | } |
3077 | 3077 | ||
3078 | static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *uid) | 3078 | static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, |
3079 | struct nfs_client *clp, uint32_t *uid, int may_sleep) | ||
3079 | { | 3080 | { |
3080 | uint32_t len; | 3081 | uint32_t len; |
3081 | __be32 *p; | 3082 | __be32 *p; |
@@ -3088,7 +3089,9 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf | |||
3088 | READ_BUF(4); | 3089 | READ_BUF(4); |
3089 | READ32(len); | 3090 | READ32(len); |
3090 | READ_BUF(len); | 3091 | READ_BUF(len); |
3091 | if (len < XDR_MAX_NETOBJ) { | 3092 | if (!may_sleep) { |
3093 | /* do nothing */ | ||
3094 | } else if (len < XDR_MAX_NETOBJ) { | ||
3092 | if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0) | 3095 | if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0) |
3093 | ret = NFS_ATTR_FATTR_OWNER; | 3096 | ret = NFS_ATTR_FATTR_OWNER; |
3094 | else | 3097 | else |
@@ -3103,7 +3106,8 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf | |||
3103 | return ret; | 3106 | return ret; |
3104 | } | 3107 | } |
3105 | 3108 | ||
3106 | static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *gid) | 3109 | static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, |
3110 | struct nfs_client *clp, uint32_t *gid, int may_sleep) | ||
3107 | { | 3111 | { |
3108 | uint32_t len; | 3112 | uint32_t len; |
3109 | __be32 *p; | 3113 | __be32 *p; |
@@ -3116,7 +3120,9 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf | |||
3116 | READ_BUF(4); | 3120 | READ_BUF(4); |
3117 | READ32(len); | 3121 | READ32(len); |
3118 | READ_BUF(len); | 3122 | READ_BUF(len); |
3119 | if (len < XDR_MAX_NETOBJ) { | 3123 | if (!may_sleep) { |
3124 | /* do nothing */ | ||
3125 | } else if (len < XDR_MAX_NETOBJ) { | ||
3120 | if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0) | 3126 | if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0) |
3121 | ret = NFS_ATTR_FATTR_GROUP; | 3127 | ret = NFS_ATTR_FATTR_GROUP; |
3122 | else | 3128 | else |
@@ -3466,7 +3472,8 @@ xdr_error: | |||
3466 | return status; | 3472 | return status; |
3467 | } | 3473 | } |
3468 | 3474 | ||
3469 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server) | 3475 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, |
3476 | const struct nfs_server *server, int may_sleep) | ||
3470 | { | 3477 | { |
3471 | __be32 *savep; | 3478 | __be32 *savep; |
3472 | uint32_t attrlen, | 3479 | uint32_t attrlen, |
@@ -3538,12 +3545,14 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons | |||
3538 | goto xdr_error; | 3545 | goto xdr_error; |
3539 | fattr->valid |= status; | 3546 | fattr->valid |= status; |
3540 | 3547 | ||
3541 | status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid); | 3548 | status = decode_attr_owner(xdr, bitmap, server->nfs_client, |
3549 | &fattr->uid, may_sleep); | ||
3542 | if (status < 0) | 3550 | if (status < 0) |
3543 | goto xdr_error; | 3551 | goto xdr_error; |
3544 | fattr->valid |= status; | 3552 | fattr->valid |= status; |
3545 | 3553 | ||
3546 | status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid); | 3554 | status = decode_attr_group(xdr, bitmap, server->nfs_client, |
3555 | &fattr->gid, may_sleep); | ||
3547 | if (status < 0) | 3556 | if (status < 0) |
3548 | goto xdr_error; | 3557 | goto xdr_error; |
3549 | fattr->valid |= status; | 3558 | fattr->valid |= status; |
@@ -4370,7 +4379,8 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct | |||
4370 | status = decode_open_downgrade(&xdr, res); | 4379 | status = decode_open_downgrade(&xdr, res); |
4371 | if (status != 0) | 4380 | if (status != 0) |
4372 | goto out; | 4381 | goto out; |
4373 | decode_getfattr(&xdr, res->fattr, res->server); | 4382 | decode_getfattr(&xdr, res->fattr, res->server, |
4383 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4374 | out: | 4384 | out: |
4375 | return status; | 4385 | return status; |
4376 | } | 4386 | } |
@@ -4397,7 +4407,8 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac | |||
4397 | status = decode_access(&xdr, res); | 4407 | status = decode_access(&xdr, res); |
4398 | if (status != 0) | 4408 | if (status != 0) |
4399 | goto out; | 4409 | goto out; |
4400 | decode_getfattr(&xdr, res->fattr, res->server); | 4410 | decode_getfattr(&xdr, res->fattr, res->server, |
4411 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4401 | out: | 4412 | out: |
4402 | return status; | 4413 | return status; |
4403 | } | 4414 | } |
@@ -4424,7 +4435,8 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lo | |||
4424 | goto out; | 4435 | goto out; |
4425 | if ((status = decode_getfh(&xdr, res->fh)) != 0) | 4436 | if ((status = decode_getfh(&xdr, res->fh)) != 0) |
4426 | goto out; | 4437 | goto out; |
4427 | status = decode_getfattr(&xdr, res->fattr, res->server); | 4438 | status = decode_getfattr(&xdr, res->fattr, res->server |
4439 | ,!RPC_IS_ASYNC(rqstp->rq_task)); | ||
4428 | out: | 4440 | out: |
4429 | return status; | 4441 | return status; |
4430 | } | 4442 | } |
@@ -4448,7 +4460,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
4448 | if ((status = decode_putrootfh(&xdr)) != 0) | 4460 | if ((status = decode_putrootfh(&xdr)) != 0) |
4449 | goto out; | 4461 | goto out; |
4450 | if ((status = decode_getfh(&xdr, res->fh)) == 0) | 4462 | if ((status = decode_getfh(&xdr, res->fh)) == 0) |
4451 | status = decode_getfattr(&xdr, res->fattr, res->server); | 4463 | status = decode_getfattr(&xdr, res->fattr, res->server, |
4464 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4452 | out: | 4465 | out: |
4453 | return status; | 4466 | return status; |
4454 | } | 4467 | } |
@@ -4473,7 +4486,8 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem | |||
4473 | goto out; | 4486 | goto out; |
4474 | if ((status = decode_remove(&xdr, &res->cinfo)) != 0) | 4487 | if ((status = decode_remove(&xdr, &res->cinfo)) != 0) |
4475 | goto out; | 4488 | goto out; |
4476 | decode_getfattr(&xdr, &res->dir_attr, res->server); | 4489 | decode_getfattr(&xdr, &res->dir_attr, res->server, |
4490 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4477 | out: | 4491 | out: |
4478 | return status; | 4492 | return status; |
4479 | } | 4493 | } |
@@ -4503,11 +4517,13 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re | |||
4503 | if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0) | 4517 | if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0) |
4504 | goto out; | 4518 | goto out; |
4505 | /* Current FH is target directory */ | 4519 | /* Current FH is target directory */ |
4506 | if (decode_getfattr(&xdr, res->new_fattr, res->server) != 0) | 4520 | if (decode_getfattr(&xdr, res->new_fattr, res->server, |
4521 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
4507 | goto out; | 4522 | goto out; |
4508 | if ((status = decode_restorefh(&xdr)) != 0) | 4523 | if ((status = decode_restorefh(&xdr)) != 0) |
4509 | goto out; | 4524 | goto out; |
4510 | decode_getfattr(&xdr, res->old_fattr, res->server); | 4525 | decode_getfattr(&xdr, res->old_fattr, res->server, |
4526 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4511 | out: | 4527 | out: |
4512 | return status; | 4528 | return status; |
4513 | } | 4529 | } |
@@ -4540,11 +4556,13 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link | |||
4540 | * Note order: OP_LINK leaves the directory as the current | 4556 | * Note order: OP_LINK leaves the directory as the current |
4541 | * filehandle. | 4557 | * filehandle. |
4542 | */ | 4558 | */ |
4543 | if (decode_getfattr(&xdr, res->dir_attr, res->server) != 0) | 4559 | if (decode_getfattr(&xdr, res->dir_attr, res->server, |
4560 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
4544 | goto out; | 4561 | goto out; |
4545 | if ((status = decode_restorefh(&xdr)) != 0) | 4562 | if ((status = decode_restorefh(&xdr)) != 0) |
4546 | goto out; | 4563 | goto out; |
4547 | decode_getfattr(&xdr, res->fattr, res->server); | 4564 | decode_getfattr(&xdr, res->fattr, res->server, |
4565 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4548 | out: | 4566 | out: |
4549 | return status; | 4567 | return status; |
4550 | } | 4568 | } |
@@ -4573,11 +4591,13 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_cr | |||
4573 | goto out; | 4591 | goto out; |
4574 | if ((status = decode_getfh(&xdr, res->fh)) != 0) | 4592 | if ((status = decode_getfh(&xdr, res->fh)) != 0) |
4575 | goto out; | 4593 | goto out; |
4576 | if (decode_getfattr(&xdr, res->fattr, res->server) != 0) | 4594 | if (decode_getfattr(&xdr, res->fattr, res->server, |
4595 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
4577 | goto out; | 4596 | goto out; |
4578 | if ((status = decode_restorefh(&xdr)) != 0) | 4597 | if ((status = decode_restorefh(&xdr)) != 0) |
4579 | goto out; | 4598 | goto out; |
4580 | decode_getfattr(&xdr, res->dir_fattr, res->server); | 4599 | decode_getfattr(&xdr, res->dir_fattr, res->server, |
4600 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4581 | out: | 4601 | out: |
4582 | return status; | 4602 | return status; |
4583 | } | 4603 | } |
@@ -4609,7 +4629,8 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g | |||
4609 | status = decode_putfh(&xdr); | 4629 | status = decode_putfh(&xdr); |
4610 | if (status) | 4630 | if (status) |
4611 | goto out; | 4631 | goto out; |
4612 | status = decode_getfattr(&xdr, res->fattr, res->server); | 4632 | status = decode_getfattr(&xdr, res->fattr, res->server, |
4633 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4613 | out: | 4634 | out: |
4614 | return status; | 4635 | return status; |
4615 | } | 4636 | } |
@@ -4716,7 +4737,8 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_clos | |||
4716 | * an ESTALE error. Shouldn't be a problem, | 4737 | * an ESTALE error. Shouldn't be a problem, |
4717 | * though, since fattr->valid will remain unset. | 4738 | * though, since fattr->valid will remain unset. |
4718 | */ | 4739 | */ |
4719 | decode_getfattr(&xdr, res->fattr, res->server); | 4740 | decode_getfattr(&xdr, res->fattr, res->server, |
4741 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4720 | out: | 4742 | out: |
4721 | return status; | 4743 | return status; |
4722 | } | 4744 | } |
@@ -4748,11 +4770,13 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr | |||
4748 | goto out; | 4770 | goto out; |
4749 | if (decode_getfh(&xdr, &res->fh) != 0) | 4771 | if (decode_getfh(&xdr, &res->fh) != 0) |
4750 | goto out; | 4772 | goto out; |
4751 | if (decode_getfattr(&xdr, res->f_attr, res->server) != 0) | 4773 | if (decode_getfattr(&xdr, res->f_attr, res->server, |
4774 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
4752 | goto out; | 4775 | goto out; |
4753 | if (decode_restorefh(&xdr) != 0) | 4776 | if (decode_restorefh(&xdr) != 0) |
4754 | goto out; | 4777 | goto out; |
4755 | decode_getfattr(&xdr, res->dir_attr, res->server); | 4778 | decode_getfattr(&xdr, res->dir_attr, res->server, |
4779 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4756 | out: | 4780 | out: |
4757 | return status; | 4781 | return status; |
4758 | } | 4782 | } |
@@ -4800,7 +4824,8 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
4800 | status = decode_open(&xdr, res); | 4824 | status = decode_open(&xdr, res); |
4801 | if (status) | 4825 | if (status) |
4802 | goto out; | 4826 | goto out; |
4803 | decode_getfattr(&xdr, res->f_attr, res->server); | 4827 | decode_getfattr(&xdr, res->f_attr, res->server, |
4828 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4804 | out: | 4829 | out: |
4805 | return status; | 4830 | return status; |
4806 | } | 4831 | } |
@@ -4827,7 +4852,8 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se | |||
4827 | status = decode_setattr(&xdr); | 4852 | status = decode_setattr(&xdr); |
4828 | if (status) | 4853 | if (status) |
4829 | goto out; | 4854 | goto out; |
4830 | decode_getfattr(&xdr, res->fattr, res->server); | 4855 | decode_getfattr(&xdr, res->fattr, res->server, |
4856 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4831 | out: | 4857 | out: |
4832 | return status; | 4858 | return status; |
4833 | } | 4859 | } |
@@ -5001,7 +5027,8 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writ | |||
5001 | status = decode_write(&xdr, res); | 5027 | status = decode_write(&xdr, res); |
5002 | if (status) | 5028 | if (status) |
5003 | goto out; | 5029 | goto out; |
5004 | decode_getfattr(&xdr, res->fattr, res->server); | 5030 | decode_getfattr(&xdr, res->fattr, res->server, |
5031 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5005 | if (!status) | 5032 | if (!status) |
5006 | status = res->count; | 5033 | status = res->count; |
5007 | out: | 5034 | out: |
@@ -5030,7 +5057,8 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_wri | |||
5030 | status = decode_commit(&xdr, res); | 5057 | status = decode_commit(&xdr, res); |
5031 | if (status) | 5058 | if (status) |
5032 | goto out; | 5059 | goto out; |
5033 | decode_getfattr(&xdr, res->fattr, res->server); | 5060 | decode_getfattr(&xdr, res->fattr, res->server, |
5061 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5034 | out: | 5062 | out: |
5035 | return status; | 5063 | return status; |
5036 | } | 5064 | } |
@@ -5194,7 +5222,8 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
5194 | if (status != 0) | 5222 | if (status != 0) |
5195 | goto out; | 5223 | goto out; |
5196 | status = decode_delegreturn(&xdr); | 5224 | status = decode_delegreturn(&xdr); |
5197 | decode_getfattr(&xdr, res->fattr, res->server); | 5225 | decode_getfattr(&xdr, res->fattr, res->server, |
5226 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5198 | out: | 5227 | out: |
5199 | return status; | 5228 | return status; |
5200 | } | 5229 | } |
@@ -5222,7 +5251,8 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, | |||
5222 | goto out; | 5251 | goto out; |
5223 | xdr_enter_page(&xdr, PAGE_SIZE); | 5252 | xdr_enter_page(&xdr, PAGE_SIZE); |
5224 | status = decode_getfattr(&xdr, &res->fs_locations->fattr, | 5253 | status = decode_getfattr(&xdr, &res->fs_locations->fattr, |
5225 | res->fs_locations->server); | 5254 | res->fs_locations->server, |
5255 | !RPC_IS_ASYNC(req->rq_task)); | ||
5226 | out: | 5256 | out: |
5227 | return status; | 5257 | return status; |
5228 | } | 5258 | } |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 0a0a2ff767c3..6240e644f249 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/file.h> | 13 | #include <linux/file.h> |
14 | #include <linux/writeback.h> | 14 | #include <linux/writeback.h> |
15 | #include <linux/swap.h> | 15 | #include <linux/swap.h> |
16 | #include <linux/migrate.h> | ||
16 | 17 | ||
17 | #include <linux/sunrpc/clnt.h> | 18 | #include <linux/sunrpc/clnt.h> |
18 | #include <linux/nfs_fs.h> | 19 | #include <linux/nfs_fs.h> |
@@ -26,6 +27,7 @@ | |||
26 | #include "internal.h" | 27 | #include "internal.h" |
27 | #include "iostat.h" | 28 | #include "iostat.h" |
28 | #include "nfs4_fs.h" | 29 | #include "nfs4_fs.h" |
30 | #include "fscache.h" | ||
29 | 31 | ||
30 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 32 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
31 | 33 | ||
@@ -220,24 +222,17 @@ static void nfs_end_page_writeback(struct page *page) | |||
220 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); | 222 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
221 | } | 223 | } |
222 | 224 | ||
223 | /* | 225 | static struct nfs_page *nfs_find_and_lock_request(struct page *page) |
224 | * Find an associated nfs write request, and prepare to flush it out | ||
225 | * May return an error if the user signalled nfs_wait_on_request(). | ||
226 | */ | ||
227 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | ||
228 | struct page *page) | ||
229 | { | 226 | { |
230 | struct inode *inode = page->mapping->host; | 227 | struct inode *inode = page->mapping->host; |
231 | struct nfs_page *req; | 228 | struct nfs_page *req; |
232 | int ret; | 229 | int ret; |
233 | 230 | ||
234 | spin_lock(&inode->i_lock); | 231 | spin_lock(&inode->i_lock); |
235 | for(;;) { | 232 | for (;;) { |
236 | req = nfs_page_find_request_locked(page); | 233 | req = nfs_page_find_request_locked(page); |
237 | if (req == NULL) { | 234 | if (req == NULL) |
238 | spin_unlock(&inode->i_lock); | 235 | break; |
239 | return 0; | ||
240 | } | ||
241 | if (nfs_set_page_tag_locked(req)) | 236 | if (nfs_set_page_tag_locked(req)) |
242 | break; | 237 | break; |
243 | /* Note: If we hold the page lock, as is the case in nfs_writepage, | 238 | /* Note: If we hold the page lock, as is the case in nfs_writepage, |
@@ -249,23 +244,40 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
249 | ret = nfs_wait_on_request(req); | 244 | ret = nfs_wait_on_request(req); |
250 | nfs_release_request(req); | 245 | nfs_release_request(req); |
251 | if (ret != 0) | 246 | if (ret != 0) |
252 | return ret; | 247 | return ERR_PTR(ret); |
253 | spin_lock(&inode->i_lock); | 248 | spin_lock(&inode->i_lock); |
254 | } | 249 | } |
255 | if (test_bit(PG_CLEAN, &req->wb_flags)) { | ||
256 | spin_unlock(&inode->i_lock); | ||
257 | BUG(); | ||
258 | } | ||
259 | if (nfs_set_page_writeback(page) != 0) { | ||
260 | spin_unlock(&inode->i_lock); | ||
261 | BUG(); | ||
262 | } | ||
263 | spin_unlock(&inode->i_lock); | 250 | spin_unlock(&inode->i_lock); |
251 | return req; | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Find an associated nfs write request, and prepare to flush it out | ||
256 | * May return an error if the user signalled nfs_wait_on_request(). | ||
257 | */ | ||
258 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | ||
259 | struct page *page) | ||
260 | { | ||
261 | struct nfs_page *req; | ||
262 | int ret = 0; | ||
263 | |||
264 | req = nfs_find_and_lock_request(page); | ||
265 | if (!req) | ||
266 | goto out; | ||
267 | ret = PTR_ERR(req); | ||
268 | if (IS_ERR(req)) | ||
269 | goto out; | ||
270 | |||
271 | ret = nfs_set_page_writeback(page); | ||
272 | BUG_ON(ret != 0); | ||
273 | BUG_ON(test_bit(PG_CLEAN, &req->wb_flags)); | ||
274 | |||
264 | if (!nfs_pageio_add_request(pgio, req)) { | 275 | if (!nfs_pageio_add_request(pgio, req)) { |
265 | nfs_redirty_request(req); | 276 | nfs_redirty_request(req); |
266 | return pgio->pg_error; | 277 | ret = pgio->pg_error; |
267 | } | 278 | } |
268 | return 0; | 279 | out: |
280 | return ret; | ||
269 | } | 281 | } |
270 | 282 | ||
271 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) | 283 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) |
@@ -1582,6 +1594,41 @@ int nfs_wb_page(struct inode *inode, struct page* page) | |||
1582 | return nfs_wb_page_priority(inode, page, FLUSH_STABLE); | 1594 | return nfs_wb_page_priority(inode, page, FLUSH_STABLE); |
1583 | } | 1595 | } |
1584 | 1596 | ||
1597 | #ifdef CONFIG_MIGRATION | ||
1598 | int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | ||
1599 | struct page *page) | ||
1600 | { | ||
1601 | struct nfs_page *req; | ||
1602 | int ret; | ||
1603 | |||
1604 | if (PageFsCache(page)) | ||
1605 | nfs_fscache_release_page(page, GFP_KERNEL); | ||
1606 | |||
1607 | req = nfs_find_and_lock_request(page); | ||
1608 | ret = PTR_ERR(req); | ||
1609 | if (IS_ERR(req)) | ||
1610 | goto out; | ||
1611 | |||
1612 | ret = migrate_page(mapping, newpage, page); | ||
1613 | if (!req) | ||
1614 | goto out; | ||
1615 | if (ret) | ||
1616 | goto out_unlock; | ||
1617 | page_cache_get(newpage); | ||
1618 | req->wb_page = newpage; | ||
1619 | SetPagePrivate(newpage); | ||
1620 | set_page_private(newpage, page_private(page)); | ||
1621 | ClearPagePrivate(page); | ||
1622 | set_page_private(page, 0); | ||
1623 | page_cache_release(page); | ||
1624 | out_unlock: | ||
1625 | nfs_clear_page_tag_locked(req); | ||
1626 | nfs_release_request(req); | ||
1627 | out: | ||
1628 | return ret; | ||
1629 | } | ||
1630 | #endif | ||
1631 | |||
1585 | int __init nfs_init_writepagecache(void) | 1632 | int __init nfs_init_writepagecache(void) |
1586 | { | 1633 | { |
1587 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", | 1634 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", |