diff --git a/Documentation/admin-guide/sysctl/fs.rst b/Documentation/admin-guide/sysctl/fs.rst index 89d645546f34d0..6c54718c9d04ba 100644 --- a/Documentation/admin-guide/sysctl/fs.rst +++ b/Documentation/admin-guide/sysctl/fs.rst @@ -367,12 +367,6 @@ greater than max_request_timeout, the system will use max_request_timeout as the timeout. 0 indicates no max request timeout. The maximum value that can be set is 65535. -If the server did not specify a timeout at mount and both of the above are set -to 0, the timeout is derived from ``/proc/sys/kernel/hung_task_timeout_secs`` -instead, so that a server that stops answering aborts the connection rather than -leaving the waiters around for the hung task detector to report on. Setting -hung_task_timeout_secs to 0 disables this fallback as well. - For timeouts, if the server does not respond to the request by the time the set timeout elapses, then the connection to the fuse server will be aborted. Please note that the timeouts are not 100% precise (eg you may set 60 seconds but diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 096e0953cdcbca..5f426228f4c76a 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -2129,7 +2129,6 @@ int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry, if (fc->dlm && fc->writeback_cache) fuse_dlm_cache_release_locks(fi); spin_lock(&fi->lock); - fi->server_size = 0; i_size_write(inode, 0); spin_unlock(&fi->lock); truncate_pagecache(inode, 0); @@ -2225,13 +2224,6 @@ int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry, /* see the comment in fuse_change_attributes() */ if (!is_wb || is_truncate) i_size_write(inode, outarg.attr.size); - /* - * A truncate settles the size on the server; only shrink the - * server-materialized bound: growing just exposes zeros, which the - * bound need not cover (see fuse_iomap_read_folio_range()). - */ - if (is_truncate && (loff_t) outarg.attr.size < fi->server_size) - fi->server_size = outarg.attr.size; if (is_truncate) { /* NOTE: this may release/reacquire fi->lock */ diff --git a/fs/fuse/file.c b/fs/fuse/file.c index c30da1a6452ed6..7c5b5e8b4ba268 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -334,7 +334,6 @@ static void fuse_truncate_update_attr(struct inode *inode, struct file *file) spin_lock(&fi->lock); fi->attr_version = atomic64_inc_return(&fc->attr_version); - fi->server_size = 0; i_size_write(inode, 0); spin_unlock(&fi->lock); file_update_time(file); @@ -1034,41 +1033,9 @@ static int fuse_iomap_read_folio_range(const struct iomap_iter *iter, struct file *file = iter->private; struct inode *inode = file_inode(file); struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_inode *fi = get_fuse_inode(inode); size_t off = offset_in_folio(folio, pos); - bool hole; int ret; - /* - * Expanding writes claim their new i_size up front (see - * fuse_cache_write_iter()), which keeps iomap's own beyond-EOF - * zeroing in iomap_block_needs_zeroing() from ever firing for the - * write's own range: every block of a file expansion would be read - * from the server although it cannot contain data. Zero-fill - * locally instead when the server is known to hold no data in the - * range and we hold the DLM write lock covering it: - * - * - fi->server_size bounds the data materialized on the server - * (writeback and direct write acknowledgements, server - * attributes), - * - local data not yet acknowledged sits in uptodate blocks, which - * iomap never passes to this callback, - * - the page-granular DLM write lock excludes data written by - * other nodes, re-checked against the live lock tree so a - * revoked lock falls back to reading. - */ - if (fc->dlm) { - spin_lock(&fi->lock); - hole = pos >= fi->server_size; - spin_unlock(&fi->lock); - - if (hole && fuse_dlm_range_is_locked(fi, pos, pos + len - 1, - FUSE_PAGE_LOCK_WRITE)) { - folio_zero_range(folio, off, len); - return 0; - } - } - ret = fuse_do_readfolio(file, folio, off, len); /* @@ -1423,15 +1390,6 @@ bool fuse_write_update_attr(struct inode *inode, loff_t pos, ssize_t written) spin_lock(&fi->lock); fi->attr_version = atomic64_inc_return(&fc->attr_version); - if (written > 0 && S_ISREG(inode->i_mode)) { - /* - * The server acknowledged data up to @pos, keep the - * server-materialized bound in sync for the expansion - * zero-fill in fuse_iomap_read_folio_range(). - */ - if (pos > fi->server_size) - fi->server_size = pos; - } if (written > 0 && pos > inode->i_size) { i_size_write(inode, pos); ret = true; @@ -1587,7 +1545,8 @@ static inline unsigned int fuse_wr_pages(loff_t pos, size_t len, max_pages); } -static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii) +static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii, + bool cache) { struct address_space *mapping = iocb->ki_filp->f_mapping; struct inode *inode = mapping->host; @@ -1617,6 +1576,14 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii) if (count <= 0) { err = count; } else { + /* + * On behalf of a buffered write whose bytes bypass + * the page cache (DLM unaligned edges): the server + * must classify them like the writeback they + * replace. + */ + if (cache) + ia.write.in.write_flags |= FUSE_WRITE_CACHE; err = fuse_send_write_pages(&ia, iocb, inode, pos, count); if (!err) { @@ -1807,6 +1774,88 @@ static ssize_t fuse_writeback_write_iter(struct kiocb *iocb, return written < 0 ? written : total_written; } +/* + * Write @len bytes of @from at the current iocb position, either straight + * through to the server (@through, for an unaligned edge) or through the + * iomap page cache path (@through == false, for the aligned interior). + * Both primitives consume @len bytes from @from and advance iocb->ki_pos; + * the iterator is temporarily capped to @len so the unconsumed tail stays + * available for the next chunk. Returns bytes written (< @len means a + * short write, the caller stops) or a negative error. + */ +static ssize_t fuse_dlm_write_chunk(struct kiocb *iocb, struct iov_iter *from, + struct file *file, size_t len, bool through) +{ + size_t hidden; + ssize_t res; + + if (!len) + return 0; + + /* Cap the iterator to this chunk, keeping the tail for later chunks. */ + hidden = iov_iter_count(from) - len; + iov_iter_truncate(from, len); + res = through ? fuse_perform_write(iocb, from, true) + : fuse_writeback_write_iter(iocb, from, file); + /* Restore from the iterator's own residue, so short writes/errors + * (which leave it partly advanced) reexpand to the exact remainder. */ + iov_iter_reexpand(from, iov_iter_count(from) + hidden); + + return res; +} + +/* + * Buffered write under DLM. A partial page dirtied for writeback would + * have to be completed by reading the untouched remainder back from the + * server, and for a write past the server EOF that READ can only return + * zero bytes: a wasted round trip per unaligned edge. So cache only the + * page-aligned interior, whole pages need no read-modify-write, and + * route the unaligned head and tail straight through to the server. The + * writethrough path writes just those bytes and leaves the page + * non-uptodate, doing no read, and each edge lands as an independent + * FUSE_WRITE carrying FUSE_WRITE_CACHE like the writeback it replaces, + * so writers sharing a boundary page accumulate their bytes on the + * server. Aligned writes take the interior path whole; a + * sub-page write with no aligned interior goes fully through. + */ +static ssize_t fuse_dlm_buffered_write(struct kiocb *iocb, + struct iov_iter *from, + struct file *file) +{ + loff_t pos = iocb->ki_pos; + loff_t end = pos + iov_iter_count(from); + loff_t mid_start = round_up(pos, PAGE_SIZE); + loff_t mid_end = round_down(end, PAGE_SIZE); + ssize_t res, total = 0; + + /* No whole page inside the write: nothing cacheable, all through. */ + if (mid_end <= mid_start) + return fuse_perform_write(iocb, from, true); + + /* Unaligned head [pos, mid_start): through. */ + res = fuse_dlm_write_chunk(iocb, from, file, mid_start - pos, true); + if (res < 0) + return res; + total += res; + if (res < mid_start - pos) + return total; + + /* Aligned interior [mid_start, mid_end): cached whole pages. */ + res = fuse_dlm_write_chunk(iocb, from, file, mid_end - mid_start, false); + if (res < 0) + return total; + total += res; + if (res < mid_end - mid_start) + return total; + + /* Unaligned tail [mid_end, end): through. */ + res = fuse_dlm_write_chunk(iocb, from, file, end - mid_end, true); + if (res > 0) + total += res; + + return total; +} + static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from); /* @@ -1975,9 +2024,7 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from) /* * An append write lands at the current EOF no matter what * ki_pos holds: generic_write_checks() rewrites ki_pos to - * i_size for IOCB_APPEND, and i_size is stable here because - * append writes hold the inode lock exclusive. Lock where - * the data will land. + * i_size for IOCB_APPEND. Lock where the data will land. */ dlm_pos = i_size_read(inode); dlm_len = iov_iter_count(from); @@ -1992,6 +2039,24 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from) if (err <= 0) goto out; + /* + * The exclusive inode lock does not pin i_size for the append: + * attribute replies move it under fi->lock alone, so + * generic_write_checks() may have put ki_pos past the granted + * range. Re-lock where the write really lands; dlm_pos tracks it + * so the in-gate re-validation below guards the same range. + */ + if (writeback && fc->dlm && (iocb->ki_flags & IOCB_APPEND) && + iocb->ki_pos != dlm_pos) { + dlm_pos = iocb->ki_pos; + dlm_len = count; + + err = fuse_cache_wr_dlm_lock(file, dlm_pos, dlm_len, + &dlm_unrecorded); + if (err) + goto out; + } + /* * Kill suid/sgid and stamp the timestamps here, before the gate, * instead of leaving them next to the write itself. kiocb_modified() @@ -2044,7 +2109,8 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from) if (written < 0 || !iov_iter_count(from)) goto out; written = direct_write_fallback(iocb, from, written, - fuse_perform_write(iocb, from)); + fuse_perform_write(iocb, from, + false)); } else if (writeback) { loff_t pos = iocb->ki_pos; loff_t end = pos + count; @@ -2085,7 +2151,16 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from) pagecache_isize_extended(inode, orig_size, pos); } - written = fuse_writeback_write_iter(iocb, from, file); + /* + * Under DLM the unaligned edges go through to the server + * instead of being completed by a read-modify-write READ + * (see fuse_dlm_buffered_write()); only whole pages are + * cached for writeback. + */ + if (fc->dlm) + written = fuse_dlm_buffered_write(iocb, from, file); + else + written = fuse_writeback_write_iter(iocb, from, file); /* * Reconcile the speculative extension with what was actually @@ -2111,7 +2186,7 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from) goto out; } } else { - written = fuse_perform_write(iocb, from); + written = fuse_perform_write(iocb, from, false); } out: if (wb_guard) @@ -2598,20 +2673,6 @@ static void fuse_writepage_end(struct fuse_mount *fm, struct fuse_args *args, if (!fc->writeback_cache) fuse_invalidate_attr_mask(inode, FUSE_STATX_MODIFY); spin_lock(&fi->lock); - if (!error) { - struct fuse_write_in *inarg = &wpa->ia.write.in; - - /* - * The server acknowledged this writeback, so data up to the - * end of the request is materialized on the server. Advance - * the bound before the folios end writeback below, i.e. - * before they can go clean and be reclaimed, so that - * fuse_iomap_read_folio_range() can never zero-fill a - * reclaimed range the server holds data in. - */ - if ((loff_t) (inarg->offset + inarg->size) > fi->server_size) - fi->server_size = inarg->offset + inarg->size; - } fi->writectr--; fuse_writepage_finish(wpa); spin_unlock(&fi->lock); @@ -3921,7 +3982,6 @@ void fuse_init_file_inode(struct inode *inode, unsigned int flags) fuse_dlm_cache_init(fi); fi->writectr = 0; fi->iocachectr = 0; - fi->server_size = 0; init_waitqueue_head(&fi->page_waitq); init_waitqueue_head(&fi->direct_io_waitq); /* diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 55fe9a5368f481..31580b7834e296 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -53,12 +53,6 @@ /* Frequency (in seconds) of request timeout checks, if opted into */ #define FUSE_TIMEOUT_TIMER_FREQ 15 -/* - * Upper bound (in seconds) for request timeouts. fuse_init_out request - * timeouts are u16, and this goes up to ~18 hours, which is plenty. - */ -#define FUSE_REQ_TIMEOUT_LIMIT 65535 - /** Frequency (in jiffies) of request timeout checks, if opted into */ extern const unsigned long fuse_timeout_timer_freq; @@ -208,20 +202,6 @@ struct fuse_inode { /* dlm locked areas we have sent lock requests for */ struct fuse_dlm_cache dlm_locked_areas; - /* - * Server-materialized size: an upper bound for how far - * the server holds file data. Seeded from - * server-reported attributes, advanced when the server - * acknowledges data (writeback completion, - * fuse_write_update_attr()), lowered again on - * truncate. A read-modify-write of a block starting - * at or past this bound needs no READ request under a - * held DLM write lock: the server has no data there - * (see fuse_iomap_read_folio_range()). Protected by - * fi->lock. - */ - loff_t server_size; - /* * Serializes buffered-write page-cache dirtying against * the forced-direct-IO latch transition driven by diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 2ef8dd685a4c25..d54676b73abf9e 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -584,13 +583,10 @@ static void fuse_change_attributes_i(struct inode *inode, struct fuse_attr *attr loff_t oldsize; struct timespec64 old_mtime; bool have_size = !sx || (sx->mask & STATX_SIZE); - u64 srv_size; cache_mask = fuse_attr_cache_mask(inode, attr, have_size); spin_lock(&fi->lock); - srv_size = attr->size; - if (cache_mask & STATX_SIZE) attr->size = i_size_read(inode); @@ -609,19 +605,6 @@ static void fuse_change_attributes_i(struct inode *inode, struct fuse_attr *attr return; } - /* - * srv_size is the size the server reported before the writeback - * cache_mask above replaced attr->size with the local value. It - * bounds how far the server can hold data, letting the iomap write - * path zero-fill expansion read-modify-writes instead of sending - * READ requests, see fuse_iomap_read_folio_range(). Only ever grow - * it here: stale attributes were rejected above and truncation - * lowers it directly. - */ - if (have_size && S_ISREG(inode->i_mode) && - (loff_t) srv_size > fi->server_size) - fi->server_size = srv_size; - old_mtime = inode_get_mtime(inode); fuse_change_attributes_common(inode, attr, sx, attr_valid, cache_mask, evict_ctr); @@ -1804,31 +1787,11 @@ static void set_request_timeout(struct fuse_conn *fc, unsigned int timeout) fuse_timeout_timer_freq); } -/* - * Timeout to use when neither the server nor the admin asked for one: keep it - * in sync with the hung task detector, which is the system wide notion of "this - * has been stuck for too long". Returns 0 if the detector is disabled. - */ -static unsigned int hung_task_req_timeout(void) -{ - unsigned long timeout = sysctl_hung_task_timeout_secs; - - if (!timeout) - return 0; - - /* - * Requests are only checked every FUSE_TIMEOUT_TIMER_FREQ seconds, so - * aim one period below the hung task timeout in order to abort the - * connection before the detector reports on the waiters. - */ - if (timeout > FUSE_TIMEOUT_TIMER_FREQ) - timeout -= FUSE_TIMEOUT_TIMER_FREQ; - - return min_t(unsigned long, timeout, FUSE_REQ_TIMEOUT_LIMIT); -} - static void init_server_timeout(struct fuse_conn *fc, unsigned int timeout) { + if (!timeout && !fuse_max_req_timeout && !fuse_default_req_timeout) + return; + if (!timeout) timeout = fuse_default_req_timeout; @@ -1839,12 +1802,6 @@ static void init_server_timeout(struct fuse_conn *fc, unsigned int timeout) timeout = fuse_max_req_timeout; } - if (!timeout) - timeout = hung_task_req_timeout(); - - if (!timeout) - return; - timeout = max(FUSE_TIMEOUT_TIMER_FREQ, timeout); set_request_timeout(fc, timeout); diff --git a/fs/fuse/sysctl.c b/fs/fuse/sysctl.c index 107ecae0e4f9dd..e2d921abcb8832 100644 --- a/fs/fuse/sysctl.c +++ b/fs/fuse/sysctl.c @@ -13,7 +13,11 @@ static struct ctl_table_header *fuse_table_header; /* Bound by fuse_init_out max_pages, which is a u16 */ static unsigned int sysctl_fuse_max_pages_limit = 65535; -static unsigned int sysctl_fuse_req_timeout_limit = FUSE_REQ_TIMEOUT_LIMIT; +/* + * fuse_init_out request timeouts are u16. + * This goes up to ~18 hours, which is plenty for a timeout. + */ +static unsigned int sysctl_fuse_req_timeout_limit = 65535; static const struct ctl_table fuse_sysctl_table[] = { {