summaryrefslogtreecommitdiff
path: root/fs/fuse
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse')
-rw-r--r--fs/fuse/dir.c28
-rw-r--r--fs/fuse/file.c47
-rw-r--r--fs/fuse/fuse_i.h3
-rw-r--r--fs/fuse/inode.c2
4 files changed, 56 insertions, 24 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index d50160714595..9f63e493a9b6 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -382,7 +382,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
struct fuse_entry_out outentry;
struct fuse_file *ff;
struct file *file;
- int flags = nd->intent.open.flags - 1;
+ int flags = nd->intent.open.flags;
if (fc->no_create)
return -ENOSYS;
@@ -576,7 +576,7 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
struct nameidata *nd)
{
- if (nd && (nd->flags & LOOKUP_OPEN)) {
+ if (nd) {
int err = fuse_create_open(dir, entry, mode, nd);
if (err != -ENOSYS)
return err;
@@ -971,9 +971,9 @@ static int fuse_access(struct inode *inode, int mask)
return err;
}
-static int fuse_perm_getattr(struct inode *inode, int flags)
+static int fuse_perm_getattr(struct inode *inode, int mask)
{
- if (flags & IPERM_FLAG_RCU)
+ if (mask & MAY_NOT_BLOCK)
return -ECHILD;
return fuse_do_getattr(inode, NULL, NULL);
@@ -992,7 +992,7 @@ static int fuse_perm_getattr(struct inode *inode, int flags)
* access request is sent. Execute permission is still checked
* locally based on file mode.
*/
-static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
+static int fuse_permission(struct inode *inode, int mask)
{
struct fuse_conn *fc = get_fuse_conn(inode);
bool refreshed = false;
@@ -1011,23 +1011,22 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
if (fi->i_time < get_jiffies_64()) {
refreshed = true;
- err = fuse_perm_getattr(inode, flags);
+ err = fuse_perm_getattr(inode, mask);
if (err)
return err;
}
}
if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
- err = generic_permission(inode, mask, flags, NULL);
+ err = generic_permission(inode, mask);
/* If permission is denied, try to refresh file
attributes. This is also needed, because the root
node will at first have no permissions */
if (err == -EACCES && !refreshed) {
- err = fuse_perm_getattr(inode, flags);
+ err = fuse_perm_getattr(inode, mask);
if (!err)
- err = generic_permission(inode, mask,
- flags, NULL);
+ err = generic_permission(inode, mask);
}
/* Note: the opposite of the above test does not
@@ -1035,7 +1034,7 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
noticed immediately, only after the attribute
timeout has expired */
} else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
- if (flags & IPERM_FLAG_RCU)
+ if (mask & MAY_NOT_BLOCK)
return -ECHILD;
err = fuse_access(inode, mask);
@@ -1044,7 +1043,7 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
if (refreshed)
return -EACCES;
- err = fuse_perm_getattr(inode, flags);
+ err = fuse_perm_getattr(inode, mask);
if (!err && !(inode->i_mode & S_IXUGO))
return -EACCES;
}
@@ -1177,9 +1176,10 @@ static int fuse_dir_release(struct inode *inode, struct file *file)
return 0;
}
-static int fuse_dir_fsync(struct file *file, int datasync)
+static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end,
+ int datasync)
{
- return fuse_fsync_common(file, datasync, 1);
+ return fuse_fsync_common(file, start, end, datasync, 1);
}
static bool update_mtime(unsigned ivalid)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 82a66466a24c..d480d9af46c9 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -400,7 +400,8 @@ static void fuse_sync_writes(struct inode *inode)
fuse_release_nowrite(inode);
}
-int fuse_fsync_common(struct file *file, int datasync, int isdir)
+int fuse_fsync_common(struct file *file, loff_t start, loff_t end,
+ int datasync, int isdir)
{
struct inode *inode = file->f_mapping->host;
struct fuse_conn *fc = get_fuse_conn(inode);
@@ -412,9 +413,15 @@ int fuse_fsync_common(struct file *file, int datasync, int isdir)
if (is_bad_inode(inode))
return -EIO;
+ err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+ if (err)
+ return err;
+
if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir))
return 0;
+ mutex_lock(&inode->i_mutex);
+
/*
* Start writeback against all dirty pages of the inode, then
* wait for all outstanding writes, before sending the FSYNC
@@ -422,13 +429,15 @@ int fuse_fsync_common(struct file *file, int datasync, int isdir)
*/
err = write_inode_now(inode, 0);
if (err)
- return err;
+ goto out;
fuse_sync_writes(inode);
req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto out;
+ }
memset(&inarg, 0, sizeof(inarg));
inarg.fh = ff->fh;
@@ -448,12 +457,15 @@ int fuse_fsync_common(struct file *file, int datasync, int isdir)
fc->no_fsync = 1;
err = 0;
}
+out:
+ mutex_unlock(&inode->i_mutex);
return err;
}
-static int fuse_fsync(struct file *file, int datasync)
+static int fuse_fsync(struct file *file, loff_t start, loff_t end,
+ int datasync)
{
- return fuse_fsync_common(file, datasync, 0);
+ return fuse_fsync_common(file, start, end, datasync, 0);
}
void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos,
@@ -1495,7 +1507,7 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock)
pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;
int err;
- if (fl->fl_lmops && fl->fl_lmops->fl_grant) {
+ if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
/* NLM needs asynchronous locks, which we don't support yet */
return -ENOLCK;
}
@@ -1600,15 +1612,32 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin)
struct inode *inode = file->f_path.dentry->d_inode;
mutex_lock(&inode->i_mutex);
- switch (origin) {
- case SEEK_END:
+ if (origin != SEEK_CUR || origin != SEEK_SET) {
retval = fuse_update_attributes(inode, NULL, file, NULL);
if (retval)
goto exit;
+ }
+
+ switch (origin) {
+ case SEEK_END:
offset += i_size_read(inode);
break;
case SEEK_CUR:
offset += file->f_pos;
+ break;
+ case SEEK_DATA:
+ if (offset >= i_size_read(inode)) {
+ retval = -ENXIO;
+ goto exit;
+ }
+ break;
+ case SEEK_HOLE:
+ if (offset >= i_size_read(inode)) {
+ retval = -ENXIO;
+ goto exit;
+ }
+ offset = i_size_read(inode);
+ break;
}
retval = -EINVAL;
if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index b788becada76..c6aa2d4b8517 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -589,7 +589,8 @@ void fuse_release_common(struct file *file, int opcode);
/**
* Send FSYNC or FSYNCDIR request
*/
-int fuse_fsync_common(struct file *file, int datasync, int isdir);
+int fuse_fsync_common(struct file *file, loff_t start, loff_t end,
+ int datasync, int isdir);
/**
* Notify poll wakeup
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index cc6ec4b2f0ff..38f84cd48b67 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -921,6 +921,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
if (sb->s_flags & MS_MANDLOCK)
goto err;
+ sb->s_flags &= ~MS_NOSEC;
+
if (!parse_fuse_opt((char *) data, &d, is_bdev))
goto err;