summaryrefslogtreecommitdiff
path: root/fs/libfs.c
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2023-12-04 12:31:42 +0000
committerMark Brown <broonie@kernel.org>2023-12-04 12:31:42 +0000
commit06891af2709b5dfa4081ff1f07b9f4c2743834b7 (patch)
tree672f337b94d3af79268a54b5307af1392f708a1a /fs/libfs.c
parent7a030abc0185b30a3fd19a7431347c6f5a82c588 (diff)
parent9b2ef250b31d46f7ef522bd1bd84942f998bb3f9 (diff)
spi: spl022: fix sleeping in interrupt context
Merge series from Nam Cao <namcao@linutronix.de>: While running the spl022, I got the following warning: BUG: sleeping function called from invalid context at drivers/spi/spi.c:1428 This is because between spi transfers, spi_transfer_delay_exec() (who may sleep if the delay is >10us) is called in interrupt context. This is a problem for anyone who runs this driver and need more than 10us delay. Patch 1 adds an error reporting mechanism, needed by patch 2 who switch to use the default spi_transfer_one_message(), which fix the problem. The series is tested with polling transfer mode and interrupt transfer mode. I can't test the DMA mode, so some help testing here is very appreciated.
Diffstat (limited to 'fs/libfs.c')
-rw-r--r--fs/libfs.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/fs/libfs.c b/fs/libfs.c
index e9440d55073c..c2aa6fd4795c 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -399,6 +399,8 @@ static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence)
return -EINVAL;
}
+ /* In this case, ->private_data is protected by f_pos_lock */
+ file->private_data = NULL;
return vfs_setpos(file, offset, U32_MAX);
}
@@ -428,7 +430,7 @@ static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry)
inode->i_ino, fs_umode_to_dtype(inode->i_mode));
}
-static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
+static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
{
struct offset_ctx *so_ctx = inode->i_op->get_offset_ctx(inode);
XA_STATE(xas, &so_ctx->xa, ctx->pos);
@@ -437,7 +439,7 @@ static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
while (true) {
dentry = offset_find_next(&xas);
if (!dentry)
- break;
+ return ERR_PTR(-ENOENT);
if (!offset_dir_emit(ctx, dentry)) {
dput(dentry);
@@ -447,6 +449,7 @@ static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
dput(dentry);
ctx->pos = xas.xa_index + 1;
}
+ return NULL;
}
/**
@@ -479,7 +482,12 @@ static int offset_readdir(struct file *file, struct dir_context *ctx)
if (!dir_emit_dots(file, ctx))
return 0;
- offset_iterate_dir(d_inode(dir), ctx);
+ /* In this case, ->private_data is protected by f_pos_lock */
+ if (ctx->pos == 2)
+ file->private_data = NULL;
+ else if (file->private_data == ERR_PTR(-ENOENT))
+ return 0;
+ file->private_data = offset_iterate_dir(d_inode(dir), ctx);
return 0;
}