diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2012-06-05 09:10:15 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-14 08:33:01 -0400 |
commit | d58ffd35c1e595df2cf8ac4803f178c8be95ca7a (patch) | |
tree | c0cb0b2201a641521a4d26f702b5b18b15541772 | |
parent | 7157486541bffc0dfec912e21ae639b029dae3d3 (diff) |
vfs: add lookup_open()
Split out lookup + maybe create from do_last(). This is the part under i_mutex
protection.
The function is called lookup_open() and returns a filp even though the open
part is not used yet.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/namei.c | 99 |
1 files changed, 61 insertions, 38 deletions
diff --git a/fs/namei.c b/fs/namei.c index 285e62e925f7..fad7117dbb28 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2197,19 +2197,73 @@ static inline int open_to_namei_flags(int flag) | |||
2197 | } | 2197 | } |
2198 | 2198 | ||
2199 | /* | 2199 | /* |
2200 | * Lookup, maybe create and open the last component | ||
2201 | * | ||
2202 | * Must be called with i_mutex held on parent. | ||
2203 | * | ||
2204 | * Returns open file or NULL on success, error otherwise. NULL means no open | ||
2205 | * was performed, only lookup. | ||
2206 | */ | ||
2207 | static struct file *lookup_open(struct nameidata *nd, struct path *path, | ||
2208 | const struct open_flags *op, | ||
2209 | int *want_write, bool *created) | ||
2210 | { | ||
2211 | struct dentry *dir = nd->path.dentry; | ||
2212 | struct dentry *dentry; | ||
2213 | int error; | ||
2214 | |||
2215 | *created = false; | ||
2216 | dentry = lookup_hash(nd); | ||
2217 | if (IS_ERR(dentry)) | ||
2218 | return ERR_CAST(dentry); | ||
2219 | |||
2220 | /* Negative dentry, just create the file */ | ||
2221 | if (!dentry->d_inode && (op->open_flag & O_CREAT)) { | ||
2222 | umode_t mode = op->mode; | ||
2223 | if (!IS_POSIXACL(dir->d_inode)) | ||
2224 | mode &= ~current_umask(); | ||
2225 | /* | ||
2226 | * This write is needed to ensure that a | ||
2227 | * rw->ro transition does not occur between | ||
2228 | * the time when the file is created and when | ||
2229 | * a permanent write count is taken through | ||
2230 | * the 'struct file' in nameidata_to_filp(). | ||
2231 | */ | ||
2232 | error = mnt_want_write(nd->path.mnt); | ||
2233 | if (error) | ||
2234 | goto out_dput; | ||
2235 | *want_write = 1; | ||
2236 | *created = true; | ||
2237 | error = security_path_mknod(&nd->path, dentry, mode, 0); | ||
2238 | if (error) | ||
2239 | goto out_dput; | ||
2240 | error = vfs_create(dir->d_inode, dentry, mode, nd); | ||
2241 | if (error) | ||
2242 | goto out_dput; | ||
2243 | } | ||
2244 | path->dentry = dentry; | ||
2245 | path->mnt = nd->path.mnt; | ||
2246 | return NULL; | ||
2247 | |||
2248 | out_dput: | ||
2249 | dput(dentry); | ||
2250 | return ERR_PTR(error); | ||
2251 | } | ||
2252 | |||
2253 | /* | ||
2200 | * Handle the last step of open() | 2254 | * Handle the last step of open() |
2201 | */ | 2255 | */ |
2202 | static struct file *do_last(struct nameidata *nd, struct path *path, | 2256 | static struct file *do_last(struct nameidata *nd, struct path *path, |
2203 | const struct open_flags *op, const char *pathname) | 2257 | const struct open_flags *op, const char *pathname) |
2204 | { | 2258 | { |
2205 | struct dentry *dir = nd->path.dentry; | 2259 | struct dentry *dir = nd->path.dentry; |
2206 | struct dentry *dentry; | ||
2207 | int open_flag = op->open_flag; | 2260 | int open_flag = op->open_flag; |
2208 | int will_truncate = open_flag & O_TRUNC; | 2261 | int will_truncate = open_flag & O_TRUNC; |
2209 | int want_write = 0; | 2262 | int want_write = 0; |
2210 | int acc_mode = op->acc_mode; | 2263 | int acc_mode = op->acc_mode; |
2211 | struct file *filp; | 2264 | struct file *filp; |
2212 | struct inode *inode; | 2265 | struct inode *inode; |
2266 | bool created; | ||
2213 | int symlink_ok = 0; | 2267 | int symlink_ok = 0; |
2214 | struct path save_parent = { .dentry = NULL, .mnt = NULL }; | 2268 | struct path save_parent = { .dentry = NULL, .mnt = NULL }; |
2215 | bool retried = false; | 2269 | bool retried = false; |
@@ -2277,53 +2331,24 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2277 | 2331 | ||
2278 | retry_lookup: | 2332 | retry_lookup: |
2279 | mutex_lock(&dir->d_inode->i_mutex); | 2333 | mutex_lock(&dir->d_inode->i_mutex); |
2334 | filp = lookup_open(nd, path, op, &want_write, &created); | ||
2335 | mutex_unlock(&dir->d_inode->i_mutex); | ||
2280 | 2336 | ||
2281 | dentry = lookup_hash(nd); | 2337 | if (IS_ERR(filp)) |
2282 | error = PTR_ERR(dentry); | 2338 | goto out; |
2283 | if (IS_ERR(dentry)) { | ||
2284 | mutex_unlock(&dir->d_inode->i_mutex); | ||
2285 | goto exit; | ||
2286 | } | ||
2287 | |||
2288 | path->dentry = dentry; | ||
2289 | path->mnt = nd->path.mnt; | ||
2290 | 2339 | ||
2291 | /* Negative dentry, just create the file */ | 2340 | if (created) { |
2292 | if (!dentry->d_inode && (open_flag & O_CREAT)) { | ||
2293 | umode_t mode = op->mode; | ||
2294 | if (!IS_POSIXACL(dir->d_inode)) | ||
2295 | mode &= ~current_umask(); | ||
2296 | /* | ||
2297 | * This write is needed to ensure that a | ||
2298 | * rw->ro transition does not occur between | ||
2299 | * the time when the file is created and when | ||
2300 | * a permanent write count is taken through | ||
2301 | * the 'struct file' in nameidata_to_filp(). | ||
2302 | */ | ||
2303 | error = mnt_want_write(nd->path.mnt); | ||
2304 | if (error) | ||
2305 | goto exit_mutex_unlock; | ||
2306 | want_write = 1; | ||
2307 | /* Don't check for write permission, don't truncate */ | 2341 | /* Don't check for write permission, don't truncate */ |
2308 | open_flag &= ~O_TRUNC; | 2342 | open_flag &= ~O_TRUNC; |
2309 | will_truncate = 0; | 2343 | will_truncate = 0; |
2310 | acc_mode = MAY_OPEN; | 2344 | acc_mode = MAY_OPEN; |
2311 | error = security_path_mknod(&nd->path, dentry, mode, 0); | 2345 | path_to_nameidata(path, nd); |
2312 | if (error) | ||
2313 | goto exit_mutex_unlock; | ||
2314 | error = vfs_create(dir->d_inode, dentry, mode, nd); | ||
2315 | if (error) | ||
2316 | goto exit_mutex_unlock; | ||
2317 | mutex_unlock(&dir->d_inode->i_mutex); | ||
2318 | dput(nd->path.dentry); | ||
2319 | nd->path.dentry = dentry; | ||
2320 | goto common; | 2346 | goto common; |
2321 | } | 2347 | } |
2322 | 2348 | ||
2323 | /* | 2349 | /* |
2324 | * It already exists. | 2350 | * It already exists. |
2325 | */ | 2351 | */ |
2326 | mutex_unlock(&dir->d_inode->i_mutex); | ||
2327 | audit_inode(pathname, path->dentry); | 2352 | audit_inode(pathname, path->dentry); |
2328 | 2353 | ||
2329 | error = -EEXIST; | 2354 | error = -EEXIST; |
@@ -2432,8 +2457,6 @@ out: | |||
2432 | terminate_walk(nd); | 2457 | terminate_walk(nd); |
2433 | return filp; | 2458 | return filp; |
2434 | 2459 | ||
2435 | exit_mutex_unlock: | ||
2436 | mutex_unlock(&dir->d_inode->i_mutex); | ||
2437 | exit_dput: | 2460 | exit_dput: |
2438 | path_put_conditional(path, nd); | 2461 | path_put_conditional(path, nd); |
2439 | exit: | 2462 | exit: |