summaryrefslogtreecommitdiff
path: root/fs/bcachefs/fs-io-buffered.c
diff options
context:
space:
mode:
authorWolfram Sang <wsa+renesas@sang-engineering.com>2024-09-21 12:46:00 +0200
committerWolfram Sang <wsa+renesas@sang-engineering.com>2024-09-21 12:46:00 +0200
commitc24999e61b2187578fe4256b7bc6190a046c4b93 (patch)
treec6c5d2046a4a6b3a70fd5b374245c538c27f984b /fs/bcachefs/fs-io-buffered.c
parent7e722083fcc3e148838fc3dc2486c498908c4677 (diff)
parentf56f4ba2fc1dbefd3242946f2fad35338a60e3bc (diff)
Merge tag 'i2c-host-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux into i2c/for-mergewindow
The DesignWare and the Renesas I2C drivers have received most of the changes in this pull request. The first has has undergone through a series of cleanups that have been sent to the mailing list a year ago for the first time and finally get merged in this pull request. They are many, from typos (e.g. i2/i2c), to cosmetics, to refactoring (e.g. move inline functions to librarieas) and many others. Besides that, all the DesignWare Kconfig options have been grouped under the I2C_DESIGNWARE_CORE and this required some adaptation in many of the kernel configuration files for different arm and mips boards. Follows the list of the rest of the changes grouped by type of change. Cleanups -------- The Qualcomm Geni platform improves the exit path in the runtime resume function. The Intel LJCA driver loses "target_addr" parameter in ljca_i2c_stop() because it was unused. The MediaTek controller intializes the restart_flag in the transfer function using the ternary conditional operator ("? :") instead of initializing it in different parts. Constified a few global data structures in the virtio driver. The Renesas driver simplifies the bus speed handling in the init function making it more readable. Improved an if/else statement in probe function of the Renesas R-Car driver. The iMX/MXC driver switches to using the RUNTIME_PM_OPS() instead of SET_RUNTIME_PM_OPS(). Still in the iMX/MXC driver a comma ',' has been replaced by a semicolon ';', while in different drivers the ',' has been removed from the '{ }' delimiters. Finally three devm_clk_get_enabled() have been used to simplify the devm_clk_get/clk_prepare_enable tuple in the Renesas EMEV2, Ingenic and MPC drivers. Refactors --------- The Nuvoton fixes a potential out of boundary array access. This is not a bug fix because the issue could never occur due to hardware not having the properties listed in the array. The change makes the driver more future proof and, at the same time, silences code analyzers. Improvements ------------ The Renesas I2C (riic) driver undergoes several patches improving the runtime power management handling. The Intel i801 driver uses a more descriptive adapter's name to show the presence of the IDF feature. In the Intel Denverton (ismt) adapter the pending transactions are killed when irq's can't complete their handling, triggering a timeout. This could have been considered as a bug fix, but because, standing to Vasily, it's very sporadic, I preferred considering the patch rather as an improvement. New Feature ----------- The Renesas I2C (riic) driver now supports the fast mode plus. New support ----------- Added support for: - Renesas R9A08G045 - Rockchip RK3576 - KEBA I2C - Theobroma Systems Mule Multiplexer. The Keba comes with a new driver, i2c-keba.c. The Mule is an i2c multiplexer and it also comes with a new driver, mux/i2c-mux-mule.c. Core patch ---------- This pull request includes also a patch in the I2C framework, in i2c-core-base.c where the runtime PM functions have been replaced in order to allow to be accessed during the device add. Devicetree ---------- Some cleanups in the devicetree, as well. nVidia and Qualcomm bindings improve their "if:then:" blocks. While the aspeed binding loses the "multi-master" property because it was redundant. The i2c-sprd binding has been converted to YAML.
Diffstat (limited to 'fs/bcachefs/fs-io-buffered.c')
-rw-r--r--fs/bcachefs/fs-io-buffered.c151
1 files changed, 41 insertions, 110 deletions
diff --git a/fs/bcachefs/fs-io-buffered.c b/fs/bcachefs/fs-io-buffered.c
index cc33d763f722..ec8c427bf588 100644
--- a/fs/bcachefs/fs-io-buffered.c
+++ b/fs/bcachefs/fs-io-buffered.c
@@ -534,7 +534,7 @@ do_io:
if (f_sectors > w->tmp_sectors) {
kfree(w->tmp);
- w->tmp = kcalloc(f_sectors, sizeof(struct bch_folio_sector), __GFP_NOFAIL);
+ w->tmp = kcalloc(f_sectors, sizeof(struct bch_folio_sector), GFP_NOFS|__GFP_NOFAIL);
w->tmp_sectors = f_sectors;
}
@@ -802,8 +802,7 @@ static noinline void folios_trunc(folios *fs, struct folio **fi)
static int __bch2_buffered_write(struct bch_inode_info *inode,
struct address_space *mapping,
struct iov_iter *iter,
- loff_t pos, unsigned len,
- bool inode_locked)
+ loff_t pos, unsigned len)
{
struct bch_fs *c = inode->v.i_sb->s_fs_info;
struct bch2_folio_reservation res;
@@ -827,15 +826,6 @@ static int __bch2_buffered_write(struct bch_inode_info *inode,
BUG_ON(!fs.nr);
- /*
- * If we're not using the inode lock, we need to lock all the folios for
- * atomiticity of writes vs. other writes:
- */
- if (!inode_locked && folio_end_pos(darray_last(fs)) < end) {
- ret = -BCH_ERR_need_inode_lock;
- goto out;
- }
-
f = darray_first(fs);
if (pos != folio_pos(f) && !folio_test_uptodate(f)) {
ret = bch2_read_single_folio(f, mapping);
@@ -932,10 +922,8 @@ static int __bch2_buffered_write(struct bch_inode_info *inode,
end = pos + copied;
spin_lock(&inode->v.i_lock);
- if (end > inode->v.i_size) {
- BUG_ON(!inode_locked);
+ if (end > inode->v.i_size)
i_size_write(&inode->v, end);
- }
spin_unlock(&inode->v.i_lock);
f_pos = pos;
@@ -979,68 +967,12 @@ static ssize_t bch2_buffered_write(struct kiocb *iocb, struct iov_iter *iter)
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
struct bch_inode_info *inode = file_bch_inode(file);
- loff_t pos;
- bool inode_locked = false;
- ssize_t written = 0, written2 = 0, ret = 0;
-
- /*
- * We don't take the inode lock unless i_size will be changing. Folio
- * locks provide exclusion with other writes, and the pagecache add lock
- * provides exclusion with truncate and hole punching.
- *
- * There is one nasty corner case where atomicity would be broken
- * without great care: when copying data from userspace to the page
- * cache, we do that with faults disable - a page fault would recurse
- * back into the filesystem, taking filesystem locks again, and
- * deadlock; so it's done with faults disabled, and we fault in the user
- * buffer when we aren't holding locks.
- *
- * If we do part of the write, but we then race and in the userspace
- * buffer have been evicted and are no longer resident, then we have to
- * drop our folio locks to re-fault them in, breaking write atomicity.
- *
- * To fix this, we restart the write from the start, if we weren't
- * holding the inode lock.
- *
- * There is another wrinkle after that; if we restart the write from the
- * start, and then get an unrecoverable error, we _cannot_ claim to
- * userspace that we did not write data we actually did - so we must
- * track (written2) the most we ever wrote.
- */
-
- if ((iocb->ki_flags & IOCB_APPEND) ||
- (iocb->ki_pos + iov_iter_count(iter) > i_size_read(&inode->v))) {
- inode_lock(&inode->v);
- inode_locked = true;
- }
-
- ret = generic_write_checks(iocb, iter);
- if (ret <= 0)
- goto unlock;
-
- ret = file_remove_privs_flags(file, !inode_locked ? IOCB_NOWAIT : 0);
- if (ret) {
- if (!inode_locked) {
- inode_lock(&inode->v);
- inode_locked = true;
- ret = file_remove_privs_flags(file, 0);
- }
- if (ret)
- goto unlock;
- }
-
- ret = file_update_time(file);
- if (ret)
- goto unlock;
-
- pos = iocb->ki_pos;
+ loff_t pos = iocb->ki_pos;
+ ssize_t written = 0;
+ int ret = 0;
bch2_pagecache_add_get(inode);
- if (!inode_locked &&
- (iocb->ki_pos + iov_iter_count(iter) > i_size_read(&inode->v)))
- goto get_inode_lock;
-
do {
unsigned offset = pos & (PAGE_SIZE - 1);
unsigned bytes = iov_iter_count(iter);
@@ -1065,17 +997,12 @@ again:
}
}
- if (unlikely(bytes != iov_iter_count(iter) && !inode_locked))
- goto get_inode_lock;
-
if (unlikely(fatal_signal_pending(current))) {
ret = -EINTR;
break;
}
- ret = __bch2_buffered_write(inode, mapping, iter, pos, bytes, inode_locked);
- if (ret == -BCH_ERR_need_inode_lock)
- goto get_inode_lock;
+ ret = __bch2_buffered_write(inode, mapping, iter, pos, bytes);
if (unlikely(ret < 0))
break;
@@ -1096,46 +1023,50 @@ again:
}
pos += ret;
written += ret;
- written2 = max(written, written2);
-
- if (ret != bytes && !inode_locked)
- goto get_inode_lock;
ret = 0;
balance_dirty_pages_ratelimited(mapping);
-
- if (0) {
-get_inode_lock:
- bch2_pagecache_add_put(inode);
- inode_lock(&inode->v);
- inode_locked = true;
- bch2_pagecache_add_get(inode);
-
- iov_iter_revert(iter, written);
- pos -= written;
- written = 0;
- ret = 0;
- }
} while (iov_iter_count(iter));
- bch2_pagecache_add_put(inode);
-unlock:
- if (inode_locked)
- inode_unlock(&inode->v);
- iocb->ki_pos += written;
+ bch2_pagecache_add_put(inode);
- ret = max(written, written2) ?: ret;
- if (ret > 0)
- ret = generic_write_sync(iocb, ret);
- return ret;
+ return written ? written : ret;
}
-ssize_t bch2_write_iter(struct kiocb *iocb, struct iov_iter *iter)
+ssize_t bch2_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
- ssize_t ret = iocb->ki_flags & IOCB_DIRECT
- ? bch2_direct_write(iocb, iter)
- : bch2_buffered_write(iocb, iter);
+ struct file *file = iocb->ki_filp;
+ struct bch_inode_info *inode = file_bch_inode(file);
+ ssize_t ret;
+
+ if (iocb->ki_flags & IOCB_DIRECT) {
+ ret = bch2_direct_write(iocb, from);
+ goto out;
+ }
+
+ inode_lock(&inode->v);
+
+ ret = generic_write_checks(iocb, from);
+ if (ret <= 0)
+ goto unlock;
+
+ ret = file_remove_privs(file);
+ if (ret)
+ goto unlock;
+
+ ret = file_update_time(file);
+ if (ret)
+ goto unlock;
+
+ ret = bch2_buffered_write(iocb, from);
+ if (likely(ret > 0))
+ iocb->ki_pos += ret;
+unlock:
+ inode_unlock(&inode->v);
+ if (ret > 0)
+ ret = generic_write_sync(iocb, ret);
+out:
return bch2_err_class(ret);
}