Skip to content

Commit 99a4a90

Browse files
author
Al Viro
committed
lookup_open(): don't bother with fallbacks to lookup+create
We fall back to lookup+create (instead of atomic_open) in several cases: 1) we don't have write access to filesystem and O_TRUNC is present in the flags. It's not something we want ->atomic_open() to see - it just might go ahead and truncate the file. However, we can pass it the flags sans O_TRUNC - eventually do_open() will call handle_truncate() anyway. 2) we have O_CREAT | O_EXCL and we can't write to parent. That's going to be an error, of course, but we want to know _which_ error should that be - might be EEXIST (if file exists), might be EACCES or EROFS. Simply stripping O_CREAT (and checking if we see ENOENT) would suffice, if not for O_EXCL. However, we used to have ->atomic_open() fully responsible for rejecting O_CREAT | O_EXCL on existing file and just stripping O_CREAT would've disarmed those checks. With nothing downstream to catch the problem - FMODE_OPENED used to be "don't bother with EEXIST checks, ->atomic_open() has done those". Now EEXIST checks downstream are skipped only if FMODE_CREATED is set - FMODE_OPENED alone is not enough. That has eliminated the need to fall back onto lookup+create path in this case. 3) O_WRONLY or O_RDWR when we have no write access to filesystem, with nothing else objectionable. Fallback is (and had always been) pointless. IOW, we don't really need that fallback; all we need in such cases is to trim O_TRUNC and O_CREAT properly. Signed-off-by: Al Viro <[email protected]>
1 parent d489cf9 commit 99a4a90

File tree

1 file changed

+9
-25
lines changed

1 file changed

+9
-25
lines changed

fs/namei.c

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2939,9 +2939,6 @@ static struct dentry *atomic_open(struct nameidata *nd, struct dentry *dentry,
29392939
struct inode *dir = nd->path.dentry->d_inode;
29402940
int error;
29412941

2942-
if (!(~open_flag & (O_EXCL | O_CREAT))) /* both O_EXCL and O_CREAT */
2943-
open_flag &= ~O_TRUNC;
2944-
29452942
if (nd->flags & LOOKUP_DIRECTORY)
29462943
open_flag |= O_DIRECTORY;
29472944

@@ -3038,40 +3035,27 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file,
30383035
* Another problem is returing the "right" error value (e.g. for an
30393036
* O_EXCL open we want to return EEXIST not EROFS).
30403037
*/
3038+
if (unlikely(!got_write))
3039+
open_flag &= ~O_TRUNC;
30413040
if (open_flag & O_CREAT) {
3041+
if (open_flag & O_EXCL)
3042+
open_flag &= ~O_TRUNC;
30423043
if (!IS_POSIXACL(dir->d_inode))
30433044
mode &= ~current_umask();
3044-
if (unlikely(!got_write)) {
3045-
create_error = -EROFS;
3046-
open_flag &= ~O_CREAT;
3047-
if (open_flag & (O_EXCL | O_TRUNC))
3048-
goto no_open;
3049-
/* No side effects, safe to clear O_CREAT */
3050-
} else {
3045+
if (likely(got_write))
30513046
create_error = may_o_create(&nd->path, dentry, mode);
3052-
if (create_error) {
3053-
open_flag &= ~O_CREAT;
3054-
if (open_flag & O_EXCL)
3055-
goto no_open;
3056-
}
3057-
}
3058-
} else if ((open_flag & (O_TRUNC|O_WRONLY|O_RDWR)) &&
3059-
unlikely(!got_write)) {
3060-
/*
3061-
* No O_CREATE -> atomicity not a requirement -> fall
3062-
* back to lookup + open
3063-
*/
3064-
goto no_open;
3047+
else
3048+
create_error = -EROFS;
30653049
}
3066-
3050+
if (create_error)
3051+
open_flag &= ~O_CREAT;
30673052
if (dir_inode->i_op->atomic_open) {
30683053
dentry = atomic_open(nd, dentry, file, open_flag, mode);
30693054
if (unlikely(create_error) && dentry == ERR_PTR(-ENOENT))
30703055
dentry = ERR_PTR(create_error);
30713056
return dentry;
30723057
}
30733058

3074-
no_open:
30753059
if (d_in_lookup(dentry)) {
30763060
struct dentry *res = dir_inode->i_op->lookup(dir_inode, dentry,
30773061
nd->flags);

0 commit comments

Comments
 (0)