diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-02 11:17:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-02 11:17:57 -0400 |
commit | 529acf58981440eefeaf1451387e2a0aa4825c12 (patch) | |
tree | ffcf408493a34ab1e0e1530dca83aa279708560c /fs | |
parent | b821861b905a79f71746945237968c3382d99adc (diff) | |
parent | 3617e5031b3acec04efaa36566a8111ac8f07325 (diff) |
Merge tag 'nfs-for-3.4-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust:
- Fixes for the NFSv4 security negotiation
- Use the correct hostname when mounting from a private namespace
- NFS net namespace bugfixes for the pipefs filesystem
- NFSv4 GETACL bugfixes
- IPv6 bugfix for NFSv4 referrals
* tag 'nfs-for-3.4-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFSv4.1: Use the correct hostname in the client identifier string
SUNRPC: RPC client must use the current utsname hostname string
NFS: get module in idmap PipeFS notifier callback
NFS: Remove unused function nfs_lookup_with_sec()
NFS: Honor the authflavor set in the clone mount data
NFS: Fix following referral mount points with different security
NFS: Do secinfo as part of lookup
NFS: Handle exceptions coming out of nfs4_proc_fs_locations()
NFS: Fix SECINFO_NO_NAME
SUNRPC: traverse clients tree on PipeFS event
SUNRPC: set per-net PipeFS superblock before notification
SUNRPC: skip clients with program without PipeFS entries
SUNRPC: skip dead but not buried clients on PipeFS events
Avoid beyond bounds copy while caching ACL
Avoid reading past buffer when calling GETACL
fix page number calculation bug for block layout decode buffer
NFSv4.1 fix page number calculation bug for filelayout decode buffers
pnfs-obj: Remove unused variable from objlayout_get_deviceinfo()
nfs4: fix referrals on mounts that use IPv6 addrs
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.c | 4 | ||||
-rw-r--r-- | fs/nfs/client.c | 5 | ||||
-rw-r--r-- | fs/nfs/idmap.c | 4 | ||||
-rw-r--r-- | fs/nfs/internal.h | 8 | ||||
-rw-r--r-- | fs/nfs/namespace.c | 93 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 10 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayoutdev.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 86 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 142 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 44 | ||||
-rw-r--r-- | fs/nfs/objlayout/objlayout.c | 2 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 2 | ||||
-rw-r--r-- | fs/nfs/super.c | 4 |
13 files changed, 267 insertions, 139 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 9c94297bb70e..7f6a23f0244e 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
@@ -38,6 +38,8 @@ | |||
38 | #include <linux/buffer_head.h> /* various write calls */ | 38 | #include <linux/buffer_head.h> /* various write calls */ |
39 | #include <linux/prefetch.h> | 39 | #include <linux/prefetch.h> |
40 | 40 | ||
41 | #include "../pnfs.h" | ||
42 | #include "../internal.h" | ||
41 | #include "blocklayout.h" | 43 | #include "blocklayout.h" |
42 | 44 | ||
43 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD | 45 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD |
@@ -868,7 +870,7 @@ nfs4_blk_get_deviceinfo(struct nfs_server *server, const struct nfs_fh *fh, | |||
868 | * GETDEVICEINFO's maxcount | 870 | * GETDEVICEINFO's maxcount |
869 | */ | 871 | */ |
870 | max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | 872 | max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; |
871 | max_pages = max_resp_sz >> PAGE_SHIFT; | 873 | max_pages = nfs_page_array_len(0, max_resp_sz); |
872 | dprintk("%s max_resp_sz %u max_pages %d\n", | 874 | dprintk("%s max_resp_sz %u max_pages %d\n", |
873 | __func__, max_resp_sz, max_pages); | 875 | __func__, max_resp_sz, max_pages); |
874 | 876 | ||
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index da7b5e4ff9ec..60f7e4ec842c 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -1729,7 +1729,8 @@ error: | |||
1729 | */ | 1729 | */ |
1730 | struct nfs_server *nfs_clone_server(struct nfs_server *source, | 1730 | struct nfs_server *nfs_clone_server(struct nfs_server *source, |
1731 | struct nfs_fh *fh, | 1731 | struct nfs_fh *fh, |
1732 | struct nfs_fattr *fattr) | 1732 | struct nfs_fattr *fattr, |
1733 | rpc_authflavor_t flavor) | ||
1733 | { | 1734 | { |
1734 | struct nfs_server *server; | 1735 | struct nfs_server *server; |
1735 | struct nfs_fattr *fattr_fsinfo; | 1736 | struct nfs_fattr *fattr_fsinfo; |
@@ -1758,7 +1759,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
1758 | 1759 | ||
1759 | error = nfs_init_server_rpcclient(server, | 1760 | error = nfs_init_server_rpcclient(server, |
1760 | source->client->cl_timeout, | 1761 | source->client->cl_timeout, |
1761 | source->client->cl_auth->au_flavor); | 1762 | flavor); |
1762 | if (error < 0) | 1763 | if (error < 0) |
1763 | goto out_free_server; | 1764 | goto out_free_server; |
1764 | if (!IS_ERR(source->client_acl)) | 1765 | if (!IS_ERR(source->client_acl)) |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index b7f348bb618b..ba3019f5934c 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -554,12 +554,16 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, | |||
554 | struct nfs_client *clp; | 554 | struct nfs_client *clp; |
555 | int error = 0; | 555 | int error = 0; |
556 | 556 | ||
557 | if (!try_module_get(THIS_MODULE)) | ||
558 | return 0; | ||
559 | |||
557 | while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) { | 560 | while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) { |
558 | error = __rpc_pipefs_event(clp, event, sb); | 561 | error = __rpc_pipefs_event(clp, event, sb); |
559 | nfs_put_client(clp); | 562 | nfs_put_client(clp); |
560 | if (error) | 563 | if (error) |
561 | break; | 564 | break; |
562 | } | 565 | } |
566 | module_put(THIS_MODULE); | ||
563 | return error; | 567 | return error; |
564 | } | 568 | } |
565 | 569 | ||
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 2476dc69365f..b777bdaba4c5 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -165,7 +165,8 @@ extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, | |||
165 | extern void nfs_free_server(struct nfs_server *server); | 165 | extern void nfs_free_server(struct nfs_server *server); |
166 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, | 166 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, |
167 | struct nfs_fh *, | 167 | struct nfs_fh *, |
168 | struct nfs_fattr *); | 168 | struct nfs_fattr *, |
169 | rpc_authflavor_t); | ||
169 | extern void nfs_mark_client_ready(struct nfs_client *clp, int state); | 170 | extern void nfs_mark_client_ready(struct nfs_client *clp, int state); |
170 | extern int nfs4_check_client_ready(struct nfs_client *clp); | 171 | extern int nfs4_check_client_ready(struct nfs_client *clp); |
171 | extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, | 172 | extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, |
@@ -186,10 +187,10 @@ static inline void nfs_fs_proc_exit(void) | |||
186 | 187 | ||
187 | /* nfs4namespace.c */ | 188 | /* nfs4namespace.c */ |
188 | #ifdef CONFIG_NFS_V4 | 189 | #ifdef CONFIG_NFS_V4 |
189 | extern struct vfsmount *nfs_do_refmount(struct dentry *dentry); | 190 | extern struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry); |
190 | #else | 191 | #else |
191 | static inline | 192 | static inline |
192 | struct vfsmount *nfs_do_refmount(struct dentry *dentry) | 193 | struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry) |
193 | { | 194 | { |
194 | return ERR_PTR(-ENOENT); | 195 | return ERR_PTR(-ENOENT); |
195 | } | 196 | } |
@@ -234,7 +235,6 @@ extern const u32 nfs41_maxwrite_overhead; | |||
234 | /* nfs4proc.c */ | 235 | /* nfs4proc.c */ |
235 | #ifdef CONFIG_NFS_V4 | 236 | #ifdef CONFIG_NFS_V4 |
236 | extern struct rpc_procinfo nfs4_procedures[]; | 237 | extern struct rpc_procinfo nfs4_procedures[]; |
237 | void nfs_fixup_secinfo_attributes(struct nfs_fattr *, struct nfs_fh *); | ||
238 | #endif | 238 | #endif |
239 | 239 | ||
240 | extern int nfs4_init_ds_session(struct nfs_client *clp); | 240 | extern int nfs4_init_ds_session(struct nfs_client *clp); |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 1807866bb3ab..d51868e5683c 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -148,66 +148,31 @@ rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) | |||
148 | return pseudoflavor; | 148 | return pseudoflavor; |
149 | } | 149 | } |
150 | 150 | ||
151 | static int nfs_negotiate_security(const struct dentry *parent, | 151 | static struct rpc_clnt *nfs_lookup_mountpoint(struct inode *dir, |
152 | const struct dentry *dentry, | 152 | struct qstr *name, |
153 | rpc_authflavor_t *flavor) | 153 | struct nfs_fh *fh, |
154 | struct nfs_fattr *fattr) | ||
154 | { | 155 | { |
155 | struct page *page; | ||
156 | struct nfs4_secinfo_flavors *flavors; | ||
157 | int (*secinfo)(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); | ||
158 | int ret = -EPERM; | ||
159 | |||
160 | secinfo = NFS_PROTO(parent->d_inode)->secinfo; | ||
161 | if (secinfo != NULL) { | ||
162 | page = alloc_page(GFP_KERNEL); | ||
163 | if (!page) { | ||
164 | ret = -ENOMEM; | ||
165 | goto out; | ||
166 | } | ||
167 | flavors = page_address(page); | ||
168 | ret = secinfo(parent->d_inode, &dentry->d_name, flavors); | ||
169 | *flavor = nfs_find_best_sec(flavors); | ||
170 | put_page(page); | ||
171 | } | ||
172 | |||
173 | out: | ||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | static int nfs_lookup_with_sec(struct nfs_server *server, struct dentry *parent, | ||
178 | struct dentry *dentry, struct path *path, | ||
179 | struct nfs_fh *fh, struct nfs_fattr *fattr, | ||
180 | rpc_authflavor_t *flavor) | ||
181 | { | ||
182 | struct rpc_clnt *clone; | ||
183 | struct rpc_auth *auth; | ||
184 | int err; | 156 | int err; |
185 | 157 | ||
186 | err = nfs_negotiate_security(parent, path->dentry, flavor); | 158 | if (NFS_PROTO(dir)->version == 4) |
187 | if (err < 0) | 159 | return nfs4_proc_lookup_mountpoint(dir, name, fh, fattr); |
188 | goto out; | 160 | |
189 | clone = rpc_clone_client(server->client); | 161 | err = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, name, fh, fattr); |
190 | auth = rpcauth_create(*flavor, clone); | 162 | if (err) |
191 | if (!auth) { | 163 | return ERR_PTR(err); |
192 | err = -EIO; | 164 | return rpc_clone_client(NFS_SERVER(dir)->client); |
193 | goto out_shutdown; | ||
194 | } | ||
195 | err = server->nfs_client->rpc_ops->lookup(clone, parent->d_inode, | ||
196 | &path->dentry->d_name, | ||
197 | fh, fattr); | ||
198 | out_shutdown: | ||
199 | rpc_shutdown_client(clone); | ||
200 | out: | ||
201 | return err; | ||
202 | } | 165 | } |
203 | #else /* CONFIG_NFS_V4 */ | 166 | #else /* CONFIG_NFS_V4 */ |
204 | static inline int nfs_lookup_with_sec(struct nfs_server *server, | 167 | static inline struct rpc_clnt *nfs_lookup_mountpoint(struct inode *dir, |
205 | struct dentry *parent, struct dentry *dentry, | 168 | struct qstr *name, |
206 | struct path *path, struct nfs_fh *fh, | 169 | struct nfs_fh *fh, |
207 | struct nfs_fattr *fattr, | 170 | struct nfs_fattr *fattr) |
208 | rpc_authflavor_t *flavor) | ||
209 | { | 171 | { |
210 | return -EPERM; | 172 | int err = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, name, fh, fattr); |
173 | if (err) | ||
174 | return ERR_PTR(err); | ||
175 | return rpc_clone_client(NFS_SERVER(dir)->client); | ||
211 | } | 176 | } |
212 | #endif /* CONFIG_NFS_V4 */ | 177 | #endif /* CONFIG_NFS_V4 */ |
213 | 178 | ||
@@ -226,12 +191,10 @@ static inline int nfs_lookup_with_sec(struct nfs_server *server, | |||
226 | struct vfsmount *nfs_d_automount(struct path *path) | 191 | struct vfsmount *nfs_d_automount(struct path *path) |
227 | { | 192 | { |
228 | struct vfsmount *mnt; | 193 | struct vfsmount *mnt; |
229 | struct nfs_server *server = NFS_SERVER(path->dentry->d_inode); | ||
230 | struct dentry *parent; | 194 | struct dentry *parent; |
231 | struct nfs_fh *fh = NULL; | 195 | struct nfs_fh *fh = NULL; |
232 | struct nfs_fattr *fattr = NULL; | 196 | struct nfs_fattr *fattr = NULL; |
233 | int err; | 197 | struct rpc_clnt *client; |
234 | rpc_authflavor_t flavor = RPC_AUTH_UNIX; | ||
235 | 198 | ||
236 | dprintk("--> nfs_d_automount()\n"); | 199 | dprintk("--> nfs_d_automount()\n"); |
237 | 200 | ||
@@ -249,21 +212,19 @@ struct vfsmount *nfs_d_automount(struct path *path) | |||
249 | 212 | ||
250 | /* Look it up again to get its attributes */ | 213 | /* Look it up again to get its attributes */ |
251 | parent = dget_parent(path->dentry); | 214 | parent = dget_parent(path->dentry); |
252 | err = server->nfs_client->rpc_ops->lookup(server->client, parent->d_inode, | 215 | client = nfs_lookup_mountpoint(parent->d_inode, &path->dentry->d_name, fh, fattr); |
253 | &path->dentry->d_name, | ||
254 | fh, fattr); | ||
255 | if (err == -EPERM && NFS_PROTO(parent->d_inode)->secinfo != NULL) | ||
256 | err = nfs_lookup_with_sec(server, parent, path->dentry, path, fh, fattr, &flavor); | ||
257 | dput(parent); | 216 | dput(parent); |
258 | if (err != 0) { | 217 | if (IS_ERR(client)) { |
259 | mnt = ERR_PTR(err); | 218 | mnt = ERR_CAST(client); |
260 | goto out; | 219 | goto out; |
261 | } | 220 | } |
262 | 221 | ||
263 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) | 222 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) |
264 | mnt = nfs_do_refmount(path->dentry); | 223 | mnt = nfs_do_refmount(client, path->dentry); |
265 | else | 224 | else |
266 | mnt = nfs_do_submount(path->dentry, fh, fattr, flavor); | 225 | mnt = nfs_do_submount(path->dentry, fh, fattr, client->cl_auth->au_flavor); |
226 | rpc_shutdown_client(client); | ||
227 | |||
267 | if (IS_ERR(mnt)) | 228 | if (IS_ERR(mnt)) |
268 | goto out; | 229 | goto out; |
269 | 230 | ||
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index b6db9e33fb7b..8d75021020b3 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -205,6 +205,9 @@ struct nfs4_state_maintenance_ops { | |||
205 | extern const struct dentry_operations nfs4_dentry_operations; | 205 | extern const struct dentry_operations nfs4_dentry_operations; |
206 | extern const struct inode_operations nfs4_dir_inode_operations; | 206 | extern const struct inode_operations nfs4_dir_inode_operations; |
207 | 207 | ||
208 | /* nfs4namespace.c */ | ||
209 | struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *); | ||
210 | |||
208 | /* nfs4proc.c */ | 211 | /* nfs4proc.c */ |
209 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); | 212 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); |
210 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, struct rpc_cred *); | 213 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, struct rpc_cred *); |
@@ -213,8 +216,11 @@ extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); | |||
213 | extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); | 216 | extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); |
214 | extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc); | 217 | extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc); |
215 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); | 218 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); |
216 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | 219 | extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *, |
217 | struct nfs4_fs_locations *fs_locations, struct page *page); | 220 | struct nfs4_fs_locations *, struct page *); |
221 | extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *, | ||
222 | struct nfs_fh *, struct nfs_fattr *); | ||
223 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); | ||
218 | extern int nfs4_release_lockowner(struct nfs4_lock_state *); | 224 | extern int nfs4_release_lockowner(struct nfs4_lock_state *); |
219 | extern const struct xattr_handler *nfs4_xattr_handlers[]; | 225 | extern const struct xattr_handler *nfs4_xattr_handlers[]; |
220 | 226 | ||
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index a866bbd2890a..c9cff9adb2d3 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c | |||
@@ -699,7 +699,7 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_fla | |||
699 | * GETDEVICEINFO's maxcount | 699 | * GETDEVICEINFO's maxcount |
700 | */ | 700 | */ |
701 | max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | 701 | max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; |
702 | max_pages = max_resp_sz >> PAGE_SHIFT; | 702 | max_pages = nfs_page_array_len(0, max_resp_sz); |
703 | dprintk("%s inode %p max_resp_sz %u max_pages %d\n", | 703 | dprintk("%s inode %p max_resp_sz %u max_pages %d\n", |
704 | __func__, inode, max_resp_sz, max_pages); | 704 | __func__, inode, max_resp_sz, max_pages); |
705 | 705 | ||
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 9c8eca315f43..a7f3dedc4ec7 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -52,6 +52,30 @@ Elong: | |||
52 | } | 52 | } |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * return the path component of "<server>:<path>" | ||
56 | * nfspath - the "<server>:<path>" string | ||
57 | * end - one past the last char that could contain "<server>:" | ||
58 | * returns NULL on failure | ||
59 | */ | ||
60 | static char *nfs_path_component(const char *nfspath, const char *end) | ||
61 | { | ||
62 | char *p; | ||
63 | |||
64 | if (*nfspath == '[') { | ||
65 | /* parse [] escaped IPv6 addrs */ | ||
66 | p = strchr(nfspath, ']'); | ||
67 | if (p != NULL && ++p < end && *p == ':') | ||
68 | return p + 1; | ||
69 | } else { | ||
70 | /* otherwise split on first colon */ | ||
71 | p = strchr(nfspath, ':'); | ||
72 | if (p != NULL && p < end) | ||
73 | return p + 1; | ||
74 | } | ||
75 | return NULL; | ||
76 | } | ||
77 | |||
78 | /* | ||
55 | * Determine the mount path as a string | 79 | * Determine the mount path as a string |
56 | */ | 80 | */ |
57 | static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) | 81 | static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) |
@@ -59,9 +83,9 @@ static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) | |||
59 | char *limit; | 83 | char *limit; |
60 | char *path = nfs_path(&limit, dentry, buffer, buflen); | 84 | char *path = nfs_path(&limit, dentry, buffer, buflen); |
61 | if (!IS_ERR(path)) { | 85 | if (!IS_ERR(path)) { |
62 | char *colon = strchr(path, ':'); | 86 | char *path_component = nfs_path_component(path, limit); |
63 | if (colon && colon < limit) | 87 | if (path_component) |
64 | path = colon + 1; | 88 | return path_component; |
65 | } | 89 | } |
66 | return path; | 90 | return path; |
67 | } | 91 | } |
@@ -108,6 +132,58 @@ static size_t nfs_parse_server_name(char *string, size_t len, | |||
108 | return ret; | 132 | return ret; |
109 | } | 133 | } |
110 | 134 | ||
135 | static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name) | ||
136 | { | ||
137 | struct page *page; | ||
138 | struct nfs4_secinfo_flavors *flavors; | ||
139 | rpc_authflavor_t flavor; | ||
140 | int err; | ||
141 | |||
142 | page = alloc_page(GFP_KERNEL); | ||
143 | if (!page) | ||
144 | return -ENOMEM; | ||
145 | flavors = page_address(page); | ||
146 | |||
147 | err = nfs4_proc_secinfo(inode, name, flavors); | ||
148 | if (err < 0) { | ||
149 | flavor = err; | ||
150 | goto out; | ||
151 | } | ||
152 | |||
153 | flavor = nfs_find_best_sec(flavors); | ||
154 | |||
155 | out: | ||
156 | put_page(page); | ||
157 | return flavor; | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * Please call rpc_shutdown_client() when you are done with this client. | ||
162 | */ | ||
163 | struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *inode, | ||
164 | struct qstr *name) | ||
165 | { | ||
166 | struct rpc_clnt *clone; | ||
167 | struct rpc_auth *auth; | ||
168 | rpc_authflavor_t flavor; | ||
169 | |||
170 | flavor = nfs4_negotiate_security(inode, name); | ||
171 | if (flavor < 0) | ||
172 | return ERR_PTR(flavor); | ||
173 | |||
174 | clone = rpc_clone_client(clnt); | ||
175 | if (IS_ERR(clone)) | ||
176 | return clone; | ||
177 | |||
178 | auth = rpcauth_create(flavor, clone); | ||
179 | if (!auth) { | ||
180 | rpc_shutdown_client(clone); | ||
181 | clone = ERR_PTR(-EIO); | ||
182 | } | ||
183 | |||
184 | return clone; | ||
185 | } | ||
186 | |||
111 | static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | 187 | static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, |
112 | char *page, char *page2, | 188 | char *page, char *page2, |
113 | const struct nfs4_fs_location *location) | 189 | const struct nfs4_fs_location *location) |
@@ -224,7 +300,7 @@ out: | |||
224 | * @dentry - dentry of referral | 300 | * @dentry - dentry of referral |
225 | * | 301 | * |
226 | */ | 302 | */ |
227 | struct vfsmount *nfs_do_refmount(struct dentry *dentry) | 303 | struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry) |
228 | { | 304 | { |
229 | struct vfsmount *mnt = ERR_PTR(-ENOMEM); | 305 | struct vfsmount *mnt = ERR_PTR(-ENOMEM); |
230 | struct dentry *parent; | 306 | struct dentry *parent; |
@@ -250,7 +326,7 @@ struct vfsmount *nfs_do_refmount(struct dentry *dentry) | |||
250 | dprintk("%s: getting locations for %s/%s\n", | 326 | dprintk("%s: getting locations for %s/%s\n", |
251 | __func__, parent->d_name.name, dentry->d_name.name); | 327 | __func__, parent->d_name.name, dentry->d_name.name); |
252 | 328 | ||
253 | err = nfs4_proc_fs_locations(parent->d_inode, &dentry->d_name, fs_locations, page); | 329 | err = nfs4_proc_fs_locations(client, parent->d_inode, &dentry->d_name, fs_locations, page); |
254 | dput(parent); | 330 | dput(parent); |
255 | if (err != 0 || | 331 | if (err != 0 || |
256 | fs_locations->nlocations <= 0 || | 332 | fs_locations->nlocations <= 0 || |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 60d5f4c26dda..99650aaf8937 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -2377,8 +2377,9 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2377 | * Note that we'll actually follow the referral later when | 2377 | * Note that we'll actually follow the referral later when |
2378 | * we detect fsid mismatch in inode revalidation | 2378 | * we detect fsid mismatch in inode revalidation |
2379 | */ | 2379 | */ |
2380 | static int nfs4_get_referral(struct inode *dir, const struct qstr *name, | 2380 | static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir, |
2381 | struct nfs_fattr *fattr, struct nfs_fh *fhandle) | 2381 | const struct qstr *name, struct nfs_fattr *fattr, |
2382 | struct nfs_fh *fhandle) | ||
2382 | { | 2383 | { |
2383 | int status = -ENOMEM; | 2384 | int status = -ENOMEM; |
2384 | struct page *page = NULL; | 2385 | struct page *page = NULL; |
@@ -2391,7 +2392,7 @@ static int nfs4_get_referral(struct inode *dir, const struct qstr *name, | |||
2391 | if (locations == NULL) | 2392 | if (locations == NULL) |
2392 | goto out; | 2393 | goto out; |
2393 | 2394 | ||
2394 | status = nfs4_proc_fs_locations(dir, name, locations, page); | 2395 | status = nfs4_proc_fs_locations(client, dir, name, locations, page); |
2395 | if (status != 0) | 2396 | if (status != 0) |
2396 | goto out; | 2397 | goto out; |
2397 | /* Make sure server returned a different fsid for the referral */ | 2398 | /* Make sure server returned a different fsid for the referral */ |
@@ -2528,39 +2529,84 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, | |||
2528 | return status; | 2529 | return status; |
2529 | } | 2530 | } |
2530 | 2531 | ||
2531 | void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr, struct nfs_fh *fh) | 2532 | static void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr) |
2532 | { | 2533 | { |
2533 | memset(fh, 0, sizeof(struct nfs_fh)); | ||
2534 | fattr->fsid.major = 1; | ||
2535 | fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE | | 2534 | fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE | |
2536 | NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_FSID | NFS_ATTR_FATTR_MOUNTPOINT; | 2535 | NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_MOUNTPOINT; |
2537 | fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 2536 | fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO; |
2538 | fattr->nlink = 2; | 2537 | fattr->nlink = 2; |
2539 | } | 2538 | } |
2540 | 2539 | ||
2541 | static int nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name, | 2540 | static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir, |
2542 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2541 | struct qstr *name, struct nfs_fh *fhandle, |
2542 | struct nfs_fattr *fattr) | ||
2543 | { | 2543 | { |
2544 | struct nfs4_exception exception = { }; | 2544 | struct nfs4_exception exception = { }; |
2545 | struct rpc_clnt *client = *clnt; | ||
2545 | int err; | 2546 | int err; |
2546 | do { | 2547 | do { |
2547 | int status; | 2548 | err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr); |
2548 | 2549 | switch (err) { | |
2549 | status = _nfs4_proc_lookup(clnt, dir, name, fhandle, fattr); | ||
2550 | switch (status) { | ||
2551 | case -NFS4ERR_BADNAME: | 2550 | case -NFS4ERR_BADNAME: |
2552 | return -ENOENT; | 2551 | err = -ENOENT; |
2552 | goto out; | ||
2553 | case -NFS4ERR_MOVED: | 2553 | case -NFS4ERR_MOVED: |
2554 | return nfs4_get_referral(dir, name, fattr, fhandle); | 2554 | err = nfs4_get_referral(client, dir, name, fattr, fhandle); |
2555 | goto out; | ||
2555 | case -NFS4ERR_WRONGSEC: | 2556 | case -NFS4ERR_WRONGSEC: |
2556 | nfs_fixup_secinfo_attributes(fattr, fhandle); | 2557 | err = -EPERM; |
2558 | if (client != *clnt) | ||
2559 | goto out; | ||
2560 | |||
2561 | client = nfs4_create_sec_client(client, dir, name); | ||
2562 | if (IS_ERR(client)) | ||
2563 | return PTR_ERR(client); | ||
2564 | |||
2565 | exception.retry = 1; | ||
2566 | break; | ||
2567 | default: | ||
2568 | err = nfs4_handle_exception(NFS_SERVER(dir), err, &exception); | ||
2557 | } | 2569 | } |
2558 | err = nfs4_handle_exception(NFS_SERVER(dir), | ||
2559 | status, &exception); | ||
2560 | } while (exception.retry); | 2570 | } while (exception.retry); |
2571 | |||
2572 | out: | ||
2573 | if (err == 0) | ||
2574 | *clnt = client; | ||
2575 | else if (client != *clnt) | ||
2576 | rpc_shutdown_client(client); | ||
2577 | |||
2561 | return err; | 2578 | return err; |
2562 | } | 2579 | } |
2563 | 2580 | ||
2581 | static int nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name, | ||
2582 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | ||
2583 | { | ||
2584 | int status; | ||
2585 | struct rpc_clnt *client = NFS_CLIENT(dir); | ||
2586 | |||
2587 | status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr); | ||
2588 | if (client != NFS_CLIENT(dir)) { | ||
2589 | rpc_shutdown_client(client); | ||
2590 | nfs_fixup_secinfo_attributes(fattr); | ||
2591 | } | ||
2592 | return status; | ||
2593 | } | ||
2594 | |||
2595 | struct rpc_clnt * | ||
2596 | nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name, | ||
2597 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | ||
2598 | { | ||
2599 | int status; | ||
2600 | struct rpc_clnt *client = rpc_clone_client(NFS_CLIENT(dir)); | ||
2601 | |||
2602 | status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr); | ||
2603 | if (status < 0) { | ||
2604 | rpc_shutdown_client(client); | ||
2605 | return ERR_PTR(status); | ||
2606 | } | ||
2607 | return client; | ||
2608 | } | ||
2609 | |||
2564 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) | 2610 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) |
2565 | { | 2611 | { |
2566 | struct nfs_server *server = NFS_SERVER(inode); | 2612 | struct nfs_server *server = NFS_SERVER(inode); |
@@ -3628,16 +3674,16 @@ out: | |||
3628 | return ret; | 3674 | return ret; |
3629 | } | 3675 | } |
3630 | 3676 | ||
3631 | static void nfs4_write_cached_acl(struct inode *inode, const char *buf, size_t acl_len) | 3677 | static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len) |
3632 | { | 3678 | { |
3633 | struct nfs4_cached_acl *acl; | 3679 | struct nfs4_cached_acl *acl; |
3634 | 3680 | ||
3635 | if (buf && acl_len <= PAGE_SIZE) { | 3681 | if (pages && acl_len <= PAGE_SIZE) { |
3636 | acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL); | 3682 | acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL); |
3637 | if (acl == NULL) | 3683 | if (acl == NULL) |
3638 | goto out; | 3684 | goto out; |
3639 | acl->cached = 1; | 3685 | acl->cached = 1; |
3640 | memcpy(acl->data, buf, acl_len); | 3686 | _copy_from_pages(acl->data, pages, pgbase, acl_len); |
3641 | } else { | 3687 | } else { |
3642 | acl = kmalloc(sizeof(*acl), GFP_KERNEL); | 3688 | acl = kmalloc(sizeof(*acl), GFP_KERNEL); |
3643 | if (acl == NULL) | 3689 | if (acl == NULL) |
@@ -3670,7 +3716,6 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3670 | struct nfs_getaclres res = { | 3716 | struct nfs_getaclres res = { |
3671 | .acl_len = buflen, | 3717 | .acl_len = buflen, |
3672 | }; | 3718 | }; |
3673 | void *resp_buf; | ||
3674 | struct rpc_message msg = { | 3719 | struct rpc_message msg = { |
3675 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], | 3720 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], |
3676 | .rpc_argp = &args, | 3721 | .rpc_argp = &args, |
@@ -3684,24 +3729,27 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3684 | if (npages == 0) | 3729 | if (npages == 0) |
3685 | npages = 1; | 3730 | npages = 1; |
3686 | 3731 | ||
3732 | /* Add an extra page to handle the bitmap returned */ | ||
3733 | npages++; | ||
3734 | |||
3687 | for (i = 0; i < npages; i++) { | 3735 | for (i = 0; i < npages; i++) { |
3688 | pages[i] = alloc_page(GFP_KERNEL); | 3736 | pages[i] = alloc_page(GFP_KERNEL); |
3689 | if (!pages[i]) | 3737 | if (!pages[i]) |
3690 | goto out_free; | 3738 | goto out_free; |
3691 | } | 3739 | } |
3692 | if (npages > 1) { | 3740 | |
3693 | /* for decoding across pages */ | 3741 | /* for decoding across pages */ |
3694 | res.acl_scratch = alloc_page(GFP_KERNEL); | 3742 | res.acl_scratch = alloc_page(GFP_KERNEL); |
3695 | if (!res.acl_scratch) | 3743 | if (!res.acl_scratch) |
3696 | goto out_free; | 3744 | goto out_free; |
3697 | } | 3745 | |
3698 | args.acl_len = npages * PAGE_SIZE; | 3746 | args.acl_len = npages * PAGE_SIZE; |
3699 | args.acl_pgbase = 0; | 3747 | args.acl_pgbase = 0; |
3748 | |||
3700 | /* Let decode_getfacl know not to fail if the ACL data is larger than | 3749 | /* Let decode_getfacl know not to fail if the ACL data is larger than |
3701 | * the page we send as a guess */ | 3750 | * the page we send as a guess */ |
3702 | if (buf == NULL) | 3751 | if (buf == NULL) |
3703 | res.acl_flags |= NFS4_ACL_LEN_REQUEST; | 3752 | res.acl_flags |= NFS4_ACL_LEN_REQUEST; |
3704 | resp_buf = page_address(pages[0]); | ||
3705 | 3753 | ||
3706 | dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n", | 3754 | dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n", |
3707 | __func__, buf, buflen, npages, args.acl_len); | 3755 | __func__, buf, buflen, npages, args.acl_len); |
@@ -3712,9 +3760,9 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3712 | 3760 | ||
3713 | acl_len = res.acl_len - res.acl_data_offset; | 3761 | acl_len = res.acl_len - res.acl_data_offset; |
3714 | if (acl_len > args.acl_len) | 3762 | if (acl_len > args.acl_len) |
3715 | nfs4_write_cached_acl(inode, NULL, acl_len); | 3763 | nfs4_write_cached_acl(inode, NULL, 0, acl_len); |
3716 | else | 3764 | else |
3717 | nfs4_write_cached_acl(inode, resp_buf + res.acl_data_offset, | 3765 | nfs4_write_cached_acl(inode, pages, res.acl_data_offset, |
3718 | acl_len); | 3766 | acl_len); |
3719 | if (buf) { | 3767 | if (buf) { |
3720 | ret = -ERANGE; | 3768 | ret = -ERANGE; |
@@ -4919,8 +4967,10 @@ static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr) | |||
4919 | fattr->nlink = 2; | 4967 | fattr->nlink = 2; |
4920 | } | 4968 | } |
4921 | 4969 | ||
4922 | int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | 4970 | static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir, |
4923 | struct nfs4_fs_locations *fs_locations, struct page *page) | 4971 | const struct qstr *name, |
4972 | struct nfs4_fs_locations *fs_locations, | ||
4973 | struct page *page) | ||
4924 | { | 4974 | { |
4925 | struct nfs_server *server = NFS_SERVER(dir); | 4975 | struct nfs_server *server = NFS_SERVER(dir); |
4926 | u32 bitmask[2] = { | 4976 | u32 bitmask[2] = { |
@@ -4954,11 +5004,26 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
4954 | nfs_fattr_init(&fs_locations->fattr); | 5004 | nfs_fattr_init(&fs_locations->fattr); |
4955 | fs_locations->server = server; | 5005 | fs_locations->server = server; |
4956 | fs_locations->nlocations = 0; | 5006 | fs_locations->nlocations = 0; |
4957 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); | 5007 | status = nfs4_call_sync(client, server, &msg, &args.seq_args, &res.seq_res, 0); |
4958 | dprintk("%s: returned status = %d\n", __func__, status); | 5008 | dprintk("%s: returned status = %d\n", __func__, status); |
4959 | return status; | 5009 | return status; |
4960 | } | 5010 | } |
4961 | 5011 | ||
5012 | int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir, | ||
5013 | const struct qstr *name, | ||
5014 | struct nfs4_fs_locations *fs_locations, | ||
5015 | struct page *page) | ||
5016 | { | ||
5017 | struct nfs4_exception exception = { }; | ||
5018 | int err; | ||
5019 | do { | ||
5020 | err = nfs4_handle_exception(NFS_SERVER(dir), | ||
5021 | _nfs4_proc_fs_locations(client, dir, name, fs_locations, page), | ||
5022 | &exception); | ||
5023 | } while (exception.retry); | ||
5024 | return err; | ||
5025 | } | ||
5026 | |||
4962 | static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) | 5027 | static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) |
4963 | { | 5028 | { |
4964 | int status; | 5029 | int status; |
@@ -4981,8 +5046,8 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct | |||
4981 | return status; | 5046 | return status; |
4982 | } | 5047 | } |
4983 | 5048 | ||
4984 | static int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, | 5049 | int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, |
4985 | struct nfs4_secinfo_flavors *flavors) | 5050 | struct nfs4_secinfo_flavors *flavors) |
4986 | { | 5051 | { |
4987 | struct nfs4_exception exception = { }; | 5052 | struct nfs4_exception exception = { }; |
4988 | int err; | 5053 | int err; |
@@ -5057,10 +5122,9 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
5057 | nfs4_construct_boot_verifier(clp, &verifier); | 5122 | nfs4_construct_boot_verifier(clp, &verifier); |
5058 | 5123 | ||
5059 | args.id_len = scnprintf(args.id, sizeof(args.id), | 5124 | args.id_len = scnprintf(args.id, sizeof(args.id), |
5060 | "%s/%s.%s/%u", | 5125 | "%s/%s/%u", |
5061 | clp->cl_ipaddr, | 5126 | clp->cl_ipaddr, |
5062 | init_utsname()->nodename, | 5127 | clp->cl_rpcclient->cl_nodename, |
5063 | init_utsname()->domainname, | ||
5064 | clp->cl_rpcclient->cl_auth->au_flavor); | 5128 | clp->cl_rpcclient->cl_auth->au_flavor); |
5065 | 5129 | ||
5066 | res.server_scope = kzalloc(sizeof(struct server_scope), GFP_KERNEL); | 5130 | res.server_scope = kzalloc(sizeof(struct server_scope), GFP_KERNEL); |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 77fc5f959c4e..c54aae364bee 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -4258,8 +4258,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | |||
4258 | status = decode_attr_error(xdr, bitmap, &err); | 4258 | status = decode_attr_error(xdr, bitmap, &err); |
4259 | if (status < 0) | 4259 | if (status < 0) |
4260 | goto xdr_error; | 4260 | goto xdr_error; |
4261 | if (err == -NFS4ERR_WRONGSEC) | ||
4262 | nfs_fixup_secinfo_attributes(fattr, fh); | ||
4263 | 4261 | ||
4264 | status = decode_attr_filehandle(xdr, bitmap, fh); | 4262 | status = decode_attr_filehandle(xdr, bitmap, fh); |
4265 | if (status < 0) | 4263 | if (status < 0) |
@@ -4902,11 +4900,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
4902 | bitmap[3] = {0}; | 4900 | bitmap[3] = {0}; |
4903 | struct kvec *iov = req->rq_rcv_buf.head; | 4901 | struct kvec *iov = req->rq_rcv_buf.head; |
4904 | int status; | 4902 | int status; |
4903 | size_t page_len = xdr->buf->page_len; | ||
4905 | 4904 | ||
4906 | res->acl_len = 0; | 4905 | res->acl_len = 0; |
4907 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) | 4906 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) |
4908 | goto out; | 4907 | goto out; |
4908 | |||
4909 | bm_p = xdr->p; | 4909 | bm_p = xdr->p; |
4910 | res->acl_data_offset = be32_to_cpup(bm_p) + 2; | ||
4911 | res->acl_data_offset <<= 2; | ||
4912 | /* Check if the acl data starts beyond the allocated buffer */ | ||
4913 | if (res->acl_data_offset > page_len) | ||
4914 | return -ERANGE; | ||
4915 | |||
4910 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) | 4916 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) |
4911 | goto out; | 4917 | goto out; |
4912 | if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) | 4918 | if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) |
@@ -4916,28 +4922,24 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
4916 | return -EIO; | 4922 | return -EIO; |
4917 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { | 4923 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { |
4918 | size_t hdrlen; | 4924 | size_t hdrlen; |
4919 | u32 recvd; | ||
4920 | 4925 | ||
4921 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words | 4926 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words |
4922 | * are stored with the acl data to handle the problem of | 4927 | * are stored with the acl data to handle the problem of |
4923 | * variable length bitmaps.*/ | 4928 | * variable length bitmaps.*/ |
4924 | xdr->p = bm_p; | 4929 | xdr->p = bm_p; |
4925 | res->acl_data_offset = be32_to_cpup(bm_p) + 2; | ||
4926 | res->acl_data_offset <<= 2; | ||
4927 | 4930 | ||
4928 | /* We ignore &savep and don't do consistency checks on | 4931 | /* We ignore &savep and don't do consistency checks on |
4929 | * the attr length. Let userspace figure it out.... */ | 4932 | * the attr length. Let userspace figure it out.... */ |
4930 | hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; | 4933 | hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; |
4931 | attrlen += res->acl_data_offset; | 4934 | attrlen += res->acl_data_offset; |
4932 | recvd = req->rq_rcv_buf.len - hdrlen; | 4935 | if (attrlen > page_len) { |
4933 | if (attrlen > recvd) { | ||
4934 | if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { | 4936 | if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { |
4935 | /* getxattr interface called with a NULL buf */ | 4937 | /* getxattr interface called with a NULL buf */ |
4936 | res->acl_len = attrlen; | 4938 | res->acl_len = attrlen; |
4937 | goto out; | 4939 | goto out; |
4938 | } | 4940 | } |
4939 | dprintk("NFS: acl reply: attrlen %u > recvd %u\n", | 4941 | dprintk("NFS: acl reply: attrlen %u > page_len %zu\n", |
4940 | attrlen, recvd); | 4942 | attrlen, page_len); |
4941 | return -EINVAL; | 4943 | return -EINVAL; |
4942 | } | 4944 | } |
4943 | xdr_read_pages(xdr, attrlen); | 4945 | xdr_read_pages(xdr, attrlen); |
@@ -5090,16 +5092,13 @@ out_err: | |||
5090 | return -EINVAL; | 5092 | return -EINVAL; |
5091 | } | 5093 | } |
5092 | 5094 | ||
5093 | static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | 5095 | static int decode_secinfo_common(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) |
5094 | { | 5096 | { |
5095 | struct nfs4_secinfo_flavor *sec_flavor; | 5097 | struct nfs4_secinfo_flavor *sec_flavor; |
5096 | int status; | 5098 | int status; |
5097 | __be32 *p; | 5099 | __be32 *p; |
5098 | int i, num_flavors; | 5100 | int i, num_flavors; |
5099 | 5101 | ||
5100 | status = decode_op_hdr(xdr, OP_SECINFO); | ||
5101 | if (status) | ||
5102 | goto out; | ||
5103 | p = xdr_inline_decode(xdr, 4); | 5102 | p = xdr_inline_decode(xdr, 4); |
5104 | if (unlikely(!p)) | 5103 | if (unlikely(!p)) |
5105 | goto out_overflow; | 5104 | goto out_overflow; |
@@ -5125,6 +5124,7 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | |||
5125 | res->flavors->num_flavors++; | 5124 | res->flavors->num_flavors++; |
5126 | } | 5125 | } |
5127 | 5126 | ||
5127 | status = 0; | ||
5128 | out: | 5128 | out: |
5129 | return status; | 5129 | return status; |
5130 | out_overflow: | 5130 | out_overflow: |
@@ -5132,7 +5132,23 @@ out_overflow: | |||
5132 | return -EIO; | 5132 | return -EIO; |
5133 | } | 5133 | } |
5134 | 5134 | ||
5135 | static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | ||
5136 | { | ||
5137 | int status = decode_op_hdr(xdr, OP_SECINFO); | ||
5138 | if (status) | ||
5139 | return status; | ||
5140 | return decode_secinfo_common(xdr, res); | ||
5141 | } | ||
5142 | |||
5135 | #if defined(CONFIG_NFS_V4_1) | 5143 | #if defined(CONFIG_NFS_V4_1) |
5144 | static int decode_secinfo_no_name(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | ||
5145 | { | ||
5146 | int status = decode_op_hdr(xdr, OP_SECINFO_NO_NAME); | ||
5147 | if (status) | ||
5148 | return status; | ||
5149 | return decode_secinfo_common(xdr, res); | ||
5150 | } | ||
5151 | |||
5136 | static int decode_exchange_id(struct xdr_stream *xdr, | 5152 | static int decode_exchange_id(struct xdr_stream *xdr, |
5137 | struct nfs41_exchange_id_res *res) | 5153 | struct nfs41_exchange_id_res *res) |
5138 | { | 5154 | { |
@@ -6817,7 +6833,7 @@ static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp, | |||
6817 | status = decode_putrootfh(xdr); | 6833 | status = decode_putrootfh(xdr); |
6818 | if (status) | 6834 | if (status) |
6819 | goto out; | 6835 | goto out; |
6820 | status = decode_secinfo(xdr, res); | 6836 | status = decode_secinfo_no_name(xdr, res); |
6821 | out: | 6837 | out: |
6822 | return status; | 6838 | return status; |
6823 | } | 6839 | } |
diff --git a/fs/nfs/objlayout/objlayout.c b/fs/nfs/objlayout/objlayout.c index 8d45f1c318ce..595c5fc21a19 100644 --- a/fs/nfs/objlayout/objlayout.c +++ b/fs/nfs/objlayout/objlayout.c | |||
@@ -604,7 +604,6 @@ int objlayout_get_deviceinfo(struct pnfs_layout_hdr *pnfslay, | |||
604 | { | 604 | { |
605 | struct objlayout_deviceinfo *odi; | 605 | struct objlayout_deviceinfo *odi; |
606 | struct pnfs_device pd; | 606 | struct pnfs_device pd; |
607 | struct super_block *sb; | ||
608 | struct page *page, **pages; | 607 | struct page *page, **pages; |
609 | u32 *p; | 608 | u32 *p; |
610 | int err; | 609 | int err; |
@@ -623,7 +622,6 @@ int objlayout_get_deviceinfo(struct pnfs_layout_hdr *pnfslay, | |||
623 | pd.pglen = PAGE_SIZE; | 622 | pd.pglen = PAGE_SIZE; |
624 | pd.mincount = 0; | 623 | pd.mincount = 0; |
625 | 624 | ||
626 | sb = pnfslay->plh_inode->i_sb; | ||
627 | err = nfs4_proc_getdeviceinfo(NFS_SERVER(pnfslay->plh_inode), &pd); | 625 | err = nfs4_proc_getdeviceinfo(NFS_SERVER(pnfslay->plh_inode), &pd); |
628 | dprintk("%s nfs_getdeviceinfo returned %d\n", __func__, err); | 626 | dprintk("%s nfs_getdeviceinfo returned %d\n", __func__, err); |
629 | if (err) | 627 | if (err) |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index b5d451586943..38512bcd2e98 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -587,7 +587,7 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
587 | 587 | ||
588 | /* allocate pages for xdr post processing */ | 588 | /* allocate pages for xdr post processing */ |
589 | max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | 589 | max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; |
590 | max_pages = max_resp_sz >> PAGE_SHIFT; | 590 | max_pages = nfs_page_array_len(0, max_resp_sz); |
591 | 591 | ||
592 | pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags); | 592 | pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags); |
593 | if (!pages) | 593 | if (!pages) |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 1e6715f0616c..4ac7fca7e4bf 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -2428,7 +2428,7 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags, | |||
2428 | dprintk("--> nfs_xdev_mount()\n"); | 2428 | dprintk("--> nfs_xdev_mount()\n"); |
2429 | 2429 | ||
2430 | /* create a new volume representation */ | 2430 | /* create a new volume representation */ |
2431 | server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr); | 2431 | server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor); |
2432 | if (IS_ERR(server)) { | 2432 | if (IS_ERR(server)) { |
2433 | error = PTR_ERR(server); | 2433 | error = PTR_ERR(server); |
2434 | goto out_err_noserver; | 2434 | goto out_err_noserver; |
@@ -2955,7 +2955,7 @@ nfs4_xdev_mount(struct file_system_type *fs_type, int flags, | |||
2955 | dprintk("--> nfs4_xdev_mount()\n"); | 2955 | dprintk("--> nfs4_xdev_mount()\n"); |
2956 | 2956 | ||
2957 | /* create a new volume representation */ | 2957 | /* create a new volume representation */ |
2958 | server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr); | 2958 | server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor); |
2959 | if (IS_ERR(server)) { | 2959 | if (IS_ERR(server)) { |
2960 | error = PTR_ERR(server); | 2960 | error = PTR_ERR(server); |
2961 | goto out_err_noserver; | 2961 | goto out_err_noserver; |