|
@@ -724,27 +724,13 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
|
|
|
return ksys_fchown(fd, user, group);
|
|
|
}
|
|
|
|
|
|
-int open_check_o_direct(struct file *f)
|
|
|
-{
|
|
|
- /* NB: we're sure to have correct a_ops only after f_op->open */
|
|
|
- if (f->f_flags & O_DIRECT) {
|
|
|
- if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO)
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static int do_dentry_open(struct file *f,
|
|
|
struct inode *inode,
|
|
|
- int (*open)(struct inode *, struct file *),
|
|
|
- const struct cred *cred)
|
|
|
+ int (*open)(struct inode *, struct file *))
|
|
|
{
|
|
|
static const struct file_operations empty_fops = {};
|
|
|
int error;
|
|
|
|
|
|
- f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
|
|
|
- FMODE_PREAD | FMODE_PWRITE;
|
|
|
-
|
|
|
path_get(&f->f_path);
|
|
|
f->f_inode = inode;
|
|
|
f->f_mapping = inode->i_mapping;
|
|
@@ -753,7 +739,7 @@ static int do_dentry_open(struct file *f,
|
|
|
f->f_wb_err = filemap_sample_wb_err(f->f_mapping);
|
|
|
|
|
|
if (unlikely(f->f_flags & O_PATH)) {
|
|
|
- f->f_mode = FMODE_PATH;
|
|
|
+ f->f_mode = FMODE_PATH | FMODE_OPENED;
|
|
|
f->f_op = &empty_fops;
|
|
|
return 0;
|
|
|
}
|
|
@@ -780,7 +766,7 @@ static int do_dentry_open(struct file *f,
|
|
|
goto cleanup_all;
|
|
|
}
|
|
|
|
|
|
- error = security_file_open(f, cred);
|
|
|
+ error = security_file_open(f);
|
|
|
if (error)
|
|
|
goto cleanup_all;
|
|
|
|
|
@@ -788,6 +774,8 @@ static int do_dentry_open(struct file *f,
|
|
|
if (error)
|
|
|
goto cleanup_all;
|
|
|
|
|
|
+ /* normally all 3 are set; ->open() can clear them if needed */
|
|
|
+ f->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
|
|
|
if (!open)
|
|
|
open = f->f_op->open;
|
|
|
if (open) {
|
|
@@ -795,6 +783,7 @@ static int do_dentry_open(struct file *f,
|
|
|
if (error)
|
|
|
goto cleanup_all;
|
|
|
}
|
|
|
+ f->f_mode |= FMODE_OPENED;
|
|
|
if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
|
|
|
i_readcount_inc(inode);
|
|
|
if ((f->f_mode & FMODE_READ) &&
|
|
@@ -809,9 +798,16 @@ static int do_dentry_open(struct file *f,
|
|
|
|
|
|
file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
|
|
|
|
|
|
+ /* NB: we're sure to have correct a_ops only after f_op->open */
|
|
|
+ if (f->f_flags & O_DIRECT) {
|
|
|
+ if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO)
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
return 0;
|
|
|
|
|
|
cleanup_all:
|
|
|
+ if (WARN_ON_ONCE(error > 0))
|
|
|
+ error = -EINVAL;
|
|
|
fops_put(f->f_op);
|
|
|
if (f->f_mode & FMODE_WRITER) {
|
|
|
put_write_access(inode);
|
|
@@ -854,8 +850,7 @@ int finish_open(struct file *file, struct dentry *dentry,
|
|
|
BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
|
|
|
|
|
|
file->f_path.dentry = dentry;
|
|
|
- error = do_dentry_open(file, d_backing_inode(dentry), open,
|
|
|
- current_cred());
|
|
|
+ error = do_dentry_open(file, d_backing_inode(dentry), open);
|
|
|
if (!error)
|
|
|
*opened |= FILE_OPENED;
|
|
|
|
|
@@ -896,8 +891,7 @@ EXPORT_SYMBOL(file_path);
|
|
|
* @file: newly allocated file with f_flag initialized
|
|
|
* @cred: credentials to use
|
|
|
*/
|
|
|
-int vfs_open(const struct path *path, struct file *file,
|
|
|
- const struct cred *cred)
|
|
|
+int vfs_open(const struct path *path, struct file *file)
|
|
|
{
|
|
|
struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags, 0);
|
|
|
|
|
@@ -905,7 +899,7 @@ int vfs_open(const struct path *path, struct file *file,
|
|
|
return PTR_ERR(dentry);
|
|
|
|
|
|
file->f_path = *path;
|
|
|
- return do_dentry_open(file, d_backing_inode(dentry), NULL, cred);
|
|
|
+ return do_dentry_open(file, d_backing_inode(dentry), NULL);
|
|
|
}
|
|
|
|
|
|
struct file *dentry_open(const struct path *path, int flags,
|
|
@@ -919,19 +913,11 @@ struct file *dentry_open(const struct path *path, int flags,
|
|
|
/* We must always pass in a valid mount pointer. */
|
|
|
BUG_ON(!path->mnt);
|
|
|
|
|
|
- f = get_empty_filp();
|
|
|
+ f = alloc_empty_file(flags, cred);
|
|
|
if (!IS_ERR(f)) {
|
|
|
- f->f_flags = flags;
|
|
|
- error = vfs_open(path, f, cred);
|
|
|
- if (!error) {
|
|
|
- /* from now on we need fput() to dispose of f */
|
|
|
- error = open_check_o_direct(f);
|
|
|
- if (error) {
|
|
|
- fput(f);
|
|
|
- f = ERR_PTR(error);
|
|
|
- }
|
|
|
- } else {
|
|
|
- put_filp(f);
|
|
|
+ error = vfs_open(path, f);
|
|
|
+ if (error) {
|
|
|
+ fput(f);
|
|
|
f = ERR_PTR(error);
|
|
|
}
|
|
|
}
|
|
@@ -939,6 +925,24 @@ struct file *dentry_open(const struct path *path, int flags,
|
|
|
}
|
|
|
EXPORT_SYMBOL(dentry_open);
|
|
|
|
|
|
+struct file *open_with_fake_path(const struct path *path, int flags,
|
|
|
+ struct inode *inode, const struct cred *cred)
|
|
|
+{
|
|
|
+ struct file *f = alloc_empty_file(flags, cred);
|
|
|
+ if (!IS_ERR(f)) {
|
|
|
+ int error;
|
|
|
+
|
|
|
+ f->f_path = *path;
|
|
|
+ error = do_dentry_open(f, inode, NULL);
|
|
|
+ if (error) {
|
|
|
+ fput(f);
|
|
|
+ f = ERR_PTR(error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return f;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(open_with_fake_path);
|
|
|
+
|
|
|
static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op)
|
|
|
{
|
|
|
int lookup_flags = 0;
|
|
@@ -1063,26 +1067,6 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
|
|
|
}
|
|
|
EXPORT_SYMBOL(file_open_root);
|
|
|
|
|
|
-struct file *filp_clone_open(struct file *oldfile)
|
|
|
-{
|
|
|
- struct file *file;
|
|
|
- int retval;
|
|
|
-
|
|
|
- file = get_empty_filp();
|
|
|
- if (IS_ERR(file))
|
|
|
- return file;
|
|
|
-
|
|
|
- file->f_flags = oldfile->f_flags;
|
|
|
- retval = vfs_open(&oldfile->f_path, file, oldfile->f_cred);
|
|
|
- if (retval) {
|
|
|
- put_filp(file);
|
|
|
- return ERR_PTR(retval);
|
|
|
- }
|
|
|
-
|
|
|
- return file;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(filp_clone_open);
|
|
|
-
|
|
|
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
|
|
|
{
|
|
|
struct open_flags op;
|