new function: file_open_root(dentry, mnt, name, flags) opens the file vfs_path_lookup would arrive to. Note that name can be empty; in that case the usual requirement that dentry should be a directory is lifted. open-coded equivalents switched to it, may_open() got down exactly one caller and became static.
Unified · Split
| @@ -124,35 +124,18 @@ void mconsole_log(struct mc_request *req) · 123 unmodified lines | |||
| 124 | #if 0 | 124 | #if 0 |
| 125 | void mconsole_proc(struct mc_request *req) | 125 | void mconsole_proc(struct mc_request *req) |
| 126 | { | 126 | { |
| 127 | struct nameidata nd; | ||
| 128 | struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt; | 127 | struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt; |
| 129 | struct file *file; | 128 | struct file *file; |
| 130 | int n, err; | 129 | int n; |
| 131 | char *ptr = req->request.data, *buf; | 130 | char *ptr = req->request.data, *buf; |
| 132 | mm_segment_t old_fs = get_fs(); | 131 | mm_segment_t old_fs = get_fs(); |
| 133 | 132 | ||
| 134 | ptr += strlen("proc"); | 133 | ptr += strlen("proc"); |
| 135 | ptr = skip_spaces(ptr); | 134 | ptr = skip_spaces(ptr); |
| 136 | 135 | ||
| 137 | err = vfs_path_lookup(mnt->mnt_root, mnt, ptr, LOOKUP_FOLLOW, &nd); | 136 | file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY); |
| 138 | if (err) { | ||
| 139 | mconsole_reply(req, "Failed to look up file", 1, 0); | ||
| 140 | goto out; | ||
| 141 | } | ||
| 142 | |||
| 143 | err = may_open(&nd.path, MAY_READ, O_RDONLY); | ||
| 144 | if (result) { | ||
| 145 | mconsole_reply(req, "Failed to open file", 1, 0); | ||
| 146 | path_put(&nd.path); | ||
| 147 | goto out; | ||
| 148 | } | ||
| 149 | |||
| 150 | file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY, | ||
| 151 | current_cred()); | ||
| 152 | err = PTR_ERR(file); | ||
| 153 | if (IS_ERR(file)) { | 137 | if (IS_ERR(file)) { |
| 154 | mconsole_reply(req, "Failed to open file", 1, 0); | 138 | mconsole_reply(req, "Failed to open file", 1, 0); |
| 155 | path_put(&nd.path); | ||
| 156 | goto out; | 139 | goto out; |
| 157 | } | 140 | } |
| 158 | 141 | ||
| @@ -114,6 +114,8 @@ struct open_flags { · 113 unmodified lines | |||
| 114 | }; | 114 | }; |
| 115 | extern struct file *do_filp_open(int dfd, const char *pathname, | 115 | extern 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); |
| 117 | extern 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 |
| @@ -1487,11 +1487,13 @@ static int path_init(int dfd, const char *name, unsigned int flags, · 1486 unmodified lines | |||
| 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, · 439 unmodified lines | |||
| 1937 | return error; | 1939 | return error; |
| 1938 | } | 1940 | } |
| 1939 | 1941 | ||
| 1940 | int may_open(struct path *path, int acc_mode, int flag) | 1942 | static 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: · 306 unmodified lines | |||
| 2250 | } | 2252 | } |
| 2251 | 2253 | ||
| 2252 | static struct file *path_openat(int dfd, const char *pathname, | 2254 | static 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, · 3 unmodified lines | |||
| 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, · 8 unmodified lines | |||
| 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 | } |
| 2313 | out: | 2314 | out: |
| 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 | ||
| 2321 | out_filp: | 2322 | out_filp: |
| @@ -2326,16 +2327,39 @@ out_filp: · 4 unmodified lines | |||
| 2326 | struct file *do_filp_open(int dfd, const char *pathname, | 2327 | struct 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 | ||
| 2341 | struct 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 |
| @@ -22,30 +22,17 @@ · 21 unmodified lines | |||
| 22 | 22 | ||
| 23 | static struct file *do_open(char *name, int flags) | 23 | static 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 | ||
| 51 | static struct { | 38 | static struct { |
| @@ -959,6 +959,20 @@ struct file *filp_open(const char *filename, int flags, int mode) · 958 unmodified lines | |||
| 959 | } | 959 | } |
| 960 | EXPORT_SYMBOL(filp_open); | 960 | EXPORT_SYMBOL(filp_open); |
| 961 | 961 | ||
| 962 | struct 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 | } | ||
| 974 | EXPORT_SYMBOL(file_open_root); | ||
| 975 | |||
| 962 | long do_sys_open(int dfd, const char __user *filename, int flags, int mode) | 976 | long 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; |
| @@ -1990,6 +1990,8 @@ extern int do_fallocate(struct file *file, int mode, loff_t offset, · 1989 unmodified lines | |||
| 1990 | extern long do_sys_open(int dfd, const char __user *filename, int flags, | 1990 | extern long do_sys_open(int dfd, const char __user *filename, int flags, |
| 1991 | int mode); | 1991 | int mode); |
| 1992 | extern struct file *filp_open(const char *, int, int); | 1992 | extern struct file *filp_open(const char *, int, int); |
| 1993 | extern struct file *file_open_root(struct dentry *, struct vfsmount *, | ||
| 1994 | const char *, int); | ||
| 1993 | extern struct file * dentry_open(struct dentry *, struct vfsmount *, int, | 1995 | extern struct file * dentry_open(struct dentry *, struct vfsmount *, int, |
| 1994 | const struct cred *); | 1996 | const struct cred *); |
| 1995 | extern int filp_close(struct file *, fl_owner_t id); | 1997 | extern int filp_close(struct file *, fl_owner_t id); |
| @@ -2205,8 +2207,6 @@ extern struct file *create_read_pipe(struct file *f, int flags); · 209 unmodified lines | |||
| 2205 | extern struct file *create_write_pipe(int flags); | 2207 | extern struct file *create_write_pipe(int flags); |
| 2206 | extern void free_write_pipe(struct file *); | 2208 | extern void free_write_pipe(struct file *); |
| 2207 | 2209 | ||
| 2208 | extern int may_open(struct path *, int, int); | ||
| 2209 | |||
| 2210 | extern int kernel_read(struct file *, loff_t, char *, unsigned long); | 2210 | extern int kernel_read(struct file *, loff_t, char *, unsigned long); |
| 2211 | extern struct file * open_exec(const char *); | 2211 | extern struct file * open_exec(const char *); |
| 2212 | 2212 | ||
| @@ -1321,13 +1321,11 @@ static ssize_t binary_sysctl(const int *name, int nlen, · 1320 unmodified lines | |||
| 1321 | void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) | 1321 | void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) |
| 1322 | { | 1322 | { |
| 1323 | const struct bin_table *table = NULL; | 1323 | const struct bin_table *table = NULL; |
| 1324 | struct nameidata nd; | ||
| 1325 | struct vfsmount *mnt; | 1324 | struct vfsmount *mnt; |
| 1326 | struct file *file; | 1325 | struct file *file; |
| 1327 | ssize_t result; | 1326 | ssize_t result; |
| 1328 | char *pathname; | 1327 | char *pathname; |
| 1329 | int flags; | 1328 | int flags; |
| 1330 | int acc_mode; | ||
| 1331 | 1329 | ||
| 1332 | pathname = sysctl_getname(name, nlen, &table); | 1330 | pathname = sysctl_getname(name, nlen, &table); |
| 1333 | result = PTR_ERR(pathname); | 1331 | result = PTR_ERR(pathname); |
| @@ -1337,28 +1335,17 @@ static ssize_t binary_sysctl(const int *name, int nlen, · 3 unmodified lines | |||
| 1337 | /* How should the sysctl be accessed? */ | 1335 | /* How should the sysctl be accessed? */ |
| 1338 | if (oldval && oldlen && newval && newlen) { | 1336 | if (oldval && oldlen && newval && newlen) { |
| 1339 | flags = O_RDWR; | 1337 | flags = O_RDWR; |
| 1340 | acc_mode = MAY_READ | MAY_WRITE; | ||
| 1341 | } else if (newval && newlen) { | 1338 | } else if (newval && newlen) { |
| 1342 | flags = O_WRONLY; | 1339 | flags = O_WRONLY; |
| 1343 | acc_mode = MAY_WRITE; | ||
| 1344 | } else if (oldval && oldlen) { | 1340 | } else if (oldval && oldlen) { |
| 1345 | flags = O_RDONLY; | 1341 | flags = O_RDONLY; |
| 1346 | acc_mode = MAY_READ; | ||
| 1347 | } else { | 1342 | } else { |
| 1348 | result = 0; | 1343 | result = 0; |
| 1349 | goto out_putname; | 1344 | goto out_putname; |
| 1350 | } | 1345 | } |
| 1351 | 1346 | ||
| 1352 | mnt = current->nsproxy->pid_ns->proc_mnt; | 1347 | mnt = current->nsproxy->pid_ns->proc_mnt; |
| 1353 | result = vfs_path_lookup(mnt->mnt_root, mnt, pathname, 0, &nd); | 1348 | file = file_open_root(mnt->mnt_root, mnt, pathname, flags); |
| 1354 | if (result) | ||
| 1355 | goto out_putname; | ||
| 1356 | |||
| 1357 | result = may_open(&nd.path, acc_mode, flags); | ||
| 1358 | if (result) | ||
| 1359 | goto out_putpath; | ||
| 1360 | |||
| 1361 | file = dentry_open(nd.path.dentry, nd.path.mnt, flags, current_cred()); | ||
| 1362 | result = PTR_ERR(file); | 1349 | result = PTR_ERR(file); |
| 1363 | if (IS_ERR(file)) | 1350 | if (IS_ERR(file)) |
| 1364 | goto out_putname; | 1351 | goto out_putname; |
| @@ -1370,10 +1357,6 @@ out_putname: · 5 unmodified lines | |||
| 1370 | putname(pathname); | 1357 | putname(pathname); |
| 1371 | out: | 1358 | out: |
| 1372 | return result; | 1359 | return result; |
| 1373 | |||
| 1374 | out_putpath: | ||
| 1375 | path_put(&nd.path); | ||
| 1376 | goto out_putname; | ||
| 1377 | } | 1360 | } |
| 1378 | 1361 | ||
| 1379 | 1362 | ||