From patchwork Tue May 28 16:48:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Wilcox X-Patchwork-Id: 13677031 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C841D172BCE; Tue, 28 May 2024 16:48:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914914; cv=none; b=pNbW/Kh6zTVjdtejPuX/HJ6BW4t9o+Bc0twq9RDeJ8A+2hapztIO2uddqFBRHX+/1yN/Yxz5hxXxy+T/wiGEWyQ88TYotM33GNt+YuYYisZn0g/KZz/nkTp5WJdefAySSyQa7DaQs4k6IK9NyB7sq7SEl1G90+yjjps4B3DYpYw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914914; c=relaxed/simple; bh=ZUIxx2xeFJYxqRMAfylam9w+4tK2gVq5ifvkLE0pePw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Q1MpC/ShSJAPCy0VHkMoIy+Tq4aFFmH2l74aCG7kng1GFY3spSpGqq4gGOmZIfZTCl1/XTG07jh/n8WXZt1xeZQLYjsLXrnHrziUA3jpFMofFzIsxzJdBTw5i6D/7qoCGIM0CZtl6RoZVycwfFialFXGrnKSQkwK3zvnt8kVauE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=e+/iCc0Q; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="e+/iCc0Q" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Transfer-Encoding:MIME-Version: References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To: Content-Type:Content-ID:Content-Description; bh=rNhqStnPi0LQIT1jWD+BHswn8m4DZffZMrQiTgaOunA=; b=e+/iCc0QLvuuxR+UQ68sbys9bL NnFieCYhYgcNRXIZz0irZsz7essAW2lr6Nfu7LGTxabfQB0gDN/2jzaJQnIOhxBOKMZkXQJ67VOtI E0teEhPWNoz92oKsv4fi6rNe3n+HrwDaf1XQ6fmggrPVjVPT3b4poMAZAxABHkjSzlIrFJVQWwini +t0jVAAUS1Qm0cw7tP0r1PQYiLohUywQJMSP7rdUv80LWRfb9Qx5kn07jG7qQcWHsaNHW0DNb4khh 3UZCS6nrY8WC5FvpPwweJ8bHtueHssBwFikQ81olBEgX29x9EW2eoN/qvvPi8I8KMmLTM/9EaI7uU czTj4LOg==; Received: from willy by casper.infradead.org with local (Exim 4.97.1 #2 (Red Hat Linux)) id 1sBzzz-00000008pj3-0mih; Tue, 28 May 2024 16:48:31 +0000 From: "Matthew Wilcox (Oracle)" To: Christoph Hellwig Cc: "Matthew Wilcox (Oracle)" , linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org Subject: [PATCH 1/7] fs: Introduce buffered_write_operations Date: Tue, 28 May 2024 17:48:22 +0100 Message-ID: <20240528164829.2105447-2-willy@infradead.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240528164829.2105447-1-willy@infradead.org> References: <20240528164829.2105447-1-willy@infradead.org> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Start the process of moving write_begin and write_end out from the address_space_operations to their own struct. The new write_begin returns the folio or an ERR_PTR instead of returning the folio by reference. It also accepts len as a size_t and (as documented) the len may be larger than PAGE_SIZE. Pass an optional buffered_write_operations pointer to various functions in filemap.c. The old names are available as macros for now, except for generic_file_write_iter() which is used as a function pointer by many filesystems. If using the new functions, the filesystem can have per-operation fsdata instead of per-page fsdata. Signed-off-by: Matthew Wilcox (Oracle) --- Documentation/filesystems/locking.rst | 23 ++++++++ fs/jfs/file.c | 3 +- fs/ramfs/file-mmu.c | 3 +- fs/ufs/file.c | 2 +- include/linux/fs.h | 3 -- include/linux/pagemap.h | 21 ++++++++ mm/filemap.c | 77 +++++++++++++++++---------- 7 files changed, 97 insertions(+), 35 deletions(-) diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst index e664061ed55d..e62a8a83ea9e 100644 --- a/Documentation/filesystems/locking.rst +++ b/Documentation/filesystems/locking.rst @@ -413,6 +413,29 @@ path after ->swap_activate() returned success. ->swap_rw will be called for swap IO if SWP_FS_OPS was set by ->swap_activate(). +buffered_write_operations +========================= + + struct folio *(*write_begin)(struct file *, struct address_space *, + loff_t pos, size_t len, void **fsdata); + size_t (*write_end)(struct file *, struct address_space *, + loff_t pos, size_t len, size_t copied, + struct folio *folio, void **fsdata); + +For write_begin, 'len' is typically the remaining length of the write, +and is not capped to PAGE_SIZE. For write_end, len will be limited so +that pos + len <= folio_pos(folio) + folio_size(folio). copied will +not exceed len. pos + len will not exceed MAX_LFS_FILESIZE. + +write_begin may return an ERR_PTR. write_end may return a number less +than copied if it needs the caller to retry from an earlier position in +the file. It cannot signal an error; that must be done by write_begin(). + +write_begin should lock the folio and increase its refcount. write_end +should unlock it and drop the refcount, possibly after setting it +uptodate (it can only use folio_end_read() for this if it knows the folio +was not previously uptodate; probably best not to use it). + file_lock_operations ==================== diff --git a/fs/jfs/file.c b/fs/jfs/file.c index 01b6912e60f8..9c62445ea6be 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -4,8 +4,7 @@ * Portions Copyright (C) Christoph Hellwig, 2001-2002 */ -#include -#include +#include #include #include #include "jfs_incore.h" diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c index b45c7edc3225..5de2a232d07f 100644 --- a/fs/ramfs/file-mmu.c +++ b/fs/ramfs/file-mmu.c @@ -24,8 +24,7 @@ * caches is sufficient. */ -#include -#include +#include #include #include diff --git a/fs/ufs/file.c b/fs/ufs/file.c index 6558882a89ef..b557d4a14143 100644 --- a/fs/ufs/file.c +++ b/fs/ufs/file.c @@ -24,7 +24,7 @@ * ext2 fs regular file handling primitives */ -#include +#include #include "ufs_fs.h" #include "ufs.h" diff --git a/include/linux/fs.h b/include/linux/fs.h index 0283cf366c2a..4c6c2042cbeb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3115,10 +3115,7 @@ extern int generic_file_rw_checks(struct file *file_in, struct file *file_out); ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *to, ssize_t already_read); extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *); -extern ssize_t __generic_file_write_iter(struct kiocb *, struct iov_iter *); -extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *); extern ssize_t generic_file_direct_write(struct kiocb *, struct iov_iter *); -ssize_t generic_perform_write(struct kiocb *, struct iov_iter *); ssize_t direct_write_fallback(struct kiocb *iocb, struct iov_iter *iter, ssize_t direct_written, ssize_t buffered_written); diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index ee633712bba0..2921c1cc6335 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -18,6 +18,27 @@ struct folio_batch; +struct buffered_write_operations { + struct folio *(*write_begin)(struct file *, struct address_space *, + loff_t pos, size_t len, void **fsdata); + size_t (*write_end)(struct file *, struct address_space *, + loff_t pos, size_t len, size_t copied, + struct folio *folio, void **fsdata); +}; + +ssize_t filemap_write_iter(struct kiocb *, struct iov_iter *, + const struct buffered_write_operations *, void *fsdata); +ssize_t __filemap_write_iter(struct kiocb *, struct iov_iter *, + const struct buffered_write_operations *, void *fsdata); +ssize_t filemap_perform_write(struct kiocb *, struct iov_iter *, + const struct buffered_write_operations *, void *fsdata); + +ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *); +#define generic_perform_write(kiocb, iter) \ + filemap_perform_write(kiocb, iter, NULL, NULL) +#define __generic_file_write_iter(kiocb, iter) \ + __filemap_write_iter(kiocb, iter, NULL, NULL) + unsigned long invalidate_mapping_pages(struct address_space *mapping, pgoff_t start, pgoff_t end); diff --git a/mm/filemap.c b/mm/filemap.c index 382c3d06bfb1..162ac110c423 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -95,7 +95,7 @@ * ->invalidate_lock (filemap_fault) * ->lock_page (filemap_fault, access_process_vm) * - * ->i_rwsem (generic_perform_write) + * ->i_rwsem (filemap_perform_write) * ->mmap_lock (fault_in_readable->do_page_fault) * * bdi->wb.list_lock @@ -3975,7 +3975,8 @@ generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from) } EXPORT_SYMBOL(generic_file_direct_write); -ssize_t generic_perform_write(struct kiocb *iocb, struct iov_iter *i) +ssize_t filemap_perform_write(struct kiocb *iocb, struct iov_iter *i, + const struct buffered_write_operations *ops, void *fsdata) { struct file *file = iocb->ki_filp; loff_t pos = iocb->ki_pos; @@ -3985,11 +3986,10 @@ ssize_t generic_perform_write(struct kiocb *iocb, struct iov_iter *i) ssize_t written = 0; do { - struct page *page; - unsigned long offset; /* Offset into pagecache page */ - unsigned long bytes; /* Bytes to write to page */ + struct folio *folio; + size_t offset; /* Offset into pagecache folio */ + size_t bytes; /* Bytes to write to page */ size_t copied; /* Bytes copied from user */ - void *fsdata = NULL; offset = (pos & (PAGE_SIZE - 1)); bytes = min_t(unsigned long, PAGE_SIZE - offset, @@ -4012,19 +4012,33 @@ ssize_t generic_perform_write(struct kiocb *iocb, struct iov_iter *i) break; } - status = a_ops->write_begin(file, mapping, pos, bytes, + if (ops) { + folio = ops->write_begin(file, mapping, pos, bytes, &fsdata); + if (IS_ERR(folio)) { + status = PTR_ERR(folio); + break; + } + } else { + struct page *page; + status = a_ops->write_begin(file, mapping, pos, bytes, &page, &fsdata); - if (unlikely(status < 0)) - break; + if (unlikely(status < 0)) + break; + folio = page_folio(page); + } if (mapping_writably_mapped(mapping)) - flush_dcache_page(page); + flush_dcache_folio(folio); - copied = copy_page_from_iter_atomic(page, offset, bytes, i); - flush_dcache_page(page); + copied = copy_folio_from_iter_atomic(folio, offset, bytes, i); + flush_dcache_folio(folio); - status = a_ops->write_end(file, mapping, pos, bytes, copied, - page, fsdata); + if (ops) + status = ops->write_end(file, mapping, pos, bytes, + copied, folio, &fsdata); + else + status = a_ops->write_end(file, mapping, pos, bytes, + copied, &folio->page, fsdata); if (unlikely(status != copied)) { iov_iter_revert(i, copied - max(status, 0L)); if (unlikely(status < 0)) @@ -4054,12 +4068,13 @@ ssize_t generic_perform_write(struct kiocb *iocb, struct iov_iter *i) iocb->ki_pos += written; return written; } -EXPORT_SYMBOL(generic_perform_write); +EXPORT_SYMBOL(filemap_perform_write); /** - * __generic_file_write_iter - write data to a file - * @iocb: IO state structure (file, offset, etc.) - * @from: iov_iter with data to write + * __filemap_write_iter - write data to a file + * @iocb: IO state structure (file, offset, etc.) + * @from: iov_iter with data to write + * @ops: How to inform the filesystem that a write is starting/finishing. * * This function does all the work needed for actually writing data to a * file. It does all basic checks, removes SUID from the file, updates @@ -4077,7 +4092,8 @@ EXPORT_SYMBOL(generic_perform_write); * * number of bytes written, even for truncated writes * * negative error code if no data has been written at all */ -ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) +ssize_t __filemap_write_iter(struct kiocb *iocb, struct iov_iter *from, + const struct buffered_write_operations *ops, void *fsdata) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -4104,27 +4120,29 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (ret < 0 || !iov_iter_count(from) || IS_DAX(inode)) return ret; return direct_write_fallback(iocb, from, ret, - generic_perform_write(iocb, from)); + filemap_perform_write(iocb, from, ops, fsdata)); } - return generic_perform_write(iocb, from); + return filemap_perform_write(iocb, from, ops, fsdata); } -EXPORT_SYMBOL(__generic_file_write_iter); +EXPORT_SYMBOL(__filemap_write_iter); /** - * generic_file_write_iter - write data to a file + * filemap_write_iter - write data to a file * @iocb: IO state structure * @from: iov_iter with data to write * - * This is a wrapper around __generic_file_write_iter() to be used by most + * This is a wrapper around __filemap_write_iter() to be used by most * filesystems. It takes care of syncing the file in case of O_SYNC file * and acquires i_rwsem as needed. + * * Return: - * * negative error code if no data has been written at all of + * * negative error code if no data has been written at all or if * vfs_fsync_range() failed for a synchronous write * * number of bytes written, even for truncated writes */ -ssize_t generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) +ssize_t filemap_write_iter(struct kiocb *iocb, struct iov_iter *from, + const struct buffered_write_operations *ops, void *fsdata) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; @@ -4133,13 +4151,18 @@ ssize_t generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) inode_lock(inode); ret = generic_write_checks(iocb, from); if (ret > 0) - ret = __generic_file_write_iter(iocb, from); + ret = __filemap_write_iter(iocb, from, ops, fsdata); inode_unlock(inode); if (ret > 0) ret = generic_write_sync(iocb, ret); return ret; } + +ssize_t generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + return filemap_write_iter(iocb, from, NULL, NULL); +} EXPORT_SYMBOL(generic_file_write_iter); /** From patchwork Tue May 28 16:48:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Wilcox X-Patchwork-Id: 13677036 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ED588172BD5; Tue, 28 May 2024 16:48:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914915; cv=none; b=Ycp5VSVJjBEMrWcVXT4aKAwQl50y9LRJSQ+6Ct1ALIAM9FnYHd2ESMY4I7iXDSDCSr4LIAYGvlltu8xdM8vsiNWTdCoGhLC8tDtgQgY6wG7ZJRDUWbWXrOMID7fB723IUxP6wwl+bMESELFKdwgWKGQajHeQU5WLKI4QfSX0RzM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914915; c=relaxed/simple; bh=UumrTljUiV9/fFu9UljiSySKbgCeWWnkBNY7Ez7gFM8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YzR1f7NO6BLhRpj0jMtkLe6qz0wxXF2Z9YDf1UChJTegWIu2jjtZJMYdb2i/0J3CWr9Fr81Y0hQJSBKlx3+CPPL1wWZZ0qrxCU6jHL2RE6lVlDIF3XdoXjqNIRJBG/JoQ4gP+CuZIIrDoI+rhfisfe/6GGY2iAEzrEbvC+rLl1M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=FGRrsv3y; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="FGRrsv3y" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Transfer-Encoding:MIME-Version: References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To: Content-Type:Content-ID:Content-Description; bh=eOxBR5VEbisG9xilapnBHP0KrNMLEjBVgRMaOXofMC0=; b=FGRrsv3yu9nhx2UDc930DU6Q9H IglvDotpBNRV2jnKEcE1hwwpOVMs1czSJI3zBRWrmkdwvI852egvneMzy6Q7NkIwADGMOQkGRpcNy O6ahJ9qGUs8Atp3hJt7J3PnJ1pBK1isTVGHipHnlOBeD1Dw/OW88CUeEkySuFo5P6NIRPMZOBDS7D mKfRtDPfrU4i9To4fOA6S+W/OuA5xI6Hul3AMUj1T/4pxynwOnNo9fK4wT6uoWozZKUwLC38/jZcX s+OklUSMEJn0WS4UvEQ8z+0Muso8dXwwmC9fV+LcRMT3Edvg9J0RC+DppzJl8QUJHKTfzJkbVM3oQ EOPP4m0A==; Received: from willy by casper.infradead.org with local (Exim 4.97.1 #2 (Red Hat Linux)) id 1sBzzz-00000008pj6-1JcW; Tue, 28 May 2024 16:48:31 +0000 From: "Matthew Wilcox (Oracle)" To: Christoph Hellwig Cc: "Matthew Wilcox (Oracle)" , linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org Subject: [PATCH 2/7] fs: Supply optional buffered_write_operations in buffer.c Date: Tue, 28 May 2024 17:48:23 +0100 Message-ID: <20240528164829.2105447-3-willy@infradead.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240528164829.2105447-1-willy@infradead.org> References: <20240528164829.2105447-1-willy@infradead.org> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 generic_cont_expand_simple() and cont_expand_zero() currently call ->write_begin and ->write_end, so will also need to be converted to use buffered_write_operations. Use macro magic to pass NULL if no buffered_write_operations is supplied. Signed-off-by: Matthew Wilcox (Oracle) --- fs/buffer.c | 78 ++++++++++++++++++++++++++----------- include/linux/buffer_head.h | 22 +++++++++-- 2 files changed, 74 insertions(+), 26 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 8c19e705b9c3..58ac52f20bf6 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2466,23 +2466,32 @@ EXPORT_SYMBOL(block_read_full_folio); * truncates. Uses filesystem pagecache writes to allow the filesystem to * deal with the hole. */ -int generic_cont_expand_simple(struct inode *inode, loff_t size) +int generic_cont_expand_simple(struct inode *inode, loff_t size, + const struct buffered_write_operations *ops, void *fsdata) { struct address_space *mapping = inode->i_mapping; const struct address_space_operations *aops = mapping->a_ops; struct page *page; - void *fsdata = NULL; + struct folio *folio; int err; err = inode_newsize_ok(inode, size); if (err) goto out; - err = aops->write_begin(NULL, mapping, size, 0, &page, &fsdata); + if (ops) { + folio = ops->write_begin(NULL, mapping, size, 0, &fsdata); + if (IS_ERR(folio)) + err = PTR_ERR(folio); + } else + err = aops->write_begin(NULL, mapping, size, 0, &page, &fsdata); if (err) goto out; - err = aops->write_end(NULL, mapping, size, 0, 0, page, fsdata); + if (ops) + err = ops->write_end(NULL, mapping, size, 0, 0, folio, &fsdata); + else + err = aops->write_end(NULL, mapping, size, 0, 0, page, fsdata); BUG_ON(err > 0); out: @@ -2491,13 +2500,14 @@ int generic_cont_expand_simple(struct inode *inode, loff_t size) EXPORT_SYMBOL(generic_cont_expand_simple); static int cont_expand_zero(struct file *file, struct address_space *mapping, - loff_t pos, loff_t *bytes) + loff_t pos, loff_t *bytes, + const struct buffered_write_operations *ops, void **fsdata) { struct inode *inode = mapping->host; const struct address_space_operations *aops = mapping->a_ops; unsigned int blocksize = i_blocksize(inode); struct page *page; - void *fsdata = NULL; + struct folio *folio; pgoff_t index, curidx; loff_t curpos; unsigned zerofrom, offset, len; @@ -2514,13 +2524,25 @@ static int cont_expand_zero(struct file *file, struct address_space *mapping, } len = PAGE_SIZE - zerofrom; - err = aops->write_begin(file, mapping, curpos, len, - &page, &fsdata); - if (err) - goto out; + if (ops) { + folio = ops->write_begin(file, mapping, curpos, len, + fsdata); + if (IS_ERR(folio)) + return PTR_ERR(folio); + page = &folio->page; + } else { + err = aops->write_begin(file, mapping, curpos, len, + &page, fsdata); + if (err) + goto out; + } zero_user(page, zerofrom, len); - err = aops->write_end(file, mapping, curpos, len, len, - page, fsdata); + if (ops) + err = ops->write_end(file, mapping, curpos, len, len, + folio, fsdata); + else + err = aops->write_end(file, mapping, curpos, len, len, + page, *fsdata); if (err < 0) goto out; BUG_ON(err != len); @@ -2547,13 +2569,25 @@ static int cont_expand_zero(struct file *file, struct address_space *mapping, } len = offset - zerofrom; - err = aops->write_begin(file, mapping, curpos, len, - &page, &fsdata); - if (err) - goto out; + if (ops) { + folio = ops->write_begin(file, mapping, curpos, len, + fsdata); + if (IS_ERR(folio)) + return PTR_ERR(folio); + page = &folio->page; + } else { + err = aops->write_begin(file, mapping, curpos, len, + &page, fsdata); + if (err) + goto out; + } zero_user(page, zerofrom, len); - err = aops->write_end(file, mapping, curpos, len, len, - page, fsdata); + if (ops) + err = ops->write_end(file, mapping, curpos, len, len, + folio, fsdata); + else + err = aops->write_end(file, mapping, curpos, len, len, + page, *fsdata); if (err < 0) goto out; BUG_ON(err != len); @@ -2568,16 +2602,16 @@ static int cont_expand_zero(struct file *file, struct address_space *mapping, * We may have to extend the file. */ int cont_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, - struct page **pagep, void **fsdata, - get_block_t *get_block, loff_t *bytes) + loff_t pos, unsigned len, struct page **pagep, void **fsdata, + get_block_t *get_block, loff_t *bytes, + const struct buffered_write_operations *ops) { struct inode *inode = mapping->host; unsigned int blocksize = i_blocksize(inode); unsigned int zerofrom; int err; - err = cont_expand_zero(file, mapping, pos, bytes); + err = cont_expand_zero(file, mapping, pos, bytes, ops, fsdata); if (err) return err; diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index e022e40b099e..1b7f14e39ab8 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -268,16 +268,30 @@ int generic_write_end(struct file *, struct address_space *, loff_t, unsigned, unsigned, struct page *, void *); void folio_zero_new_buffers(struct folio *folio, size_t from, size_t to); -int cont_write_begin(struct file *, struct address_space *, loff_t, - unsigned, struct page **, void **, - get_block_t *, loff_t *); -int generic_cont_expand_simple(struct inode *inode, loff_t size); +int cont_write_begin(struct file *, struct address_space *, loff_t pos, + unsigned len, struct page **, void **fsdata, get_block_t *, + loff_t *bytes, const struct buffered_write_operations *); +int generic_cont_expand_simple(struct inode *inode, loff_t size, + const struct buffered_write_operations *ops, void *fsdata); void block_commit_write(struct page *page, unsigned int from, unsigned int to); int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, get_block_t get_block); sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *); int block_truncate_page(struct address_space *, loff_t, get_block_t *); +#define _cont_write_begin(file, mapping, pos, len, pagep, fsdata, \ + getblk, bytes, ops, extra...) \ + cont_write_begin(file, mapping, pos, len, pagep, fsdata, \ + getblk, bytes, ops) +#define cont_write_begin(file, mapping, pos, len, pagep, fsdata, \ + getblk, bytes, ops...) \ + _cont_write_begin(file, mapping, pos, len, pagep, fsdata, \ + getblk, bytes, ## ops, NULL) +#define _generic_cont_expand_simple(inode, size, ops, fsdata, extra...) \ + generic_cont_expand_simple(inode, size, ops, fsdata) +#define generic_cont_expand_simple(inode, size, ops_data...) \ + _generic_cont_expand_simple(inode, size, ## ops_data, NULL, NULL) + #ifdef CONFIG_MIGRATION extern int buffer_migrate_folio(struct address_space *, struct folio *dst, struct folio *src, enum migrate_mode); From patchwork Tue May 28 16:48:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Wilcox X-Patchwork-Id: 13677033 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 192D4172BD8; Tue, 28 May 2024 16:48:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914914; cv=none; b=PudnwJ2wHQZRsHA2gfYswBeCsZhbrk3S34Crlujzzlw3hDkr2bcxS7brKbyVPCf1hwnxbYRJ2RdT0KXGPyDhYDpITvwuH8jUc1NheXpRD9by4MSsvZyaMpX7f2IvzECKLGxNep5pD/1xFax9N3ZmWB0fhsziBBI6X0WX7Bg3LEA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914914; c=relaxed/simple; bh=D2tTlrFnEeMjZECR3JcvOVGURlnNgkYSaHwAoMwrgN8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NadMvNtbiv70tSzgRQl4sTWbTlU6gFBWhid2I532tV2IZYxh9IgQd2c4yvAsMdQsv5gGAnxKmSUgbOVMjtZEC0PhYXXPueoQEP3ARNP0IeC9Qivzyvgfl37ZBSs2qspOHeU8lIDSJbBFfBe+fdl5MiPpUnCt23hikho5uOnNfgY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=m5RVL4WV; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="m5RVL4WV" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Transfer-Encoding:MIME-Version: References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To: Content-Type:Content-ID:Content-Description; bh=5bqYlK1AE1ExlN3FvyGoPAxrjC2iLLgkrqD73YGe+nc=; b=m5RVL4WVT6K1NZAqVAVTje5J39 EqybgNCMsCrX93CZyUyqx5Uo07q3pOiFhUDFk+vu1HvWa62cdV0iO4PUcxZJntOD7D3T3Q6nZlQ9/ YEB2Z3NZ7KAE1N1AJHaZHYOmrI4yrb3lsdkDbqyVsfTXYzYu0wh2CLHV0MZm3lSENFMcx/Aa5YxcQ dSXODNXgfF/HVv8deaJJJujYc5hTsOsggiJkmXz4t2yfKs+gsa7NxSqYSAAbtlO2i6I7z/TPZ26Y2 Dx0WoS4RBogN3vmZizBjISR8DyITwLEPvlhxE3JcbEmXi6NARoO6fvTOnWRod42hVbP/mU8KHErKP bkDEcuQw==; Received: from willy by casper.infradead.org with local (Exim 4.97.1 #2 (Red Hat Linux)) id 1sBzzz-00000008pjF-1pxS; Tue, 28 May 2024 16:48:31 +0000 From: "Matthew Wilcox (Oracle)" To: Christoph Hellwig Cc: "Matthew Wilcox (Oracle)" , linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org Subject: [PATCH 3/7] buffer: Add buffer_write_begin, buffer_write_end and __buffer_write_end Date: Tue, 28 May 2024 17:48:24 +0100 Message-ID: <20240528164829.2105447-4-willy@infradead.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240528164829.2105447-1-willy@infradead.org> References: <20240528164829.2105447-1-willy@infradead.org> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 These functions are to be called from filesystem implementations of write_begin and write_end. They correspond to block_write_begin, generic_write_end and block_write_end. The old functions need to be kept around as they're used as function pointers. Signed-off-by: Matthew Wilcox (Oracle) --- fs/buffer.c | 80 ++++++++++++++++++++++++++----------- include/linux/buffer_head.h | 6 +++ 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 58ac52f20bf6..4064b21fe499 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2217,39 +2217,55 @@ static void __block_commit_write(struct folio *folio, size_t from, size_t to) } /* - * block_write_begin takes care of the basic task of block allocation and + * buffer_write_begin - Helper for filesystem write_begin implementations + * @mapping: Address space being written to. + * @pos: Position in bytes within the file. + * @len: Number of bytes being written. + * @get_block: How to get buffer_heads for this filesystem. + * + * Take care of the basic task of block allocation and * bringing partial write blocks uptodate first. * * The filesystem needs to handle block truncation upon failure. + * + * Return: The folio to write to, or an ERR_PTR on failure. */ -int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len, - struct page **pagep, get_block_t *get_block) +struct folio *buffer_write_begin(struct address_space *mapping, loff_t pos, + size_t len, get_block_t *get_block) { - pgoff_t index = pos >> PAGE_SHIFT; - struct page *page; + struct folio *folio = __filemap_get_folio(mapping, pos / PAGE_SIZE, + FGP_WRITEBEGIN, mapping_gfp_mask(mapping)); int status; - page = grab_cache_page_write_begin(mapping, index); - if (!page) - return -ENOMEM; + if (IS_ERR(folio)) + return folio; - status = __block_write_begin(page, pos, len, get_block); + status = __block_write_begin_int(folio, pos, len, get_block, NULL); if (unlikely(status)) { - unlock_page(page); - put_page(page); - page = NULL; + folio_unlock(folio); + folio_put(folio); + folio = ERR_PTR(status); } - *pagep = page; - return status; + return folio; +} +EXPORT_SYMBOL(buffer_write_begin); + +int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len, + struct page **pagep, get_block_t *get_block) +{ + struct folio *folio = buffer_write_begin(mapping, pos, len, get_block); + + if (IS_ERR(folio)) + return PTR_ERR(folio); + *pagep = &folio->page; + return 0; } EXPORT_SYMBOL(block_write_begin); -int block_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) +size_t __buffer_write_end(struct file *file, struct address_space *mapping, + loff_t pos, size_t len, size_t copied, struct folio *folio) { - struct folio *folio = page_folio(page); size_t start = pos - folio_pos(folio); if (unlikely(copied < len)) { @@ -2277,17 +2293,26 @@ int block_write_end(struct file *file, struct address_space *mapping, return copied; } -EXPORT_SYMBOL(block_write_end); +EXPORT_SYMBOL(__buffer_write_end); -int generic_write_end(struct file *file, struct address_space *mapping, +int block_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata) +{ + return buffer_write_end(file, mapping, pos, len, copied, + page_folio(page)); +} +EXPORT_SYMBOL(block_write_end); + +size_t buffer_write_end(struct file *file, struct address_space *mapping, + loff_t pos, size_t len, size_t copied, + struct folio *folio) { struct inode *inode = mapping->host; loff_t old_size = inode->i_size; bool i_size_changed = false; - copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); + copied = __buffer_write_end(file, mapping, pos, len, copied, folio); /* * No need to use i_size_read() here, the i_size cannot change under us @@ -2301,8 +2326,8 @@ int generic_write_end(struct file *file, struct address_space *mapping, i_size_changed = true; } - unlock_page(page); - put_page(page); + folio_unlock(folio); + folio_put(folio); if (old_size < pos) pagecache_isize_extended(inode, old_size, pos); @@ -2316,6 +2341,15 @@ int generic_write_end(struct file *file, struct address_space *mapping, mark_inode_dirty(inode); return copied; } +EXPORT_SYMBOL(buffer_write_end); + +int generic_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ + return buffer_write_end(file, mapping, pos, len, copied, + page_folio(page)); +} EXPORT_SYMBOL(generic_write_end); /* diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 1b7f14e39ab8..44e4b2b18cc0 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -267,6 +267,12 @@ int block_write_end(struct file *, struct address_space *, int generic_write_end(struct file *, struct address_space *, loff_t, unsigned, unsigned, struct page *, void *); +struct folio *buffer_write_begin(struct address_space *mapping, loff_t pos, + size_t len, get_block_t *get_block); +size_t buffer_write_end(struct file *, struct address_space *, loff_t pos, + size_t len, size_t copied, struct folio *); +size_t __buffer_write_end(struct file *, struct address_space *, loff_t pos, + size_t len, size_t copied, struct folio *); void folio_zero_new_buffers(struct folio *folio, size_t from, size_t to); int cont_write_begin(struct file *, struct address_space *, loff_t pos, unsigned len, struct page **, void **fsdata, get_block_t *, From patchwork Tue May 28 16:48:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Wilcox X-Patchwork-Id: 13677032 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 446D9173324; Tue, 28 May 2024 16:48:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914914; cv=none; b=q7iSKLilaAFU4KNR36uzm/JqrWcWHxUauaFovXdw1uhJmzRHZIcm8WUHh+Xq2hMsn7y6hQKfd/7LLhWK638pHy/V9lK3ZzE/kKjM9IteuCbLAVw8/11GlzElEF6ibGwhJsvyI1oYjq9uiUJByIRHi+Q0SYrppWdW/hTBcKCSGIU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914914; c=relaxed/simple; bh=ZCJeakTcJ6p69GvYR2jMvA2yFZ2ccNHLw/EMpWoY354=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FrODt33zE5XnYcxgUaE5ia3Mtp3/WTHCnpH1kgS7b5Qau407/QJX79C/j7E/a97ZNsY3o12Bt85mvQEC1qqf2qaHS94yG4qhL805BmmUqPcNNOiX3EkpDc+Njzgoeml3MYt+SKlwv/9FFHIuHuTJftvgUlzh+GfFDvQ1lau29Dg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=Xf1WvXMv; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="Xf1WvXMv" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Transfer-Encoding:MIME-Version: References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To: Content-Type:Content-ID:Content-Description; bh=+R2mjNBAIE/TqRuotFDeDo18cL36mswtB3So/eMZdyk=; b=Xf1WvXMvl5WlVX8u0ljEDCV5So uItvkVqBDJLPub2s/K4y487zJ4rn+Z4P48WTZRTL6e876elM3+diD72CEGB4yK0hvCZSVoNSWO76u 3TJJYaRWItJ2InVUFt1swNPhcgMvBS43fDG5fxqcKjqHJUxXMWHAvFdeJPFCUPGulkhlSZK1Dr2GY Y9UOcdOE0a6KEIx4/BF41ksKTAW4HAE7+eqOnFBMh28U88q5Mer/Dyd0DCht6KzGP0OJ1w1dCVBcJ huYVfcq4G7+Q+ICGYrp3snMztABD31qRrkNcxS3Drjbh9QCr1Sm24PvY79ksTP9j9M57XVNARVvRA +nr27XNg==; Received: from willy by casper.infradead.org with local (Exim 4.97.1 #2 (Red Hat Linux)) id 1sBzzz-00000008pjL-2Mcf; Tue, 28 May 2024 16:48:31 +0000 From: "Matthew Wilcox (Oracle)" To: Christoph Hellwig Cc: "Matthew Wilcox (Oracle)" , linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org Subject: [PATCH 4/7] fs: Add filemap_symlink() Date: Tue, 28 May 2024 17:48:25 +0100 Message-ID: <20240528164829.2105447-5-willy@infradead.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240528164829.2105447-1-willy@infradead.org> References: <20240528164829.2105447-1-willy@infradead.org> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 This is the equivalent of page_symlink() but takes a buffered_write_operations structure. It also doesn't handle GFP_NOFS for you; if you need that, use memalloc_nofs_save() yourself. Signed-off-by: Matthew Wilcox (Oracle) --- fs/namei.c | 25 +++++++++++++++++++++++++ include/linux/pagemap.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/fs/namei.c b/fs/namei.c index 37fb0a8aa09a..4352206b0408 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -5255,6 +5255,31 @@ int page_symlink(struct inode *inode, const char *symname, int len) } EXPORT_SYMBOL(page_symlink); +int filemap_symlink(struct inode *inode, const char *symname, int len, + const struct buffered_write_operations *ops, void **fsdata) +{ + struct address_space *mapping = inode->i_mapping; + struct folio *folio; + int err; + +retry: + folio = ops->write_begin(NULL, mapping, 0, len-1, fsdata); + if (IS_ERR(folio)) + return PTR_ERR(folio); + + memcpy(folio_address(folio), symname, len-1); + + err = ops->write_end(NULL, mapping, 0, len-1, len-1, folio, fsdata); + if (err < 0) + return err; + if (err < len-1) + goto retry; + + mark_inode_dirty(inode); + return 0; +} +EXPORT_SYMBOL(filemap_symlink); + const struct inode_operations page_symlink_inode_operations = { .get_link = page_get_link, }; diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 2921c1cc6335..a7540f757368 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -39,6 +39,8 @@ ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *); #define __generic_file_write_iter(kiocb, iter) \ __filemap_write_iter(kiocb, iter, NULL, NULL) +int filemap_symlink(struct inode *inode, const char *symname, int len, + const struct buffered_write_operations *bw, void **fsdata); unsigned long invalidate_mapping_pages(struct address_space *mapping, pgoff_t start, pgoff_t end); From patchwork Tue May 28 16:48:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Wilcox X-Patchwork-Id: 13677034 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5550617332A; Tue, 28 May 2024 16:48:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914914; cv=none; b=aaj5wgbroJrReAiibYqElaHSeTRBNe5mFYBlZFKRlm17YazNSjjWZ9I4KYARULPoZllw2lxlXmBUFuEFBfOq/cB+tVYuLn0V4hEg4fdV2vAcBCod8tuidvmpMtnDSyXh3nFQbF5EEavQojLCg8t8xkMbsuZnMAEHBt4I/1AGhlc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914914; c=relaxed/simple; bh=3Pjpp2P09PE5rEltCX5jMmUoMU02SiNpRbHgjiGkpzY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IwlnrN2ONMg5TipCuw4SOR2CFRf8z8ns5gzbS7182XXOyiEpdxR4nVfOUzKgMFTRLPKo6Oo5/5sGKhgjsCuhDVtr8RsXi6HhVBMmkSqiLW7qTq5e4ym3npL+ja5QM3HJX9nJ0q0M9aXUnLhubl2GPG8od/KSz6O/TqcqDKGrfRo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=edCpatfO; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="edCpatfO" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Transfer-Encoding:MIME-Version: References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To: Content-Type:Content-ID:Content-Description; bh=OM8uDx7VjJ0gwoeodjHhQfGhwJlDV1N5xXOB75yQ0vQ=; b=edCpatfOyuveWnzurf/9dQewBY tSk1iTDUilIJESZsVhA7kPWjsblYQ/UTaoTKfK7aOdA8mhQ4wFFWfOV8/Dq8uRw5KHuoFm4IbWTvN hI/VvO72W6Mm0T4gjRpoTyill8Ho3cmxZ7IKpwwE/VE0SKR0SYHiejj7CCy61yw6so+5bOb0wKomc GKWkOOf1N5lp7n3m+F0EVordxNybfp2LRTg4jKhTn3sY932jXt7pwahZqI4e2FUMZPh1O4s+Nxz4z 7y6tbLL13ELfus/7ymp02uIC8zSnBrJyLIRIH9YamtZfyvKH6h+PSNYnOMSlu8s2bADdwYw2/ofLr qMGQgJRA==; Received: from willy by casper.infradead.org with local (Exim 4.97.1 #2 (Red Hat Linux)) id 1sBzzz-00000008pjR-2rSv; Tue, 28 May 2024 16:48:31 +0000 From: "Matthew Wilcox (Oracle)" To: Christoph Hellwig Cc: "Matthew Wilcox (Oracle)" , linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org Subject: [PATCH 5/7] ext2: Convert to buffered_write_operations Date: Tue, 28 May 2024 17:48:26 +0100 Message-ID: <20240528164829.2105447-6-willy@infradead.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240528164829.2105447-1-willy@infradead.org> References: <20240528164829.2105447-1-willy@infradead.org> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Move write_begin and write_end from the address_space_operations to the new buffered_write_operations. Removes a number of hidden calls to compound_head(). Signed-off-by: Matthew Wilcox (Oracle) --- fs/ext2/ext2.h | 1 + fs/ext2/file.c | 4 ++-- fs/ext2/inode.c | 55 ++++++++++++++++++++++++++----------------------- fs/ext2/namei.c | 2 +- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index f38bdd46e4f7..89b498c81f18 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -784,6 +784,7 @@ extern const struct file_operations ext2_file_operations; extern void ext2_set_file_ops(struct inode *inode); extern const struct address_space_operations ext2_aops; extern const struct iomap_ops ext2_iomap_ops; +extern const struct buffered_write_operations ext2_bw_ops; /* namei.c */ extern const struct inode_operations ext2_dir_inode_operations; diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 10b061ac5bc0..108e8d2e9654 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -252,7 +252,7 @@ static ssize_t ext2_dio_write_iter(struct kiocb *iocb, struct iov_iter *from) iocb->ki_flags &= ~IOCB_DIRECT; pos = iocb->ki_pos; - status = generic_perform_write(iocb, from); + status = filemap_perform_write(iocb, from, &ext2_bw_ops, NULL); if (unlikely(status < 0)) { ret = status; goto out_unlock; @@ -299,7 +299,7 @@ static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (iocb->ki_flags & IOCB_DIRECT) return ext2_dio_write_iter(iocb, from); - return generic_file_write_iter(iocb, from); + return filemap_write_iter(iocb, from, &ext2_bw_ops, NULL); } static int ext2_file_open(struct inode *inode, struct file *filp) diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 0caa1650cee8..a89525d08aa3 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -914,30 +914,6 @@ static void ext2_readahead(struct readahead_control *rac) mpage_readahead(rac, ext2_get_block); } -static int -ext2_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, struct page **pagep, void **fsdata) -{ - int ret; - - ret = block_write_begin(mapping, pos, len, pagep, ext2_get_block); - if (ret < 0) - ext2_write_failed(mapping, pos + len); - return ret; -} - -static int ext2_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - int ret; - - ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); - if (ret < len) - ext2_write_failed(mapping, pos + len); - return ret; -} - static sector_t ext2_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,ext2_get_block); @@ -962,8 +938,6 @@ const struct address_space_operations ext2_aops = { .invalidate_folio = block_invalidate_folio, .read_folio = ext2_read_folio, .readahead = ext2_readahead, - .write_begin = ext2_write_begin, - .write_end = ext2_write_end, .bmap = ext2_bmap, .writepages = ext2_writepages, .migrate_folio = buffer_migrate_folio, @@ -976,6 +950,35 @@ static const struct address_space_operations ext2_dax_aops = { .dirty_folio = noop_dirty_folio, }; +static struct folio *ext2_write_begin(struct file *file, + struct address_space *mapping, loff_t pos, size_t len, + void **fsdata) +{ + struct folio *folio; + + folio = buffer_write_begin(mapping, pos, len, ext2_get_block); + + if (IS_ERR(folio)) + ext2_write_failed(mapping, pos + len); + return folio; +} + +static size_t ext2_write_end(struct file *file, struct address_space *mapping, + loff_t pos, size_t len, size_t copied, struct folio *folio, + void **fsdata) +{ + size_t ret = buffer_write_end(file, mapping, pos, len, copied, folio); + + if (ret < len) + ext2_write_failed(mapping, pos + len); + return ret; +} + +const struct buffered_write_operations ext2_bw_ops = { + .write_begin = ext2_write_begin, + .write_end = ext2_write_end, +}; + /* * Probably it should be a library function... search for first non-zero word * or memcmp with zero_page, whatever is better for particular architecture. diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 8346ab9534c1..a0edb11be826 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -179,7 +179,7 @@ static int ext2_symlink (struct mnt_idmap * idmap, struct inode * dir, inode->i_op = &ext2_symlink_inode_operations; inode_nohighmem(inode); inode->i_mapping->a_ops = &ext2_aops; - err = page_symlink(inode, symname, l); + err = filemap_symlink(inode, symname, l, &ext2_bw_ops, NULL); if (err) goto out_fail; } else { From patchwork Tue May 28 16:48:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Wilcox X-Patchwork-Id: 13677037 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 53D97173328; Tue, 28 May 2024 16:48:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914915; cv=none; b=LjHIdrXDNIHfEfQ3UsgOmpG0IfkjM8jEdvihFrOcWZG5f66gH9/jhb0mm923BFEdBuVvKsIc021XeE+5K4k6l4E4RYfSk9h6Be4zJbHH4bv3FzblPozW3aiumuXwNqVZyMImRHWhTUJc8MR9QbKUiOa+g2c6nSSGjm3fiDU8ms8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914915; c=relaxed/simple; bh=qvj9AvSuAO7iaLziIsdmDUA6I+Nze224/7M2Onq5khw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fKzdVY/kgVQaqksVInQYEUFrZuOheIsCYjJ0zj1hP5LyO+7BsYweZnWxpTXVf8YgIVOl3uPRMGb9ART9ZtL0aId/Qs8kOyGHoXwPK+mJg9lZ3jJzRdDR2TMGIPJG4PdTHXxyFsRv1x7HCzBgfdJmXY2CWN4wSrTC06tTK2Oz9k0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=MMaip63m; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="MMaip63m" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Transfer-Encoding:MIME-Version: References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To: Content-Type:Content-ID:Content-Description; bh=b8tfGuIMOOtLkmj3SquUXuuoroZe0OEB7YzKy418gEI=; b=MMaip63m2bQhZOUOE+hCdWk/WN N4/iissAi3Nj1MQN/Fy7XMqSiTZl7OUQHEVyEkIdbtGYjQv6FNcNjOPkJqOQ4eY7JIj1Hpm2X7Jgg 6jkPh4D9kCdbgG+0Lz17uyhiBUHpG++firTza704gBHRSWbDGLxPjKR2/2B4XFgWCwPEA4uoiXOB0 NLWSk5XalpdH18THTTedhreow4SmIhC98DIcL7IxQ+eSZuVx+RFFTz9dVzOUQvpxhnVO0OD4FdT81 Yzhabwo8mmuiCfn9heQqbs0+Dco8ZYE8LK94w9SpOGSNPDxXr6pMG6bVQTRe9Bb/baeaGkIjTBeb4 28jUoyUw==; Received: from willy by casper.infradead.org with local (Exim 4.97.1 #2 (Red Hat Linux)) id 1sBzzz-00000008pjX-3R2f; Tue, 28 May 2024 16:48:31 +0000 From: "Matthew Wilcox (Oracle)" To: Christoph Hellwig Cc: "Matthew Wilcox (Oracle)" , linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org Subject: [PATCH 6/7] ext4: Convert to buffered_write_operations Date: Tue, 28 May 2024 17:48:27 +0100 Message-ID: <20240528164829.2105447-7-willy@infradead.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240528164829.2105447-1-willy@infradead.org> References: <20240528164829.2105447-1-willy@infradead.org> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Pass the appropriate buffered_write_operations to filemap_perform_write(). Saves a lot of page<->folio conversions. Signed-off-by: Matthew Wilcox (Oracle) --- fs/buffer.c | 2 +- fs/ext4/ext4.h | 24 ++++----- fs/ext4/file.c | 12 ++++- fs/ext4/inline.c | 66 ++++++++++------------- fs/ext4/inode.c | 134 ++++++++++++++++++++--------------------------- 5 files changed, 108 insertions(+), 130 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 4064b21fe499..98f116e8abde 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2299,7 +2299,7 @@ int block_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata) { - return buffer_write_end(file, mapping, pos, len, copied, + return __buffer_write_end(file, mapping, pos, len, copied, page_folio(page)); } EXPORT_SYMBOL(block_write_end); diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 983dad8c07ec..b6f7509e3f55 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2971,8 +2971,6 @@ int ext4_walk_page_buffers(handle_t *handle, struct buffer_head *bh)); int do_journal_get_write_access(handle_t *handle, struct inode *inode, struct buffer_head *bh); -#define FALL_BACK_TO_NONDELALLOC 1 -#define CONVERT_INLINE_DATA 2 typedef enum { EXT4_IGET_NORMAL = 0, @@ -3011,6 +3009,7 @@ extern int ext4_break_layouts(struct inode *); extern int ext4_punch_hole(struct file *file, loff_t offset, loff_t length); extern void ext4_set_inode_flags(struct inode *, bool init); extern int ext4_alloc_da_blocks(struct inode *inode); +int ext4_nonda_switch(struct super_block *sb); extern void ext4_set_aops(struct inode *inode); extern int ext4_writepage_trans_blocks(struct inode *); extern int ext4_normal_submit_inode_data_buffers(struct jbd2_inode *jinode); @@ -3026,6 +3025,10 @@ extern void ext4_da_update_reserve_space(struct inode *inode, extern int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk, ext4_lblk_t len); +extern const struct buffered_write_operations ext4_bw_ops; +extern const struct buffered_write_operations ext4_journalled_bw_ops; +extern const struct buffered_write_operations ext4_da_bw_ops; + /* indirect.c */ extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, struct ext4_map_blocks *map, int flags); @@ -3551,17 +3554,12 @@ extern int ext4_find_inline_data_nolock(struct inode *inode); extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode); int ext4_readpage_inline(struct inode *inode, struct folio *folio); -extern int ext4_try_to_write_inline_data(struct address_space *mapping, - struct inode *inode, - loff_t pos, unsigned len, - struct page **pagep); -int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, - unsigned copied, struct folio *folio); -extern int ext4_da_write_inline_data_begin(struct address_space *mapping, - struct inode *inode, - loff_t pos, unsigned len, - struct page **pagep, - void **fsdata); +struct folio *ext4_try_to_write_inline_data(struct address_space *mapping, + struct inode *inode, loff_t pos, size_t len); +size_t ext4_write_inline_data_end(struct inode *inode, loff_t pos, size_t len, + size_t copied, struct folio *folio); +struct folio *ext4_da_write_inline_data_begin(struct address_space *mapping, + struct inode *inode, loff_t pos, size_t len); extern int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname, struct inode *dir, struct inode *inode); diff --git a/fs/ext4/file.c b/fs/ext4/file.c index c89e434db6b7..08c2772966a9 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -287,16 +287,26 @@ static ssize_t ext4_buffered_write_iter(struct kiocb *iocb, { ssize_t ret; struct inode *inode = file_inode(iocb->ki_filp); + const struct buffered_write_operations *ops; if (iocb->ki_flags & IOCB_NOWAIT) return -EOPNOTSUPP; + if (ext4_should_journal_data(inode)) + ops = &ext4_journalled_bw_ops; + else if (test_opt(inode->i_sb, DELALLOC) && + !ext4_nonda_switch(inode->i_sb) && + !ext4_verity_in_progress(inode)) + ops = &ext4_da_bw_ops; + else + ops = &ext4_bw_ops; + inode_lock(inode); ret = ext4_write_checks(iocb, from); if (ret <= 0) goto out; - ret = generic_perform_write(iocb, from); + ret = filemap_perform_write(iocb, from, ops, NULL); out: inode_unlock(inode); diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index d5bd1e3a5d36..cb5cb2cc9c2b 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -538,8 +538,9 @@ int ext4_readpage_inline(struct inode *inode, struct folio *folio) return ret >= 0 ? 0 : ret; } -static int ext4_convert_inline_data_to_extent(struct address_space *mapping, - struct inode *inode) +/* Returns NULL on success, ERR_PTR on failure */ +static void *ext4_convert_inline_data_to_extent(struct address_space *mapping, + struct inode *inode) { int ret, needed_blocks, no_expand; handle_t *handle = NULL; @@ -554,14 +555,14 @@ static int ext4_convert_inline_data_to_extent(struct address_space *mapping, * will trap here again. */ ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); - return 0; + return NULL; } needed_blocks = ext4_writepage_trans_blocks(inode); ret = ext4_get_inode_loc(inode, &iloc); if (ret) - return ret; + return ERR_PTR(ret); retry: handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, needed_blocks); @@ -648,7 +649,7 @@ static int ext4_convert_inline_data_to_extent(struct address_space *mapping, if (handle) ext4_journal_stop(handle); brelse(iloc.bh); - return ret; + return ERR_PTR(ret); } /* @@ -657,10 +658,8 @@ static int ext4_convert_inline_data_to_extent(struct address_space *mapping, * in the inode also. If not, create the page the handle, move the data * to the page make it update and let the later codes create extent for it. */ -int ext4_try_to_write_inline_data(struct address_space *mapping, - struct inode *inode, - loff_t pos, unsigned len, - struct page **pagep) +struct folio *ext4_try_to_write_inline_data(struct address_space *mapping, + struct inode *inode, loff_t pos, size_t len) { int ret; handle_t *handle; @@ -672,7 +671,7 @@ int ext4_try_to_write_inline_data(struct address_space *mapping, ret = ext4_get_inode_loc(inode, &iloc); if (ret) - return ret; + return ERR_PTR(ret); /* * The possible write could happen in the inode, @@ -680,7 +679,7 @@ int ext4_try_to_write_inline_data(struct address_space *mapping, */ handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); if (IS_ERR(handle)) { - ret = PTR_ERR(handle); + folio = ERR_CAST(handle); handle = NULL; goto out; } @@ -703,17 +702,14 @@ int ext4_try_to_write_inline_data(struct address_space *mapping, folio = __filemap_get_folio(mapping, 0, FGP_WRITEBEGIN | FGP_NOFS, mapping_gfp_mask(mapping)); - if (IS_ERR(folio)) { - ret = PTR_ERR(folio); + if (IS_ERR(folio)) goto out; - } - *pagep = &folio->page; down_read(&EXT4_I(inode)->xattr_sem); if (!ext4_has_inline_data(inode)) { - ret = 0; folio_unlock(folio); folio_put(folio); + folio = NULL; goto out_up_read; } @@ -726,21 +722,22 @@ int ext4_try_to_write_inline_data(struct address_space *mapping, } } - ret = 1; handle = NULL; out_up_read: up_read(&EXT4_I(inode)->xattr_sem); out: - if (handle && (ret != 1)) + if (ret < 0) + folio = ERR_PTR(ret); + if (handle && IS_ERR_OR_NULL(folio)) ext4_journal_stop(handle); brelse(iloc.bh); - return ret; + return folio; convert: return ext4_convert_inline_data_to_extent(mapping, inode); } -int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, - unsigned copied, struct folio *folio) +size_t ext4_write_inline_data_end(struct inode *inode, loff_t pos, size_t len, + size_t copied, struct folio *folio) { handle_t *handle = ext4_journal_current_handle(); int no_expand; @@ -831,8 +828,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, * need to start the journal since the file's metadata isn't changed now. */ static int ext4_da_convert_inline_data_to_extent(struct address_space *mapping, - struct inode *inode, - void **fsdata) + struct inode *inode) { int ret = 0, inline_size; struct folio *folio; @@ -869,7 +865,6 @@ static int ext4_da_convert_inline_data_to_extent(struct address_space *mapping, folio_mark_dirty(folio); folio_mark_uptodate(folio); ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); - *fsdata = (void *)CONVERT_INLINE_DATA; out: up_read(&EXT4_I(inode)->xattr_sem); @@ -888,11 +883,8 @@ static int ext4_da_convert_inline_data_to_extent(struct address_space *mapping, * handle in writepages(the i_disksize update is left to the * normal ext4_da_write_end). */ -int ext4_da_write_inline_data_begin(struct address_space *mapping, - struct inode *inode, - loff_t pos, unsigned len, - struct page **pagep, - void **fsdata) +struct folio *ext4_da_write_inline_data_begin(struct address_space *mapping, + struct inode *inode, loff_t pos, size_t len) { int ret; handle_t *handle; @@ -902,7 +894,7 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, ret = ext4_get_inode_loc(inode, &iloc); if (ret) - return ret; + return ERR_PTR(ret); retry_journal: handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); @@ -918,8 +910,7 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, if (ret == -ENOSPC) { ext4_journal_stop(handle); ret = ext4_da_convert_inline_data_to_extent(mapping, - inode, - fsdata); + inode); if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry_journal; @@ -932,10 +923,8 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, */ folio = __filemap_get_folio(mapping, 0, FGP_WRITEBEGIN | FGP_NOFS, mapping_gfp_mask(mapping)); - if (IS_ERR(folio)) { - ret = PTR_ERR(folio); + if (IS_ERR(folio)) goto out_journal; - } down_read(&EXT4_I(inode)->xattr_sem); if (!ext4_has_inline_data(inode)) { @@ -954,18 +943,17 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, goto out_release_page; up_read(&EXT4_I(inode)->xattr_sem); - *pagep = &folio->page; - brelse(iloc.bh); - return 1; + goto out; out_release_page: up_read(&EXT4_I(inode)->xattr_sem); folio_unlock(folio); folio_put(folio); + folio = ERR_PTR(ret); out_journal: ext4_journal_stop(handle); out: brelse(iloc.bh); - return ret; + return folio; } #ifdef INLINE_DIR_DEBUG diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 4bae9ccf5fe0..e9526e55e86c 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1014,7 +1014,7 @@ int do_journal_get_write_access(handle_t *handle, struct inode *inode, #ifdef CONFIG_FS_ENCRYPTION static int ext4_block_write_begin(struct folio *folio, loff_t pos, unsigned len, - get_block_t *get_block) + get_block_t *get_block, void **fsdata) { unsigned from = pos & (PAGE_SIZE - 1); unsigned to = from + len; @@ -1114,9 +1114,9 @@ static int ext4_block_write_begin(struct folio *folio, loff_t pos, unsigned len, * and the ext4_write_end(). So doing the jbd2_journal_start at the start of * ext4_write_begin() is the right place. */ -static int ext4_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, - struct page **pagep, void **fsdata) +static struct folio *ext4_write_begin(struct file *file, + struct address_space *mapping, loff_t pos, size_t len, + void **fsdata) { struct inode *inode = mapping->host; int ret, needed_blocks; @@ -1127,7 +1127,7 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping, unsigned from, to; if (unlikely(ext4_forced_shutdown(inode->i_sb))) - return -EIO; + return ERR_PTR(-EIO); trace_ext4_write_begin(inode, pos, len); /* @@ -1140,12 +1140,9 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping, to = from + len; if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) { - ret = ext4_try_to_write_inline_data(mapping, inode, pos, len, - pagep); - if (ret < 0) - return ret; - if (ret == 1) - return 0; + folio = ext4_try_to_write_inline_data(mapping, inode, pos, len); + if (folio) + return folio; } /* @@ -1159,7 +1156,7 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping, folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN, mapping_gfp_mask(mapping)); if (IS_ERR(folio)) - return PTR_ERR(folio); + return folio; /* * The same as page allocation, we prealloc buffer heads before * starting the handle. @@ -1173,7 +1170,7 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping, handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, needed_blocks); if (IS_ERR(handle)) { folio_put(folio); - return PTR_ERR(handle); + return ERR_CAST(handle); } folio_lock(folio); @@ -1190,9 +1187,10 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping, #ifdef CONFIG_FS_ENCRYPTION if (ext4_should_dioread_nolock(inode)) ret = ext4_block_write_begin(folio, pos, len, - ext4_get_block_unwritten); + ext4_get_block_unwritten, fsdata); else - ret = ext4_block_write_begin(folio, pos, len, ext4_get_block); + ret = ext4_block_write_begin(folio, pos, len, ext4_get_block, + fsdata); #else if (ext4_should_dioread_nolock(inode)) ret = __block_write_begin(&folio->page, pos, len, @@ -1239,10 +1237,9 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping, ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry_journal; folio_put(folio); - return ret; + return ERR_PTR(ret); } - *pagep = &folio->page; - return ret; + return folio; } /* For write_end() in data=journal mode */ @@ -1266,12 +1263,10 @@ static int write_end_fn(handle_t *handle, struct inode *inode, * ext4 never places buffers on inode->i_mapping->i_private_list. metadata * buffers are managed internally. */ -static int ext4_write_end(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) +static size_t ext4_write_end(struct file *file, struct address_space *mapping, + loff_t pos, size_t len, size_t copied, struct folio *folio, + void **fsdata) { - struct folio *folio = page_folio(page); handle_t *handle = ext4_journal_current_handle(); struct inode *inode = mapping->host; loff_t old_size = inode->i_size; @@ -1286,7 +1281,7 @@ static int ext4_write_end(struct file *file, return ext4_write_inline_data_end(inode, pos, len, copied, folio); - copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); + copied = __buffer_write_end(file, mapping, pos, len, copied, folio); /* * it's important to update i_size while still holding folio lock: * page writeout could otherwise come in and zero beyond i_size. @@ -1370,12 +1365,10 @@ static void ext4_journalled_zero_new_buffers(handle_t *handle, } while (bh != head); } -static int ext4_journalled_write_end(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) +static size_t ext4_journalled_write_end(struct file *file, + struct address_space *mapping, loff_t pos, size_t len, + size_t copied, struct folio *folio, void **fsdata) { - struct folio *folio = page_folio(page); handle_t *handle = ext4_journal_current_handle(); struct inode *inode = mapping->host; loff_t old_size = inode->i_size; @@ -2816,7 +2809,7 @@ static int ext4_dax_writepages(struct address_space *mapping, return ret; } -static int ext4_nonda_switch(struct super_block *sb) +int ext4_nonda_switch(struct super_block *sb) { s64 free_clusters, dirty_clusters; struct ext4_sb_info *sbi = EXT4_SB(sb); @@ -2850,45 +2843,35 @@ static int ext4_nonda_switch(struct super_block *sb) return 0; } -static int ext4_da_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, - struct page **pagep, void **fsdata) +static struct folio *ext4_da_write_begin(struct file *file, + struct address_space *mapping, loff_t pos, size_t len, + void **fsdata) { int ret, retries = 0; struct folio *folio; - pgoff_t index; struct inode *inode = mapping->host; if (unlikely(ext4_forced_shutdown(inode->i_sb))) - return -EIO; + return ERR_PTR(-EIO); - index = pos >> PAGE_SHIFT; - - if (ext4_nonda_switch(inode->i_sb) || ext4_verity_in_progress(inode)) { - *fsdata = (void *)FALL_BACK_TO_NONDELALLOC; - return ext4_write_begin(file, mapping, pos, - len, pagep, fsdata); - } - *fsdata = (void *)0; trace_ext4_da_write_begin(inode, pos, len); if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) { - ret = ext4_da_write_inline_data_begin(mapping, inode, pos, len, - pagep, fsdata); - if (ret < 0) - return ret; - if (ret == 1) - return 0; + folio = ext4_da_write_inline_data_begin(mapping, inode, pos, + len); + if (folio) + return folio; } retry: - folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN, + folio = __filemap_get_folio(mapping, pos / PAGE_SIZE, FGP_WRITEBEGIN, mapping_gfp_mask(mapping)); if (IS_ERR(folio)) - return PTR_ERR(folio); + return folio; #ifdef CONFIG_FS_ENCRYPTION - ret = ext4_block_write_begin(folio, pos, len, ext4_da_get_block_prep); + ret = ext4_block_write_begin(folio, pos, len, ext4_da_get_block_prep, + fsdata); #else ret = __block_write_begin(&folio->page, pos, len, ext4_da_get_block_prep); #endif @@ -2906,11 +2889,10 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry; - return ret; + return ERR_PTR(ret); } - *pagep = &folio->page; - return ret; + return folio; } /* @@ -2936,9 +2918,8 @@ static int ext4_da_should_update_i_disksize(struct folio *folio, return 1; } -static int ext4_da_do_write_end(struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct folio *folio) +static size_t ext4_da_do_write_end(struct address_space *mapping, loff_t pos, + size_t len, size_t copied, struct folio *folio) { struct inode *inode = mapping->host; loff_t old_size = inode->i_size; @@ -2998,23 +2979,15 @@ static int ext4_da_do_write_end(struct address_space *mapping, return copied; } -static int ext4_da_write_end(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) +static size_t ext4_da_write_end(struct file *file, + struct address_space *mapping, loff_t pos, size_t len, + size_t copied, struct folio *folio, void **fsdata) { struct inode *inode = mapping->host; - int write_mode = (int)(unsigned long)fsdata; - struct folio *folio = page_folio(page); - - if (write_mode == FALL_BACK_TO_NONDELALLOC) - return ext4_write_end(file, mapping, pos, - len, copied, &folio->page, fsdata); trace_ext4_da_write_end(inode, pos, len, copied); - if (write_mode != CONVERT_INLINE_DATA && - ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA) && + if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA) && ext4_has_inline_data(inode)) return ext4_write_inline_data_end(inode, pos, len, copied, folio); @@ -3521,8 +3494,6 @@ static const struct address_space_operations ext4_aops = { .read_folio = ext4_read_folio, .readahead = ext4_readahead, .writepages = ext4_writepages, - .write_begin = ext4_write_begin, - .write_end = ext4_write_end, .dirty_folio = ext4_dirty_folio, .bmap = ext4_bmap, .invalidate_folio = ext4_invalidate_folio, @@ -3537,8 +3508,6 @@ static const struct address_space_operations ext4_journalled_aops = { .read_folio = ext4_read_folio, .readahead = ext4_readahead, .writepages = ext4_writepages, - .write_begin = ext4_write_begin, - .write_end = ext4_journalled_write_end, .dirty_folio = ext4_journalled_dirty_folio, .bmap = ext4_bmap, .invalidate_folio = ext4_journalled_invalidate_folio, @@ -3553,8 +3522,6 @@ static const struct address_space_operations ext4_da_aops = { .read_folio = ext4_read_folio, .readahead = ext4_readahead, .writepages = ext4_writepages, - .write_begin = ext4_da_write_begin, - .write_end = ext4_da_write_end, .dirty_folio = ext4_dirty_folio, .bmap = ext4_bmap, .invalidate_folio = ext4_invalidate_folio, @@ -3572,6 +3539,21 @@ static const struct address_space_operations ext4_dax_aops = { .swap_activate = ext4_iomap_swap_activate, }; +const struct buffered_write_operations ext4_bw_ops = { + .write_begin = ext4_write_begin, + .write_end = ext4_write_end, +}; + +const struct buffered_write_operations ext4_journalled_bw_ops = { + .write_begin = ext4_write_begin, + .write_end = ext4_journalled_write_end, +}; + +const struct buffered_write_operations ext4_da_bw_ops = { + .write_begin = ext4_da_write_begin, + .write_end = ext4_da_write_end, +}; + void ext4_set_aops(struct inode *inode) { switch (ext4_inode_journal_mode(inode)) { From patchwork Tue May 28 16:48:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Wilcox X-Patchwork-Id: 13677035 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 889E117332C; Tue, 28 May 2024 16:48:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914915; cv=none; b=GumrZuQMY0r4vjrmxyOVmzYamSknDncPDEOpWMenf+PTCPTu/NFlEiOsOW5EeEQBLPt7OKstdSVPJsMNvIBaSUiou9ekbjO4tnKnL+tOq3jkGhNc2qEsXeps8JEGhnvcmx/Ut56Y9Qrt25/aw3MrD6zNmoICNwCSj94CvMLfu5I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716914915; c=relaxed/simple; bh=Dil7xzG+ttigVw3JOerhKg5KhObdBN2RvBBGIV6q2Qc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cHxwXlQDFVeNMsNKFZ7WnlVBvnKDhlZzQNhQDj2mmEGci0seNgwqQoewKYzVkKLqABfutgsQpKzvHIuvuw0fBjTFsB0EdkfC5xgLtBb9ma0bgRPMrZKySOk+tPA4bJYT8W+USWFPPymbIkpTkB6dCXX13zvuICsbVDzHKAsie1s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=gdTXZ+oy; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="gdTXZ+oy" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Transfer-Encoding:MIME-Version: References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To: Content-Type:Content-ID:Content-Description; bh=qY7bQ3bEFdsUe0XNsM+uQnYMcwBOs7nZbaHEVgrB6fE=; b=gdTXZ+oy++Hq5yYLrcC3UcQSzv c0S8TD47Vw+ylUM9IUjWhu7PAovNnw0nG7DR6I4J3hf9TwGvcHWWYC6x4/qoyMuPaWfCoKMqr+w1g mmuLcYynwLehc8SjXv4mOHafIVivroMrV/NPv+/QYAL2Lz/mdbPZ1QqlTa2SXOOWZRa/NCdGWQoeF NgnZyp/HKMdhuSdINow5/S9TCdvxfE9kSgat+TgwWiyD3sllFM6a2GlZ4cWTTqAccMOyMIpaa7XWy 3yBSs+Bln25TVufrMdOZ3WSjNoagA6vJ4nKWgST7A/WvI++fxgnphG852wsFUoLfMOpUSSNZcggcK QR0F7pCA==; Received: from willy by casper.infradead.org with local (Exim 4.97.1 #2 (Red Hat Linux)) id 1sBzzz-00000008pjd-3xRQ; Tue, 28 May 2024 16:48:31 +0000 From: "Matthew Wilcox (Oracle)" To: Christoph Hellwig Cc: "Matthew Wilcox (Oracle)" , linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org Subject: [PATCH 7/7] iomap: Return the folio from iomap_write_begin() Date: Tue, 28 May 2024 17:48:28 +0100 Message-ID: <20240528164829.2105447-8-willy@infradead.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240528164829.2105447-1-willy@infradead.org> References: <20240528164829.2105447-1-willy@infradead.org> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Use an ERR_PTR to return any error that may have occurred, otherwise return the folio directly instead of returning it by reference. This mirrors changes which are going into the filemap ->write_begin callbacks. Signed-off-by: Matthew Wilcox (Oracle) --- fs/iomap/buffered-io.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index c5802a459334..f0c40ac425ce 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -764,27 +764,27 @@ static int iomap_write_begin_inline(const struct iomap_iter *iter, return iomap_read_inline_data(iter, folio); } -static int iomap_write_begin(struct iomap_iter *iter, loff_t pos, - size_t len, struct folio **foliop) +static struct folio *iomap_write_begin(struct iomap_iter *iter, loff_t pos, + size_t len) { const struct iomap_folio_ops *folio_ops = iter->iomap.folio_ops; const struct iomap *srcmap = iomap_iter_srcmap(iter); struct folio *folio; - int status = 0; + int status; BUG_ON(pos + len > iter->iomap.offset + iter->iomap.length); if (srcmap != &iter->iomap) BUG_ON(pos + len > srcmap->offset + srcmap->length); if (fatal_signal_pending(current)) - return -EINTR; + return ERR_PTR(-EINTR); if (!mapping_large_folio_support(iter->inode->i_mapping)) len = min_t(size_t, len, PAGE_SIZE - offset_in_page(pos)); folio = __iomap_get_folio(iter, pos, len); if (IS_ERR(folio)) - return PTR_ERR(folio); + return folio; /* * Now we have a locked folio, before we do anything with it we need to @@ -801,7 +801,6 @@ static int iomap_write_begin(struct iomap_iter *iter, loff_t pos, &iter->iomap); if (!iomap_valid) { iter->iomap.flags |= IOMAP_F_STALE; - status = 0; goto out_unlock; } } @@ -819,13 +818,12 @@ static int iomap_write_begin(struct iomap_iter *iter, loff_t pos, if (unlikely(status)) goto out_unlock; - *foliop = folio; - return 0; + return folio; out_unlock: __iomap_put_folio(iter, pos, 0, folio); - return status; + return ERR_PTR(status); } static bool __iomap_write_end(struct inode *inode, loff_t pos, size_t len, @@ -940,9 +938,10 @@ static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i) break; } - status = iomap_write_begin(iter, pos, bytes, &folio); - if (unlikely(status)) { + folio = iomap_write_begin(iter, pos, bytes); + if (IS_ERR(folio)) { iomap_write_failed(iter->inode, pos, bytes); + status = PTR_ERR(folio); break; } if (iter->iomap.flags & IOMAP_F_STALE) @@ -1330,14 +1329,13 @@ static loff_t iomap_unshare_iter(struct iomap_iter *iter) do { struct folio *folio; - int status; size_t offset; size_t bytes = min_t(u64, SIZE_MAX, length); bool ret; - status = iomap_write_begin(iter, pos, bytes, &folio); - if (unlikely(status)) - return status; + folio = iomap_write_begin(iter, pos, bytes); + if (IS_ERR(folio)) + return PTR_ERR(folio); if (iomap->flags & IOMAP_F_STALE) break; @@ -1393,14 +1391,13 @@ static loff_t iomap_zero_iter(struct iomap_iter *iter, bool *did_zero) do { struct folio *folio; - int status; size_t offset; size_t bytes = min_t(u64, SIZE_MAX, length); bool ret; - status = iomap_write_begin(iter, pos, bytes, &folio); - if (status) - return status; + folio = iomap_write_begin(iter, pos, bytes); + if (IS_ERR(folio)) + return PTR_ERR(folio); if (iter->iomap.flags & IOMAP_F_STALE) break;