diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-13 20:10:19 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-13 20:10:19 +0300 |
commit | e7989f973ae1b90ec7c0b671c81f7f553affccbe (patch) | |
tree | ef0ac4280b31e29b920fd07748de7b4bc1ec10bb /fs | |
parent | c353f88f3de485a059e5c003721e2dc276d02fad (diff) | |
parent | 5b97eeacbd80a7bb60f2534eb43304f821e1ba06 (diff) | |
download | linux-e7989f973ae1b90ec7c0b671c81f7f553affccbe.tar.xz |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
Pull fuse updates from Miklos Szeredi:
"This fixes a regression (spotted by the Sandstorm.io folks) in the pid
namespace handling introduced in 4.12.
There's also a fix for honoring sync/dsync flags for pwritev2()"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
fuse: getattr cleanup
fuse: honor iocb sync flags on write
fuse: allow server to run in different pid_ns
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fuse/cuse.c | 4 | ||||
-rw-r--r-- | fs/fuse/dev.c | 13 | ||||
-rw-r--r-- | fs/fuse/dir.c | 30 | ||||
-rw-r--r-- | fs/fuse/file.c | 52 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 8 |
5 files changed, 53 insertions, 54 deletions
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index c5b6b7165489..e9e97803442a 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c @@ -90,7 +90,7 @@ static struct list_head *cuse_conntbl_head(dev_t devt) static ssize_t cuse_read_iter(struct kiocb *kiocb, struct iov_iter *to) { - struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(kiocb->ki_filp); + struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(kiocb); loff_t pos = 0; return fuse_direct_io(&io, to, &pos, FUSE_DIO_CUSE); @@ -98,7 +98,7 @@ static ssize_t cuse_read_iter(struct kiocb *kiocb, struct iov_iter *to) static ssize_t cuse_write_iter(struct kiocb *kiocb, struct iov_iter *from) { - struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(kiocb->ki_filp); + struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(kiocb); loff_t pos = 0; /* * No locking or generic_write_checks(), the server is diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index c16d00e53264..13c65dd2d37d 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1222,9 +1222,6 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, struct fuse_in *in; unsigned reqsize; - if (task_active_pid_ns(current) != fc->pid_ns) - return -EIO; - restart: spin_lock(&fiq->waitq.lock); err = -EAGAIN; @@ -1262,6 +1259,13 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, in = &req->in; reqsize = in->h.len; + + if (task_active_pid_ns(current) != fc->pid_ns) { + rcu_read_lock(); + in->h.pid = pid_vnr(find_pid_ns(in->h.pid, fc->pid_ns)); + rcu_read_unlock(); + } + /* If request is too large, reply with an error and restart the read */ if (nbytes < reqsize) { req->out.h.error = -EIO; @@ -1823,9 +1827,6 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, struct fuse_req *req; struct fuse_out_header oh; - if (task_active_pid_ns(current) != fc->pid_ns) - return -EIO; - if (nbytes < sizeof(struct fuse_out_header)) return -EINVAL; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 00800c07ba1c..622081b97426 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -923,33 +923,29 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, return err; } -int fuse_update_attributes(struct inode *inode, struct kstat *stat, - struct file *file, bool *refreshed) +static int fuse_update_get_attr(struct inode *inode, struct file *file, + struct kstat *stat) { struct fuse_inode *fi = get_fuse_inode(inode); - int err; - bool r; + int err = 0; if (time_before64(fi->i_time, get_jiffies_64())) { - r = true; forget_all_cached_acls(inode); err = fuse_do_getattr(inode, stat, file); - } else { - r = false; - err = 0; - if (stat) { - generic_fillattr(inode, stat); - stat->mode = fi->orig_i_mode; - stat->ino = fi->orig_ino; - } + } else if (stat) { + generic_fillattr(inode, stat); + stat->mode = fi->orig_i_mode; + stat->ino = fi->orig_ino; } - if (refreshed != NULL) - *refreshed = r; - return err; } +int fuse_update_attributes(struct inode *inode, struct file *file) +{ + return fuse_update_get_attr(inode, file, NULL); +} + int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, u64 child_nodeid, struct qstr *name) { @@ -1786,7 +1782,7 @@ static int fuse_getattr(const struct path *path, struct kstat *stat, if (!fuse_allow_current_process(fc)) return -EACCES; - return fuse_update_attributes(inode, stat, NULL, NULL); + return fuse_update_get_attr(inode, NULL, stat); } static const struct inode_operations fuse_dir_inode_operations = { diff --git a/fs/fuse/file.c b/fs/fuse/file.c index d66789804287..cb7dff5c45d7 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -645,7 +645,7 @@ static size_t fuse_async_req_send(struct fuse_conn *fc, struct fuse_req *req, static size_t fuse_send_read(struct fuse_req *req, struct fuse_io_priv *io, loff_t pos, size_t count, fl_owner_t owner) { - struct file *file = io->file; + struct file *file = io->iocb->ki_filp; struct fuse_file *ff = file->private_data; struct fuse_conn *fc = ff->fc; @@ -707,7 +707,8 @@ static void fuse_short_read(struct fuse_req *req, struct inode *inode, static int fuse_do_readpage(struct file *file, struct page *page) { - struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(file); + struct kiocb iocb; + struct fuse_io_priv io; struct inode *inode = page->mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_req *req; @@ -735,6 +736,8 @@ static int fuse_do_readpage(struct file *file, struct page *page) req->num_pages = 1; req->pages[0] = page; req->page_descs[0].length = count; + init_sync_kiocb(&iocb, file); + io = (struct fuse_io_priv) FUSE_IO_PRIV_SYNC(&iocb); num_read = fuse_send_read(req, &io, pos, count, NULL); err = req->out.h.error; @@ -923,7 +926,7 @@ static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to) if (fc->auto_inval_data || (iocb->ki_pos + iov_iter_count(to) > i_size_read(inode))) { int err; - err = fuse_update_attributes(inode, NULL, iocb->ki_filp, NULL); + err = fuse_update_attributes(inode, iocb->ki_filp); if (err) return err; } @@ -957,13 +960,18 @@ static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff, static size_t fuse_send_write(struct fuse_req *req, struct fuse_io_priv *io, loff_t pos, size_t count, fl_owner_t owner) { - struct file *file = io->file; + struct kiocb *iocb = io->iocb; + struct file *file = iocb->ki_filp; struct fuse_file *ff = file->private_data; struct fuse_conn *fc = ff->fc; struct fuse_write_in *inarg = &req->misc.write.in; fuse_write_fill(req, ff, pos, count); inarg->flags = file->f_flags; + if (iocb->ki_flags & IOCB_DSYNC) + inarg->flags |= O_DSYNC; + if (iocb->ki_flags & IOCB_SYNC) + inarg->flags |= O_SYNC; if (owner != NULL) { inarg->write_flags |= FUSE_WRITE_LOCKOWNER; inarg->lock_owner = fuse_lock_owner_id(fc, owner); @@ -993,14 +1001,14 @@ bool fuse_write_update_size(struct inode *inode, loff_t pos) return ret; } -static size_t fuse_send_write_pages(struct fuse_req *req, struct file *file, +static size_t fuse_send_write_pages(struct fuse_req *req, struct kiocb *iocb, struct inode *inode, loff_t pos, size_t count) { size_t res; unsigned offset; unsigned i; - struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(file); + struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb); for (i = 0; i < req->num_pages; i++) fuse_wait_on_page_writeback(inode, req->pages[i]->index); @@ -1100,7 +1108,7 @@ static inline unsigned fuse_wr_pages(loff_t pos, size_t len) FUSE_MAX_PAGES_PER_REQ); } -static ssize_t fuse_perform_write(struct file *file, +static ssize_t fuse_perform_write(struct kiocb *iocb, struct address_space *mapping, struct iov_iter *ii, loff_t pos) { @@ -1133,7 +1141,7 @@ static ssize_t fuse_perform_write(struct file *file, } else { size_t num_written; - num_written = fuse_send_write_pages(req, file, inode, + num_written = fuse_send_write_pages(req, iocb, inode, pos, count); err = req->out.h.error; if (!err) { @@ -1169,7 +1177,7 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (get_fuse_conn(inode)->writeback_cache) { /* Update size (EOF optimization) and mode (SUID clearing) */ - err = fuse_update_attributes(mapping->host, NULL, file, NULL); + err = fuse_update_attributes(mapping->host, file); if (err) return err; @@ -1201,7 +1209,7 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) pos += written; - written_buffered = fuse_perform_write(file, mapping, from, pos); + written_buffered = fuse_perform_write(iocb, mapping, from, pos); if (written_buffered < 0) { err = written_buffered; goto out; @@ -1220,13 +1228,15 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) written += written_buffered; iocb->ki_pos = pos + written_buffered; } else { - written = fuse_perform_write(file, mapping, from, iocb->ki_pos); + written = fuse_perform_write(iocb, mapping, from, iocb->ki_pos); if (written >= 0) iocb->ki_pos += written; } out: current->backing_dev_info = NULL; inode_unlock(inode); + if (written > 0) + written = generic_write_sync(iocb, written); return written ? written : err; } @@ -1317,7 +1327,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter, { int write = flags & FUSE_DIO_WRITE; int cuse = flags & FUSE_DIO_CUSE; - struct file *file = io->file; + struct file *file = io->iocb->ki_filp; struct inode *inode = file->f_mapping->host; struct fuse_file *ff = file->private_data; struct fuse_conn *fc = ff->fc; @@ -1399,8 +1409,7 @@ static ssize_t __fuse_direct_read(struct fuse_io_priv *io, loff_t *ppos) { ssize_t res; - struct file *file = io->file; - struct inode *inode = file_inode(file); + struct inode *inode = file_inode(io->iocb->ki_filp); if (is_bad_inode(inode)) return -EIO; @@ -1414,15 +1423,14 @@ static ssize_t __fuse_direct_read(struct fuse_io_priv *io, static ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to) { - struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb->ki_filp); + struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb); return __fuse_direct_read(&io, to, &iocb->ki_pos); } static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from) { - struct file *file = iocb->ki_filp; - struct inode *inode = file_inode(file); - struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(file); + struct inode *inode = file_inode(iocb->ki_filp); + struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb); ssize_t res; if (is_bad_inode(inode)) @@ -2181,9 +2189,6 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock) if ((fl->fl_flags & FL_CLOSE_POSIX) == FL_CLOSE_POSIX) return 0; - if (pid && pid_nr == 0) - return -EOVERFLOW; - fuse_lk_fill(&args, file, fl, opcode, pid_nr, flock, &inarg); err = fuse_simple_request(fc, &args); @@ -2303,7 +2308,7 @@ static loff_t fuse_lseek(struct file *file, loff_t offset, int whence) return vfs_setpos(file, outarg.offset, inode->i_sb->s_maxbytes); fallback: - err = fuse_update_attributes(inode, NULL, file, NULL); + err = fuse_update_attributes(inode, file); if (!err) return generic_file_llseek(file, offset, whence); else @@ -2323,7 +2328,7 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence) break; case SEEK_END: inode_lock(inode); - retval = fuse_update_attributes(inode, NULL, file, NULL); + retval = fuse_update_attributes(inode, file); if (!retval) retval = generic_file_llseek(file, offset, whence); inode_unlock(inode); @@ -2874,7 +2879,6 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter) io->offset = offset; io->write = (iov_iter_rw(iter) == WRITE); io->err = 0; - io->file = file; /* * By default, we want to optimize all I/Os with async request * submission to the client filesystem if supported. diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index bd4d2a3e1ec1..d5773ca67ad2 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -252,16 +252,15 @@ struct fuse_io_priv { bool should_dirty; int err; struct kiocb *iocb; - struct file *file; struct completion *done; bool blocking; }; -#define FUSE_IO_PRIV_SYNC(f) \ +#define FUSE_IO_PRIV_SYNC(i) \ { \ .refcnt = KREF_INIT(1), \ .async = 0, \ - .file = f, \ + .iocb = i, \ } /** @@ -905,8 +904,7 @@ u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id); void fuse_update_ctime(struct inode *inode); -int fuse_update_attributes(struct inode *inode, struct kstat *stat, - struct file *file, bool *refreshed); +int fuse_update_attributes(struct inode *inode, struct file *file); void fuse_flush_writepages(struct inode *inode); |