diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-10 17:57:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-10 17:57:40 -0500 |
commit | 57eccf1c2acae2fcb748730881ba75643fc31c81 (patch) | |
tree | be47ac42ef0b2e3e7157ce196ad2ed1224739c6c /fs/nfs | |
parent | 5c395ae7033099fc657114ea997858aa622f08b2 (diff) | |
parent | 074b1d12fe2500d7d453902f9266e6674b30d84c (diff) |
Merge branch 'nfs-for-3.3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
* 'nfs-for-3.3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFSv4: Change the default setting of the nfs4_disable_idmapping parameter
NFSv4: Save the owner/group name string when doing open
NFS: Remove pNFS bloat from the generic write path
pnfs-obj: Must return layout on IO error
pnfs-obj: pNFS errors are communicated on iodata->pnfs_error
NFS: Cache state owners after files are closed
NFS: Clean up nfs4_find_state_owners_locked()
NFSv4: include bitmap in nfsv4 get acl data
nfs: fix a minor do_div portability issue
NFSv4.1: cleanup comment and debug printk
NFSv4.1: change nfs4_free_slot parameters for dynamic slots
NFSv4.1: cleanup init and reset of session slot tables
NFSv4.1: fix backchannel slotid off-by-one bug
nfs: fix regression in handling of context= option in NFSv4
NFS - fix recent breakage to NFS error handling.
NFS: Retry mounting NFSROOT
SUNRPC: Clean up the RPCSEC_GSS service ticket requests
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/callback_proc.c | 2 | ||||
-rw-r--r-- | fs/nfs/client.c | 12 | ||||
-rw-r--r-- | fs/nfs/file.c | 4 | ||||
-rw-r--r-- | fs/nfs/idmap.c | 83 | ||||
-rw-r--r-- | fs/nfs/inode.c | 2 | ||||
-rw-r--r-- | fs/nfs/internal.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 3 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 9 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 177 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 104 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 137 | ||||
-rw-r--r-- | fs/nfs/objlayout/objio_osd.c | 3 | ||||
-rw-r--r-- | fs/nfs/objlayout/objlayout.c | 4 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 42 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 1 | ||||
-rw-r--r-- | fs/nfs/super.c | 43 | ||||
-rw-r--r-- | fs/nfs/write.c | 27 |
17 files changed, 422 insertions, 233 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 43926add945b..54cea8ad5a76 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -339,7 +339,7 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args) | |||
339 | dprintk("%s enter. slotid %d seqid %d\n", | 339 | dprintk("%s enter. slotid %d seqid %d\n", |
340 | __func__, args->csa_slotid, args->csa_sequenceid); | 340 | __func__, args->csa_slotid, args->csa_sequenceid); |
341 | 341 | ||
342 | if (args->csa_slotid > NFS41_BC_MAX_CALLBACKS) | 342 | if (args->csa_slotid >= NFS41_BC_MAX_CALLBACKS) |
343 | return htonl(NFS4ERR_BADSLOT); | 343 | return htonl(NFS4ERR_BADSLOT); |
344 | 344 | ||
345 | slot = tbl->slots + args->csa_slotid; | 345 | slot = tbl->slots + args->csa_slotid; |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 873bf00d51a2..277dfaf2e99a 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -84,7 +84,7 @@ retry: | |||
84 | /* | 84 | /* |
85 | * Turn off NFSv4 uid/gid mapping when using AUTH_SYS | 85 | * Turn off NFSv4 uid/gid mapping when using AUTH_SYS |
86 | */ | 86 | */ |
87 | static int nfs4_disable_idmapping = 0; | 87 | static int nfs4_disable_idmapping = 1; |
88 | 88 | ||
89 | /* | 89 | /* |
90 | * RPC cruft for NFS | 90 | * RPC cruft for NFS |
@@ -185,7 +185,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
185 | clp->cl_minorversion = cl_init->minorversion; | 185 | clp->cl_minorversion = cl_init->minorversion; |
186 | clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion]; | 186 | clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion]; |
187 | #endif | 187 | #endif |
188 | cred = rpc_lookup_machine_cred(); | 188 | cred = rpc_lookup_machine_cred("*"); |
189 | if (!IS_ERR(cred)) | 189 | if (!IS_ERR(cred)) |
190 | clp->cl_machine_cred = cred; | 190 | clp->cl_machine_cred = cred; |
191 | nfs_fscache_get_client_cookie(clp); | 191 | nfs_fscache_get_client_cookie(clp); |
@@ -250,6 +250,11 @@ static void pnfs_init_server(struct nfs_server *server) | |||
250 | rpc_init_wait_queue(&server->roc_rpcwaitq, "pNFS ROC"); | 250 | rpc_init_wait_queue(&server->roc_rpcwaitq, "pNFS ROC"); |
251 | } | 251 | } |
252 | 252 | ||
253 | static void nfs4_destroy_server(struct nfs_server *server) | ||
254 | { | ||
255 | nfs4_purge_state_owners(server); | ||
256 | } | ||
257 | |||
253 | #else | 258 | #else |
254 | static void nfs4_shutdown_client(struct nfs_client *clp) | 259 | static void nfs4_shutdown_client(struct nfs_client *clp) |
255 | { | 260 | { |
@@ -1065,6 +1070,7 @@ static struct nfs_server *nfs_alloc_server(void) | |||
1065 | INIT_LIST_HEAD(&server->master_link); | 1070 | INIT_LIST_HEAD(&server->master_link); |
1066 | INIT_LIST_HEAD(&server->delegations); | 1071 | INIT_LIST_HEAD(&server->delegations); |
1067 | INIT_LIST_HEAD(&server->layouts); | 1072 | INIT_LIST_HEAD(&server->layouts); |
1073 | INIT_LIST_HEAD(&server->state_owners_lru); | ||
1068 | 1074 | ||
1069 | atomic_set(&server->active, 0); | 1075 | atomic_set(&server->active, 0); |
1070 | 1076 | ||
@@ -1538,6 +1544,7 @@ static int nfs4_server_common_setup(struct nfs_server *server, | |||
1538 | 1544 | ||
1539 | nfs_server_insert_lists(server); | 1545 | nfs_server_insert_lists(server); |
1540 | server->mount_time = jiffies; | 1546 | server->mount_time = jiffies; |
1547 | server->destroy = nfs4_destroy_server; | ||
1541 | out: | 1548 | out: |
1542 | nfs_free_fattr(fattr); | 1549 | nfs_free_fattr(fattr); |
1543 | return error; | 1550 | return error; |
@@ -1719,6 +1726,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
1719 | 1726 | ||
1720 | /* Copy data from the source */ | 1727 | /* Copy data from the source */ |
1721 | server->nfs_client = source->nfs_client; | 1728 | server->nfs_client = source->nfs_client; |
1729 | server->destroy = source->destroy; | ||
1722 | atomic_inc(&server->nfs_client->cl_count); | 1730 | atomic_inc(&server->nfs_client->cl_count); |
1723 | nfs_server_copy_userdata(server, source); | 1731 | nfs_server_copy_userdata(server, source); |
1724 | 1732 | ||
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 606ef0f20aed..c43a452f7da2 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -272,13 +272,13 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) | |||
272 | datasync); | 272 | datasync); |
273 | 273 | ||
274 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | 274 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); |
275 | if (ret) | ||
276 | return ret; | ||
277 | mutex_lock(&inode->i_mutex); | 275 | mutex_lock(&inode->i_mutex); |
278 | 276 | ||
279 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); | 277 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); |
280 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | 278 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); |
281 | status = nfs_commit_inode(inode, FLUSH_SYNC); | 279 | status = nfs_commit_inode(inode, FLUSH_SYNC); |
280 | if (status >= 0 && ret < 0) | ||
281 | status = ret; | ||
282 | have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | 282 | have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); |
283 | if (have_error) | 283 | if (have_error) |
284 | ret = xchg(&ctx->error, 0); | 284 | ret = xchg(&ctx->error, 0); |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 47d1c6ff2d8e..2c05f1991e1e 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -38,6 +38,89 @@ | |||
38 | #include <linux/kernel.h> | 38 | #include <linux/kernel.h> |
39 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
40 | #include <linux/nfs_idmap.h> | 40 | #include <linux/nfs_idmap.h> |
41 | #include <linux/nfs_fs.h> | ||
42 | |||
43 | /** | ||
44 | * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields | ||
45 | * @fattr: fully initialised struct nfs_fattr | ||
46 | * @owner_name: owner name string cache | ||
47 | * @group_name: group name string cache | ||
48 | */ | ||
49 | void nfs_fattr_init_names(struct nfs_fattr *fattr, | ||
50 | struct nfs4_string *owner_name, | ||
51 | struct nfs4_string *group_name) | ||
52 | { | ||
53 | fattr->owner_name = owner_name; | ||
54 | fattr->group_name = group_name; | ||
55 | } | ||
56 | |||
57 | static void nfs_fattr_free_owner_name(struct nfs_fattr *fattr) | ||
58 | { | ||
59 | fattr->valid &= ~NFS_ATTR_FATTR_OWNER_NAME; | ||
60 | kfree(fattr->owner_name->data); | ||
61 | } | ||
62 | |||
63 | static void nfs_fattr_free_group_name(struct nfs_fattr *fattr) | ||
64 | { | ||
65 | fattr->valid &= ~NFS_ATTR_FATTR_GROUP_NAME; | ||
66 | kfree(fattr->group_name->data); | ||
67 | } | ||
68 | |||
69 | static bool nfs_fattr_map_owner_name(struct nfs_server *server, struct nfs_fattr *fattr) | ||
70 | { | ||
71 | struct nfs4_string *owner = fattr->owner_name; | ||
72 | __u32 uid; | ||
73 | |||
74 | if (!(fattr->valid & NFS_ATTR_FATTR_OWNER_NAME)) | ||
75 | return false; | ||
76 | if (nfs_map_name_to_uid(server, owner->data, owner->len, &uid) == 0) { | ||
77 | fattr->uid = uid; | ||
78 | fattr->valid |= NFS_ATTR_FATTR_OWNER; | ||
79 | } | ||
80 | return true; | ||
81 | } | ||
82 | |||
83 | static bool nfs_fattr_map_group_name(struct nfs_server *server, struct nfs_fattr *fattr) | ||
84 | { | ||
85 | struct nfs4_string *group = fattr->group_name; | ||
86 | __u32 gid; | ||
87 | |||
88 | if (!(fattr->valid & NFS_ATTR_FATTR_GROUP_NAME)) | ||
89 | return false; | ||
90 | if (nfs_map_group_to_gid(server, group->data, group->len, &gid) == 0) { | ||
91 | fattr->gid = gid; | ||
92 | fattr->valid |= NFS_ATTR_FATTR_GROUP; | ||
93 | } | ||
94 | return true; | ||
95 | } | ||
96 | |||
97 | /** | ||
98 | * nfs_fattr_free_names - free up the NFSv4 owner and group strings | ||
99 | * @fattr: a fully initialised nfs_fattr structure | ||
100 | */ | ||
101 | void nfs_fattr_free_names(struct nfs_fattr *fattr) | ||
102 | { | ||
103 | if (fattr->valid & NFS_ATTR_FATTR_OWNER_NAME) | ||
104 | nfs_fattr_free_owner_name(fattr); | ||
105 | if (fattr->valid & NFS_ATTR_FATTR_GROUP_NAME) | ||
106 | nfs_fattr_free_group_name(fattr); | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * nfs_fattr_map_and_free_names - map owner/group strings into uid/gid and free | ||
111 | * @server: pointer to the filesystem nfs_server structure | ||
112 | * @fattr: a fully initialised nfs_fattr structure | ||
113 | * | ||
114 | * This helper maps the cached NFSv4 owner/group strings in fattr into | ||
115 | * their numeric uid/gid equivalents, and then frees the cached strings. | ||
116 | */ | ||
117 | void nfs_fattr_map_and_free_names(struct nfs_server *server, struct nfs_fattr *fattr) | ||
118 | { | ||
119 | if (nfs_fattr_map_owner_name(server, fattr)) | ||
120 | nfs_fattr_free_owner_name(fattr); | ||
121 | if (nfs_fattr_map_group_name(server, fattr)) | ||
122 | nfs_fattr_free_group_name(fattr); | ||
123 | } | ||
41 | 124 | ||
42 | static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res) | 125 | static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res) |
43 | { | 126 | { |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 81db25e92e10..25c3bfad7953 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -1020,6 +1020,8 @@ void nfs_fattr_init(struct nfs_fattr *fattr) | |||
1020 | fattr->valid = 0; | 1020 | fattr->valid = 0; |
1021 | fattr->time_start = jiffies; | 1021 | fattr->time_start = jiffies; |
1022 | fattr->gencount = nfs_inc_attr_generation_counter(); | 1022 | fattr->gencount = nfs_inc_attr_generation_counter(); |
1023 | fattr->owner_name = NULL; | ||
1024 | fattr->group_name = NULL; | ||
1023 | } | 1025 | } |
1024 | 1026 | ||
1025 | struct nfs_fattr *nfs_alloc_fattr(void) | 1027 | struct nfs_fattr *nfs_alloc_fattr(void) |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 3f4d95751d52..5ee92538b063 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -307,6 +307,8 @@ extern void nfs_readdata_release(struct nfs_read_data *rdata); | |||
307 | /* write.c */ | 307 | /* write.c */ |
308 | extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc, | 308 | extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc, |
309 | struct list_head *head); | 309 | struct list_head *head); |
310 | extern void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio, | ||
311 | struct inode *inode, int ioflags); | ||
310 | extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio); | 312 | extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio); |
311 | extern void nfs_writedata_release(struct nfs_write_data *wdata); | 313 | extern void nfs_writedata_release(struct nfs_write_data *wdata); |
312 | extern void nfs_commit_free(struct nfs_write_data *p); | 314 | extern void nfs_commit_free(struct nfs_write_data *p); |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 693ae22f8731..4d7d0aedc101 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -94,6 +94,8 @@ struct nfs_unique_id { | |||
94 | struct nfs4_state_owner { | 94 | struct nfs4_state_owner { |
95 | struct nfs_unique_id so_owner_id; | 95 | struct nfs_unique_id so_owner_id; |
96 | struct nfs_server *so_server; | 96 | struct nfs_server *so_server; |
97 | struct list_head so_lru; | ||
98 | unsigned long so_expires; | ||
97 | struct rb_node so_server_node; | 99 | struct rb_node so_server_node; |
98 | 100 | ||
99 | struct rpc_cred *so_cred; /* Associated cred */ | 101 | struct rpc_cred *so_cred; /* Associated cred */ |
@@ -319,6 +321,7 @@ static inline void nfs4_schedule_session_recovery(struct nfs4_session *session) | |||
319 | 321 | ||
320 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | 322 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); |
321 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | 323 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); |
324 | extern void nfs4_purge_state_owners(struct nfs_server *); | ||
322 | extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); | 325 | extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); |
323 | extern void nfs4_put_open_state(struct nfs4_state *); | 326 | extern void nfs4_put_open_state(struct nfs4_state *); |
324 | extern void nfs4_close_state(struct nfs4_state *, fmode_t); | 327 | extern void nfs4_close_state(struct nfs4_state *, fmode_t); |
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index a62d36b9a99e..71ec08617e23 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -49,13 +49,14 @@ filelayout_get_dense_offset(struct nfs4_filelayout_segment *flseg, | |||
49 | loff_t offset) | 49 | loff_t offset) |
50 | { | 50 | { |
51 | u32 stripe_width = flseg->stripe_unit * flseg->dsaddr->stripe_count; | 51 | u32 stripe_width = flseg->stripe_unit * flseg->dsaddr->stripe_count; |
52 | u64 tmp; | 52 | u64 stripe_no; |
53 | u32 rem; | ||
53 | 54 | ||
54 | offset -= flseg->pattern_offset; | 55 | offset -= flseg->pattern_offset; |
55 | tmp = offset; | 56 | stripe_no = div_u64(offset, stripe_width); |
56 | do_div(tmp, stripe_width); | 57 | div_u64_rem(offset, flseg->stripe_unit, &rem); |
57 | 58 | ||
58 | return tmp * flseg->stripe_unit + do_div(offset, flseg->stripe_unit); | 59 | return stripe_no * flseg->stripe_unit + rem; |
59 | } | 60 | } |
60 | 61 | ||
61 | /* This function is used by the layout driver to calculate the | 62 | /* This function is used by the layout driver to calculate the |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index dcda0ba7af60..75366dc89686 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #include <linux/namei.h> | 52 | #include <linux/namei.h> |
53 | #include <linux/mount.h> | 53 | #include <linux/mount.h> |
54 | #include <linux/module.h> | 54 | #include <linux/module.h> |
55 | #include <linux/nfs_idmap.h> | ||
55 | #include <linux/sunrpc/bc_xprt.h> | 56 | #include <linux/sunrpc/bc_xprt.h> |
56 | #include <linux/xattr.h> | 57 | #include <linux/xattr.h> |
57 | #include <linux/utsname.h> | 58 | #include <linux/utsname.h> |
@@ -364,9 +365,8 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
364 | * Must be called while holding tbl->slot_tbl_lock | 365 | * Must be called while holding tbl->slot_tbl_lock |
365 | */ | 366 | */ |
366 | static void | 367 | static void |
367 | nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *free_slot) | 368 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) |
368 | { | 369 | { |
369 | int free_slotid = free_slot - tbl->slots; | ||
370 | int slotid = free_slotid; | 370 | int slotid = free_slotid; |
371 | 371 | ||
372 | BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE); | 372 | BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE); |
@@ -431,7 +431,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) | |||
431 | } | 431 | } |
432 | 432 | ||
433 | spin_lock(&tbl->slot_tbl_lock); | 433 | spin_lock(&tbl->slot_tbl_lock); |
434 | nfs4_free_slot(tbl, res->sr_slot); | 434 | nfs4_free_slot(tbl, res->sr_slot - tbl->slots); |
435 | nfs4_check_drain_fc_complete(res->sr_session); | 435 | nfs4_check_drain_fc_complete(res->sr_session); |
436 | spin_unlock(&tbl->slot_tbl_lock); | 436 | spin_unlock(&tbl->slot_tbl_lock); |
437 | res->sr_slot = NULL; | 437 | res->sr_slot = NULL; |
@@ -554,13 +554,10 @@ int nfs41_setup_sequence(struct nfs4_session *session, | |||
554 | spin_lock(&tbl->slot_tbl_lock); | 554 | spin_lock(&tbl->slot_tbl_lock); |
555 | if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) && | 555 | if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) && |
556 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { | 556 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { |
557 | /* | 557 | /* The state manager will wait until the slot table is empty */ |
558 | * The state manager will wait until the slot table is empty. | ||
559 | * Schedule the reset thread | ||
560 | */ | ||
561 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | 558 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); |
562 | spin_unlock(&tbl->slot_tbl_lock); | 559 | spin_unlock(&tbl->slot_tbl_lock); |
563 | dprintk("%s Schedule Session Reset\n", __func__); | 560 | dprintk("%s session is draining\n", __func__); |
564 | return -EAGAIN; | 561 | return -EAGAIN; |
565 | } | 562 | } |
566 | 563 | ||
@@ -765,6 +762,8 @@ struct nfs4_opendata { | |||
765 | struct nfs_openres o_res; | 762 | struct nfs_openres o_res; |
766 | struct nfs_open_confirmargs c_arg; | 763 | struct nfs_open_confirmargs c_arg; |
767 | struct nfs_open_confirmres c_res; | 764 | struct nfs_open_confirmres c_res; |
765 | struct nfs4_string owner_name; | ||
766 | struct nfs4_string group_name; | ||
768 | struct nfs_fattr f_attr; | 767 | struct nfs_fattr f_attr; |
769 | struct nfs_fattr dir_attr; | 768 | struct nfs_fattr dir_attr; |
770 | struct dentry *dir; | 769 | struct dentry *dir; |
@@ -788,6 +787,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
788 | p->o_res.server = p->o_arg.server; | 787 | p->o_res.server = p->o_arg.server; |
789 | nfs_fattr_init(&p->f_attr); | 788 | nfs_fattr_init(&p->f_attr); |
790 | nfs_fattr_init(&p->dir_attr); | 789 | nfs_fattr_init(&p->dir_attr); |
790 | nfs_fattr_init_names(&p->f_attr, &p->owner_name, &p->group_name); | ||
791 | } | 791 | } |
792 | 792 | ||
793 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | 793 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, |
@@ -819,6 +819,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
819 | p->o_arg.name = &dentry->d_name; | 819 | p->o_arg.name = &dentry->d_name; |
820 | p->o_arg.server = server; | 820 | p->o_arg.server = server; |
821 | p->o_arg.bitmask = server->attr_bitmask; | 821 | p->o_arg.bitmask = server->attr_bitmask; |
822 | p->o_arg.dir_bitmask = server->cache_consistency_bitmask; | ||
822 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 823 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
823 | if (flags & O_CREAT) { | 824 | if (flags & O_CREAT) { |
824 | u32 *s; | 825 | u32 *s; |
@@ -855,6 +856,7 @@ static void nfs4_opendata_free(struct kref *kref) | |||
855 | dput(p->dir); | 856 | dput(p->dir); |
856 | dput(p->dentry); | 857 | dput(p->dentry); |
857 | nfs_sb_deactive(sb); | 858 | nfs_sb_deactive(sb); |
859 | nfs_fattr_free_names(&p->f_attr); | ||
858 | kfree(p); | 860 | kfree(p); |
859 | } | 861 | } |
860 | 862 | ||
@@ -1579,6 +1581,8 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data) | |||
1579 | if (status != 0 || !data->rpc_done) | 1581 | if (status != 0 || !data->rpc_done) |
1580 | return status; | 1582 | return status; |
1581 | 1583 | ||
1584 | nfs_fattr_map_and_free_names(NFS_SERVER(dir), &data->f_attr); | ||
1585 | |||
1582 | nfs_refresh_inode(dir, o_res->dir_attr); | 1586 | nfs_refresh_inode(dir, o_res->dir_attr); |
1583 | 1587 | ||
1584 | if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | 1588 | if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { |
@@ -1611,6 +1615,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
1611 | return status; | 1615 | return status; |
1612 | } | 1616 | } |
1613 | 1617 | ||
1618 | nfs_fattr_map_and_free_names(server, &data->f_attr); | ||
1619 | |||
1614 | if (o_arg->open_flags & O_CREAT) { | 1620 | if (o_arg->open_flags & O_CREAT) { |
1615 | update_changeattr(dir, &o_res->cinfo); | 1621 | update_changeattr(dir, &o_res->cinfo); |
1616 | nfs_post_op_update_inode(dir, o_res->dir_attr); | 1622 | nfs_post_op_update_inode(dir, o_res->dir_attr); |
@@ -3431,19 +3437,6 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server) | |||
3431 | */ | 3437 | */ |
3432 | #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) | 3438 | #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) |
3433 | 3439 | ||
3434 | static void buf_to_pages(const void *buf, size_t buflen, | ||
3435 | struct page **pages, unsigned int *pgbase) | ||
3436 | { | ||
3437 | const void *p = buf; | ||
3438 | |||
3439 | *pgbase = offset_in_page(buf); | ||
3440 | p -= *pgbase; | ||
3441 | while (p < buf + buflen) { | ||
3442 | *(pages++) = virt_to_page(p); | ||
3443 | p += PAGE_CACHE_SIZE; | ||
3444 | } | ||
3445 | } | ||
3446 | |||
3447 | static int buf_to_pages_noslab(const void *buf, size_t buflen, | 3440 | static int buf_to_pages_noslab(const void *buf, size_t buflen, |
3448 | struct page **pages, unsigned int *pgbase) | 3441 | struct page **pages, unsigned int *pgbase) |
3449 | { | 3442 | { |
@@ -3540,9 +3533,19 @@ out: | |||
3540 | nfs4_set_cached_acl(inode, acl); | 3533 | nfs4_set_cached_acl(inode, acl); |
3541 | } | 3534 | } |
3542 | 3535 | ||
3536 | /* | ||
3537 | * The getxattr API returns the required buffer length when called with a | ||
3538 | * NULL buf. The NFSv4 acl tool then calls getxattr again after allocating | ||
3539 | * the required buf. On a NULL buf, we send a page of data to the server | ||
3540 | * guessing that the ACL request can be serviced by a page. If so, we cache | ||
3541 | * up to the page of ACL data, and the 2nd call to getxattr is serviced by | ||
3542 | * the cache. If not so, we throw away the page, and cache the required | ||
3543 | * length. The next getxattr call will then produce another round trip to | ||
3544 | * the server, this time with the input buf of the required size. | ||
3545 | */ | ||
3543 | static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) | 3546 | static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) |
3544 | { | 3547 | { |
3545 | struct page *pages[NFS4ACL_MAXPAGES]; | 3548 | struct page *pages[NFS4ACL_MAXPAGES] = {NULL, }; |
3546 | struct nfs_getaclargs args = { | 3549 | struct nfs_getaclargs args = { |
3547 | .fh = NFS_FH(inode), | 3550 | .fh = NFS_FH(inode), |
3548 | .acl_pages = pages, | 3551 | .acl_pages = pages, |
@@ -3557,41 +3560,60 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3557 | .rpc_argp = &args, | 3560 | .rpc_argp = &args, |
3558 | .rpc_resp = &res, | 3561 | .rpc_resp = &res, |
3559 | }; | 3562 | }; |
3560 | struct page *localpage = NULL; | 3563 | int ret = -ENOMEM, npages, i, acl_len = 0; |
3561 | int ret; | ||
3562 | 3564 | ||
3563 | if (buflen < PAGE_SIZE) { | 3565 | npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT; |
3564 | /* As long as we're doing a round trip to the server anyway, | 3566 | /* As long as we're doing a round trip to the server anyway, |
3565 | * let's be prepared for a page of acl data. */ | 3567 | * let's be prepared for a page of acl data. */ |
3566 | localpage = alloc_page(GFP_KERNEL); | 3568 | if (npages == 0) |
3567 | resp_buf = page_address(localpage); | 3569 | npages = 1; |
3568 | if (localpage == NULL) | 3570 | |
3569 | return -ENOMEM; | 3571 | for (i = 0; i < npages; i++) { |
3570 | args.acl_pages[0] = localpage; | 3572 | pages[i] = alloc_page(GFP_KERNEL); |
3571 | args.acl_pgbase = 0; | 3573 | if (!pages[i]) |
3572 | args.acl_len = PAGE_SIZE; | 3574 | goto out_free; |
3573 | } else { | ||
3574 | resp_buf = buf; | ||
3575 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | ||
3576 | } | 3575 | } |
3577 | ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0); | 3576 | if (npages > 1) { |
3577 | /* for decoding across pages */ | ||
3578 | args.acl_scratch = alloc_page(GFP_KERNEL); | ||
3579 | if (!args.acl_scratch) | ||
3580 | goto out_free; | ||
3581 | } | ||
3582 | args.acl_len = npages * PAGE_SIZE; | ||
3583 | args.acl_pgbase = 0; | ||
3584 | /* Let decode_getfacl know not to fail if the ACL data is larger than | ||
3585 | * the page we send as a guess */ | ||
3586 | if (buf == NULL) | ||
3587 | res.acl_flags |= NFS4_ACL_LEN_REQUEST; | ||
3588 | resp_buf = page_address(pages[0]); | ||
3589 | |||
3590 | dprintk("%s buf %p buflen %ld npages %d args.acl_len %ld\n", | ||
3591 | __func__, buf, buflen, npages, args.acl_len); | ||
3592 | ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), | ||
3593 | &msg, &args.seq_args, &res.seq_res, 0); | ||
3578 | if (ret) | 3594 | if (ret) |
3579 | goto out_free; | 3595 | goto out_free; |
3580 | if (res.acl_len > args.acl_len) | 3596 | |
3581 | nfs4_write_cached_acl(inode, NULL, res.acl_len); | 3597 | acl_len = res.acl_len - res.acl_data_offset; |
3598 | if (acl_len > args.acl_len) | ||
3599 | nfs4_write_cached_acl(inode, NULL, acl_len); | ||
3582 | else | 3600 | else |
3583 | nfs4_write_cached_acl(inode, resp_buf, res.acl_len); | 3601 | nfs4_write_cached_acl(inode, resp_buf + res.acl_data_offset, |
3602 | acl_len); | ||
3584 | if (buf) { | 3603 | if (buf) { |
3585 | ret = -ERANGE; | 3604 | ret = -ERANGE; |
3586 | if (res.acl_len > buflen) | 3605 | if (acl_len > buflen) |
3587 | goto out_free; | 3606 | goto out_free; |
3588 | if (localpage) | 3607 | _copy_from_pages(buf, pages, res.acl_data_offset, |
3589 | memcpy(buf, resp_buf, res.acl_len); | 3608 | res.acl_len); |
3590 | } | 3609 | } |
3591 | ret = res.acl_len; | 3610 | ret = acl_len; |
3592 | out_free: | 3611 | out_free: |
3593 | if (localpage) | 3612 | for (i = 0; i < npages; i++) |
3594 | __free_page(localpage); | 3613 | if (pages[i]) |
3614 | __free_page(pages[i]); | ||
3615 | if (args.acl_scratch) | ||
3616 | __free_page(args.acl_scratch); | ||
3595 | return ret; | 3617 | return ret; |
3596 | } | 3618 | } |
3597 | 3619 | ||
@@ -3622,6 +3644,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | |||
3622 | nfs_zap_acl_cache(inode); | 3644 | nfs_zap_acl_cache(inode); |
3623 | ret = nfs4_read_cached_acl(inode, buf, buflen); | 3645 | ret = nfs4_read_cached_acl(inode, buf, buflen); |
3624 | if (ret != -ENOENT) | 3646 | if (ret != -ENOENT) |
3647 | /* -ENOENT is returned if there is no ACL or if there is an ACL | ||
3648 | * but no cached acl data, just the acl length */ | ||
3625 | return ret; | 3649 | return ret; |
3626 | return nfs4_get_acl_uncached(inode, buf, buflen); | 3650 | return nfs4_get_acl_uncached(inode, buf, buflen); |
3627 | } | 3651 | } |
@@ -5022,23 +5046,6 @@ out: | |||
5022 | return ret; | 5046 | return ret; |
5023 | } | 5047 | } |
5024 | 5048 | ||
5025 | /* | ||
5026 | * Reset the forechannel and backchannel slot tables | ||
5027 | */ | ||
5028 | static int nfs4_reset_slot_tables(struct nfs4_session *session) | ||
5029 | { | ||
5030 | int status; | ||
5031 | |||
5032 | status = nfs4_reset_slot_table(&session->fc_slot_table, | ||
5033 | session->fc_attrs.max_reqs, 1); | ||
5034 | if (status) | ||
5035 | return status; | ||
5036 | |||
5037 | status = nfs4_reset_slot_table(&session->bc_slot_table, | ||
5038 | session->bc_attrs.max_reqs, 0); | ||
5039 | return status; | ||
5040 | } | ||
5041 | |||
5042 | /* Destroy the slot table */ | 5049 | /* Destroy the slot table */ |
5043 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) | 5050 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) |
5044 | { | 5051 | { |
@@ -5084,29 +5091,35 @@ out: | |||
5084 | } | 5091 | } |
5085 | 5092 | ||
5086 | /* | 5093 | /* |
5087 | * Initialize the forechannel and backchannel tables | 5094 | * Initialize or reset the forechannel and backchannel tables |
5088 | */ | 5095 | */ |
5089 | static int nfs4_init_slot_tables(struct nfs4_session *session) | 5096 | static int nfs4_setup_session_slot_tables(struct nfs4_session *ses) |
5090 | { | 5097 | { |
5091 | struct nfs4_slot_table *tbl; | 5098 | struct nfs4_slot_table *tbl; |
5092 | int status = 0; | 5099 | int status; |
5093 | 5100 | ||
5094 | tbl = &session->fc_slot_table; | 5101 | dprintk("--> %s\n", __func__); |
5102 | /* Fore channel */ | ||
5103 | tbl = &ses->fc_slot_table; | ||
5095 | if (tbl->slots == NULL) { | 5104 | if (tbl->slots == NULL) { |
5096 | status = nfs4_init_slot_table(tbl, | 5105 | status = nfs4_init_slot_table(tbl, ses->fc_attrs.max_reqs, 1); |
5097 | session->fc_attrs.max_reqs, 1); | 5106 | if (status) /* -ENOMEM */ |
5107 | return status; | ||
5108 | } else { | ||
5109 | status = nfs4_reset_slot_table(tbl, ses->fc_attrs.max_reqs, 1); | ||
5098 | if (status) | 5110 | if (status) |
5099 | return status; | 5111 | return status; |
5100 | } | 5112 | } |
5101 | 5113 | /* Back channel */ | |
5102 | tbl = &session->bc_slot_table; | 5114 | tbl = &ses->bc_slot_table; |
5103 | if (tbl->slots == NULL) { | 5115 | if (tbl->slots == NULL) { |
5104 | status = nfs4_init_slot_table(tbl, | 5116 | status = nfs4_init_slot_table(tbl, ses->bc_attrs.max_reqs, 0); |
5105 | session->bc_attrs.max_reqs, 0); | ||
5106 | if (status) | 5117 | if (status) |
5107 | nfs4_destroy_slot_tables(session); | 5118 | /* Fore and back channel share a connection so get |
5108 | } | 5119 | * both slot tables or neither */ |
5109 | 5120 | nfs4_destroy_slot_tables(ses); | |
5121 | } else | ||
5122 | status = nfs4_reset_slot_table(tbl, ses->bc_attrs.max_reqs, 0); | ||
5110 | return status; | 5123 | return status; |
5111 | } | 5124 | } |
5112 | 5125 | ||
@@ -5294,13 +5307,9 @@ int nfs4_proc_create_session(struct nfs_client *clp) | |||
5294 | if (status) | 5307 | if (status) |
5295 | goto out; | 5308 | goto out; |
5296 | 5309 | ||
5297 | /* Init and reset the fore channel */ | 5310 | /* Init or reset the session slot tables */ |
5298 | status = nfs4_init_slot_tables(session); | 5311 | status = nfs4_setup_session_slot_tables(session); |
5299 | dprintk("slot table initialization returned %d\n", status); | 5312 | dprintk("slot table setup returned %d\n", status); |
5300 | if (status) | ||
5301 | goto out; | ||
5302 | status = nfs4_reset_slot_tables(session); | ||
5303 | dprintk("slot table reset returned %d\n", status); | ||
5304 | if (status) | 5313 | if (status) |
5305 | goto out; | 5314 | goto out; |
5306 | 5315 | ||
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 6a7107ae6b72..a53f33b4ac3a 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <linux/ratelimit.h> | 49 | #include <linux/ratelimit.h> |
50 | #include <linux/workqueue.h> | 50 | #include <linux/workqueue.h> |
51 | #include <linux/bitops.h> | 51 | #include <linux/bitops.h> |
52 | #include <linux/jiffies.h> | ||
52 | 53 | ||
53 | #include "nfs4_fs.h" | 54 | #include "nfs4_fs.h" |
54 | #include "callback.h" | 55 | #include "callback.h" |
@@ -377,31 +378,24 @@ nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred) | |||
377 | { | 378 | { |
378 | struct rb_node **p = &server->state_owners.rb_node, | 379 | struct rb_node **p = &server->state_owners.rb_node, |
379 | *parent = NULL; | 380 | *parent = NULL; |
380 | struct nfs4_state_owner *sp, *res = NULL; | 381 | struct nfs4_state_owner *sp; |
381 | 382 | ||
382 | while (*p != NULL) { | 383 | while (*p != NULL) { |
383 | parent = *p; | 384 | parent = *p; |
384 | sp = rb_entry(parent, struct nfs4_state_owner, so_server_node); | 385 | sp = rb_entry(parent, struct nfs4_state_owner, so_server_node); |
385 | 386 | ||
386 | if (server < sp->so_server) { | ||
387 | p = &parent->rb_left; | ||
388 | continue; | ||
389 | } | ||
390 | if (server > sp->so_server) { | ||
391 | p = &parent->rb_right; | ||
392 | continue; | ||
393 | } | ||
394 | if (cred < sp->so_cred) | 387 | if (cred < sp->so_cred) |
395 | p = &parent->rb_left; | 388 | p = &parent->rb_left; |
396 | else if (cred > sp->so_cred) | 389 | else if (cred > sp->so_cred) |
397 | p = &parent->rb_right; | 390 | p = &parent->rb_right; |
398 | else { | 391 | else { |
392 | if (!list_empty(&sp->so_lru)) | ||
393 | list_del_init(&sp->so_lru); | ||
399 | atomic_inc(&sp->so_count); | 394 | atomic_inc(&sp->so_count); |
400 | res = sp; | 395 | return sp; |
401 | break; | ||
402 | } | 396 | } |
403 | } | 397 | } |
404 | return res; | 398 | return NULL; |
405 | } | 399 | } |
406 | 400 | ||
407 | static struct nfs4_state_owner * | 401 | static struct nfs4_state_owner * |
@@ -421,6 +415,8 @@ nfs4_insert_state_owner_locked(struct nfs4_state_owner *new) | |||
421 | else if (new->so_cred > sp->so_cred) | 415 | else if (new->so_cred > sp->so_cred) |
422 | p = &parent->rb_right; | 416 | p = &parent->rb_right; |
423 | else { | 417 | else { |
418 | if (!list_empty(&sp->so_lru)) | ||
419 | list_del_init(&sp->so_lru); | ||
424 | atomic_inc(&sp->so_count); | 420 | atomic_inc(&sp->so_count); |
425 | return sp; | 421 | return sp; |
426 | } | 422 | } |
@@ -462,6 +458,7 @@ nfs4_alloc_state_owner(void) | |||
462 | spin_lock_init(&sp->so_sequence.lock); | 458 | spin_lock_init(&sp->so_sequence.lock); |
463 | INIT_LIST_HEAD(&sp->so_sequence.list); | 459 | INIT_LIST_HEAD(&sp->so_sequence.list); |
464 | atomic_set(&sp->so_count, 1); | 460 | atomic_set(&sp->so_count, 1); |
461 | INIT_LIST_HEAD(&sp->so_lru); | ||
465 | return sp; | 462 | return sp; |
466 | } | 463 | } |
467 | 464 | ||
@@ -479,6 +476,38 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp) | |||
479 | } | 476 | } |
480 | } | 477 | } |
481 | 478 | ||
479 | static void nfs4_free_state_owner(struct nfs4_state_owner *sp) | ||
480 | { | ||
481 | rpc_destroy_wait_queue(&sp->so_sequence.wait); | ||
482 | put_rpccred(sp->so_cred); | ||
483 | kfree(sp); | ||
484 | } | ||
485 | |||
486 | static void nfs4_gc_state_owners(struct nfs_server *server) | ||
487 | { | ||
488 | struct nfs_client *clp = server->nfs_client; | ||
489 | struct nfs4_state_owner *sp, *tmp; | ||
490 | unsigned long time_min, time_max; | ||
491 | LIST_HEAD(doomed); | ||
492 | |||
493 | spin_lock(&clp->cl_lock); | ||
494 | time_max = jiffies; | ||
495 | time_min = (long)time_max - (long)clp->cl_lease_time; | ||
496 | list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) { | ||
497 | /* NB: LRU is sorted so that oldest is at the head */ | ||
498 | if (time_in_range(sp->so_expires, time_min, time_max)) | ||
499 | break; | ||
500 | list_move(&sp->so_lru, &doomed); | ||
501 | nfs4_remove_state_owner_locked(sp); | ||
502 | } | ||
503 | spin_unlock(&clp->cl_lock); | ||
504 | |||
505 | list_for_each_entry_safe(sp, tmp, &doomed, so_lru) { | ||
506 | list_del(&sp->so_lru); | ||
507 | nfs4_free_state_owner(sp); | ||
508 | } | ||
509 | } | ||
510 | |||
482 | /** | 511 | /** |
483 | * nfs4_get_state_owner - Look up a state owner given a credential | 512 | * nfs4_get_state_owner - Look up a state owner given a credential |
484 | * @server: nfs_server to search | 513 | * @server: nfs_server to search |
@@ -496,10 +525,10 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, | |||
496 | sp = nfs4_find_state_owner_locked(server, cred); | 525 | sp = nfs4_find_state_owner_locked(server, cred); |
497 | spin_unlock(&clp->cl_lock); | 526 | spin_unlock(&clp->cl_lock); |
498 | if (sp != NULL) | 527 | if (sp != NULL) |
499 | return sp; | 528 | goto out; |
500 | new = nfs4_alloc_state_owner(); | 529 | new = nfs4_alloc_state_owner(); |
501 | if (new == NULL) | 530 | if (new == NULL) |
502 | return NULL; | 531 | goto out; |
503 | new->so_server = server; | 532 | new->so_server = server; |
504 | new->so_cred = cred; | 533 | new->so_cred = cred; |
505 | spin_lock(&clp->cl_lock); | 534 | spin_lock(&clp->cl_lock); |
@@ -511,26 +540,58 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, | |||
511 | rpc_destroy_wait_queue(&new->so_sequence.wait); | 540 | rpc_destroy_wait_queue(&new->so_sequence.wait); |
512 | kfree(new); | 541 | kfree(new); |
513 | } | 542 | } |
543 | out: | ||
544 | nfs4_gc_state_owners(server); | ||
514 | return sp; | 545 | return sp; |
515 | } | 546 | } |
516 | 547 | ||
517 | /** | 548 | /** |
518 | * nfs4_put_state_owner - Release a nfs4_state_owner | 549 | * nfs4_put_state_owner - Release a nfs4_state_owner |
519 | * @sp: state owner data to release | 550 | * @sp: state owner data to release |
520 | * | ||
521 | */ | 551 | */ |
522 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) | 552 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) |
523 | { | 553 | { |
524 | struct nfs_client *clp = sp->so_server->nfs_client; | 554 | struct nfs_server *server = sp->so_server; |
525 | struct rpc_cred *cred = sp->so_cred; | 555 | struct nfs_client *clp = server->nfs_client; |
526 | 556 | ||
527 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) | 557 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) |
528 | return; | 558 | return; |
529 | nfs4_remove_state_owner_locked(sp); | 559 | |
560 | if (!RB_EMPTY_NODE(&sp->so_server_node)) { | ||
561 | sp->so_expires = jiffies; | ||
562 | list_add_tail(&sp->so_lru, &server->state_owners_lru); | ||
563 | spin_unlock(&clp->cl_lock); | ||
564 | } else { | ||
565 | nfs4_remove_state_owner_locked(sp); | ||
566 | spin_unlock(&clp->cl_lock); | ||
567 | nfs4_free_state_owner(sp); | ||
568 | } | ||
569 | } | ||
570 | |||
571 | /** | ||
572 | * nfs4_purge_state_owners - Release all cached state owners | ||
573 | * @server: nfs_server with cached state owners to release | ||
574 | * | ||
575 | * Called at umount time. Remaining state owners will be on | ||
576 | * the LRU with ref count of zero. | ||
577 | */ | ||
578 | void nfs4_purge_state_owners(struct nfs_server *server) | ||
579 | { | ||
580 | struct nfs_client *clp = server->nfs_client; | ||
581 | struct nfs4_state_owner *sp, *tmp; | ||
582 | LIST_HEAD(doomed); | ||
583 | |||
584 | spin_lock(&clp->cl_lock); | ||
585 | list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) { | ||
586 | list_move(&sp->so_lru, &doomed); | ||
587 | nfs4_remove_state_owner_locked(sp); | ||
588 | } | ||
530 | spin_unlock(&clp->cl_lock); | 589 | spin_unlock(&clp->cl_lock); |
531 | rpc_destroy_wait_queue(&sp->so_sequence.wait); | 590 | |
532 | put_rpccred(cred); | 591 | list_for_each_entry_safe(sp, tmp, &doomed, so_lru) { |
533 | kfree(sp); | 592 | list_del(&sp->so_lru); |
593 | nfs4_free_state_owner(sp); | ||
594 | } | ||
534 | } | 595 | } |
535 | 596 | ||
536 | static struct nfs4_state * | 597 | static struct nfs4_state * |
@@ -1402,6 +1463,7 @@ static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recov | |||
1402 | restart: | 1463 | restart: |
1403 | rcu_read_lock(); | 1464 | rcu_read_lock(); |
1404 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { | 1465 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { |
1466 | nfs4_purge_state_owners(server); | ||
1405 | spin_lock(&clp->cl_lock); | 1467 | spin_lock(&clp->cl_lock); |
1406 | for (pos = rb_first(&server->state_owners); | 1468 | for (pos = rb_first(&server->state_owners); |
1407 | pos != NULL; | 1469 | pos != NULL; |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index e6161b213ed1..95e92e438407 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -2298,7 +2298,7 @@ static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
2298 | encode_getfh(xdr, &hdr); | 2298 | encode_getfh(xdr, &hdr); |
2299 | encode_getfattr(xdr, args->bitmask, &hdr); | 2299 | encode_getfattr(xdr, args->bitmask, &hdr); |
2300 | encode_restorefh(xdr, &hdr); | 2300 | encode_restorefh(xdr, &hdr); |
2301 | encode_getfattr(xdr, args->bitmask, &hdr); | 2301 | encode_getfattr(xdr, args->dir_bitmask, &hdr); |
2302 | encode_nops(&hdr); | 2302 | encode_nops(&hdr); |
2303 | } | 2303 | } |
2304 | 2304 | ||
@@ -2517,11 +2517,13 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
2517 | encode_compound_hdr(xdr, req, &hdr); | 2517 | encode_compound_hdr(xdr, req, &hdr); |
2518 | encode_sequence(xdr, &args->seq_args, &hdr); | 2518 | encode_sequence(xdr, &args->seq_args, &hdr); |
2519 | encode_putfh(xdr, args->fh, &hdr); | 2519 | encode_putfh(xdr, args->fh, &hdr); |
2520 | replen = hdr.replen + op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz + 1; | 2520 | replen = hdr.replen + op_decode_hdr_maxsz + 1; |
2521 | encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr); | 2521 | encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr); |
2522 | 2522 | ||
2523 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, | 2523 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, |
2524 | args->acl_pages, args->acl_pgbase, args->acl_len); | 2524 | args->acl_pages, args->acl_pgbase, args->acl_len); |
2525 | xdr_set_scratch_buffer(xdr, page_address(args->acl_scratch), PAGE_SIZE); | ||
2526 | |||
2525 | encode_nops(&hdr); | 2527 | encode_nops(&hdr); |
2526 | } | 2528 | } |
2527 | 2529 | ||
@@ -3790,7 +3792,8 @@ out_overflow: | |||
3790 | } | 3792 | } |
3791 | 3793 | ||
3792 | static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, | 3794 | static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, |
3793 | const struct nfs_server *server, uint32_t *uid, int may_sleep) | 3795 | const struct nfs_server *server, uint32_t *uid, |
3796 | struct nfs4_string *owner_name) | ||
3794 | { | 3797 | { |
3795 | uint32_t len; | 3798 | uint32_t len; |
3796 | __be32 *p; | 3799 | __be32 *p; |
@@ -3807,8 +3810,12 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, | |||
3807 | p = xdr_inline_decode(xdr, len); | 3810 | p = xdr_inline_decode(xdr, len); |
3808 | if (unlikely(!p)) | 3811 | if (unlikely(!p)) |
3809 | goto out_overflow; | 3812 | goto out_overflow; |
3810 | if (!may_sleep) { | 3813 | if (owner_name != NULL) { |
3811 | /* do nothing */ | 3814 | owner_name->data = kmemdup(p, len, GFP_NOWAIT); |
3815 | if (owner_name->data != NULL) { | ||
3816 | owner_name->len = len; | ||
3817 | ret = NFS_ATTR_FATTR_OWNER_NAME; | ||
3818 | } | ||
3812 | } else if (len < XDR_MAX_NETOBJ) { | 3819 | } else if (len < XDR_MAX_NETOBJ) { |
3813 | if (nfs_map_name_to_uid(server, (char *)p, len, uid) == 0) | 3820 | if (nfs_map_name_to_uid(server, (char *)p, len, uid) == 0) |
3814 | ret = NFS_ATTR_FATTR_OWNER; | 3821 | ret = NFS_ATTR_FATTR_OWNER; |
@@ -3828,7 +3835,8 @@ out_overflow: | |||
3828 | } | 3835 | } |
3829 | 3836 | ||
3830 | static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, | 3837 | static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, |
3831 | const struct nfs_server *server, uint32_t *gid, int may_sleep) | 3838 | const struct nfs_server *server, uint32_t *gid, |
3839 | struct nfs4_string *group_name) | ||
3832 | { | 3840 | { |
3833 | uint32_t len; | 3841 | uint32_t len; |
3834 | __be32 *p; | 3842 | __be32 *p; |
@@ -3845,8 +3853,12 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, | |||
3845 | p = xdr_inline_decode(xdr, len); | 3853 | p = xdr_inline_decode(xdr, len); |
3846 | if (unlikely(!p)) | 3854 | if (unlikely(!p)) |
3847 | goto out_overflow; | 3855 | goto out_overflow; |
3848 | if (!may_sleep) { | 3856 | if (group_name != NULL) { |
3849 | /* do nothing */ | 3857 | group_name->data = kmemdup(p, len, GFP_NOWAIT); |
3858 | if (group_name->data != NULL) { | ||
3859 | group_name->len = len; | ||
3860 | ret = NFS_ATTR_FATTR_GROUP_NAME; | ||
3861 | } | ||
3850 | } else if (len < XDR_MAX_NETOBJ) { | 3862 | } else if (len < XDR_MAX_NETOBJ) { |
3851 | if (nfs_map_group_to_gid(server, (char *)p, len, gid) == 0) | 3863 | if (nfs_map_group_to_gid(server, (char *)p, len, gid) == 0) |
3852 | ret = NFS_ATTR_FATTR_GROUP; | 3864 | ret = NFS_ATTR_FATTR_GROUP; |
@@ -4283,7 +4295,7 @@ xdr_error: | |||
4283 | 4295 | ||
4284 | static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | 4296 | static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, |
4285 | struct nfs_fattr *fattr, struct nfs_fh *fh, | 4297 | struct nfs_fattr *fattr, struct nfs_fh *fh, |
4286 | const struct nfs_server *server, int may_sleep) | 4298 | const struct nfs_server *server) |
4287 | { | 4299 | { |
4288 | int status; | 4300 | int status; |
4289 | umode_t fmode = 0; | 4301 | umode_t fmode = 0; |
@@ -4350,12 +4362,12 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | |||
4350 | goto xdr_error; | 4362 | goto xdr_error; |
4351 | fattr->valid |= status; | 4363 | fattr->valid |= status; |
4352 | 4364 | ||
4353 | status = decode_attr_owner(xdr, bitmap, server, &fattr->uid, may_sleep); | 4365 | status = decode_attr_owner(xdr, bitmap, server, &fattr->uid, fattr->owner_name); |
4354 | if (status < 0) | 4366 | if (status < 0) |
4355 | goto xdr_error; | 4367 | goto xdr_error; |
4356 | fattr->valid |= status; | 4368 | fattr->valid |= status; |
4357 | 4369 | ||
4358 | status = decode_attr_group(xdr, bitmap, server, &fattr->gid, may_sleep); | 4370 | status = decode_attr_group(xdr, bitmap, server, &fattr->gid, fattr->group_name); |
4359 | if (status < 0) | 4371 | if (status < 0) |
4360 | goto xdr_error; | 4372 | goto xdr_error; |
4361 | fattr->valid |= status; | 4373 | fattr->valid |= status; |
@@ -4396,7 +4408,7 @@ xdr_error: | |||
4396 | } | 4408 | } |
4397 | 4409 | ||
4398 | static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr, | 4410 | static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr, |
4399 | struct nfs_fh *fh, const struct nfs_server *server, int may_sleep) | 4411 | struct nfs_fh *fh, const struct nfs_server *server) |
4400 | { | 4412 | { |
4401 | __be32 *savep; | 4413 | __be32 *savep; |
4402 | uint32_t attrlen, | 4414 | uint32_t attrlen, |
@@ -4415,7 +4427,7 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat | |||
4415 | if (status < 0) | 4427 | if (status < 0) |
4416 | goto xdr_error; | 4428 | goto xdr_error; |
4417 | 4429 | ||
4418 | status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server, may_sleep); | 4430 | status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server); |
4419 | if (status < 0) | 4431 | if (status < 0) |
4420 | goto xdr_error; | 4432 | goto xdr_error; |
4421 | 4433 | ||
@@ -4426,9 +4438,9 @@ xdr_error: | |||
4426 | } | 4438 | } |
4427 | 4439 | ||
4428 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, | 4440 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, |
4429 | const struct nfs_server *server, int may_sleep) | 4441 | const struct nfs_server *server) |
4430 | { | 4442 | { |
4431 | return decode_getfattr_generic(xdr, fattr, NULL, server, may_sleep); | 4443 | return decode_getfattr_generic(xdr, fattr, NULL, server); |
4432 | } | 4444 | } |
4433 | 4445 | ||
4434 | /* | 4446 | /* |
@@ -4957,17 +4969,18 @@ decode_restorefh(struct xdr_stream *xdr) | |||
4957 | } | 4969 | } |
4958 | 4970 | ||
4959 | static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | 4971 | static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, |
4960 | size_t *acl_len) | 4972 | struct nfs_getaclres *res) |
4961 | { | 4973 | { |
4962 | __be32 *savep; | 4974 | __be32 *savep, *bm_p; |
4963 | uint32_t attrlen, | 4975 | uint32_t attrlen, |
4964 | bitmap[3] = {0}; | 4976 | bitmap[3] = {0}; |
4965 | struct kvec *iov = req->rq_rcv_buf.head; | 4977 | struct kvec *iov = req->rq_rcv_buf.head; |
4966 | int status; | 4978 | int status; |
4967 | 4979 | ||
4968 | *acl_len = 0; | 4980 | res->acl_len = 0; |
4969 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) | 4981 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) |
4970 | goto out; | 4982 | goto out; |
4983 | bm_p = xdr->p; | ||
4971 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) | 4984 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) |
4972 | goto out; | 4985 | goto out; |
4973 | if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) | 4986 | if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) |
@@ -4979,18 +4992,30 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
4979 | size_t hdrlen; | 4992 | size_t hdrlen; |
4980 | u32 recvd; | 4993 | u32 recvd; |
4981 | 4994 | ||
4995 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words | ||
4996 | * are stored with the acl data to handle the problem of | ||
4997 | * variable length bitmaps.*/ | ||
4998 | xdr->p = bm_p; | ||
4999 | res->acl_data_offset = be32_to_cpup(bm_p) + 2; | ||
5000 | res->acl_data_offset <<= 2; | ||
5001 | |||
4982 | /* We ignore &savep and don't do consistency checks on | 5002 | /* We ignore &savep and don't do consistency checks on |
4983 | * the attr length. Let userspace figure it out.... */ | 5003 | * the attr length. Let userspace figure it out.... */ |
4984 | hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; | 5004 | hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; |
5005 | attrlen += res->acl_data_offset; | ||
4985 | recvd = req->rq_rcv_buf.len - hdrlen; | 5006 | recvd = req->rq_rcv_buf.len - hdrlen; |
4986 | if (attrlen > recvd) { | 5007 | if (attrlen > recvd) { |
4987 | dprintk("NFS: server cheating in getattr" | 5008 | if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { |
4988 | " acl reply: attrlen %u > recvd %u\n", | 5009 | /* getxattr interface called with a NULL buf */ |
5010 | res->acl_len = attrlen; | ||
5011 | goto out; | ||
5012 | } | ||
5013 | dprintk("NFS: acl reply: attrlen %u > recvd %u\n", | ||
4989 | attrlen, recvd); | 5014 | attrlen, recvd); |
4990 | return -EINVAL; | 5015 | return -EINVAL; |
4991 | } | 5016 | } |
4992 | xdr_read_pages(xdr, attrlen); | 5017 | xdr_read_pages(xdr, attrlen); |
4993 | *acl_len = attrlen; | 5018 | res->acl_len = attrlen; |
4994 | } else | 5019 | } else |
4995 | status = -EOPNOTSUPP; | 5020 | status = -EOPNOTSUPP; |
4996 | 5021 | ||
@@ -5696,8 +5721,7 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, | |||
5696 | status = decode_open_downgrade(xdr, res); | 5721 | status = decode_open_downgrade(xdr, res); |
5697 | if (status != 0) | 5722 | if (status != 0) |
5698 | goto out; | 5723 | goto out; |
5699 | decode_getfattr(xdr, res->fattr, res->server, | 5724 | decode_getfattr(xdr, res->fattr, res->server); |
5700 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5701 | out: | 5725 | out: |
5702 | return status; | 5726 | return status; |
5703 | } | 5727 | } |
@@ -5723,8 +5747,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
5723 | status = decode_access(xdr, res); | 5747 | status = decode_access(xdr, res); |
5724 | if (status != 0) | 5748 | if (status != 0) |
5725 | goto out; | 5749 | goto out; |
5726 | decode_getfattr(xdr, res->fattr, res->server, | 5750 | decode_getfattr(xdr, res->fattr, res->server); |
5727 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5728 | out: | 5751 | out: |
5729 | return status; | 5752 | return status; |
5730 | } | 5753 | } |
@@ -5753,8 +5776,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
5753 | status = decode_getfh(xdr, res->fh); | 5776 | status = decode_getfh(xdr, res->fh); |
5754 | if (status) | 5777 | if (status) |
5755 | goto out; | 5778 | goto out; |
5756 | status = decode_getfattr(xdr, res->fattr, res->server | 5779 | status = decode_getfattr(xdr, res->fattr, res->server); |
5757 | ,!RPC_IS_ASYNC(rqstp->rq_task)); | ||
5758 | out: | 5780 | out: |
5759 | return status; | 5781 | return status; |
5760 | } | 5782 | } |
@@ -5780,8 +5802,7 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, | |||
5780 | goto out; | 5802 | goto out; |
5781 | status = decode_getfh(xdr, res->fh); | 5803 | status = decode_getfh(xdr, res->fh); |
5782 | if (status == 0) | 5804 | if (status == 0) |
5783 | status = decode_getfattr(xdr, res->fattr, res->server, | 5805 | status = decode_getfattr(xdr, res->fattr, res->server); |
5784 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5785 | out: | 5806 | out: |
5786 | return status; | 5807 | return status; |
5787 | } | 5808 | } |
@@ -5807,8 +5828,7 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
5807 | status = decode_remove(xdr, &res->cinfo); | 5828 | status = decode_remove(xdr, &res->cinfo); |
5808 | if (status) | 5829 | if (status) |
5809 | goto out; | 5830 | goto out; |
5810 | decode_getfattr(xdr, res->dir_attr, res->server, | 5831 | decode_getfattr(xdr, res->dir_attr, res->server); |
5811 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5812 | out: | 5832 | out: |
5813 | return status; | 5833 | return status; |
5814 | } | 5834 | } |
@@ -5841,14 +5861,12 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
5841 | if (status) | 5861 | if (status) |
5842 | goto out; | 5862 | goto out; |
5843 | /* Current FH is target directory */ | 5863 | /* Current FH is target directory */ |
5844 | if (decode_getfattr(xdr, res->new_fattr, res->server, | 5864 | if (decode_getfattr(xdr, res->new_fattr, res->server)) |
5845 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
5846 | goto out; | 5865 | goto out; |
5847 | status = decode_restorefh(xdr); | 5866 | status = decode_restorefh(xdr); |
5848 | if (status) | 5867 | if (status) |
5849 | goto out; | 5868 | goto out; |
5850 | decode_getfattr(xdr, res->old_fattr, res->server, | 5869 | decode_getfattr(xdr, res->old_fattr, res->server); |
5851 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5852 | out: | 5870 | out: |
5853 | return status; | 5871 | return status; |
5854 | } | 5872 | } |
@@ -5884,14 +5902,12 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
5884 | * Note order: OP_LINK leaves the directory as the current | 5902 | * Note order: OP_LINK leaves the directory as the current |
5885 | * filehandle. | 5903 | * filehandle. |
5886 | */ | 5904 | */ |
5887 | if (decode_getfattr(xdr, res->dir_attr, res->server, | 5905 | if (decode_getfattr(xdr, res->dir_attr, res->server)) |
5888 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
5889 | goto out; | 5906 | goto out; |
5890 | status = decode_restorefh(xdr); | 5907 | status = decode_restorefh(xdr); |
5891 | if (status) | 5908 | if (status) |
5892 | goto out; | 5909 | goto out; |
5893 | decode_getfattr(xdr, res->fattr, res->server, | 5910 | decode_getfattr(xdr, res->fattr, res->server); |
5894 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5895 | out: | 5911 | out: |
5896 | return status; | 5912 | return status; |
5897 | } | 5913 | } |
@@ -5923,14 +5939,12 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
5923 | status = decode_getfh(xdr, res->fh); | 5939 | status = decode_getfh(xdr, res->fh); |
5924 | if (status) | 5940 | if (status) |
5925 | goto out; | 5941 | goto out; |
5926 | if (decode_getfattr(xdr, res->fattr, res->server, | 5942 | if (decode_getfattr(xdr, res->fattr, res->server)) |
5927 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
5928 | goto out; | 5943 | goto out; |
5929 | status = decode_restorefh(xdr); | 5944 | status = decode_restorefh(xdr); |
5930 | if (status) | 5945 | if (status) |
5931 | goto out; | 5946 | goto out; |
5932 | decode_getfattr(xdr, res->dir_fattr, res->server, | 5947 | decode_getfattr(xdr, res->dir_fattr, res->server); |
5933 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5934 | out: | 5948 | out: |
5935 | return status; | 5949 | return status; |
5936 | } | 5950 | } |
@@ -5962,8 +5976,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
5962 | status = decode_putfh(xdr); | 5976 | status = decode_putfh(xdr); |
5963 | if (status) | 5977 | if (status) |
5964 | goto out; | 5978 | goto out; |
5965 | status = decode_getfattr(xdr, res->fattr, res->server, | 5979 | status = decode_getfattr(xdr, res->fattr, res->server); |
5966 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5967 | out: | 5980 | out: |
5968 | return status; | 5981 | return status; |
5969 | } | 5982 | } |
@@ -6028,7 +6041,7 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
6028 | status = decode_putfh(xdr); | 6041 | status = decode_putfh(xdr); |
6029 | if (status) | 6042 | if (status) |
6030 | goto out; | 6043 | goto out; |
6031 | status = decode_getacl(xdr, rqstp, &res->acl_len); | 6044 | status = decode_getacl(xdr, rqstp, res); |
6032 | 6045 | ||
6033 | out: | 6046 | out: |
6034 | return status; | 6047 | return status; |
@@ -6061,8 +6074,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
6061 | * an ESTALE error. Shouldn't be a problem, | 6074 | * an ESTALE error. Shouldn't be a problem, |
6062 | * though, since fattr->valid will remain unset. | 6075 | * though, since fattr->valid will remain unset. |
6063 | */ | 6076 | */ |
6064 | decode_getfattr(xdr, res->fattr, res->server, | 6077 | decode_getfattr(xdr, res->fattr, res->server); |
6065 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
6066 | out: | 6078 | out: |
6067 | return status; | 6079 | return status; |
6068 | } | 6080 | } |
@@ -6093,13 +6105,11 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
6093 | goto out; | 6105 | goto out; |
6094 | if (decode_getfh(xdr, &res->fh) != 0) | 6106 | if (decode_getfh(xdr, &res->fh) != 0) |
6095 | goto out; | 6107 | goto out; |
6096 | if (decode_getfattr(xdr, res->f_attr, res->server, | 6108 | if (decode_getfattr(xdr, res->f_attr, res->server) != 0) |
6097 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
6098 | goto out; | 6109 | goto out; |
6099 | if (decode_restorefh(xdr) != 0) | 6110 | if (decode_restorefh(xdr) != 0) |
6100 | goto out; | 6111 | goto out; |
6101 | decode_getfattr(xdr, res->dir_attr, res->server, | 6112 | decode_getfattr(xdr, res->dir_attr, res->server); |
6102 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
6103 | out: | 6113 | out: |
6104 | return status; | 6114 | return status; |
6105 | } | 6115 | } |
@@ -6147,8 +6157,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, | |||
6147 | status = decode_open(xdr, res); | 6157 | status = decode_open(xdr, res); |
6148 | if (status) | 6158 | if (status) |
6149 | goto out; | 6159 | goto out; |
6150 | decode_getfattr(xdr, res->f_attr, res->server, | 6160 | decode_getfattr(xdr, res->f_attr, res->server); |
6151 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
6152 | out: | 6161 | out: |
6153 | return status; | 6162 | return status; |
6154 | } | 6163 | } |
@@ -6175,8 +6184,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, | |||
6175 | status = decode_setattr(xdr); | 6184 | status = decode_setattr(xdr); |
6176 | if (status) | 6185 | if (status) |
6177 | goto out; | 6186 | goto out; |
6178 | decode_getfattr(xdr, res->fattr, res->server, | 6187 | decode_getfattr(xdr, res->fattr, res->server); |
6179 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
6180 | out: | 6188 | out: |
6181 | return status; | 6189 | return status; |
6182 | } | 6190 | } |
@@ -6356,8 +6364,7 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
6356 | if (status) | 6364 | if (status) |
6357 | goto out; | 6365 | goto out; |
6358 | if (res->fattr) | 6366 | if (res->fattr) |
6359 | decode_getfattr(xdr, res->fattr, res->server, | 6367 | decode_getfattr(xdr, res->fattr, res->server); |
6360 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
6361 | if (!status) | 6368 | if (!status) |
6362 | status = res->count; | 6369 | status = res->count; |
6363 | out: | 6370 | out: |
@@ -6386,8 +6393,7 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
6386 | if (status) | 6393 | if (status) |
6387 | goto out; | 6394 | goto out; |
6388 | if (res->fattr) | 6395 | if (res->fattr) |
6389 | decode_getfattr(xdr, res->fattr, res->server, | 6396 | decode_getfattr(xdr, res->fattr, res->server); |
6390 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
6391 | out: | 6397 | out: |
6392 | return status; | 6398 | return status; |
6393 | } | 6399 | } |
@@ -6546,8 +6552,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, | |||
6546 | status = decode_delegreturn(xdr); | 6552 | status = decode_delegreturn(xdr); |
6547 | if (status != 0) | 6553 | if (status != 0) |
6548 | goto out; | 6554 | goto out; |
6549 | decode_getfattr(xdr, res->fattr, res->server, | 6555 | decode_getfattr(xdr, res->fattr, res->server); |
6550 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
6551 | out: | 6556 | out: |
6552 | return status; | 6557 | return status; |
6553 | } | 6558 | } |
@@ -6576,8 +6581,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, | |||
6576 | goto out; | 6581 | goto out; |
6577 | xdr_enter_page(xdr, PAGE_SIZE); | 6582 | xdr_enter_page(xdr, PAGE_SIZE); |
6578 | status = decode_getfattr(xdr, &res->fs_locations->fattr, | 6583 | status = decode_getfattr(xdr, &res->fs_locations->fattr, |
6579 | res->fs_locations->server, | 6584 | res->fs_locations->server); |
6580 | !RPC_IS_ASYNC(req->rq_task)); | ||
6581 | out: | 6585 | out: |
6582 | return status; | 6586 | return status; |
6583 | } | 6587 | } |
@@ -6826,8 +6830,7 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp, | |||
6826 | status = decode_layoutcommit(xdr, rqstp, res); | 6830 | status = decode_layoutcommit(xdr, rqstp, res); |
6827 | if (status) | 6831 | if (status) |
6828 | goto out; | 6832 | goto out; |
6829 | decode_getfattr(xdr, res->fattr, res->server, | 6833 | decode_getfattr(xdr, res->fattr, res->server); |
6830 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
6831 | out: | 6834 | out: |
6832 | return status; | 6835 | return status; |
6833 | } | 6836 | } |
@@ -6958,7 +6961,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |||
6958 | goto out_overflow; | 6961 | goto out_overflow; |
6959 | 6962 | ||
6960 | if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, | 6963 | if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, |
6961 | entry->server, 1) < 0) | 6964 | entry->server) < 0) |
6962 | goto out_overflow; | 6965 | goto out_overflow; |
6963 | if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) | 6966 | if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) |
6964 | entry->ino = entry->fattr->mounted_on_fileid; | 6967 | entry->ino = entry->fattr->mounted_on_fileid; |
diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c index c807ab93140e..55d01280a609 100644 --- a/fs/nfs/objlayout/objio_osd.c +++ b/fs/nfs/objlayout/objio_osd.c | |||
@@ -551,7 +551,8 @@ static const struct nfs_pageio_ops objio_pg_write_ops = { | |||
551 | static struct pnfs_layoutdriver_type objlayout_type = { | 551 | static struct pnfs_layoutdriver_type objlayout_type = { |
552 | .id = LAYOUT_OSD2_OBJECTS, | 552 | .id = LAYOUT_OSD2_OBJECTS, |
553 | .name = "LAYOUT_OSD2_OBJECTS", | 553 | .name = "LAYOUT_OSD2_OBJECTS", |
554 | .flags = PNFS_LAYOUTRET_ON_SETATTR, | 554 | .flags = PNFS_LAYOUTRET_ON_SETATTR | |
555 | PNFS_LAYOUTRET_ON_ERROR, | ||
555 | 556 | ||
556 | .alloc_layout_hdr = objlayout_alloc_layout_hdr, | 557 | .alloc_layout_hdr = objlayout_alloc_layout_hdr, |
557 | .free_layout_hdr = objlayout_free_layout_hdr, | 558 | .free_layout_hdr = objlayout_free_layout_hdr, |
diff --git a/fs/nfs/objlayout/objlayout.c b/fs/nfs/objlayout/objlayout.c index 72074e3a04f9..b3c29039f5b8 100644 --- a/fs/nfs/objlayout/objlayout.c +++ b/fs/nfs/objlayout/objlayout.c | |||
@@ -254,6 +254,8 @@ objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync) | |||
254 | oir->status = rdata->task.tk_status = status; | 254 | oir->status = rdata->task.tk_status = status; |
255 | if (status >= 0) | 255 | if (status >= 0) |
256 | rdata->res.count = status; | 256 | rdata->res.count = status; |
257 | else | ||
258 | rdata->pnfs_error = status; | ||
257 | objlayout_iodone(oir); | 259 | objlayout_iodone(oir); |
258 | /* must not use oir after this point */ | 260 | /* must not use oir after this point */ |
259 | 261 | ||
@@ -334,6 +336,8 @@ objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync) | |||
334 | if (status >= 0) { | 336 | if (status >= 0) { |
335 | wdata->res.count = status; | 337 | wdata->res.count = status; |
336 | wdata->verf.committed = oir->committed; | 338 | wdata->verf.committed = oir->committed; |
339 | } else { | ||
340 | wdata->pnfs_error = status; | ||
337 | } | 341 | } |
338 | objlayout_iodone(oir); | 342 | objlayout_iodone(oir); |
339 | /* must not use oir after this point */ | 343 | /* must not use oir after this point */ |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 8e672a2b2d69..17149a490065 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -1166,6 +1166,33 @@ pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, | |||
1166 | } | 1166 | } |
1167 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_test); | 1167 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_test); |
1168 | 1168 | ||
1169 | static int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head *head) | ||
1170 | { | ||
1171 | struct nfs_pageio_descriptor pgio; | ||
1172 | LIST_HEAD(failed); | ||
1173 | |||
1174 | /* Resend all requests through the MDS */ | ||
1175 | nfs_pageio_init_write_mds(&pgio, inode, FLUSH_STABLE); | ||
1176 | while (!list_empty(head)) { | ||
1177 | struct nfs_page *req = nfs_list_entry(head->next); | ||
1178 | |||
1179 | nfs_list_remove_request(req); | ||
1180 | if (!nfs_pageio_add_request(&pgio, req)) | ||
1181 | nfs_list_add_request(req, &failed); | ||
1182 | } | ||
1183 | nfs_pageio_complete(&pgio); | ||
1184 | |||
1185 | if (!list_empty(&failed)) { | ||
1186 | /* For some reason our attempt to resend pages. Mark the | ||
1187 | * overall send request as having failed, and let | ||
1188 | * nfs_writeback_release_full deal with the error. | ||
1189 | */ | ||
1190 | list_move(&failed, head); | ||
1191 | return -EIO; | ||
1192 | } | ||
1193 | return 0; | ||
1194 | } | ||
1195 | |||
1169 | /* | 1196 | /* |
1170 | * Called by non rpc-based layout drivers | 1197 | * Called by non rpc-based layout drivers |
1171 | */ | 1198 | */ |
@@ -1175,9 +1202,17 @@ void pnfs_ld_write_done(struct nfs_write_data *data) | |||
1175 | pnfs_set_layoutcommit(data); | 1202 | pnfs_set_layoutcommit(data); |
1176 | data->mds_ops->rpc_call_done(&data->task, data); | 1203 | data->mds_ops->rpc_call_done(&data->task, data); |
1177 | } else { | 1204 | } else { |
1178 | put_lseg(data->lseg); | ||
1179 | data->lseg = NULL; | ||
1180 | dprintk("pnfs write error = %d\n", data->pnfs_error); | 1205 | dprintk("pnfs write error = %d\n", data->pnfs_error); |
1206 | if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags & | ||
1207 | PNFS_LAYOUTRET_ON_ERROR) { | ||
1208 | /* Don't lo_commit on error, Server will needs to | ||
1209 | * preform a file recovery. | ||
1210 | */ | ||
1211 | clear_bit(NFS_INO_LAYOUTCOMMIT, | ||
1212 | &NFS_I(data->inode)->flags); | ||
1213 | pnfs_return_layout(data->inode); | ||
1214 | } | ||
1215 | data->task.tk_status = pnfs_write_done_resend_to_mds(data->inode, &data->pages); | ||
1181 | } | 1216 | } |
1182 | data->mds_ops->rpc_release(data); | 1217 | data->mds_ops->rpc_release(data); |
1183 | } | 1218 | } |
@@ -1267,6 +1302,9 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data) | |||
1267 | put_lseg(data->lseg); | 1302 | put_lseg(data->lseg); |
1268 | data->lseg = NULL; | 1303 | data->lseg = NULL; |
1269 | dprintk("pnfs write error = %d\n", data->pnfs_error); | 1304 | dprintk("pnfs write error = %d\n", data->pnfs_error); |
1305 | if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags & | ||
1306 | PNFS_LAYOUTRET_ON_ERROR) | ||
1307 | pnfs_return_layout(data->inode); | ||
1270 | 1308 | ||
1271 | nfs_pageio_init_read_mds(&pgio, data->inode); | 1309 | nfs_pageio_init_read_mds(&pgio, data->inode); |
1272 | 1310 | ||
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 1509530cb111..53d593a0a4f2 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -68,6 +68,7 @@ enum { | |||
68 | enum layoutdriver_policy_flags { | 68 | enum layoutdriver_policy_flags { |
69 | /* Should the pNFS client commit and return the layout upon a setattr */ | 69 | /* Should the pNFS client commit and return the layout upon a setattr */ |
70 | PNFS_LAYOUTRET_ON_SETATTR = 1 << 0, | 70 | PNFS_LAYOUTRET_ON_SETATTR = 1 << 0, |
71 | PNFS_LAYOUTRET_ON_ERROR = 1 << 1, | ||
71 | }; | 72 | }; |
72 | 73 | ||
73 | struct nfs4_deviceid_node; | 74 | struct nfs4_deviceid_node; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index e463967aafb8..3dfa4f112c0a 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -908,10 +908,24 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int ve | |||
908 | data->auth_flavor_len = 1; | 908 | data->auth_flavor_len = 1; |
909 | data->version = version; | 909 | data->version = version; |
910 | data->minorversion = 0; | 910 | data->minorversion = 0; |
911 | security_init_mnt_opts(&data->lsm_opts); | ||
911 | } | 912 | } |
912 | return data; | 913 | return data; |
913 | } | 914 | } |
914 | 915 | ||
916 | static void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data) | ||
917 | { | ||
918 | if (data) { | ||
919 | kfree(data->client_address); | ||
920 | kfree(data->mount_server.hostname); | ||
921 | kfree(data->nfs_server.export_path); | ||
922 | kfree(data->nfs_server.hostname); | ||
923 | kfree(data->fscache_uniq); | ||
924 | security_free_mnt_opts(&data->lsm_opts); | ||
925 | kfree(data); | ||
926 | } | ||
927 | } | ||
928 | |||
915 | /* | 929 | /* |
916 | * Sanity-check a server address provided by the mount command. | 930 | * Sanity-check a server address provided by the mount command. |
917 | * | 931 | * |
@@ -2219,9 +2233,7 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type, | |||
2219 | data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION); | 2233 | data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION); |
2220 | mntfh = nfs_alloc_fhandle(); | 2234 | mntfh = nfs_alloc_fhandle(); |
2221 | if (data == NULL || mntfh == NULL) | 2235 | if (data == NULL || mntfh == NULL) |
2222 | goto out_free_fh; | 2236 | goto out; |
2223 | |||
2224 | security_init_mnt_opts(&data->lsm_opts); | ||
2225 | 2237 | ||
2226 | /* Validate the mount data */ | 2238 | /* Validate the mount data */ |
2227 | error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name); | 2239 | error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name); |
@@ -2233,8 +2245,6 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type, | |||
2233 | #ifdef CONFIG_NFS_V4 | 2245 | #ifdef CONFIG_NFS_V4 |
2234 | if (data->version == 4) { | 2246 | if (data->version == 4) { |
2235 | mntroot = nfs4_try_mount(flags, dev_name, data); | 2247 | mntroot = nfs4_try_mount(flags, dev_name, data); |
2236 | kfree(data->client_address); | ||
2237 | kfree(data->nfs_server.export_path); | ||
2238 | goto out; | 2248 | goto out; |
2239 | } | 2249 | } |
2240 | #endif /* CONFIG_NFS_V4 */ | 2250 | #endif /* CONFIG_NFS_V4 */ |
@@ -2289,13 +2299,8 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type, | |||
2289 | s->s_flags |= MS_ACTIVE; | 2299 | s->s_flags |= MS_ACTIVE; |
2290 | 2300 | ||
2291 | out: | 2301 | out: |
2292 | kfree(data->nfs_server.hostname); | 2302 | nfs_free_parsed_mount_data(data); |
2293 | kfree(data->mount_server.hostname); | ||
2294 | kfree(data->fscache_uniq); | ||
2295 | security_free_mnt_opts(&data->lsm_opts); | ||
2296 | out_free_fh: | ||
2297 | nfs_free_fhandle(mntfh); | 2303 | nfs_free_fhandle(mntfh); |
2298 | kfree(data); | ||
2299 | return mntroot; | 2304 | return mntroot; |
2300 | 2305 | ||
2301 | out_err_nosb: | 2306 | out_err_nosb: |
@@ -2622,9 +2627,7 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags, | |||
2622 | 2627 | ||
2623 | mntfh = nfs_alloc_fhandle(); | 2628 | mntfh = nfs_alloc_fhandle(); |
2624 | if (data == NULL || mntfh == NULL) | 2629 | if (data == NULL || mntfh == NULL) |
2625 | goto out_free_fh; | 2630 | goto out; |
2626 | |||
2627 | security_init_mnt_opts(&data->lsm_opts); | ||
2628 | 2631 | ||
2629 | /* Get a volume representation */ | 2632 | /* Get a volume representation */ |
2630 | server = nfs4_create_server(data, mntfh); | 2633 | server = nfs4_create_server(data, mntfh); |
@@ -2676,13 +2679,10 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags, | |||
2676 | 2679 | ||
2677 | s->s_flags |= MS_ACTIVE; | 2680 | s->s_flags |= MS_ACTIVE; |
2678 | 2681 | ||
2679 | security_free_mnt_opts(&data->lsm_opts); | ||
2680 | nfs_free_fhandle(mntfh); | 2682 | nfs_free_fhandle(mntfh); |
2681 | return mntroot; | 2683 | return mntroot; |
2682 | 2684 | ||
2683 | out: | 2685 | out: |
2684 | security_free_mnt_opts(&data->lsm_opts); | ||
2685 | out_free_fh: | ||
2686 | nfs_free_fhandle(mntfh); | 2686 | nfs_free_fhandle(mntfh); |
2687 | return ERR_PTR(error); | 2687 | return ERR_PTR(error); |
2688 | 2688 | ||
@@ -2839,7 +2839,7 @@ static struct dentry *nfs4_mount(struct file_system_type *fs_type, | |||
2839 | 2839 | ||
2840 | data = nfs_alloc_parsed_mount_data(4); | 2840 | data = nfs_alloc_parsed_mount_data(4); |
2841 | if (data == NULL) | 2841 | if (data == NULL) |
2842 | goto out_free_data; | 2842 | goto out; |
2843 | 2843 | ||
2844 | /* Validate the mount data */ | 2844 | /* Validate the mount data */ |
2845 | error = nfs4_validate_mount_data(raw_data, data, dev_name); | 2845 | error = nfs4_validate_mount_data(raw_data, data, dev_name); |
@@ -2853,12 +2853,7 @@ static struct dentry *nfs4_mount(struct file_system_type *fs_type, | |||
2853 | error = PTR_ERR(res); | 2853 | error = PTR_ERR(res); |
2854 | 2854 | ||
2855 | out: | 2855 | out: |
2856 | kfree(data->client_address); | 2856 | nfs_free_parsed_mount_data(data); |
2857 | kfree(data->nfs_server.export_path); | ||
2858 | kfree(data->nfs_server.hostname); | ||
2859 | kfree(data->fscache_uniq); | ||
2860 | out_free_data: | ||
2861 | kfree(data); | ||
2862 | dprintk("<-- nfs4_mount() = %d%s\n", error, | 2857 | dprintk("<-- nfs4_mount() = %d%s\n", error, |
2863 | error != 0 ? " [error]" : ""); | 2858 | error != 0 ? " [error]" : ""); |
2864 | return res; | 2859 | return res; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 1dda78db6a73..0c3885255f97 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -1052,7 +1052,7 @@ static const struct nfs_pageio_ops nfs_pageio_write_ops = { | |||
1052 | .pg_doio = nfs_generic_pg_writepages, | 1052 | .pg_doio = nfs_generic_pg_writepages, |
1053 | }; | 1053 | }; |
1054 | 1054 | ||
1055 | static void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio, | 1055 | void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio, |
1056 | struct inode *inode, int ioflags) | 1056 | struct inode *inode, int ioflags) |
1057 | { | 1057 | { |
1058 | nfs_pageio_init(pgio, inode, &nfs_pageio_write_ops, | 1058 | nfs_pageio_init(pgio, inode, &nfs_pageio_write_ops, |
@@ -1166,13 +1166,7 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | |||
1166 | static void nfs_writeback_release_full(void *calldata) | 1166 | static void nfs_writeback_release_full(void *calldata) |
1167 | { | 1167 | { |
1168 | struct nfs_write_data *data = calldata; | 1168 | struct nfs_write_data *data = calldata; |
1169 | int ret, status = data->task.tk_status; | 1169 | int status = data->task.tk_status; |
1170 | struct nfs_pageio_descriptor pgio; | ||
1171 | |||
1172 | if (data->pnfs_error) { | ||
1173 | nfs_pageio_init_write_mds(&pgio, data->inode, FLUSH_STABLE); | ||
1174 | pgio.pg_recoalesce = 1; | ||
1175 | } | ||
1176 | 1170 | ||
1177 | /* Update attributes as result of writeback. */ | 1171 | /* Update attributes as result of writeback. */ |
1178 | while (!list_empty(&data->pages)) { | 1172 | while (!list_empty(&data->pages)) { |
@@ -1188,11 +1182,6 @@ static void nfs_writeback_release_full(void *calldata) | |||
1188 | req->wb_bytes, | 1182 | req->wb_bytes, |
1189 | (long long)req_offset(req)); | 1183 | (long long)req_offset(req)); |
1190 | 1184 | ||
1191 | if (data->pnfs_error) { | ||
1192 | dprintk(", pnfs error = %d\n", data->pnfs_error); | ||
1193 | goto next; | ||
1194 | } | ||
1195 | |||
1196 | if (status < 0) { | 1185 | if (status < 0) { |
1197 | nfs_set_pageerror(page); | 1186 | nfs_set_pageerror(page); |
1198 | nfs_context_set_write_error(req->wb_context, status); | 1187 | nfs_context_set_write_error(req->wb_context, status); |
@@ -1212,19 +1201,7 @@ remove_request: | |||
1212 | next: | 1201 | next: |
1213 | nfs_clear_page_tag_locked(req); | 1202 | nfs_clear_page_tag_locked(req); |
1214 | nfs_end_page_writeback(page); | 1203 | nfs_end_page_writeback(page); |
1215 | if (data->pnfs_error) { | ||
1216 | lock_page(page); | ||
1217 | nfs_pageio_cond_complete(&pgio, page->index); | ||
1218 | ret = nfs_page_async_flush(&pgio, page, 0); | ||
1219 | if (ret) { | ||
1220 | nfs_set_pageerror(page); | ||
1221 | dprintk("rewrite to MDS error = %d\n", ret); | ||
1222 | } | ||
1223 | unlock_page(page); | ||
1224 | } | ||
1225 | } | 1204 | } |
1226 | if (data->pnfs_error) | ||
1227 | nfs_pageio_complete(&pgio); | ||
1228 | nfs_writedata_release(calldata); | 1205 | nfs_writedata_release(calldata); |
1229 | } | 1206 | } |
1230 | 1207 | ||