[PATCH] Take i_mutex in splice_from_pipe()
The splice_actor may be calling ->prepare_write() and ->commit_write(). We want i_mutex on the inode being written to before calling those so that we don't race i_size changes. The double locking behavior is done elsewhere in splice.c, and if we eventually want _nolock variants of generic_file_splice_write(), fs modules might have to replicate the nasty locking code. We introduce inode_double_lock() and inode_double_unlock() to consolidate the locking rules into one set of functions. Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
This commit is contained in:
parent
ce9e3d9953
commit
62752ee198
36
fs/inode.c
36
fs/inode.c
|
@ -1306,6 +1306,42 @@ void wake_up_inode(struct inode *inode)
|
||||||
wake_up_bit(&inode->i_state, __I_LOCK);
|
wake_up_bit(&inode->i_state, __I_LOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We rarely want to lock two inodes that do not have a parent/child
|
||||||
|
* relationship (such as directory, child inode) simultaneously. The
|
||||||
|
* vast majority of file systems should be able to get along fine
|
||||||
|
* without this. Do not use these functions except as a last resort.
|
||||||
|
*/
|
||||||
|
void inode_double_lock(struct inode *inode1, struct inode *inode2)
|
||||||
|
{
|
||||||
|
if (inode1 == NULL || inode2 == NULL || inode1 == inode2) {
|
||||||
|
if (inode1)
|
||||||
|
mutex_lock(&inode1->i_mutex);
|
||||||
|
else if (inode2)
|
||||||
|
mutex_lock(&inode2->i_mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inode1 < inode2) {
|
||||||
|
mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT);
|
||||||
|
mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD);
|
||||||
|
} else {
|
||||||
|
mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT);
|
||||||
|
mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(inode_double_lock);
|
||||||
|
|
||||||
|
void inode_double_unlock(struct inode *inode1, struct inode *inode2)
|
||||||
|
{
|
||||||
|
if (inode1)
|
||||||
|
mutex_unlock(&inode1->i_mutex);
|
||||||
|
|
||||||
|
if (inode2 && inode2 != inode1)
|
||||||
|
mutex_unlock(&inode2->i_mutex);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(inode_double_unlock);
|
||||||
|
|
||||||
static __initdata unsigned long ihash_entries;
|
static __initdata unsigned long ihash_entries;
|
||||||
static int __init set_ihash_entries(char *str)
|
static int __init set_ihash_entries(char *str)
|
||||||
{
|
{
|
||||||
|
|
24
fs/splice.c
24
fs/splice.c
|
@ -713,6 +713,7 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
|
||||||
{
|
{
|
||||||
int ret, do_wakeup, err;
|
int ret, do_wakeup, err;
|
||||||
struct splice_desc sd;
|
struct splice_desc sd;
|
||||||
|
struct inode *inode = out->f_mapping->host;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
do_wakeup = 0;
|
do_wakeup = 0;
|
||||||
|
@ -722,8 +723,13 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
|
||||||
sd.file = out;
|
sd.file = out;
|
||||||
sd.pos = *ppos;
|
sd.pos = *ppos;
|
||||||
|
|
||||||
if (pipe->inode)
|
/*
|
||||||
mutex_lock(&pipe->inode->i_mutex);
|
* The actor worker might be calling ->prepare_write and
|
||||||
|
* ->commit_write. Most of the time, these expect i_mutex to
|
||||||
|
* be held. Since this may result in an ABBA deadlock with
|
||||||
|
* pipe->inode, we have to order lock acquiry here.
|
||||||
|
*/
|
||||||
|
inode_double_lock(inode, pipe->inode);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (pipe->nrbufs) {
|
if (pipe->nrbufs) {
|
||||||
|
@ -797,8 +803,7 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
|
||||||
pipe_wait(pipe);
|
pipe_wait(pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pipe->inode)
|
inode_double_unlock(inode, pipe->inode);
|
||||||
mutex_unlock(&pipe->inode->i_mutex);
|
|
||||||
|
|
||||||
if (do_wakeup) {
|
if (do_wakeup) {
|
||||||
smp_mb();
|
smp_mb();
|
||||||
|
@ -1400,13 +1405,7 @@ static int link_pipe(struct pipe_inode_info *ipipe,
|
||||||
* grabbing by inode address. Otherwise two different processes
|
* grabbing by inode address. Otherwise two different processes
|
||||||
* could deadlock (one doing tee from A -> B, the other from B -> A).
|
* could deadlock (one doing tee from A -> B, the other from B -> A).
|
||||||
*/
|
*/
|
||||||
if (ipipe->inode < opipe->inode) {
|
inode_double_lock(ipipe->inode, opipe->inode);
|
||||||
mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_PARENT);
|
|
||||||
mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_CHILD);
|
|
||||||
} else {
|
|
||||||
mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_PARENT);
|
|
||||||
mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_CHILD);
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (!opipe->readers) {
|
if (!opipe->readers) {
|
||||||
|
@ -1450,8 +1449,7 @@ static int link_pipe(struct pipe_inode_info *ipipe,
|
||||||
i++;
|
i++;
|
||||||
} while (len);
|
} while (len);
|
||||||
|
|
||||||
mutex_unlock(&ipipe->inode->i_mutex);
|
inode_double_unlock(ipipe->inode, opipe->inode);
|
||||||
mutex_unlock(&opipe->inode->i_mutex);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we put data in the output pipe, wakeup any potential readers.
|
* If we put data in the output pipe, wakeup any potential readers.
|
||||||
|
|
|
@ -623,6 +623,9 @@ enum inode_i_mutex_lock_class
|
||||||
I_MUTEX_QUOTA
|
I_MUTEX_QUOTA
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern void inode_double_lock(struct inode *inode1, struct inode *inode2);
|
||||||
|
extern void inode_double_unlock(struct inode *inode1, struct inode *inode2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE: in a 32bit arch with a preemptable kernel and
|
* NOTE: in a 32bit arch with a preemptable kernel and
|
||||||
* an UP compile the i_size_read/write must be atomic
|
* an UP compile the i_size_read/write must be atomic
|
||||||
|
|
Loading…
Reference in New Issue