Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
1643b43f
Commit
1643b43f
authored
Apr 27, 2016
by
Al Viro
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
lookup_open(): lift the "fallback to !O_CREAT" logics from atomic_open()
Signed-off-by:
Al Viro
<
viro@zeniv.linux.org.uk
>
parent
b3d58eaf
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
55 additions
and
89 deletions
+55
-89
fs/namei.c
fs/namei.c
+55
-89
No files found.
fs/namei.c
View file @
1643b43f
...
@@ -2824,63 +2824,19 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode)
...
@@ -2824,63 +2824,19 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode)
static
int
atomic_open
(
struct
nameidata
*
nd
,
struct
dentry
*
dentry
,
static
int
atomic_open
(
struct
nameidata
*
nd
,
struct
dentry
*
dentry
,
struct
path
*
path
,
struct
file
*
file
,
struct
path
*
path
,
struct
file
*
file
,
const
struct
open_flags
*
op
,
const
struct
open_flags
*
op
,
bool
got_write
,
bool
need_lookup
,
int
open_flag
,
umode_t
mode
,
int
*
opened
)
int
*
opened
)
{
{
struct
inode
*
dir
=
nd
->
path
.
dentry
->
d_inode
;
struct
inode
*
dir
=
nd
->
path
.
dentry
->
d_inode
;
unsigned
open_flag
=
op
->
open_flag
;
umode_t
mode
;
int
error
;
int
error
;
int
acc_mode
;
int
acc_mode
;
int
create_error
=
0
;
struct
dentry
*
const
DENTRY_NOT_SET
=
(
void
*
)
-
1UL
;
struct
dentry
*
const
DENTRY_NOT_SET
=
(
void
*
)
-
1UL
;
bool
excl
;
bool
excl
;
BUG_ON
(
dentry
->
d_inode
);
mode
=
op
->
mode
;
if
((
open_flag
&
O_CREAT
)
&&
!
IS_POSIXACL
(
dir
))
mode
&=
~
current_umask
();
excl
=
(
open_flag
&
(
O_EXCL
|
O_CREAT
))
==
(
O_EXCL
|
O_CREAT
);
excl
=
(
open_flag
&
(
O_EXCL
|
O_CREAT
))
==
(
O_EXCL
|
O_CREAT
);
if
(
excl
)
if
(
excl
)
open_flag
&=
~
O_TRUNC
;
open_flag
&=
~
O_TRUNC
;
/*
* Checking write permission is tricky, bacuse we don't know if we are
* going to actually need it: O_CREAT opens should work as long as the
* file exists. But checking existence breaks atomicity. The trick is
* to check access and if not granted clear O_CREAT from the flags.
*
* Another problem is returing the "right" error value (e.g. for an
* O_EXCL open we want to return EEXIST not EROFS).
*/
if
(
open_flag
&
O_CREAT
)
{
if
(
unlikely
(
!
got_write
))
{
create_error
=
-
EROFS
;
if
(
open_flag
&
(
O_EXCL
|
O_TRUNC
))
{
/* Fall back and fail with the right error */
goto
no_open
;
}
/* No side effects, safe to clear O_CREAT */
open_flag
&=
~
O_CREAT
;
}
else
{
create_error
=
may_o_create
(
&
nd
->
path
,
dentry
,
mode
);
if
(
create_error
)
{
if
(
open_flag
&
O_EXCL
)
goto
no_open
;
open_flag
&=
~
O_CREAT
;
}
}
}
else
if
((
open_flag
&
(
O_TRUNC
|
O_WRONLY
|
O_RDWR
))
&&
unlikely
(
!
got_write
))
{
/*
* No O_CREATE -> atomicity not a requirement -> fall
* back to lookup + open
*/
goto
no_open
;
}
if
(
nd
->
flags
&
LOOKUP_DIRECTORY
)
if
(
nd
->
flags
&
LOOKUP_DIRECTORY
)
open_flag
|=
O_DIRECTORY
;
open_flag
|=
O_DIRECTORY
;
...
@@ -2889,11 +2845,8 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
...
@@ -2889,11 +2845,8 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
error
=
dir
->
i_op
->
atomic_open
(
dir
,
dentry
,
file
,
error
=
dir
->
i_op
->
atomic_open
(
dir
,
dentry
,
file
,
open_to_namei_flags
(
open_flag
),
open_to_namei_flags
(
open_flag
),
mode
,
opened
);
mode
,
opened
);
if
(
error
<
0
)
{
if
(
error
<
0
)
if
(
create_error
&&
error
==
-
ENOENT
)
error
=
create_error
;
goto
out
;
goto
out
;
}
if
(
error
)
{
/* returned 1, that is */
if
(
error
)
{
/* returned 1, that is */
if
(
WARN_ON
(
file
->
f_path
.
dentry
==
DENTRY_NOT_SET
))
{
if
(
WARN_ON
(
file
->
f_path
.
dentry
==
DENTRY_NOT_SET
))
{
...
@@ -2906,7 +2859,9 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
...
@@ -2906,7 +2859,9 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
}
}
if
(
*
opened
&
FILE_CREATED
)
if
(
*
opened
&
FILE_CREATED
)
fsnotify_create
(
dir
,
dentry
);
fsnotify_create
(
dir
,
dentry
);
goto
looked_up
;
path
->
dentry
=
dentry
;
path
->
mnt
=
nd
->
path
.
mnt
;
return
1
;
}
}
/*
/*
...
@@ -2925,21 +2880,6 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
...
@@ -2925,21 +2880,6 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
out:
out:
dput
(
dentry
);
dput
(
dentry
);
return
error
;
return
error
;
no_open:
if
(
need_lookup
)
{
dentry
=
lookup_real
(
dir
,
dentry
,
nd
->
flags
);
if
(
IS_ERR
(
dentry
))
return
PTR_ERR
(
dentry
);
}
looked_up:
if
(
create_error
&&
!
dentry
->
d_inode
)
{
error
=
create_error
;
goto
out
;
}
path
->
dentry
=
dentry
;
path
->
mnt
=
nd
->
path
.
mnt
;
return
1
;
}
}
/*
/*
...
@@ -2967,9 +2907,11 @@ static int lookup_open(struct nameidata *nd, struct path *path,
...
@@ -2967,9 +2907,11 @@ static int lookup_open(struct nameidata *nd, struct path *path,
{
{
struct
dentry
*
dir
=
nd
->
path
.
dentry
;
struct
dentry
*
dir
=
nd
->
path
.
dentry
;
struct
inode
*
dir_inode
=
dir
->
d_inode
;
struct
inode
*
dir_inode
=
dir
->
d_inode
;
int
open_flag
=
op
->
open_flag
;
struct
dentry
*
dentry
;
struct
dentry
*
dentry
;
int
error
;
int
error
,
create_error
=
0
;
bool
need_lookup
=
false
;
bool
need_lookup
=
false
;
umode_t
mode
=
op
->
mode
;
if
(
unlikely
(
IS_DEADDIR
(
dir_inode
)))
if
(
unlikely
(
IS_DEADDIR
(
dir_inode
)))
return
-
ENOENT
;
return
-
ENOENT
;
...
@@ -2989,50 +2931,74 @@ static int lookup_open(struct nameidata *nd, struct path *path,
...
@@ -2989,50 +2931,74 @@ static int lookup_open(struct nameidata *nd, struct path *path,
goto
out_no_open
;
goto
out_no_open
;
}
}
/*
* Checking write permission is tricky, bacuse we don't know if we are
* going to actually need it: O_CREAT opens should work as long as the
* file exists. But checking existence breaks atomicity. The trick is
* to check access and if not granted clear O_CREAT from the flags.
*
* Another problem is returing the "right" error value (e.g. for an
* O_EXCL open we want to return EEXIST not EROFS).
*/
if
(
open_flag
&
O_CREAT
)
{
if
(
!
IS_POSIXACL
(
dir
->
d_inode
))
mode
&=
~
current_umask
();
if
(
unlikely
(
!
got_write
))
{
create_error
=
-
EROFS
;
open_flag
&=
~
O_CREAT
;
if
(
open_flag
&
(
O_EXCL
|
O_TRUNC
))
goto
no_open
;
/* No side effects, safe to clear O_CREAT */
}
else
{
create_error
=
may_o_create
(
&
nd
->
path
,
dentry
,
mode
);
if
(
create_error
)
{
open_flag
&=
~
O_CREAT
;
if
(
open_flag
&
O_EXCL
)
goto
no_open
;
}
}
}
else
if
((
open_flag
&
(
O_TRUNC
|
O_WRONLY
|
O_RDWR
))
&&
unlikely
(
!
got_write
))
{
/*
* No O_CREATE -> atomicity not a requirement -> fall
* back to lookup + open
*/
goto
no_open
;
}
if
(
dir_inode
->
i_op
->
atomic_open
)
{
if
(
dir_inode
->
i_op
->
atomic_open
)
{
return
atomic_open
(
nd
,
dentry
,
path
,
file
,
op
,
got_write
,
error
=
atomic_open
(
nd
,
dentry
,
path
,
file
,
op
,
open_flag
,
need_lookup
,
opened
);
mode
,
opened
);
if
(
unlikely
(
error
==
-
ENOENT
)
&&
create_error
)
error
=
create_error
;
return
error
;
}
}
no_open:
if
(
need_lookup
)
{
if
(
need_lookup
)
{
BUG_ON
(
dentry
->
d_inode
);
dentry
=
lookup_real
(
dir_inode
,
dentry
,
nd
->
flags
);
dentry
=
lookup_real
(
dir_inode
,
dentry
,
nd
->
flags
);
if
(
IS_ERR
(
dentry
))
if
(
IS_ERR
(
dentry
))
return
PTR_ERR
(
dentry
);
return
PTR_ERR
(
dentry
);
}
}
/* Negative dentry, just create the file */
/* Negative dentry, just create the file */
if
(
!
dentry
->
d_inode
&&
(
op
->
open_flag
&
O_CREAT
))
{
if
(
!
dentry
->
d_inode
&&
(
open_flag
&
O_CREAT
))
{
umode_t
mode
=
op
->
mode
;
if
(
!
IS_POSIXACL
(
dir
->
d_inode
))
mode
&=
~
current_umask
();
/*
* This write is needed to ensure that a
* rw->ro transition does not occur between
* the time when the file is created and when
* a permanent write count is taken through
* the 'struct file' in finish_open().
*/
if
(
!
got_write
)
{
error
=
-
EROFS
;
goto
out_dput
;
}
*
opened
|=
FILE_CREATED
;
*
opened
|=
FILE_CREATED
;
audit_inode_child
(
dir_inode
,
dentry
,
AUDIT_TYPE_CHILD_CREATE
);
audit_inode_child
(
dir_inode
,
dentry
,
AUDIT_TYPE_CHILD_CREATE
);
error
=
may_o_create
(
&
nd
->
path
,
dentry
,
mode
);
if
(
error
)
goto
out_dput
;
if
(
!
dir_inode
->
i_op
->
create
)
{
if
(
!
dir_inode
->
i_op
->
create
)
{
error
=
-
EACCES
;
error
=
-
EACCES
;
goto
out_dput
;
goto
out_dput
;
}
}
error
=
dir_inode
->
i_op
->
create
(
dir_inode
,
dentry
,
mode
,
error
=
dir_inode
->
i_op
->
create
(
dir_inode
,
dentry
,
mode
,
op
->
op
en_flag
&
O_EXCL
);
open_flag
&
O_EXCL
);
if
(
error
)
if
(
error
)
goto
out_dput
;
goto
out_dput
;
fsnotify_create
(
dir_inode
,
dentry
);
fsnotify_create
(
dir_inode
,
dentry
);
}
}
if
(
unlikely
(
create_error
)
&&
!
dentry
->
d_inode
)
{
error
=
create_error
;
goto
out_dput
;
}
out_no_open:
out_no_open:
path
->
dentry
=
dentry
;
path
->
dentry
=
dentry
;
path
->
mnt
=
nd
->
path
.
mnt
;
path
->
mnt
=
nd
->
path
.
mnt
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment