diff options
Diffstat (limited to 'fs/nfs')
-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/idmap.c | 6 | ||||
-rw-r--r-- | fs/nfs/inode.c | 92 | ||||
-rw-r--r-- | fs/nfs/internal.h | 29 | ||||
-rw-r--r-- | fs/nfs/mount_clnt.c | 83 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 8 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 40 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 86 | ||||
-rw-r--r-- | fs/nfs/super.c | 247 | ||||
-rw-r--r-- | fs/nfs/write.c | 91 |
12 files changed, 490 insertions, 282 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/idmap.c b/fs/nfs/idmap.c index 86147b0ab2cf..21a84d45916f 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -101,7 +101,7 @@ static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); | |||
101 | 101 | ||
102 | static unsigned int fnvhash32(const void *, size_t); | 102 | static unsigned int fnvhash32(const void *, size_t); |
103 | 103 | ||
104 | static struct rpc_pipe_ops idmap_upcall_ops = { | 104 | static const struct rpc_pipe_ops idmap_upcall_ops = { |
105 | .upcall = idmap_pipe_upcall, | 105 | .upcall = idmap_pipe_upcall, |
106 | .downcall = idmap_pipe_downcall, | 106 | .downcall = idmap_pipe_downcall, |
107 | .destroy_msg = idmap_pipe_destroy_msg, | 107 | .destroy_msg = idmap_pipe_destroy_msg, |
@@ -119,8 +119,8 @@ nfs_idmap_new(struct nfs_client *clp) | |||
119 | if (idmap == NULL) | 119 | if (idmap == NULL) |
120 | return -ENOMEM; | 120 | return -ENOMEM; |
121 | 121 | ||
122 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap", | 122 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry, |
123 | idmap, &idmap_upcall_ops, 0); | 123 | "idmap", idmap, &idmap_upcall_ops, 0); |
124 | if (IS_ERR(idmap->idmap_dentry)) { | 124 | if (IS_ERR(idmap->idmap_dentry)) { |
125 | error = PTR_ERR(idmap->idmap_dentry); | 125 | error = PTR_ERR(idmap->idmap_dentry); |
126 | kfree(idmap); | 126 | kfree(idmap); |
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 7dd90a6769d0..2e485677019c 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -102,6 +102,7 @@ struct nfs_mount_request { | |||
102 | }; | 102 | }; |
103 | 103 | ||
104 | extern int nfs_mount(struct nfs_mount_request *info); | 104 | extern int nfs_mount(struct nfs_mount_request *info); |
105 | extern void nfs_umount(const struct nfs_mount_request *info); | ||
105 | 106 | ||
106 | /* client.c */ | 107 | /* client.c */ |
107 | extern struct rpc_program nfs_program; | 108 | extern struct rpc_program nfs_program; |
@@ -213,7 +214,6 @@ void nfs_zap_acl_cache(struct inode *inode); | |||
213 | extern int nfs_wait_bit_killable(void *word); | 214 | extern int nfs_wait_bit_killable(void *word); |
214 | 215 | ||
215 | /* super.c */ | 216 | /* super.c */ |
216 | void nfs_parse_ip_address(char *, size_t, struct sockaddr *, size_t *); | ||
217 | extern struct file_system_type nfs_xdev_fs_type; | 217 | extern struct file_system_type nfs_xdev_fs_type; |
218 | #ifdef CONFIG_NFS_V4 | 218 | #ifdef CONFIG_NFS_V4 |
219 | extern struct file_system_type nfs4_xdev_fs_type; | 219 | extern struct file_system_type nfs4_xdev_fs_type; |
@@ -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, |
@@ -368,24 +374,3 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len) | |||
368 | return ((unsigned long)len + (unsigned long)base + | 374 | return ((unsigned long)len + (unsigned long)base + |
369 | PAGE_SIZE - 1) >> PAGE_SHIFT; | 375 | PAGE_SIZE - 1) >> PAGE_SHIFT; |
370 | } | 376 | } |
371 | |||
372 | #define IPV6_SCOPE_DELIMITER '%' | ||
373 | |||
374 | /* | ||
375 | * Set the port number in an address. Be agnostic about the address | ||
376 | * family. | ||
377 | */ | ||
378 | static inline void nfs_set_port(struct sockaddr *sap, unsigned short port) | ||
379 | { | ||
380 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
381 | struct sockaddr_in6 *ap6 = (struct sockaddr_in6 *)sap; | ||
382 | |||
383 | switch (sap->sa_family) { | ||
384 | case AF_INET: | ||
385 | ap->sin_port = htons(port); | ||
386 | break; | ||
387 | case AF_INET6: | ||
388 | ap6->sin6_port = htons(port); | ||
389 | break; | ||
390 | } | ||
391 | } | ||
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 38ef9eaec407..0adefc40cc89 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -209,6 +209,71 @@ out_mnt_err: | |||
209 | goto out; | 209 | goto out; |
210 | } | 210 | } |
211 | 211 | ||
212 | /** | ||
213 | * nfs_umount - Notify a server that we have unmounted this export | ||
214 | * @info: pointer to umount request arguments | ||
215 | * | ||
216 | * MOUNTPROC_UMNT is advisory, so we set a short timeout, and always | ||
217 | * use UDP. | ||
218 | */ | ||
219 | void nfs_umount(const struct nfs_mount_request *info) | ||
220 | { | ||
221 | static const struct rpc_timeout nfs_umnt_timeout = { | ||
222 | .to_initval = 1 * HZ, | ||
223 | .to_maxval = 3 * HZ, | ||
224 | .to_retries = 2, | ||
225 | }; | ||
226 | struct rpc_create_args args = { | ||
227 | .protocol = IPPROTO_UDP, | ||
228 | .address = info->sap, | ||
229 | .addrsize = info->salen, | ||
230 | .timeout = &nfs_umnt_timeout, | ||
231 | .servername = info->hostname, | ||
232 | .program = &mnt_program, | ||
233 | .version = info->version, | ||
234 | .authflavor = RPC_AUTH_UNIX, | ||
235 | .flags = RPC_CLNT_CREATE_NOPING, | ||
236 | }; | ||
237 | struct mountres result; | ||
238 | struct rpc_message msg = { | ||
239 | .rpc_argp = info->dirpath, | ||
240 | .rpc_resp = &result, | ||
241 | }; | ||
242 | struct rpc_clnt *clnt; | ||
243 | int status; | ||
244 | |||
245 | if (info->noresvport) | ||
246 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; | ||
247 | |||
248 | clnt = rpc_create(&args); | ||
249 | if (unlikely(IS_ERR(clnt))) | ||
250 | goto out_clnt_err; | ||
251 | |||
252 | dprintk("NFS: sending UMNT request for %s:%s\n", | ||
253 | (info->hostname ? info->hostname : "server"), info->dirpath); | ||
254 | |||
255 | if (info->version == NFS_MNT3_VERSION) | ||
256 | msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC3_UMNT]; | ||
257 | else | ||
258 | msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC_UMNT]; | ||
259 | |||
260 | status = rpc_call_sync(clnt, &msg, 0); | ||
261 | rpc_shutdown_client(clnt); | ||
262 | |||
263 | if (unlikely(status < 0)) | ||
264 | goto out_call_err; | ||
265 | |||
266 | return; | ||
267 | |||
268 | out_clnt_err: | ||
269 | dprintk("NFS: failed to create UMNT RPC client, status=%ld\n", | ||
270 | PTR_ERR(clnt)); | ||
271 | return; | ||
272 | |||
273 | out_call_err: | ||
274 | dprintk("NFS: UMNT request failed, status=%d\n", status); | ||
275 | } | ||
276 | |||
212 | /* | 277 | /* |
213 | * XDR encode/decode functions for MOUNT | 278 | * XDR encode/decode functions for MOUNT |
214 | */ | 279 | */ |
@@ -258,7 +323,7 @@ static int decode_status(struct xdr_stream *xdr, struct mountres *res) | |||
258 | return -EIO; | 323 | return -EIO; |
259 | status = ntohl(*p); | 324 | status = ntohl(*p); |
260 | 325 | ||
261 | for (i = 0; i <= ARRAY_SIZE(mnt_errtbl); i++) { | 326 | for (i = 0; i < ARRAY_SIZE(mnt_errtbl); i++) { |
262 | if (mnt_errtbl[i].status == status) { | 327 | if (mnt_errtbl[i].status == status) { |
263 | res->errno = mnt_errtbl[i].errno; | 328 | res->errno = mnt_errtbl[i].errno; |
264 | return 0; | 329 | return 0; |
@@ -309,7 +374,7 @@ static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res) | |||
309 | return -EIO; | 374 | return -EIO; |
310 | status = ntohl(*p); | 375 | status = ntohl(*p); |
311 | 376 | ||
312 | for (i = 0; i <= ARRAY_SIZE(mnt3_errtbl); i++) { | 377 | for (i = 0; i < ARRAY_SIZE(mnt3_errtbl); i++) { |
313 | if (mnt3_errtbl[i].status == status) { | 378 | if (mnt3_errtbl[i].status == status) { |
314 | res->errno = mnt3_errtbl[i].errno; | 379 | res->errno = mnt3_errtbl[i].errno; |
315 | return 0; | 380 | return 0; |
@@ -407,6 +472,13 @@ static struct rpc_procinfo mnt_procedures[] = { | |||
407 | .p_statidx = MOUNTPROC_MNT, | 472 | .p_statidx = MOUNTPROC_MNT, |
408 | .p_name = "MOUNT", | 473 | .p_name = "MOUNT", |
409 | }, | 474 | }, |
475 | [MOUNTPROC_UMNT] = { | ||
476 | .p_proc = MOUNTPROC_UMNT, | ||
477 | .p_encode = (kxdrproc_t)mnt_enc_dirpath, | ||
478 | .p_arglen = MNT_enc_dirpath_sz, | ||
479 | .p_statidx = MOUNTPROC_UMNT, | ||
480 | .p_name = "UMOUNT", | ||
481 | }, | ||
410 | }; | 482 | }; |
411 | 483 | ||
412 | static struct rpc_procinfo mnt3_procedures[] = { | 484 | static struct rpc_procinfo mnt3_procedures[] = { |
@@ -419,6 +491,13 @@ static struct rpc_procinfo mnt3_procedures[] = { | |||
419 | .p_statidx = MOUNTPROC3_MNT, | 491 | .p_statidx = MOUNTPROC3_MNT, |
420 | .p_name = "MOUNT", | 492 | .p_name = "MOUNT", |
421 | }, | 493 | }, |
494 | [MOUNTPROC3_UMNT] = { | ||
495 | .p_proc = MOUNTPROC3_UMNT, | ||
496 | .p_encode = (kxdrproc_t)mnt_enc_dirpath, | ||
497 | .p_arglen = MNT_enc_dirpath_sz, | ||
498 | .p_statidx = MOUNTPROC3_UMNT, | ||
499 | .p_name = "UMOUNT", | ||
500 | }, | ||
422 | }; | 501 | }; |
423 | 502 | ||
424 | 503 | ||
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 2a2a0a7143ad..ef22ee89aa77 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -121,11 +121,11 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
121 | 121 | ||
122 | if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) | 122 | if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) |
123 | continue; | 123 | continue; |
124 | nfs_parse_ip_address(buf->data, buf->len, | 124 | mountdata->addrlen = rpc_pton(buf->data, buf->len, |
125 | mountdata->addr, &mountdata->addrlen); | 125 | mountdata->addr, mountdata->addrlen); |
126 | if (mountdata->addr->sa_family == AF_UNSPEC) | 126 | if (mountdata->addrlen == 0) |
127 | continue; | 127 | continue; |
128 | nfs_set_port(mountdata->addr, NFS_PORT); | 128 | rpc_set_port(mountdata->addr, NFS_PORT); |
129 | 129 | ||
130 | memcpy(page2, buf->data, buf->len); | 130 | memcpy(page2, buf->data, buf->len); |
131 | page2[buf->len] = '\0'; | 131 | page2[buf->len] = '\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 14b6f513648f..cfc30d362f94 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -3148,7 +3148,8 @@ out_overflow: | |||
3148 | return -EIO; | 3148 | return -EIO; |
3149 | } | 3149 | } |
3150 | 3150 | ||
3151 | static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *uid) | 3151 | static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, |
3152 | struct nfs_client *clp, uint32_t *uid, int may_sleep) | ||
3152 | { | 3153 | { |
3153 | uint32_t len; | 3154 | uint32_t len; |
3154 | __be32 *p; | 3155 | __be32 *p; |
@@ -3165,7 +3166,9 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf | |||
3165 | p = xdr_inline_decode(xdr, len); | 3166 | p = xdr_inline_decode(xdr, len); |
3166 | if (unlikely(!p)) | 3167 | if (unlikely(!p)) |
3167 | goto out_overflow; | 3168 | goto out_overflow; |
3168 | if (len < XDR_MAX_NETOBJ) { | 3169 | if (!may_sleep) { |
3170 | /* do nothing */ | ||
3171 | } else if (len < XDR_MAX_NETOBJ) { | ||
3169 | if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0) | 3172 | if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0) |
3170 | ret = NFS_ATTR_FATTR_OWNER; | 3173 | ret = NFS_ATTR_FATTR_OWNER; |
3171 | else | 3174 | else |
@@ -3183,7 +3186,8 @@ out_overflow: | |||
3183 | return -EIO; | 3186 | return -EIO; |
3184 | } | 3187 | } |
3185 | 3188 | ||
3186 | static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *gid) | 3189 | static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, |
3190 | struct nfs_client *clp, uint32_t *gid, int may_sleep) | ||
3187 | { | 3191 | { |
3188 | uint32_t len; | 3192 | uint32_t len; |
3189 | __be32 *p; | 3193 | __be32 *p; |
@@ -3200,7 +3204,9 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf | |||
3200 | p = xdr_inline_decode(xdr, len); | 3204 | p = xdr_inline_decode(xdr, len); |
3201 | if (unlikely(!p)) | 3205 | if (unlikely(!p)) |
3202 | goto out_overflow; | 3206 | goto out_overflow; |
3203 | if (len < XDR_MAX_NETOBJ) { | 3207 | if (!may_sleep) { |
3208 | /* do nothing */ | ||
3209 | } else if (len < XDR_MAX_NETOBJ) { | ||
3204 | if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0) | 3210 | if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0) |
3205 | ret = NFS_ATTR_FATTR_GROUP; | 3211 | ret = NFS_ATTR_FATTR_GROUP; |
3206 | else | 3212 | else |
@@ -3616,7 +3622,8 @@ xdr_error: | |||
3616 | return status; | 3622 | return status; |
3617 | } | 3623 | } |
3618 | 3624 | ||
3619 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server) | 3625 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, |
3626 | const struct nfs_server *server, int may_sleep) | ||
3620 | { | 3627 | { |
3621 | __be32 *savep; | 3628 | __be32 *savep; |
3622 | uint32_t attrlen, | 3629 | uint32_t attrlen, |
@@ -3688,12 +3695,14 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons | |||
3688 | goto xdr_error; | 3695 | goto xdr_error; |
3689 | fattr->valid |= status; | 3696 | fattr->valid |= status; |
3690 | 3697 | ||
3691 | status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid); | 3698 | status = decode_attr_owner(xdr, bitmap, server->nfs_client, |
3699 | &fattr->uid, may_sleep); | ||
3692 | if (status < 0) | 3700 | if (status < 0) |
3693 | goto xdr_error; | 3701 | goto xdr_error; |
3694 | fattr->valid |= status; | 3702 | fattr->valid |= status; |
3695 | 3703 | ||
3696 | status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid); | 3704 | status = decode_attr_group(xdr, bitmap, server->nfs_client, |
3705 | &fattr->gid, may_sleep); | ||
3697 | if (status < 0) | 3706 | if (status < 0) |
3698 | goto xdr_error; | 3707 | goto xdr_error; |
3699 | fattr->valid |= status; | 3708 | fattr->valid |= status; |
@@ -4616,7 +4625,8 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct | |||
4616 | status = decode_open_downgrade(&xdr, res); | 4625 | status = decode_open_downgrade(&xdr, res); |
4617 | if (status != 0) | 4626 | if (status != 0) |
4618 | goto out; | 4627 | goto out; |
4619 | decode_getfattr(&xdr, res->fattr, res->server); | 4628 | decode_getfattr(&xdr, res->fattr, res->server, |
4629 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4620 | out: | 4630 | out: |
4621 | return status; | 4631 | return status; |
4622 | } | 4632 | } |
@@ -4643,7 +4653,8 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac | |||
4643 | status = decode_access(&xdr, res); | 4653 | status = decode_access(&xdr, res); |
4644 | if (status != 0) | 4654 | if (status != 0) |
4645 | goto out; | 4655 | goto out; |
4646 | decode_getfattr(&xdr, res->fattr, res->server); | 4656 | decode_getfattr(&xdr, res->fattr, res->server, |
4657 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4647 | out: | 4658 | out: |
4648 | return status; | 4659 | return status; |
4649 | } | 4660 | } |
@@ -4670,7 +4681,8 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lo | |||
4670 | goto out; | 4681 | goto out; |
4671 | if ((status = decode_getfh(&xdr, res->fh)) != 0) | 4682 | if ((status = decode_getfh(&xdr, res->fh)) != 0) |
4672 | goto out; | 4683 | goto out; |
4673 | status = decode_getfattr(&xdr, res->fattr, res->server); | 4684 | status = decode_getfattr(&xdr, res->fattr, res->server |
4685 | ,!RPC_IS_ASYNC(rqstp->rq_task)); | ||
4674 | out: | 4686 | out: |
4675 | return status; | 4687 | return status; |
4676 | } | 4688 | } |
@@ -4694,7 +4706,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
4694 | if ((status = decode_putrootfh(&xdr)) != 0) | 4706 | if ((status = decode_putrootfh(&xdr)) != 0) |
4695 | goto out; | 4707 | goto out; |
4696 | if ((status = decode_getfh(&xdr, res->fh)) == 0) | 4708 | if ((status = decode_getfh(&xdr, res->fh)) == 0) |
4697 | status = decode_getfattr(&xdr, res->fattr, res->server); | 4709 | status = decode_getfattr(&xdr, res->fattr, res->server, |
4710 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4698 | out: | 4711 | out: |
4699 | return status; | 4712 | return status; |
4700 | } | 4713 | } |
@@ -4719,7 +4732,8 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem | |||
4719 | goto out; | 4732 | goto out; |
4720 | if ((status = decode_remove(&xdr, &res->cinfo)) != 0) | 4733 | if ((status = decode_remove(&xdr, &res->cinfo)) != 0) |
4721 | goto out; | 4734 | goto out; |
4722 | decode_getfattr(&xdr, &res->dir_attr, res->server); | 4735 | decode_getfattr(&xdr, &res->dir_attr, res->server, |
4736 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4723 | out: | 4737 | out: |
4724 | return status; | 4738 | return status; |
4725 | } | 4739 | } |
@@ -4749,11 +4763,13 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re | |||
4749 | if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0) | 4763 | if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0) |
4750 | goto out; | 4764 | goto out; |
4751 | /* Current FH is target directory */ | 4765 | /* Current FH is target directory */ |
4752 | if (decode_getfattr(&xdr, res->new_fattr, res->server) != 0) | 4766 | if (decode_getfattr(&xdr, res->new_fattr, res->server, |
4767 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
4753 | goto out; | 4768 | goto out; |
4754 | if ((status = decode_restorefh(&xdr)) != 0) | 4769 | if ((status = decode_restorefh(&xdr)) != 0) |
4755 | goto out; | 4770 | goto out; |
4756 | decode_getfattr(&xdr, res->old_fattr, res->server); | 4771 | decode_getfattr(&xdr, res->old_fattr, res->server, |
4772 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4757 | out: | 4773 | out: |
4758 | return status; | 4774 | return status; |
4759 | } | 4775 | } |
@@ -4786,11 +4802,13 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link | |||
4786 | * Note order: OP_LINK leaves the directory as the current | 4802 | * Note order: OP_LINK leaves the directory as the current |
4787 | * filehandle. | 4803 | * filehandle. |
4788 | */ | 4804 | */ |
4789 | if (decode_getfattr(&xdr, res->dir_attr, res->server) != 0) | 4805 | if (decode_getfattr(&xdr, res->dir_attr, res->server, |
4806 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
4790 | goto out; | 4807 | goto out; |
4791 | if ((status = decode_restorefh(&xdr)) != 0) | 4808 | if ((status = decode_restorefh(&xdr)) != 0) |
4792 | goto out; | 4809 | goto out; |
4793 | decode_getfattr(&xdr, res->fattr, res->server); | 4810 | decode_getfattr(&xdr, res->fattr, res->server, |
4811 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4794 | out: | 4812 | out: |
4795 | return status; | 4813 | return status; |
4796 | } | 4814 | } |
@@ -4819,11 +4837,13 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_cr | |||
4819 | goto out; | 4837 | goto out; |
4820 | if ((status = decode_getfh(&xdr, res->fh)) != 0) | 4838 | if ((status = decode_getfh(&xdr, res->fh)) != 0) |
4821 | goto out; | 4839 | goto out; |
4822 | if (decode_getfattr(&xdr, res->fattr, res->server) != 0) | 4840 | if (decode_getfattr(&xdr, res->fattr, res->server, |
4841 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
4823 | goto out; | 4842 | goto out; |
4824 | if ((status = decode_restorefh(&xdr)) != 0) | 4843 | if ((status = decode_restorefh(&xdr)) != 0) |
4825 | goto out; | 4844 | goto out; |
4826 | decode_getfattr(&xdr, res->dir_fattr, res->server); | 4845 | decode_getfattr(&xdr, res->dir_fattr, res->server, |
4846 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4827 | out: | 4847 | out: |
4828 | return status; | 4848 | return status; |
4829 | } | 4849 | } |
@@ -4855,7 +4875,8 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g | |||
4855 | status = decode_putfh(&xdr); | 4875 | status = decode_putfh(&xdr); |
4856 | if (status) | 4876 | if (status) |
4857 | goto out; | 4877 | goto out; |
4858 | status = decode_getfattr(&xdr, res->fattr, res->server); | 4878 | status = decode_getfattr(&xdr, res->fattr, res->server, |
4879 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4859 | out: | 4880 | out: |
4860 | return status; | 4881 | return status; |
4861 | } | 4882 | } |
@@ -4962,7 +4983,8 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_clos | |||
4962 | * an ESTALE error. Shouldn't be a problem, | 4983 | * an ESTALE error. Shouldn't be a problem, |
4963 | * though, since fattr->valid will remain unset. | 4984 | * though, since fattr->valid will remain unset. |
4964 | */ | 4985 | */ |
4965 | decode_getfattr(&xdr, res->fattr, res->server); | 4986 | decode_getfattr(&xdr, res->fattr, res->server, |
4987 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
4966 | out: | 4988 | out: |
4967 | return status; | 4989 | return status; |
4968 | } | 4990 | } |
@@ -4994,11 +5016,13 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr | |||
4994 | goto out; | 5016 | goto out; |
4995 | if (decode_getfh(&xdr, &res->fh) != 0) | 5017 | if (decode_getfh(&xdr, &res->fh) != 0) |
4996 | goto out; | 5018 | goto out; |
4997 | if (decode_getfattr(&xdr, res->f_attr, res->server) != 0) | 5019 | if (decode_getfattr(&xdr, res->f_attr, res->server, |
5020 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
4998 | goto out; | 5021 | goto out; |
4999 | if (decode_restorefh(&xdr) != 0) | 5022 | if (decode_restorefh(&xdr) != 0) |
5000 | goto out; | 5023 | goto out; |
5001 | decode_getfattr(&xdr, res->dir_attr, res->server); | 5024 | decode_getfattr(&xdr, res->dir_attr, res->server, |
5025 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5002 | out: | 5026 | out: |
5003 | return status; | 5027 | return status; |
5004 | } | 5028 | } |
@@ -5046,7 +5070,8 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
5046 | status = decode_open(&xdr, res); | 5070 | status = decode_open(&xdr, res); |
5047 | if (status) | 5071 | if (status) |
5048 | goto out; | 5072 | goto out; |
5049 | decode_getfattr(&xdr, res->f_attr, res->server); | 5073 | decode_getfattr(&xdr, res->f_attr, res->server, |
5074 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5050 | out: | 5075 | out: |
5051 | return status; | 5076 | return status; |
5052 | } | 5077 | } |
@@ -5073,7 +5098,8 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se | |||
5073 | status = decode_setattr(&xdr); | 5098 | status = decode_setattr(&xdr); |
5074 | if (status) | 5099 | if (status) |
5075 | goto out; | 5100 | goto out; |
5076 | decode_getfattr(&xdr, res->fattr, res->server); | 5101 | decode_getfattr(&xdr, res->fattr, res->server, |
5102 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5077 | out: | 5103 | out: |
5078 | return status; | 5104 | return status; |
5079 | } | 5105 | } |
@@ -5247,7 +5273,8 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writ | |||
5247 | status = decode_write(&xdr, res); | 5273 | status = decode_write(&xdr, res); |
5248 | if (status) | 5274 | if (status) |
5249 | goto out; | 5275 | goto out; |
5250 | decode_getfattr(&xdr, res->fattr, res->server); | 5276 | decode_getfattr(&xdr, res->fattr, res->server, |
5277 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5251 | if (!status) | 5278 | if (!status) |
5252 | status = res->count; | 5279 | status = res->count; |
5253 | out: | 5280 | out: |
@@ -5276,7 +5303,8 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_wri | |||
5276 | status = decode_commit(&xdr, res); | 5303 | status = decode_commit(&xdr, res); |
5277 | if (status) | 5304 | if (status) |
5278 | goto out; | 5305 | goto out; |
5279 | decode_getfattr(&xdr, res->fattr, res->server); | 5306 | decode_getfattr(&xdr, res->fattr, res->server, |
5307 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5280 | out: | 5308 | out: |
5281 | return status; | 5309 | return status; |
5282 | } | 5310 | } |
@@ -5440,7 +5468,8 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
5440 | if (status != 0) | 5468 | if (status != 0) |
5441 | goto out; | 5469 | goto out; |
5442 | status = decode_delegreturn(&xdr); | 5470 | status = decode_delegreturn(&xdr); |
5443 | decode_getfattr(&xdr, res->fattr, res->server); | 5471 | decode_getfattr(&xdr, res->fattr, res->server, |
5472 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5444 | out: | 5473 | out: |
5445 | return status; | 5474 | return status; |
5446 | } | 5475 | } |
@@ -5468,7 +5497,8 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, | |||
5468 | goto out; | 5497 | goto out; |
5469 | xdr_enter_page(&xdr, PAGE_SIZE); | 5498 | xdr_enter_page(&xdr, PAGE_SIZE); |
5470 | status = decode_getfattr(&xdr, &res->fs_locations->fattr, | 5499 | status = decode_getfattr(&xdr, &res->fs_locations->fattr, |
5471 | res->fs_locations->server); | 5500 | res->fs_locations->server, |
5501 | !RPC_IS_ASYNC(req->rq_task)); | ||
5472 | out: | 5502 | out: |
5473 | return status; | 5503 | return status; |
5474 | } | 5504 | } |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 0b4cbdc60abd..9c85cdb353aa 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -158,7 +158,7 @@ static const match_table_t nfs_mount_option_tokens = { | |||
158 | { Opt_mountvers, "mountvers=%s" }, | 158 | { Opt_mountvers, "mountvers=%s" }, |
159 | { Opt_nfsvers, "nfsvers=%s" }, | 159 | { Opt_nfsvers, "nfsvers=%s" }, |
160 | { Opt_nfsvers, "vers=%s" }, | 160 | { Opt_nfsvers, "vers=%s" }, |
161 | { Opt_minorversion, "minorversion=%u" }, | 161 | { Opt_minorversion, "minorversion=%s" }, |
162 | 162 | ||
163 | { Opt_sec, "sec=%s" }, | 163 | { Opt_sec, "sec=%s" }, |
164 | { Opt_proto, "proto=%s" }, | 164 | { Opt_proto, "proto=%s" }, |
@@ -742,129 +742,10 @@ static int nfs_verify_server_address(struct sockaddr *addr) | |||
742 | } | 742 | } |
743 | } | 743 | } |
744 | 744 | ||
745 | dfprintk(MOUNT, "NFS: Invalid IP address specified\n"); | ||
745 | return 0; | 746 | return 0; |
746 | } | 747 | } |
747 | 748 | ||
748 | static void nfs_parse_ipv4_address(char *string, size_t str_len, | ||
749 | struct sockaddr *sap, size_t *addr_len) | ||
750 | { | ||
751 | struct sockaddr_in *sin = (struct sockaddr_in *)sap; | ||
752 | u8 *addr = (u8 *)&sin->sin_addr.s_addr; | ||
753 | |||
754 | if (str_len <= INET_ADDRSTRLEN) { | ||
755 | dfprintk(MOUNT, "NFS: parsing IPv4 address %*s\n", | ||
756 | (int)str_len, string); | ||
757 | |||
758 | sin->sin_family = AF_INET; | ||
759 | *addr_len = sizeof(*sin); | ||
760 | if (in4_pton(string, str_len, addr, '\0', NULL)) | ||
761 | return; | ||
762 | } | ||
763 | |||
764 | sap->sa_family = AF_UNSPEC; | ||
765 | *addr_len = 0; | ||
766 | } | ||
767 | |||
768 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
769 | static int nfs_parse_ipv6_scope_id(const char *string, const size_t str_len, | ||
770 | const char *delim, | ||
771 | struct sockaddr_in6 *sin6) | ||
772 | { | ||
773 | char *p; | ||
774 | size_t len; | ||
775 | |||
776 | if ((string + str_len) == delim) | ||
777 | return 1; | ||
778 | |||
779 | if (*delim != IPV6_SCOPE_DELIMITER) | ||
780 | return 0; | ||
781 | |||
782 | if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) | ||
783 | return 0; | ||
784 | |||
785 | len = (string + str_len) - delim - 1; | ||
786 | p = kstrndup(delim + 1, len, GFP_KERNEL); | ||
787 | if (p) { | ||
788 | unsigned long scope_id = 0; | ||
789 | struct net_device *dev; | ||
790 | |||
791 | dev = dev_get_by_name(&init_net, p); | ||
792 | if (dev != NULL) { | ||
793 | scope_id = dev->ifindex; | ||
794 | dev_put(dev); | ||
795 | } else { | ||
796 | if (strict_strtoul(p, 10, &scope_id) == 0) { | ||
797 | kfree(p); | ||
798 | return 0; | ||
799 | } | ||
800 | } | ||
801 | |||
802 | kfree(p); | ||
803 | |||
804 | sin6->sin6_scope_id = scope_id; | ||
805 | dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id); | ||
806 | return 1; | ||
807 | } | ||
808 | |||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | static void nfs_parse_ipv6_address(char *string, size_t str_len, | ||
813 | struct sockaddr *sap, size_t *addr_len) | ||
814 | { | ||
815 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | ||
816 | u8 *addr = (u8 *)&sin6->sin6_addr.in6_u; | ||
817 | const char *delim; | ||
818 | |||
819 | if (str_len <= INET6_ADDRSTRLEN) { | ||
820 | dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n", | ||
821 | (int)str_len, string); | ||
822 | |||
823 | sin6->sin6_family = AF_INET6; | ||
824 | *addr_len = sizeof(*sin6); | ||
825 | if (in6_pton(string, str_len, addr, | ||
826 | IPV6_SCOPE_DELIMITER, &delim) != 0) { | ||
827 | if (nfs_parse_ipv6_scope_id(string, str_len, | ||
828 | delim, sin6) != 0) | ||
829 | return; | ||
830 | } | ||
831 | } | ||
832 | |||
833 | sap->sa_family = AF_UNSPEC; | ||
834 | *addr_len = 0; | ||
835 | } | ||
836 | #else | ||
837 | static void nfs_parse_ipv6_address(char *string, size_t str_len, | ||
838 | struct sockaddr *sap, size_t *addr_len) | ||
839 | { | ||
840 | sap->sa_family = AF_UNSPEC; | ||
841 | *addr_len = 0; | ||
842 | } | ||
843 | #endif | ||
844 | |||
845 | /* | ||
846 | * Construct a sockaddr based on the contents of a string that contains | ||
847 | * an IP address in presentation format. | ||
848 | * | ||
849 | * If there is a problem constructing the new sockaddr, set the address | ||
850 | * family to AF_UNSPEC. | ||
851 | */ | ||
852 | void nfs_parse_ip_address(char *string, size_t str_len, | ||
853 | struct sockaddr *sap, size_t *addr_len) | ||
854 | { | ||
855 | unsigned int i, colons; | ||
856 | |||
857 | colons = 0; | ||
858 | for (i = 0; i < str_len; i++) | ||
859 | if (string[i] == ':') | ||
860 | colons++; | ||
861 | |||
862 | if (colons >= 2) | ||
863 | nfs_parse_ipv6_address(string, str_len, sap, addr_len); | ||
864 | else | ||
865 | nfs_parse_ipv4_address(string, str_len, sap, addr_len); | ||
866 | } | ||
867 | |||
868 | /* | 749 | /* |
869 | * Sanity check the NFS transport protocol. | 750 | * Sanity check the NFS transport protocol. |
870 | * | 751 | * |
@@ -904,8 +785,6 @@ static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt) | |||
904 | 785 | ||
905 | /* | 786 | /* |
906 | * Parse the value of the 'sec=' option. | 787 | * Parse the value of the 'sec=' option. |
907 | * | ||
908 | * The flavor_len setting is for v4 mounts. | ||
909 | */ | 788 | */ |
910 | static int nfs_parse_security_flavors(char *value, | 789 | static int nfs_parse_security_flavors(char *value, |
911 | struct nfs_parsed_mount_data *mnt) | 790 | struct nfs_parsed_mount_data *mnt) |
@@ -916,53 +795,43 @@ static int nfs_parse_security_flavors(char *value, | |||
916 | 795 | ||
917 | switch (match_token(value, nfs_secflavor_tokens, args)) { | 796 | switch (match_token(value, nfs_secflavor_tokens, args)) { |
918 | case Opt_sec_none: | 797 | case Opt_sec_none: |
919 | mnt->auth_flavor_len = 0; | ||
920 | mnt->auth_flavors[0] = RPC_AUTH_NULL; | 798 | mnt->auth_flavors[0] = RPC_AUTH_NULL; |
921 | break; | 799 | break; |
922 | case Opt_sec_sys: | 800 | case Opt_sec_sys: |
923 | mnt->auth_flavor_len = 0; | ||
924 | mnt->auth_flavors[0] = RPC_AUTH_UNIX; | 801 | mnt->auth_flavors[0] = RPC_AUTH_UNIX; |
925 | break; | 802 | break; |
926 | case Opt_sec_krb5: | 803 | case Opt_sec_krb5: |
927 | mnt->auth_flavor_len = 1; | ||
928 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; | 804 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; |
929 | break; | 805 | break; |
930 | case Opt_sec_krb5i: | 806 | case Opt_sec_krb5i: |
931 | mnt->auth_flavor_len = 1; | ||
932 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; | 807 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; |
933 | break; | 808 | break; |
934 | case Opt_sec_krb5p: | 809 | case Opt_sec_krb5p: |
935 | mnt->auth_flavor_len = 1; | ||
936 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; | 810 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; |
937 | break; | 811 | break; |
938 | case Opt_sec_lkey: | 812 | case Opt_sec_lkey: |
939 | mnt->auth_flavor_len = 1; | ||
940 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; | 813 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; |
941 | break; | 814 | break; |
942 | case Opt_sec_lkeyi: | 815 | case Opt_sec_lkeyi: |
943 | mnt->auth_flavor_len = 1; | ||
944 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; | 816 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; |
945 | break; | 817 | break; |
946 | case Opt_sec_lkeyp: | 818 | case Opt_sec_lkeyp: |
947 | mnt->auth_flavor_len = 1; | ||
948 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; | 819 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; |
949 | break; | 820 | break; |
950 | case Opt_sec_spkm: | 821 | case Opt_sec_spkm: |
951 | mnt->auth_flavor_len = 1; | ||
952 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; | 822 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; |
953 | break; | 823 | break; |
954 | case Opt_sec_spkmi: | 824 | case Opt_sec_spkmi: |
955 | mnt->auth_flavor_len = 1; | ||
956 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; | 825 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; |
957 | break; | 826 | break; |
958 | case Opt_sec_spkmp: | 827 | case Opt_sec_spkmp: |
959 | mnt->auth_flavor_len = 1; | ||
960 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; | 828 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; |
961 | break; | 829 | break; |
962 | default: | 830 | default: |
963 | return 0; | 831 | return 0; |
964 | } | 832 | } |
965 | 833 | ||
834 | mnt->auth_flavor_len = 1; | ||
966 | return 1; | 835 | return 1; |
967 | } | 836 | } |
968 | 837 | ||
@@ -1001,7 +870,6 @@ static int nfs_parse_mount_options(char *raw, | |||
1001 | while ((p = strsep(&raw, ",")) != NULL) { | 870 | while ((p = strsep(&raw, ",")) != NULL) { |
1002 | substring_t args[MAX_OPT_ARGS]; | 871 | substring_t args[MAX_OPT_ARGS]; |
1003 | unsigned long option; | 872 | unsigned long option; |
1004 | int int_option; | ||
1005 | int token; | 873 | int token; |
1006 | 874 | ||
1007 | if (!*p) | 875 | if (!*p) |
@@ -1273,11 +1141,16 @@ static int nfs_parse_mount_options(char *raw, | |||
1273 | } | 1141 | } |
1274 | break; | 1142 | break; |
1275 | case Opt_minorversion: | 1143 | case Opt_minorversion: |
1276 | if (match_int(args, &int_option)) | 1144 | string = match_strdup(args); |
1277 | return 0; | 1145 | if (string == NULL) |
1278 | if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION) | 1146 | goto out_nomem; |
1279 | return 0; | 1147 | rc = strict_strtoul(string, 10, &option); |
1280 | mnt->minorversion = int_option; | 1148 | kfree(string); |
1149 | if (rc != 0) | ||
1150 | goto out_invalid_value; | ||
1151 | if (option > NFS4_MAX_MINOR_VERSION) | ||
1152 | goto out_invalid_value; | ||
1153 | mnt->minorversion = option; | ||
1281 | break; | 1154 | break; |
1282 | 1155 | ||
1283 | /* | 1156 | /* |
@@ -1352,11 +1225,14 @@ static int nfs_parse_mount_options(char *raw, | |||
1352 | string = match_strdup(args); | 1225 | string = match_strdup(args); |
1353 | if (string == NULL) | 1226 | if (string == NULL) |
1354 | goto out_nomem; | 1227 | goto out_nomem; |
1355 | nfs_parse_ip_address(string, strlen(string), | 1228 | mnt->nfs_server.addrlen = |
1356 | (struct sockaddr *) | 1229 | rpc_pton(string, strlen(string), |
1357 | &mnt->nfs_server.address, | 1230 | (struct sockaddr *) |
1358 | &mnt->nfs_server.addrlen); | 1231 | &mnt->nfs_server.address, |
1232 | sizeof(mnt->nfs_server.address)); | ||
1359 | kfree(string); | 1233 | kfree(string); |
1234 | if (mnt->nfs_server.addrlen == 0) | ||
1235 | goto out_invalid_address; | ||
1360 | break; | 1236 | break; |
1361 | case Opt_clientaddr: | 1237 | case Opt_clientaddr: |
1362 | string = match_strdup(args); | 1238 | string = match_strdup(args); |
@@ -1376,11 +1252,14 @@ static int nfs_parse_mount_options(char *raw, | |||
1376 | string = match_strdup(args); | 1252 | string = match_strdup(args); |
1377 | if (string == NULL) | 1253 | if (string == NULL) |
1378 | goto out_nomem; | 1254 | goto out_nomem; |
1379 | nfs_parse_ip_address(string, strlen(string), | 1255 | mnt->mount_server.addrlen = |
1380 | (struct sockaddr *) | 1256 | rpc_pton(string, strlen(string), |
1381 | &mnt->mount_server.address, | 1257 | (struct sockaddr *) |
1382 | &mnt->mount_server.addrlen); | 1258 | &mnt->mount_server.address, |
1259 | sizeof(mnt->mount_server.address)); | ||
1383 | kfree(string); | 1260 | kfree(string); |
1261 | if (mnt->mount_server.addrlen == 0) | ||
1262 | goto out_invalid_address; | ||
1384 | break; | 1263 | break; |
1385 | case Opt_lookupcache: | 1264 | case Opt_lookupcache: |
1386 | string = match_strdup(args); | 1265 | string = match_strdup(args); |
@@ -1432,8 +1311,11 @@ static int nfs_parse_mount_options(char *raw, | |||
1432 | 1311 | ||
1433 | return 1; | 1312 | return 1; |
1434 | 1313 | ||
1314 | out_invalid_address: | ||
1315 | printk(KERN_INFO "NFS: bad IP address specified: %s\n", p); | ||
1316 | return 0; | ||
1435 | out_invalid_value: | 1317 | out_invalid_value: |
1436 | printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p); | 1318 | printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p); |
1437 | return 0; | 1319 | return 0; |
1438 | out_nomem: | 1320 | out_nomem: |
1439 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); | 1321 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); |
@@ -1445,13 +1327,50 @@ out_security_failure: | |||
1445 | } | 1327 | } |
1446 | 1328 | ||
1447 | /* | 1329 | /* |
1330 | * Match the requested auth flavors with the list returned by | ||
1331 | * the server. Returns zero and sets the mount's authentication | ||
1332 | * flavor on success; returns -EACCES if server does not support | ||
1333 | * the requested flavor. | ||
1334 | */ | ||
1335 | static int nfs_walk_authlist(struct nfs_parsed_mount_data *args, | ||
1336 | struct nfs_mount_request *request) | ||
1337 | { | ||
1338 | unsigned int i, j, server_authlist_len = *(request->auth_flav_len); | ||
1339 | |||
1340 | /* | ||
1341 | * We avoid sophisticated negotiating here, as there are | ||
1342 | * plenty of cases where we can get it wrong, providing | ||
1343 | * either too little or too much security. | ||
1344 | * | ||
1345 | * RFC 2623, section 2.7 suggests we SHOULD prefer the | ||
1346 | * flavor listed first. However, some servers list | ||
1347 | * AUTH_NULL first. Our caller plants AUTH_SYS, the | ||
1348 | * preferred default, in args->auth_flavors[0] if user | ||
1349 | * didn't specify sec= mount option. | ||
1350 | */ | ||
1351 | for (i = 0; i < args->auth_flavor_len; i++) | ||
1352 | for (j = 0; j < server_authlist_len; j++) | ||
1353 | if (args->auth_flavors[i] == request->auth_flavs[j]) { | ||
1354 | dfprintk(MOUNT, "NFS: using auth flavor %d\n", | ||
1355 | request->auth_flavs[j]); | ||
1356 | args->auth_flavors[0] = request->auth_flavs[j]; | ||
1357 | return 0; | ||
1358 | } | ||
1359 | |||
1360 | dfprintk(MOUNT, "NFS: server does not support requested auth flavor\n"); | ||
1361 | nfs_umount(request); | ||
1362 | return -EACCES; | ||
1363 | } | ||
1364 | |||
1365 | /* | ||
1448 | * Use the remote server's MOUNT service to request the NFS file handle | 1366 | * Use the remote server's MOUNT service to request the NFS file handle |
1449 | * corresponding to the provided path. | 1367 | * corresponding to the provided path. |
1450 | */ | 1368 | */ |
1451 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, | 1369 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
1452 | struct nfs_fh *root_fh) | 1370 | struct nfs_fh *root_fh) |
1453 | { | 1371 | { |
1454 | unsigned int auth_flavor_len = 0; | 1372 | rpc_authflavor_t server_authlist[NFS_MAX_SECFLAVORS]; |
1373 | unsigned int server_authlist_len = ARRAY_SIZE(server_authlist); | ||
1455 | struct nfs_mount_request request = { | 1374 | struct nfs_mount_request request = { |
1456 | .sap = (struct sockaddr *) | 1375 | .sap = (struct sockaddr *) |
1457 | &args->mount_server.address, | 1376 | &args->mount_server.address, |
@@ -1459,7 +1378,8 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1459 | .protocol = args->mount_server.protocol, | 1378 | .protocol = args->mount_server.protocol, |
1460 | .fh = root_fh, | 1379 | .fh = root_fh, |
1461 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, | 1380 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, |
1462 | .auth_flav_len = &auth_flavor_len, | 1381 | .auth_flav_len = &server_authlist_len, |
1382 | .auth_flavs = server_authlist, | ||
1463 | }; | 1383 | }; |
1464 | int status; | 1384 | int status; |
1465 | 1385 | ||
@@ -1489,19 +1409,25 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1489 | /* | 1409 | /* |
1490 | * autobind will be used if mount_server.port == 0 | 1410 | * autobind will be used if mount_server.port == 0 |
1491 | */ | 1411 | */ |
1492 | nfs_set_port(request.sap, args->mount_server.port); | 1412 | rpc_set_port(request.sap, args->mount_server.port); |
1493 | 1413 | ||
1494 | /* | 1414 | /* |
1495 | * Now ask the mount server to map our export path | 1415 | * Now ask the mount server to map our export path |
1496 | * to a file handle. | 1416 | * to a file handle. |
1497 | */ | 1417 | */ |
1498 | status = nfs_mount(&request); | 1418 | status = nfs_mount(&request); |
1499 | if (status == 0) | 1419 | if (status != 0) { |
1500 | return 0; | 1420 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", |
1421 | request.hostname, status); | ||
1422 | return status; | ||
1423 | } | ||
1501 | 1424 | ||
1502 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", | 1425 | /* |
1503 | request.hostname, status); | 1426 | * MNTv1 (NFSv2) does not support auth flavor negotiation. |
1504 | return status; | 1427 | */ |
1428 | if (args->mount_server.version != NFS_MNT3_VERSION) | ||
1429 | return 0; | ||
1430 | return nfs_walk_authlist(args, &request); | ||
1505 | } | 1431 | } |
1506 | 1432 | ||
1507 | static int nfs_parse_simple_hostname(const char *dev_name, | 1433 | static int nfs_parse_simple_hostname(const char *dev_name, |
@@ -1676,6 +1602,7 @@ static int nfs_validate_mount_data(void *options, | |||
1676 | args->nfs_server.port = 0; /* autobind unless user sets port */ | 1602 | args->nfs_server.port = 0; /* autobind unless user sets port */ |
1677 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1603 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1678 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1604 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
1605 | args->auth_flavor_len = 1; | ||
1679 | 1606 | ||
1680 | switch (data->version) { | 1607 | switch (data->version) { |
1681 | case 1: | 1608 | case 1: |
@@ -1776,7 +1703,7 @@ static int nfs_validate_mount_data(void *options, | |||
1776 | &args->nfs_server.address)) | 1703 | &args->nfs_server.address)) |
1777 | goto out_no_address; | 1704 | goto out_no_address; |
1778 | 1705 | ||
1779 | nfs_set_port((struct sockaddr *)&args->nfs_server.address, | 1706 | rpc_set_port((struct sockaddr *)&args->nfs_server.address, |
1780 | args->nfs_server.port); | 1707 | args->nfs_server.port); |
1781 | 1708 | ||
1782 | nfs_set_mount_transport_protocol(args); | 1709 | nfs_set_mount_transport_protocol(args); |
@@ -2339,7 +2266,7 @@ static int nfs4_validate_mount_data(void *options, | |||
2339 | args->acdirmax = NFS_DEF_ACDIRMAX; | 2266 | args->acdirmax = NFS_DEF_ACDIRMAX; |
2340 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | 2267 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ |
2341 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 2268 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
2342 | args->auth_flavor_len = 0; | 2269 | args->auth_flavor_len = 1; |
2343 | args->minorversion = 0; | 2270 | args->minorversion = 0; |
2344 | 2271 | ||
2345 | switch (data->version) { | 2272 | switch (data->version) { |
@@ -2409,7 +2336,7 @@ static int nfs4_validate_mount_data(void *options, | |||
2409 | &args->nfs_server.address)) | 2336 | &args->nfs_server.address)) |
2410 | return -EINVAL; | 2337 | return -EINVAL; |
2411 | 2338 | ||
2412 | nfs_set_port((struct sockaddr *)&args->nfs_server.address, | 2339 | rpc_set_port((struct sockaddr *)&args->nfs_server.address, |
2413 | args->nfs_server.port); | 2340 | args->nfs_server.port); |
2414 | 2341 | ||
2415 | nfs_validate_transport_protocol(args); | 2342 | nfs_validate_transport_protocol(args); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index a34fae21fe10..120acadc6a84 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 | ||
@@ -218,24 +220,17 @@ static void nfs_end_page_writeback(struct page *page) | |||
218 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); | 220 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
219 | } | 221 | } |
220 | 222 | ||
221 | /* | 223 | static struct nfs_page *nfs_find_and_lock_request(struct page *page) |
222 | * Find an associated nfs write request, and prepare to flush it out | ||
223 | * May return an error if the user signalled nfs_wait_on_request(). | ||
224 | */ | ||
225 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | ||
226 | struct page *page) | ||
227 | { | 224 | { |
228 | struct inode *inode = page->mapping->host; | 225 | struct inode *inode = page->mapping->host; |
229 | struct nfs_page *req; | 226 | struct nfs_page *req; |
230 | int ret; | 227 | int ret; |
231 | 228 | ||
232 | spin_lock(&inode->i_lock); | 229 | spin_lock(&inode->i_lock); |
233 | for(;;) { | 230 | for (;;) { |
234 | req = nfs_page_find_request_locked(page); | 231 | req = nfs_page_find_request_locked(page); |
235 | if (req == NULL) { | 232 | if (req == NULL) |
236 | spin_unlock(&inode->i_lock); | 233 | break; |
237 | return 0; | ||
238 | } | ||
239 | if (nfs_set_page_tag_locked(req)) | 234 | if (nfs_set_page_tag_locked(req)) |
240 | break; | 235 | break; |
241 | /* Note: If we hold the page lock, as is the case in nfs_writepage, | 236 | /* Note: If we hold the page lock, as is the case in nfs_writepage, |
@@ -247,23 +242,40 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
247 | ret = nfs_wait_on_request(req); | 242 | ret = nfs_wait_on_request(req); |
248 | nfs_release_request(req); | 243 | nfs_release_request(req); |
249 | if (ret != 0) | 244 | if (ret != 0) |
250 | return ret; | 245 | return ERR_PTR(ret); |
251 | spin_lock(&inode->i_lock); | 246 | spin_lock(&inode->i_lock); |
252 | } | 247 | } |
253 | if (test_bit(PG_CLEAN, &req->wb_flags)) { | ||
254 | spin_unlock(&inode->i_lock); | ||
255 | BUG(); | ||
256 | } | ||
257 | if (nfs_set_page_writeback(page) != 0) { | ||
258 | spin_unlock(&inode->i_lock); | ||
259 | BUG(); | ||
260 | } | ||
261 | spin_unlock(&inode->i_lock); | 248 | spin_unlock(&inode->i_lock); |
249 | return req; | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * Find an associated nfs write request, and prepare to flush it out | ||
254 | * May return an error if the user signalled nfs_wait_on_request(). | ||
255 | */ | ||
256 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | ||
257 | struct page *page) | ||
258 | { | ||
259 | struct nfs_page *req; | ||
260 | int ret = 0; | ||
261 | |||
262 | req = nfs_find_and_lock_request(page); | ||
263 | if (!req) | ||
264 | goto out; | ||
265 | ret = PTR_ERR(req); | ||
266 | if (IS_ERR(req)) | ||
267 | goto out; | ||
268 | |||
269 | ret = nfs_set_page_writeback(page); | ||
270 | BUG_ON(ret != 0); | ||
271 | BUG_ON(test_bit(PG_CLEAN, &req->wb_flags)); | ||
272 | |||
262 | if (!nfs_pageio_add_request(pgio, req)) { | 273 | if (!nfs_pageio_add_request(pgio, req)) { |
263 | nfs_redirty_request(req); | 274 | nfs_redirty_request(req); |
264 | return pgio->pg_error; | 275 | ret = pgio->pg_error; |
265 | } | 276 | } |
266 | return 0; | 277 | out: |
278 | return ret; | ||
267 | } | 279 | } |
268 | 280 | ||
269 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) | 281 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) |
@@ -1580,6 +1592,41 @@ int nfs_wb_page(struct inode *inode, struct page* page) | |||
1580 | return nfs_wb_page_priority(inode, page, FLUSH_STABLE); | 1592 | return nfs_wb_page_priority(inode, page, FLUSH_STABLE); |
1581 | } | 1593 | } |
1582 | 1594 | ||
1595 | #ifdef CONFIG_MIGRATION | ||
1596 | int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | ||
1597 | struct page *page) | ||
1598 | { | ||
1599 | struct nfs_page *req; | ||
1600 | int ret; | ||
1601 | |||
1602 | if (PageFsCache(page)) | ||
1603 | nfs_fscache_release_page(page, GFP_KERNEL); | ||
1604 | |||
1605 | req = nfs_find_and_lock_request(page); | ||
1606 | ret = PTR_ERR(req); | ||
1607 | if (IS_ERR(req)) | ||
1608 | goto out; | ||
1609 | |||
1610 | ret = migrate_page(mapping, newpage, page); | ||
1611 | if (!req) | ||
1612 | goto out; | ||
1613 | if (ret) | ||
1614 | goto out_unlock; | ||
1615 | page_cache_get(newpage); | ||
1616 | req->wb_page = newpage; | ||
1617 | SetPagePrivate(newpage); | ||
1618 | set_page_private(newpage, page_private(page)); | ||
1619 | ClearPagePrivate(page); | ||
1620 | set_page_private(page, 0); | ||
1621 | page_cache_release(page); | ||
1622 | out_unlock: | ||
1623 | nfs_clear_page_tag_locked(req); | ||
1624 | nfs_release_request(req); | ||
1625 | out: | ||
1626 | return ret; | ||
1627 | } | ||
1628 | #endif | ||
1629 | |||
1583 | int __init nfs_init_writepagecache(void) | 1630 | int __init nfs_init_writepagecache(void) |
1584 | { | 1631 | { |
1585 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", | 1632 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", |