[PATCH] new (local) helper: user_path_parent()

Preparation to untangling intents mess: reduce the number of do_path_lookup()
callers.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 2ad94ae6 2d8f3038

+57 -80
+57 -80
fs/namei.c
··· 1352 return err; 1353 } 1354 1355 /* 1356 * It's inline, so penalty for filesystems that don't use sticky bit is 1357 * minimal. ··· 2007 asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, 2008 unsigned dev) 2009 { 2010 - int error = 0; 2011 - char * tmp; 2012 - struct dentry * dentry; 2013 struct nameidata nd; 2014 2015 if (S_ISDIR(mode)) 2016 return -EPERM; 2017 - tmp = getname(filename); 2018 - if (IS_ERR(tmp)) 2019 - return PTR_ERR(tmp); 2020 2021 - error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); 2022 if (error) 2023 - goto out; 2024 dentry = lookup_create(&nd, 0); 2025 if (IS_ERR(dentry)) { 2026 error = PTR_ERR(dentry); ··· 2050 out_unlock: 2051 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2052 path_put(&nd.path); 2053 - out: 2054 putname(tmp); 2055 2056 return error; ··· 2089 struct dentry *dentry; 2090 struct nameidata nd; 2091 2092 - tmp = getname(pathname); 2093 - error = PTR_ERR(tmp); 2094 - if (IS_ERR(tmp)) 2095 goto out_err; 2096 2097 - error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); 2098 - if (error) 2099 - goto out; 2100 dentry = lookup_create(&nd, 1); 2101 error = PTR_ERR(dentry); 2102 if (IS_ERR(dentry)) ··· 2110 out_unlock: 2111 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2112 path_put(&nd.path); 2113 - out: 2114 putname(tmp); 2115 out_err: 2116 return error; ··· 2187 struct dentry *dentry; 2188 struct nameidata nd; 2189 2190 - name = getname(pathname); 2191 - if(IS_ERR(name)) 2192 - return PTR_ERR(name); 2193 - 2194 - error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); 2195 if (error) 2196 - goto exit; 2197 2198 switch(nd.last_type) { 2199 case LAST_DOTDOT: ··· 2218 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2219 exit1: 2220 path_put(&nd.path); 2221 - exit: 2222 putname(name); 2223 return error; 2224 } ··· 2266 */ 2267 static long do_unlinkat(int dfd, const char __user *pathname) 2268 { 2269 - int error = 0; 2270 - char * name; 2271 struct dentry *dentry; 2272 struct nameidata nd; 2273 struct inode *inode = NULL; 2274 2275 - name = getname(pathname); 2276 - if(IS_ERR(name)) 2277 - return PTR_ERR(name); 2278 - 2279 - error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); 2280 if (error) 2281 - goto exit; 2282 error = -EISDIR; 2283 if (nd.last_type != LAST_NORM) 2284 goto exit1; ··· 2302 iput(inode); /* truncate the inode here */ 2303 exit1: 2304 path_put(&nd.path); 2305 - exit: 2306 putname(name); 2307 return error; 2308 ··· 2351 asmlinkage long sys_symlinkat(const char __user *oldname, 2352 int newdfd, const char __user *newname) 2353 { 2354 - int error = 0; 2355 - char * from; 2356 - char * to; 2357 struct dentry *dentry; 2358 struct nameidata nd; 2359 2360 from = getname(oldname); 2361 - if(IS_ERR(from)) 2362 return PTR_ERR(from); 2363 - to = getname(newname); 2364 - error = PTR_ERR(to); 2365 - if (IS_ERR(to)) 2366 goto out_putname; 2367 2368 - error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); 2369 - if (error) 2370 - goto out; 2371 dentry = lookup_create(&nd, 0); 2372 error = PTR_ERR(dentry); 2373 if (IS_ERR(dentry)) ··· 2380 out_unlock: 2381 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2382 path_put(&nd.path); 2383 - out: 2384 putname(to); 2385 out_putname: 2386 putname(from); ··· 2446 struct nameidata nd; 2447 struct path old_path; 2448 int error; 2449 - char * to; 2450 2451 if ((flags & ~AT_SYMLINK_FOLLOW) != 0) 2452 return -EINVAL; 2453 - 2454 - to = getname(newname); 2455 - if (IS_ERR(to)) 2456 - return PTR_ERR(to); 2457 2458 error = user_path_at(olddfd, oldname, 2459 flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0, 2460 &old_path); 2461 if (error) 2462 - goto exit; 2463 - error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); 2464 if (error) 2465 goto out; 2466 error = -EXDEV; ··· 2478 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2479 out_release: 2480 path_put(&nd.path); 2481 out: 2482 path_put(&old_path); 2483 - exit: 2484 - putname(to); 2485 2486 return error; 2487 } ··· 2636 return error; 2637 } 2638 2639 - static int do_rename(int olddfd, const char *oldname, 2640 - int newdfd, const char *newname) 2641 { 2642 - int error = 0; 2643 - struct dentry * old_dir, * new_dir; 2644 - struct dentry * old_dentry, *new_dentry; 2645 - struct dentry * trap; 2646 struct nameidata oldnd, newnd; 2647 2648 - error = do_path_lookup(olddfd, oldname, LOOKUP_PARENT, &oldnd); 2649 if (error) 2650 goto exit; 2651 2652 - error = do_path_lookup(newdfd, newname, LOOKUP_PARENT, &newnd); 2653 if (error) 2654 goto exit1; 2655 ··· 2713 unlock_rename(new_dir, old_dir); 2714 exit2: 2715 path_put(&newnd.path); 2716 exit1: 2717 path_put(&oldnd.path); 2718 - exit: 2719 - return error; 2720 - } 2721 - 2722 - asmlinkage long sys_renameat(int olddfd, const char __user *oldname, 2723 - int newdfd, const char __user *newname) 2724 - { 2725 - int error; 2726 - char * from; 2727 - char * to; 2728 - 2729 - from = getname(oldname); 2730 - if(IS_ERR(from)) 2731 - return PTR_ERR(from); 2732 - to = getname(newname); 2733 - error = PTR_ERR(to); 2734 - if (!IS_ERR(to)) { 2735 - error = do_rename(olddfd, from, newdfd, to); 2736 - putname(to); 2737 - } 2738 putname(from); 2739 return error; 2740 } 2741
··· 1352 return err; 1353 } 1354 1355 + static int user_path_parent(int dfd, const char __user *path, 1356 + struct nameidata *nd, char **name) 1357 + { 1358 + char *s = getname(path); 1359 + int error; 1360 + 1361 + if (IS_ERR(s)) 1362 + return PTR_ERR(s); 1363 + 1364 + error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd); 1365 + if (error) 1366 + putname(s); 1367 + else 1368 + *name = s; 1369 + 1370 + return error; 1371 + } 1372 + 1373 /* 1374 * It's inline, so penalty for filesystems that don't use sticky bit is 1375 * minimal. ··· 1989 asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, 1990 unsigned dev) 1991 { 1992 + int error; 1993 + char *tmp; 1994 + struct dentry *dentry; 1995 struct nameidata nd; 1996 1997 if (S_ISDIR(mode)) 1998 return -EPERM; 1999 2000 + error = user_path_parent(dfd, filename, &nd, &tmp); 2001 if (error) 2002 + return error; 2003 + 2004 dentry = lookup_create(&nd, 0); 2005 if (IS_ERR(dentry)) { 2006 error = PTR_ERR(dentry); ··· 2034 out_unlock: 2035 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2036 path_put(&nd.path); 2037 putname(tmp); 2038 2039 return error; ··· 2074 struct dentry *dentry; 2075 struct nameidata nd; 2076 2077 + error = user_path_parent(dfd, pathname, &nd, &tmp); 2078 + if (error) 2079 goto out_err; 2080 2081 dentry = lookup_create(&nd, 1); 2082 error = PTR_ERR(dentry); 2083 if (IS_ERR(dentry)) ··· 2099 out_unlock: 2100 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2101 path_put(&nd.path); 2102 putname(tmp); 2103 out_err: 2104 return error; ··· 2177 struct dentry *dentry; 2178 struct nameidata nd; 2179 2180 + error = user_path_parent(dfd, pathname, &nd, &name); 2181 if (error) 2182 + return error; 2183 2184 switch(nd.last_type) { 2185 case LAST_DOTDOT: ··· 2212 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2213 exit1: 2214 path_put(&nd.path); 2215 putname(name); 2216 return error; 2217 } ··· 2261 */ 2262 static long do_unlinkat(int dfd, const char __user *pathname) 2263 { 2264 + int error; 2265 + char *name; 2266 struct dentry *dentry; 2267 struct nameidata nd; 2268 struct inode *inode = NULL; 2269 2270 + error = user_path_parent(dfd, pathname, &nd, &name); 2271 if (error) 2272 + return error; 2273 + 2274 error = -EISDIR; 2275 if (nd.last_type != LAST_NORM) 2276 goto exit1; ··· 2300 iput(inode); /* truncate the inode here */ 2301 exit1: 2302 path_put(&nd.path); 2303 putname(name); 2304 return error; 2305 ··· 2350 asmlinkage long sys_symlinkat(const char __user *oldname, 2351 int newdfd, const char __user *newname) 2352 { 2353 + int error; 2354 + char *from; 2355 + char *to; 2356 struct dentry *dentry; 2357 struct nameidata nd; 2358 2359 from = getname(oldname); 2360 + if (IS_ERR(from)) 2361 return PTR_ERR(from); 2362 + 2363 + error = user_path_parent(newdfd, newname, &nd, &to); 2364 + if (error) 2365 goto out_putname; 2366 2367 dentry = lookup_create(&nd, 0); 2368 error = PTR_ERR(dentry); 2369 if (IS_ERR(dentry)) ··· 2382 out_unlock: 2383 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2384 path_put(&nd.path); 2385 putname(to); 2386 out_putname: 2387 putname(from); ··· 2449 struct nameidata nd; 2450 struct path old_path; 2451 int error; 2452 + char *to; 2453 2454 if ((flags & ~AT_SYMLINK_FOLLOW) != 0) 2455 return -EINVAL; 2456 2457 error = user_path_at(olddfd, oldname, 2458 flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0, 2459 &old_path); 2460 if (error) 2461 + return error; 2462 + 2463 + error = user_path_parent(newdfd, newname, &nd, &to); 2464 if (error) 2465 goto out; 2466 error = -EXDEV; ··· 2484 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2485 out_release: 2486 path_put(&nd.path); 2487 + putname(to); 2488 out: 2489 path_put(&old_path); 2490 2491 return error; 2492 } ··· 2643 return error; 2644 } 2645 2646 + asmlinkage long sys_renameat(int olddfd, const char __user *oldname, 2647 + int newdfd, const char __user *newname) 2648 { 2649 + struct dentry *old_dir, *new_dir; 2650 + struct dentry *old_dentry, *new_dentry; 2651 + struct dentry *trap; 2652 struct nameidata oldnd, newnd; 2653 + char *from; 2654 + char *to; 2655 + int error; 2656 2657 + error = user_path_parent(olddfd, oldname, &oldnd, &from); 2658 if (error) 2659 goto exit; 2660 2661 + error = user_path_parent(newdfd, newname, &newnd, &to); 2662 if (error) 2663 goto exit1; 2664 ··· 2718 unlock_rename(new_dir, old_dir); 2719 exit2: 2720 path_put(&newnd.path); 2721 + putname(to); 2722 exit1: 2723 path_put(&oldnd.path); 2724 putname(from); 2725 + exit: 2726 return error; 2727 } 2728