diff options
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/dev.c | 32 | ||||
-rw-r--r-- | fs/fuse/dir.c | 5 | ||||
-rw-r--r-- | fs/fuse/file.c | 43 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 1 | ||||
-rw-r--r-- | fs/fuse/inode.c | 2 |
5 files changed, 35 insertions, 48 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index cbece1221417..a94d2ed81ab4 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -99,19 +99,6 @@ void fuse_request_free(struct fuse_req *req) kmem_cache_free(fuse_req_cachep, req); } -static void block_sigs(sigset_t *oldset) -{ - sigset_t mask; - - siginitsetinv(&mask, sigmask(SIGKILL)); - sigprocmask(SIG_BLOCK, &mask, oldset); -} - -static void restore_sigs(sigset_t *oldset) -{ - sigprocmask(SIG_SETMASK, oldset, NULL); -} - void __fuse_get_request(struct fuse_req *req) { atomic_inc(&req->count); @@ -151,15 +138,9 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages, atomic_inc(&fc->num_waiting); if (fuse_block_alloc(fc, for_background)) { - sigset_t oldset; - int intr; - - block_sigs(&oldset); - intr = wait_event_interruptible_exclusive(fc->blocked_waitq, - !fuse_block_alloc(fc, for_background)); - restore_sigs(&oldset); err = -EINTR; - if (intr) + if (wait_event_killable_exclusive(fc->blocked_waitq, + !fuse_block_alloc(fc, for_background))) goto out; } /* Matches smp_wmb() in fuse_set_initialized() */ @@ -446,14 +427,9 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) } if (!test_bit(FR_FORCE, &req->flags)) { - sigset_t oldset; - /* Only fatal signals may interrupt this */ - block_sigs(&oldset); - err = wait_event_interruptible(req->waitq, + err = wait_event_killable(req->waitq, test_bit(FR_FINISHED, &req->flags)); - restore_sigs(&oldset); - if (!err) return; @@ -1525,7 +1501,6 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, goto err; fuse_copy_finish(cs); buf[outarg.namelen] = 0; - name.hash = full_name_hash(name.name, name.len); down_read(&fc->killsb); err = -ENOENT; @@ -1576,7 +1551,6 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size, goto err; fuse_copy_finish(cs); buf[outarg.namelen] = 0; - name.hash = full_name_hash(name.name, name.len); down_read(&fc->killsb); err = -ENOENT; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 419230a00b30..c47b7780ce37 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -480,7 +480,7 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry, struct fuse_conn *fc = get_fuse_conn(dir); struct dentry *res = NULL; - if (d_unhashed(entry)) { + if (d_in_lookup(entry)) { res = fuse_lookup(dir, entry, 0); if (IS_ERR(res)) return PTR_ERR(res); @@ -955,6 +955,7 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, if (!dir) goto unlock; + name->hash = full_name_hash(dir, name->name, name->len); entry = d_lookup(dir, name); dput(dir); if (!entry) @@ -1204,7 +1205,7 @@ static int fuse_direntplus_link(struct file *file, fc = get_fuse_conn(dir); - name.hash = full_name_hash(name.name, name.len); + name.hash = full_name_hash(parent, name.name, name.len); dentry = d_lookup(parent, &name); if (!dentry) { retry: diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 9154f8679024..f394aff59c36 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -417,6 +417,10 @@ static int fuse_flush(struct file *file, fl_owner_t id) fuse_sync_writes(inode); inode_unlock(inode); + err = filemap_check_errors(file->f_mapping); + if (err) + return err; + req = fuse_get_req_nofail_nopages(fc, file); memset(&inarg, 0, sizeof(inarg)); inarg.fh = ff->fh; @@ -462,6 +466,16 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end, goto out; fuse_sync_writes(inode); + + /* + * Due to implementation of fuse writeback + * filemap_write_and_wait_range() does not catch errors. + * We have to do this directly after fuse_sync_writes() + */ + err = filemap_check_errors(file->f_mapping); + if (err) + goto out; + err = sync_inode_metadata(inode, 1); if (err) goto out; @@ -562,7 +576,6 @@ static ssize_t fuse_get_res_by_io(struct fuse_io_priv *io) */ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos) { - bool is_sync = is_sync_kiocb(io->iocb); int left; spin_lock(&io->lock); @@ -572,11 +585,11 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos) io->bytes = pos; left = --io->reqs; - if (!left && is_sync) + if (!left && io->blocking) complete(io->done); spin_unlock(&io->lock); - if (!left && !is_sync) { + if (!left && !io->blocking) { ssize_t res = fuse_get_res_by_io(io); if (res >= 0) { @@ -1452,7 +1465,7 @@ static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req) list_del(&req->writepages_entry); for (i = 0; i < req->num_pages; i++) { dec_wb_stat(&bdi->wb, WB_WRITEBACK); - dec_zone_page_state(req->pages[i], NR_WRITEBACK_TEMP); + dec_node_page_state(req->pages[i], NR_WRITEBACK_TEMP); wb_writeout_inc(&bdi->wb); } wake_up(&fi->page_waitq); @@ -1642,7 +1655,7 @@ static int fuse_writepage_locked(struct page *page) req->inode = inode; inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK); - inc_zone_page_state(tmp_page, NR_WRITEBACK_TEMP); + inc_node_page_state(tmp_page, NR_WRITEBACK_TEMP); spin_lock(&fc->lock); list_add(&req->writepages_entry, &fi->writepages); @@ -1756,7 +1769,7 @@ static bool fuse_writepage_in_flight(struct fuse_req *new_req, spin_unlock(&fc->lock); dec_wb_stat(&bdi->wb, WB_WRITEBACK); - dec_zone_page_state(page, NR_WRITEBACK_TEMP); + dec_node_page_state(page, NR_WRITEBACK_TEMP); wb_writeout_inc(&bdi->wb); fuse_writepage_free(fc, new_req); fuse_request_free(new_req); @@ -1855,7 +1868,7 @@ static int fuse_writepages_fill(struct page *page, req->page_descs[req->num_pages].length = PAGE_SIZE; inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK); - inc_zone_page_state(tmp_page, NR_WRITEBACK_TEMP); + inc_node_page_state(tmp_page, NR_WRITEBACK_TEMP); err = 0; if (is_writeback && fuse_writepage_in_flight(req, page)) { @@ -2850,7 +2863,6 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter) size_t count = iov_iter_count(iter); loff_t offset = iocb->ki_pos; struct fuse_io_priv *io; - bool is_sync = is_sync_kiocb(iocb); pos = offset; inode = file->f_mapping->host; @@ -2885,17 +2897,16 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter) */ io->async = async_dio; io->iocb = iocb; + io->blocking = is_sync_kiocb(iocb); /* - * We cannot asynchronously extend the size of a file. We have no method - * to wait on real async I/O requests, so we must submit this request - * synchronously. + * We cannot asynchronously extend the size of a file. + * In such case the aio will behave exactly like sync io. */ - if (!is_sync && (offset + count > i_size) && - iov_iter_rw(iter) == WRITE) - io->async = false; + if ((offset + count > i_size) && iov_iter_rw(iter) == WRITE) + io->blocking = true; - if (io->async && is_sync) { + if (io->async && io->blocking) { /* * Additional reference to keep io around after * calling fuse_aio_complete() @@ -2915,7 +2926,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter) fuse_aio_complete(io, ret < 0 ? ret : 0, -1); /* we have a non-extending, async request, so return */ - if (!is_sync) + if (!io->blocking) return -EIOCBQUEUED; wait_for_completion(&wait); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 9e42c0394196..d98d8cc84def 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -259,6 +259,7 @@ struct fuse_io_priv { struct kiocb *iocb; struct file *file; struct completion *done; + bool blocking; }; #define FUSE_IO_PRIV_SYNC(f) \ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index cdc40537da41..4e05b51120f4 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -938,7 +938,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK | FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ | - FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA | + FUSE_FLOCK_LOCKS | FUSE_HAS_IOCTL_DIR | FUSE_AUTO_INVAL_DATA | FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO | FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT | FUSE_PARALLEL_DIROPS; |