mirror of https://gitee.com/openkylin/linux.git
Ocfs2: Teach 'coherency=full' O_DIRECT writes to correctly up_read i_alloc_sem.
Due to newly-introduced 'coherency=full' O_DIRECT writes also takes the EX rw_lock like buffered writes did(rw_level == 1), it turns out messing the usage of 'level' in ocfs2_dio_end_io() up, which caused i_alloc_sem being failed to get up_read'd correctly. This patch tries to teach ocfs2_dio_end_io to understand well on all locking stuffs by explicitly introducing a new bit for i_alloc_sem in iocb's private data, just like what we did for rw_lock. Signed-off-by: Tristan Ye <tristan.ye@oracle.com> Signed-off-by: Joel Becker <joel.becker@oracle.com>
This commit is contained in:
parent
388c4bcb4e
commit
39c99f12f1
|
@ -573,11 +573,14 @@ static void ocfs2_dio_end_io(struct kiocb *iocb,
|
||||||
/* this io's submitter should not have unlocked this before we could */
|
/* this io's submitter should not have unlocked this before we could */
|
||||||
BUG_ON(!ocfs2_iocb_is_rw_locked(iocb));
|
BUG_ON(!ocfs2_iocb_is_rw_locked(iocb));
|
||||||
|
|
||||||
|
if (ocfs2_iocb_is_sem_locked(iocb)) {
|
||||||
|
up_read(&inode->i_alloc_sem);
|
||||||
|
ocfs2_iocb_clear_sem_locked(iocb);
|
||||||
|
}
|
||||||
|
|
||||||
ocfs2_iocb_clear_rw_locked(iocb);
|
ocfs2_iocb_clear_rw_locked(iocb);
|
||||||
|
|
||||||
level = ocfs2_iocb_rw_locked_level(iocb);
|
level = ocfs2_iocb_rw_locked_level(iocb);
|
||||||
if (!level)
|
|
||||||
up_read(&inode->i_alloc_sem);
|
|
||||||
ocfs2_rw_unlock(inode, level);
|
ocfs2_rw_unlock(inode, level);
|
||||||
|
|
||||||
if (is_async)
|
if (is_async)
|
||||||
|
|
|
@ -68,8 +68,27 @@ static inline void ocfs2_iocb_set_rw_locked(struct kiocb *iocb, int level)
|
||||||
else
|
else
|
||||||
clear_bit(1, (unsigned long *)&iocb->private);
|
clear_bit(1, (unsigned long *)&iocb->private);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using a named enum representing lock types in terms of #N bit stored in
|
||||||
|
* iocb->private, which is going to be used for communication bewteen
|
||||||
|
* ocfs2_dio_end_io() and ocfs2_file_aio_write/read().
|
||||||
|
*/
|
||||||
|
enum ocfs2_iocb_lock_bits {
|
||||||
|
OCFS2_IOCB_RW_LOCK = 0,
|
||||||
|
OCFS2_IOCB_RW_LOCK_LEVEL,
|
||||||
|
OCFS2_IOCB_SEM,
|
||||||
|
OCFS2_IOCB_NUM_LOCKS
|
||||||
|
};
|
||||||
|
|
||||||
#define ocfs2_iocb_clear_rw_locked(iocb) \
|
#define ocfs2_iocb_clear_rw_locked(iocb) \
|
||||||
clear_bit(0, (unsigned long *)&iocb->private)
|
clear_bit(OCFS2_IOCB_RW_LOCK, (unsigned long *)&iocb->private)
|
||||||
#define ocfs2_iocb_rw_locked_level(iocb) \
|
#define ocfs2_iocb_rw_locked_level(iocb) \
|
||||||
test_bit(1, (unsigned long *)&iocb->private)
|
test_bit(OCFS2_IOCB_RW_LOCK_LEVEL, (unsigned long *)&iocb->private)
|
||||||
|
#define ocfs2_iocb_set_sem_locked(iocb) \
|
||||||
|
set_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private)
|
||||||
|
#define ocfs2_iocb_clear_sem_locked(iocb) \
|
||||||
|
clear_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private)
|
||||||
|
#define ocfs2_iocb_is_sem_locked(iocb) \
|
||||||
|
test_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private)
|
||||||
#endif /* OCFS2_FILE_H */
|
#endif /* OCFS2_FILE_H */
|
||||||
|
|
|
@ -2241,11 +2241,15 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
|
||||||
|
|
||||||
mutex_lock(&inode->i_mutex);
|
mutex_lock(&inode->i_mutex);
|
||||||
|
|
||||||
|
ocfs2_iocb_clear_sem_locked(iocb);
|
||||||
|
|
||||||
relock:
|
relock:
|
||||||
/* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */
|
/* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */
|
||||||
if (direct_io) {
|
if (direct_io) {
|
||||||
down_read(&inode->i_alloc_sem);
|
down_read(&inode->i_alloc_sem);
|
||||||
have_alloc_sem = 1;
|
have_alloc_sem = 1;
|
||||||
|
/* communicate with ocfs2_dio_end_io */
|
||||||
|
ocfs2_iocb_set_sem_locked(iocb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2382,8 +2386,10 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
|
||||||
ocfs2_rw_unlock(inode, rw_level);
|
ocfs2_rw_unlock(inode, rw_level);
|
||||||
|
|
||||||
out_sems:
|
out_sems:
|
||||||
if (have_alloc_sem)
|
if (have_alloc_sem) {
|
||||||
up_read(&inode->i_alloc_sem);
|
up_read(&inode->i_alloc_sem);
|
||||||
|
ocfs2_iocb_clear_sem_locked(iocb);
|
||||||
|
}
|
||||||
|
|
||||||
mutex_unlock(&inode->i_mutex);
|
mutex_unlock(&inode->i_mutex);
|
||||||
|
|
||||||
|
@ -2527,6 +2533,8 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ocfs2_iocb_clear_sem_locked(iocb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* buffered reads protect themselves in ->readpage(). O_DIRECT reads
|
* buffered reads protect themselves in ->readpage(). O_DIRECT reads
|
||||||
* need locks to protect pending reads from racing with truncate.
|
* need locks to protect pending reads from racing with truncate.
|
||||||
|
@ -2534,6 +2542,7 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
|
||||||
if (filp->f_flags & O_DIRECT) {
|
if (filp->f_flags & O_DIRECT) {
|
||||||
down_read(&inode->i_alloc_sem);
|
down_read(&inode->i_alloc_sem);
|
||||||
have_alloc_sem = 1;
|
have_alloc_sem = 1;
|
||||||
|
ocfs2_iocb_set_sem_locked(iocb);
|
||||||
|
|
||||||
ret = ocfs2_rw_lock(inode, 0);
|
ret = ocfs2_rw_lock(inode, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -2575,8 +2584,10 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
|
||||||
}
|
}
|
||||||
|
|
||||||
bail:
|
bail:
|
||||||
if (have_alloc_sem)
|
if (have_alloc_sem) {
|
||||||
up_read(&inode->i_alloc_sem);
|
up_read(&inode->i_alloc_sem);
|
||||||
|
ocfs2_iocb_clear_sem_locked(iocb);
|
||||||
|
}
|
||||||
if (rw_level != -1)
|
if (rw_level != -1)
|
||||||
ocfs2_rw_unlock(inode, rw_level);
|
ocfs2_rw_unlock(inode, rw_level);
|
||||||
mlog_exit(ret);
|
mlog_exit(ret);
|
||||||
|
|
Loading…
Reference in New Issue