aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/internal.h2
-rw-r--r--fs/namei.c80
-rw-r--r--fs/nfsctl.c21
-rw-r--r--fs/open.c14
4 files changed, 72 insertions, 45 deletions
diff --git a/fs/internal.h b/fs/internal.h
index 6fdbdf2c6047..52abc5287f50 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -114,6 +114,8 @@ struct open_flags {
114}; 114};
115extern struct file *do_filp_open(int dfd, const char *pathname, 115extern struct file *do_filp_open(int dfd, const char *pathname,
116 const struct open_flags *op, int lookup_flags); 116 const struct open_flags *op, int lookup_flags);
117extern struct file *do_file_open_root(struct dentry *, struct vfsmount *,
118 const char *, const struct open_flags *, int lookup_flags);
117 119
118/* 120/*
119 * inode.c 121 * inode.c
diff --git a/fs/namei.c b/fs/namei.c
index 8ee7785d5642..abc8d2df121c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1487,11 +1487,13 @@ static int path_init(int dfd, const char *name, unsigned int flags,
1487 nd->depth = 0; 1487 nd->depth = 0;
1488 if (flags & LOOKUP_ROOT) { 1488 if (flags & LOOKUP_ROOT) {
1489 struct inode *inode = nd->root.dentry->d_inode; 1489 struct inode *inode = nd->root.dentry->d_inode;
1490 if (!inode->i_op->lookup) 1490 if (*name) {
1491 return -ENOTDIR; 1491 if (!inode->i_op->lookup)
1492 retval = inode_permission(inode, MAY_EXEC); 1492 return -ENOTDIR;
1493 if (retval) 1493 retval = inode_permission(inode, MAY_EXEC);
1494 return retval; 1494 if (retval)
1495 return retval;
1496 }
1495 nd->path = nd->root; 1497 nd->path = nd->root;
1496 nd->inode = inode; 1498 nd->inode = inode;
1497 if (flags & LOOKUP_RCU) { 1499 if (flags & LOOKUP_RCU) {
@@ -1937,7 +1939,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
1937 return error; 1939 return error;
1938} 1940}
1939 1941
1940int may_open(struct path *path, int acc_mode, int flag) 1942static int may_open(struct path *path, int acc_mode, int flag)
1941{ 1943{
1942 struct dentry *dentry = path->dentry; 1944 struct dentry *dentry = path->dentry;
1943 struct inode *inode = dentry->d_inode; 1945 struct inode *inode = dentry->d_inode;
@@ -2250,11 +2252,10 @@ exit:
2250} 2252}
2251 2253
2252static struct file *path_openat(int dfd, const char *pathname, 2254static struct file *path_openat(int dfd, const char *pathname,
2253 const struct open_flags *op, int flags) 2255 struct nameidata *nd, const struct open_flags *op, int flags)
2254{ 2256{
2255 struct file *base = NULL; 2257 struct file *base = NULL;
2256 struct file *filp; 2258 struct file *filp;
2257 struct nameidata nd;
2258 struct path path; 2259 struct path path;
2259 int count = 0; 2260 int count = 0;
2260 int error; 2261 int error;
@@ -2264,27 +2265,27 @@ static struct file *path_openat(int dfd, const char *pathname,
2264 return ERR_PTR(-ENFILE); 2265 return ERR_PTR(-ENFILE);
2265 2266
2266 filp->f_flags = op->open_flag; 2267 filp->f_flags = op->open_flag;
2267 nd.intent.open.file = filp; 2268 nd->intent.open.file = filp;
2268 nd.intent.open.flags = open_to_namei_flags(op->open_flag); 2269 nd->intent.open.flags = open_to_namei_flags(op->open_flag);
2269 nd.intent.open.create_mode = op->mode; 2270 nd->intent.open.create_mode = op->mode;
2270 2271
2271 error = path_init(dfd, pathname, flags | LOOKUP_PARENT, &nd, &base); 2272 error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base);
2272 if (unlikely(error)) 2273 if (unlikely(error))
2273 goto out_filp; 2274 goto out_filp;
2274 2275
2275 current->total_link_count = 0; 2276 current->total_link_count = 0;
2276 error = link_path_walk(pathname, &nd); 2277 error = link_path_walk(pathname, nd);
2277 if (unlikely(error)) 2278 if (unlikely(error))
2278 goto out_filp; 2279 goto out_filp;
2279 2280
2280 filp = do_last(&nd, &path, op, pathname); 2281 filp = do_last(nd, &path, op, pathname);
2281 while (unlikely(!filp)) { /* trailing symlink */ 2282 while (unlikely(!filp)) { /* trailing symlink */
2282 struct path link = path; 2283 struct path link = path;
2283 struct inode *linki = link.dentry->d_inode; 2284 struct inode *linki = link.dentry->d_inode;
2284 void *cookie; 2285 void *cookie;
2285 if (!(nd.flags & LOOKUP_FOLLOW) || count++ == 32) { 2286 if (!(nd->flags & LOOKUP_FOLLOW) || count++ == 32) {
2286 path_put_conditional(&path, &nd); 2287 path_put_conditional(&path, nd);
2287 path_put(&nd.path); 2288 path_put(&nd->path);
2288 filp = ERR_PTR(-ELOOP); 2289 filp = ERR_PTR(-ELOOP);
2289 break; 2290 break;
2290 } 2291 }
@@ -2299,23 +2300,23 @@ static struct file *path_openat(int dfd, const char *pathname,
2299 * have to putname() it when we are done. Procfs-like symlinks 2300 * have to putname() it when we are done. Procfs-like symlinks
2300 * just set LAST_BIND. 2301 * just set LAST_BIND.
2301 */ 2302 */
2302 nd.flags |= LOOKUP_PARENT; 2303 nd->flags |= LOOKUP_PARENT;
2303 nd.flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); 2304 nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
2304 error = __do_follow_link(&link, &nd, &cookie); 2305 error = __do_follow_link(&link, nd, &cookie);
2305 if (unlikely(error)) 2306 if (unlikely(error))
2306 filp = ERR_PTR(error); 2307 filp = ERR_PTR(error);
2307 else 2308 else
2308 filp = do_last(&nd, &path, op, pathname); 2309 filp = do_last(nd, &path, op, pathname);
2309 if (!IS_ERR(cookie) && linki->i_op->put_link) 2310 if (!IS_ERR(cookie) && linki->i_op->put_link)
2310 linki->i_op->put_link(link.dentry, &nd, cookie); 2311 linki->i_op->put_link(link.dentry, nd, cookie);
2311 path_put(&link); 2312 path_put(&link);
2312 } 2313 }
2313out: 2314out:
2314 if (nd.root.mnt && !(nd.flags & LOOKUP_ROOT)) 2315 if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT))
2315 path_put(&nd.root); 2316 path_put(&nd->root);
2316 if (base) 2317 if (base)
2317 fput(base); 2318 fput(base);
2318 release_open_intent(&nd); 2319 release_open_intent(nd);
2319 return filp; 2320 return filp;
2320 2321
2321out_filp: 2322out_filp:
@@ -2326,16 +2327,39 @@ out_filp:
2326struct file *do_filp_open(int dfd, const char *pathname, 2327struct file *do_filp_open(int dfd, const char *pathname,
2327 const struct open_flags *op, int flags) 2328 const struct open_flags *op, int flags)
2328{ 2329{
2330 struct nameidata nd;
2329 struct file *filp; 2331 struct file *filp;
2330 2332
2331 filp = path_openat(dfd, pathname, op, flags | LOOKUP_RCU); 2333 filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);
2332 if (unlikely(filp == ERR_PTR(-ECHILD))) 2334 if (unlikely(filp == ERR_PTR(-ECHILD)))
2333 filp = path_openat(dfd, pathname, op, flags); 2335 filp = path_openat(dfd, pathname, &nd, op, flags);
2334 if (unlikely(filp == ERR_PTR(-ESTALE))) 2336 if (unlikely(filp == ERR_PTR(-ESTALE)))
2335 filp = path_openat(dfd, pathname, op, flags | LOOKUP_REVAL); 2337 filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_REVAL);
2336 return filp; 2338 return filp;
2337} 2339}
2338 2340
2341struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
2342 const char *name, const struct open_flags *op, int flags)
2343{
2344 struct nameidata nd;
2345 struct file *file;
2346
2347 nd.root.mnt = mnt;
2348 nd.root.dentry = dentry;
2349
2350 flags |= LOOKUP_ROOT;
2351
2352 if (dentry->d_inode->i_op->follow_link)
2353 return ERR_PTR(-ELOOP);
2354
2355 file = path_openat(-1, name, &nd, op, flags | LOOKUP_RCU);
2356 if (unlikely(file == ERR_PTR(-ECHILD)))
2357 file = path_openat(-1, name, &nd, op, flags);
2358 if (unlikely(file == ERR_PTR(-ESTALE)))
2359 file = path_openat(-1, name, &nd, op, flags | LOOKUP_REVAL);
2360 return file;
2361}
2362
2339/** 2363/**
2340 * lookup_create - lookup a dentry, creating it if it doesn't exist 2364 * lookup_create - lookup a dentry, creating it if it doesn't exist
2341 * @nd: nameidata info 2365 * @nd: nameidata info
diff --git a/fs/nfsctl.c b/fs/nfsctl.c
index bf9cbd242ddd..124e8fcb0dd6 100644
--- a/fs/nfsctl.c
+++ b/fs/nfsctl.c
@@ -22,30 +22,17 @@
22 22
23static struct file *do_open(char *name, int flags) 23static struct file *do_open(char *name, int flags)
24{ 24{
25 struct nameidata nd;
26 struct vfsmount *mnt; 25 struct vfsmount *mnt;
27 int error; 26 struct file *file;
28 27
29 mnt = do_kern_mount("nfsd", 0, "nfsd", NULL); 28 mnt = do_kern_mount("nfsd", 0, "nfsd", NULL);
30 if (IS_ERR(mnt)) 29 if (IS_ERR(mnt))
31 return (struct file *)mnt; 30 return (struct file *)mnt;
32 31
33 error = vfs_path_lookup(mnt->mnt_root, mnt, name, 0, &nd); 32 file = file_open_root(mnt->mnt_root, mnt, name, flags);
34 mntput(mnt); /* drop do_kern_mount reference */
35 if (error)
36 return ERR_PTR(error);
37
38 if (flags == O_RDWR)
39 error = may_open(&nd.path, MAY_READ|MAY_WRITE, flags);
40 else
41 error = may_open(&nd.path, MAY_WRITE, flags);
42 33
43 if (!error) 34 mntput(mnt); /* drop do_kern_mount reference */
44 return dentry_open(nd.path.dentry, nd.path.mnt, flags, 35 return file;
45 current_cred());
46
47 path_put(&nd.path);
48 return ERR_PTR(error);
49} 36}
50 37
51static struct { 38static struct {
diff --git a/fs/open.c b/fs/open.c
index d05e18c60bae..48afc5c139d2 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -959,6 +959,20 @@ struct file *filp_open(const char *filename, int flags, int mode)
959} 959}
960EXPORT_SYMBOL(filp_open); 960EXPORT_SYMBOL(filp_open);
961 961
962struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
963 const char *filename, int flags)
964{
965 struct open_flags op;
966 int lookup = build_open_flags(flags, 0, &op);
967 if (flags & O_CREAT)
968 return ERR_PTR(-EINVAL);
969 if (!filename && (flags & O_DIRECTORY))
970 if (!dentry->d_inode->i_op->lookup)
971 return ERR_PTR(-ENOTDIR);
972 return do_file_open_root(dentry, mnt, filename, &op, lookup);
973}
974EXPORT_SYMBOL(file_open_root);
975
962long do_sys_open(int dfd, const char __user *filename, int flags, int mode) 976long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
963{ 977{
964 struct open_flags op; 978 struct open_flags op;