Blame view
fs/nfs/nfs4namespace.c
6.28 KB
f7b422b17 NFS: Split fs/nfs... |
1 2 3 4 |
/* * linux/fs/nfs/nfs4namespace.c * * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> |
54ceac451 NFS: Share NFS su... |
5 |
* - Modified by David Howells <dhowells@redhat.com> |
f7b422b17 NFS: Split fs/nfs... |
6 7 8 |
* * NFSv4 namespace */ |
f7b422b17 NFS: Split fs/nfs... |
9 10 11 12 |
#include <linux/dcache.h> #include <linux/mount.h> #include <linux/namei.h> #include <linux/nfs_fs.h> |
5a0e3ad6a include cleanup: ... |
13 |
#include <linux/slab.h> |
f7b422b17 NFS: Split fs/nfs... |
14 15 16 17 18 |
#include <linux/string.h> #include <linux/sunrpc/clnt.h> #include <linux/vfs.h> #include <linux/inet.h> #include "internal.h" |
c228fd3ae NFSv4: Cleanups f... |
19 |
#include "nfs4_fs.h" |
7d7ea8828 NFS: Use the DNS ... |
20 |
#include "dns_resolve.h" |
f7b422b17 NFS: Split fs/nfs... |
21 22 23 24 |
#define NFSDBG_FACILITY NFSDBG_VFS /* |
ef95d31e6 NFS: Fix misparsi... |
25 26 27 |
* Convert the NFSv4 pathname components into a standard posix path. * * Note that the resulting string will be placed at the end of the buffer |
f7b422b17 NFS: Split fs/nfs... |
28 |
*/ |
509de8111 NFS: Add extra co... |
29 |
static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname, |
f7b422b17 NFS: Split fs/nfs... |
30 31 32 33 34 35 36 37 38 39 |
char *buffer, ssize_t buflen) { char *end = buffer + buflen; int n; *--end = '\0'; buflen--; n = pathname->ncomponents; while (--n >= 0) { |
509de8111 NFS: Add extra co... |
40 |
const struct nfs4_string *component = &pathname->components[n]; |
f7b422b17 NFS: Split fs/nfs... |
41 42 43 44 45 46 47 48 49 50 51 |
buflen -= component->len + 1; if (buflen < 0) goto Elong; end -= component->len; memcpy(end, component->data, component->len); *--end = '/'; } return end; Elong: return ERR_PTR(-ENAMETOOLONG); } |
54ceac451 NFS: Share NFS su... |
52 53 54 |
/* * Determine the mount path as a string */ |
b514f872f nfs: make nfs_pat... |
55 |
static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) |
54ceac451 NFS: Share NFS su... |
56 |
{ |
b514f872f nfs: make nfs_pat... |
57 58 59 60 61 62 63 64 |
char *limit; char *path = nfs_path(&limit, dentry, buffer, buflen); if (!IS_ERR(path)) { char *colon = strchr(path, ':'); if (colon && colon < limit) path = colon + 1; } return path; |
54ceac451 NFS: Share NFS su... |
65 66 67 68 69 70 |
} /* * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we * believe to be the server path to this dentry */ |
b514f872f nfs: make nfs_pat... |
71 |
static int nfs4_validate_fspath(struct dentry *dentry, |
54ceac451 NFS: Share NFS su... |
72 73 74 75 |
const struct nfs4_fs_locations *locations, char *page, char *page2) { const char *path, *fs_path; |
b514f872f nfs: make nfs_pat... |
76 |
path = nfs4_path(dentry, page, PAGE_SIZE); |
54ceac451 NFS: Share NFS su... |
77 78 79 80 81 82 83 84 85 86 |
if (IS_ERR(path)) return PTR_ERR(path); fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); if (IS_ERR(fs_path)) return PTR_ERR(fs_path); if (strncmp(path, fs_path, strlen(fs_path)) != 0) { dprintk("%s: path %s does not begin with fsroot %s ", |
3110ff804 nfs: replace rema... |
87 |
__func__, path, fs_path); |
54ceac451 NFS: Share NFS su... |
88 89 90 91 92 |
return -ENOENT; } return 0; } |
7d7ea8828 NFS: Use the DNS ... |
93 94 95 96 97 98 99 100 101 102 103 104 105 |
static size_t nfs_parse_server_name(char *string, size_t len, struct sockaddr *sa, size_t salen) { ssize_t ret; ret = rpc_pton(string, len, sa, salen); if (ret == 0) { ret = nfs_dns_resolve_name(string, len, sa, salen); if (ret < 0) ret = 0; } return ret; } |
4ada29d5c nfs: break up nfs... |
106 107 108 109 |
static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, char *page, char *page2, const struct nfs4_fs_location *location) { |
364d015e5 NFSv4: Reduce the... |
110 |
const size_t addr_bufsize = sizeof(struct sockaddr_storage); |
4ada29d5c nfs: break up nfs... |
111 112 |
struct vfsmount *mnt = ERR_PTR(-ENOENT); char *mnt_path; |
ef95d31e6 NFS: Fix misparsi... |
113 |
unsigned int maxbuflen; |
460cdbc83 nfs: replace whil... |
114 |
unsigned int s; |
4ada29d5c nfs: break up nfs... |
115 116 117 |
mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE); if (IS_ERR(mnt_path)) |
517be09de NFSv4: Fix the re... |
118 |
return ERR_CAST(mnt_path); |
4ada29d5c nfs: break up nfs... |
119 |
mountdata->mnt_path = mnt_path; |
ef95d31e6 NFS: Fix misparsi... |
120 |
maxbuflen = mnt_path - 1 - page2; |
4ada29d5c nfs: break up nfs... |
121 |
|
364d015e5 NFSv4: Reduce the... |
122 123 124 |
mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL); if (mountdata->addr == NULL) return ERR_PTR(-ENOMEM); |
460cdbc83 nfs: replace whil... |
125 |
for (s = 0; s < location->nservers; s++) { |
ea31a4437 nfs: Fix misparsi... |
126 |
const struct nfs4_string *buf = &location->servers[s]; |
4ada29d5c nfs: break up nfs... |
127 |
|
ef95d31e6 NFS: Fix misparsi... |
128 |
if (buf->len <= 0 || buf->len >= maxbuflen) |
4ada29d5c nfs: break up nfs... |
129 |
continue; |
4ada29d5c nfs: break up nfs... |
130 |
|
ea31a4437 nfs: Fix misparsi... |
131 132 |
if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) continue; |
517be09de NFSv4: Fix the re... |
133 134 |
mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, |
364d015e5 NFSv4: Reduce the... |
135 |
mountdata->addr, addr_bufsize); |
53a0b9c4c NFS: Replace nfs_... |
136 |
if (mountdata->addrlen == 0) |
ea31a4437 nfs: Fix misparsi... |
137 |
continue; |
517be09de NFSv4: Fix the re... |
138 |
|
ec6ee6125 NFS: Replace nfs_... |
139 |
rpc_set_port(mountdata->addr, NFS_PORT); |
ea31a4437 nfs: Fix misparsi... |
140 |
|
ef95d31e6 NFS: Fix misparsi... |
141 142 |
memcpy(page2, buf->data, buf->len); page2[buf->len] = '\0'; |
ea31a4437 nfs: Fix misparsi... |
143 |
mountdata->hostname = page2; |
4ada29d5c nfs: break up nfs... |
144 145 146 147 148 149 150 151 |
snprintf(page, PAGE_SIZE, "%s:%s", mountdata->hostname, mountdata->mnt_path); mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, page, mountdata); if (!IS_ERR(mnt)) break; |
4ada29d5c nfs: break up nfs... |
152 |
} |
364d015e5 NFSv4: Reduce the... |
153 |
kfree(mountdata->addr); |
4ada29d5c nfs: break up nfs... |
154 155 |
return mnt; } |
f7b422b17 NFS: Split fs/nfs... |
156 157 |
/** * nfs_follow_referral - set up mountpoint when hitting a referral on moved error |
f7b422b17 NFS: Split fs/nfs... |
158 |
* @dentry - parent directory |
3f43c6667 NFS: Address a co... |
159 |
* @locations - array of NFSv4 server location information |
f7b422b17 NFS: Split fs/nfs... |
160 161 |
* */ |
f8ad9c4ba nfs: nfs_do_{ref,... |
162 |
static struct vfsmount *nfs_follow_referral(struct dentry *dentry, |
509de8111 NFS: Add extra co... |
163 |
const struct nfs4_fs_locations *locations) |
f7b422b17 NFS: Split fs/nfs... |
164 165 166 |
{ struct vfsmount *mnt = ERR_PTR(-ENOENT); struct nfs_clone_mount mountdata = { |
f8ad9c4ba nfs: nfs_do_{ref,... |
167 |
.sb = dentry->d_sb, |
f7b422b17 NFS: Split fs/nfs... |
168 |
.dentry = dentry, |
f8ad9c4ba nfs: nfs_do_{ref,... |
169 |
.authflavor = NFS_SB(dentry->d_sb)->client->cl_auth->au_flavor, |
f7b422b17 NFS: Split fs/nfs... |
170 |
}; |
54ceac451 NFS: Share NFS su... |
171 |
char *page = NULL, *page2 = NULL; |
3f43c6667 NFS: Address a co... |
172 |
int loc, error; |
f7b422b17 NFS: Split fs/nfs... |
173 174 175 |
if (locations == NULL || locations->nlocations <= 0) goto out; |
3110ff804 nfs: replace rema... |
176 177 |
dprintk("%s: referral at %s/%s ", __func__, |
f7b422b17 NFS: Split fs/nfs... |
178 |
dentry->d_parent->d_name.name, dentry->d_name.name); |
f7b422b17 NFS: Split fs/nfs... |
179 |
page = (char *) __get_free_page(GFP_USER); |
54ceac451 NFS: Share NFS su... |
180 |
if (!page) |
f7b422b17 NFS: Split fs/nfs... |
181 |
goto out; |
54ceac451 NFS: Share NFS su... |
182 |
|
f7b422b17 NFS: Split fs/nfs... |
183 |
page2 = (char *) __get_free_page(GFP_USER); |
54ceac451 NFS: Share NFS su... |
184 |
if (!page2) |
f7b422b17 NFS: Split fs/nfs... |
185 |
goto out; |
54ceac451 NFS: Share NFS su... |
186 |
/* Ensure fs path is a prefix of current dentry path */ |
b514f872f nfs: make nfs_pat... |
187 |
error = nfs4_validate_fspath(dentry, locations, page, page2); |
54ceac451 NFS: Share NFS su... |
188 189 190 |
if (error < 0) { mnt = ERR_PTR(error); goto out; |
f7b422b17 NFS: Split fs/nfs... |
191 |
} |
460cdbc83 nfs: replace whil... |
192 |
for (loc = 0; loc < locations->nlocations; loc++) { |
509de8111 NFS: Add extra co... |
193 |
const struct nfs4_fs_location *location = &locations->locations[loc]; |
f7b422b17 NFS: Split fs/nfs... |
194 195 |
if (location == NULL || location->nservers <= 0 || |
460cdbc83 nfs: replace whil... |
196 |
location->rootpath.ncomponents == 0) |
f7b422b17 NFS: Split fs/nfs... |
197 |
continue; |
f7b422b17 NFS: Split fs/nfs... |
198 |
|
4ada29d5c nfs: break up nfs... |
199 200 201 |
mnt = try_location(&mountdata, page, page2, location); if (!IS_ERR(mnt)) break; |
f7b422b17 NFS: Split fs/nfs... |
202 |
} |
f7b422b17 NFS: Split fs/nfs... |
203 |
out: |
54ceac451 NFS: Share NFS su... |
204 205 |
free_page((unsigned long) page); free_page((unsigned long) page2); |
3110ff804 nfs: replace rema... |
206 207 |
dprintk("%s: done ", __func__); |
f7b422b17 NFS: Split fs/nfs... |
208 209 210 211 212 213 |
return mnt; } /* * nfs_do_refmount - handle crossing a referral on server * @dentry - dentry of referral |
f7b422b17 NFS: Split fs/nfs... |
214 215 |
* */ |
f8ad9c4ba nfs: nfs_do_{ref,... |
216 |
struct vfsmount *nfs_do_refmount(struct dentry *dentry) |
f7b422b17 NFS: Split fs/nfs... |
217 |
{ |
54ceac451 NFS: Share NFS su... |
218 |
struct vfsmount *mnt = ERR_PTR(-ENOMEM); |
f7b422b17 NFS: Split fs/nfs... |
219 220 221 222 223 224 |
struct dentry *parent; struct nfs4_fs_locations *fs_locations = NULL; struct page *page; int err; /* BUG_ON(IS_ROOT(dentry)); */ |
3110ff804 nfs: replace rema... |
225 226 |
dprintk("%s: enter ", __func__); |
f7b422b17 NFS: Split fs/nfs... |
227 228 229 230 231 232 233 234 235 236 |
page = alloc_page(GFP_KERNEL); if (page == NULL) goto out; fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); if (fs_locations == NULL) goto out_free; /* Get locations */ |
54ceac451 NFS: Share NFS su... |
237 |
mnt = ERR_PTR(-ENOENT); |
f7b422b17 NFS: Split fs/nfs... |
238 |
parent = dget_parent(dentry); |
54ceac451 NFS: Share NFS su... |
239 240 |
dprintk("%s: getting locations for %s/%s ", |
3110ff804 nfs: replace rema... |
241 |
__func__, parent->d_name.name, dentry->d_name.name); |
54ceac451 NFS: Share NFS su... |
242 |
|
c228fd3ae NFSv4: Cleanups f... |
243 |
err = nfs4_proc_fs_locations(parent->d_inode, &dentry->d_name, fs_locations, page); |
f7b422b17 NFS: Split fs/nfs... |
244 |
dput(parent); |
54ceac451 NFS: Share NFS su... |
245 246 |
if (err != 0 || fs_locations->nlocations <= 0 || |
f7b422b17 NFS: Split fs/nfs... |
247 248 |
fs_locations->fs_path.ncomponents <= 0) goto out_free; |
f8ad9c4ba nfs: nfs_do_{ref,... |
249 |
mnt = nfs_follow_referral(dentry, fs_locations); |
f7b422b17 NFS: Split fs/nfs... |
250 251 252 253 |
out_free: __free_page(page); kfree(fs_locations); out: |
3110ff804 nfs: replace rema... |
254 255 |
dprintk("%s: done ", __func__); |
f7b422b17 NFS: Split fs/nfs... |
256 257 |
return mnt; } |