diff options
author | Tristan Ye <tristan.ye@oracle.com> | 2010-12-07 01:35:07 -0500 |
---|---|---|
committer | Joel Becker <joel.becker@oracle.com> | 2010-12-09 18:36:48 -0500 |
commit | 39c99f12f15c8bf8257985d9b2a2548a03d18c00 (patch) | |
tree | 38f09ce41f6cbfd3a73b1dc66098ba3bf05e2d6a /fs | |
parent | 388c4bcb4e63e88fb1f312a2f5f9eb2623afcf5b (diff) |
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/aops.c | 7 | ||||
-rw-r--r-- | fs/ocfs2/aops.h | 23 | ||||
-rw-r--r-- | fs/ocfs2/file.c | 15 |
3 files changed, 39 insertions, 6 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index f1e962cb3b73..0d7c5540ad66 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -573,11 +573,14 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, | |||
573 | /* this io's submitter should not have unlocked this before we could */ | 573 | /* this io's submitter should not have unlocked this before we could */ |
574 | BUG_ON(!ocfs2_iocb_is_rw_locked(iocb)); | 574 | BUG_ON(!ocfs2_iocb_is_rw_locked(iocb)); |
575 | 575 | ||
576 | if (ocfs2_iocb_is_sem_locked(iocb)) { | ||
577 | up_read(&inode->i_alloc_sem); | ||
578 | ocfs2_iocb_clear_sem_locked(iocb); | ||
579 | } | ||
580 | |||
576 | ocfs2_iocb_clear_rw_locked(iocb); | 581 | ocfs2_iocb_clear_rw_locked(iocb); |
577 | 582 | ||
578 | level = ocfs2_iocb_rw_locked_level(iocb); | 583 | level = ocfs2_iocb_rw_locked_level(iocb); |
579 | if (!level) | ||
580 | up_read(&inode->i_alloc_sem); | ||
581 | ocfs2_rw_unlock(inode, level); | 584 | ocfs2_rw_unlock(inode, level); |
582 | 585 | ||
583 | if (is_async) | 586 | if (is_async) |
diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h index 76bfdfda691a..eceb456037c1 100644 --- a/fs/ocfs2/aops.h +++ b/fs/ocfs2/aops.h | |||
@@ -68,8 +68,27 @@ static inline void ocfs2_iocb_set_rw_locked(struct kiocb *iocb, int level) | |||
68 | else | 68 | else |
69 | clear_bit(1, (unsigned long *)&iocb->private); | 69 | clear_bit(1, (unsigned long *)&iocb->private); |
70 | } | 70 | } |
71 | |||
72 | /* | ||
73 | * Using a named enum representing lock types in terms of #N bit stored in | ||
74 | * iocb->private, which is going to be used for communication bewteen | ||
75 | * ocfs2_dio_end_io() and ocfs2_file_aio_write/read(). | ||
76 | */ | ||
77 | enum ocfs2_iocb_lock_bits { | ||
78 | OCFS2_IOCB_RW_LOCK = 0, | ||
79 | OCFS2_IOCB_RW_LOCK_LEVEL, | ||
80 | OCFS2_IOCB_SEM, | ||
81 | OCFS2_IOCB_NUM_LOCKS | ||
82 | }; | ||
83 | |||
71 | #define ocfs2_iocb_clear_rw_locked(iocb) \ | 84 | #define ocfs2_iocb_clear_rw_locked(iocb) \ |
72 | clear_bit(0, (unsigned long *)&iocb->private) | 85 | clear_bit(OCFS2_IOCB_RW_LOCK, (unsigned long *)&iocb->private) |
73 | #define ocfs2_iocb_rw_locked_level(iocb) \ | 86 | #define ocfs2_iocb_rw_locked_level(iocb) \ |
74 | test_bit(1, (unsigned long *)&iocb->private) | 87 | test_bit(OCFS2_IOCB_RW_LOCK_LEVEL, (unsigned long *)&iocb->private) |
88 | #define ocfs2_iocb_set_sem_locked(iocb) \ | ||
89 | set_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private) | ||
90 | #define ocfs2_iocb_clear_sem_locked(iocb) \ | ||
91 | clear_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private) | ||
92 | #define ocfs2_iocb_is_sem_locked(iocb) \ | ||
93 | test_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private) | ||
75 | #endif /* OCFS2_FILE_H */ | 94 | #endif /* OCFS2_FILE_H */ |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 77b4c04a2809..f6cba566429d 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -2241,11 +2241,15 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, | |||
2241 | 2241 | ||
2242 | mutex_lock(&inode->i_mutex); | 2242 | mutex_lock(&inode->i_mutex); |
2243 | 2243 | ||
2244 | ocfs2_iocb_clear_sem_locked(iocb); | ||
2245 | |||
2244 | relock: | 2246 | relock: |
2245 | /* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */ | 2247 | /* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */ |
2246 | if (direct_io) { | 2248 | if (direct_io) { |
2247 | down_read(&inode->i_alloc_sem); | 2249 | down_read(&inode->i_alloc_sem); |
2248 | have_alloc_sem = 1; | 2250 | have_alloc_sem = 1; |
2251 | /* communicate with ocfs2_dio_end_io */ | ||
2252 | ocfs2_iocb_set_sem_locked(iocb); | ||
2249 | } | 2253 | } |
2250 | 2254 | ||
2251 | /* | 2255 | /* |
@@ -2382,8 +2386,10 @@ out: | |||
2382 | ocfs2_rw_unlock(inode, rw_level); | 2386 | ocfs2_rw_unlock(inode, rw_level); |
2383 | 2387 | ||
2384 | out_sems: | 2388 | out_sems: |
2385 | if (have_alloc_sem) | 2389 | if (have_alloc_sem) { |
2386 | up_read(&inode->i_alloc_sem); | 2390 | up_read(&inode->i_alloc_sem); |
2391 | ocfs2_iocb_clear_sem_locked(iocb); | ||
2392 | } | ||
2387 | 2393 | ||
2388 | mutex_unlock(&inode->i_mutex); | 2394 | mutex_unlock(&inode->i_mutex); |
2389 | 2395 | ||
@@ -2527,6 +2533,8 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, | |||
2527 | goto bail; | 2533 | goto bail; |
2528 | } | 2534 | } |
2529 | 2535 | ||
2536 | ocfs2_iocb_clear_sem_locked(iocb); | ||
2537 | |||
2530 | /* | 2538 | /* |
2531 | * buffered reads protect themselves in ->readpage(). O_DIRECT reads | 2539 | * buffered reads protect themselves in ->readpage(). O_DIRECT reads |
2532 | * need locks to protect pending reads from racing with truncate. | 2540 | * need locks to protect pending reads from racing with truncate. |
@@ -2534,6 +2542,7 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, | |||
2534 | if (filp->f_flags & O_DIRECT) { | 2542 | if (filp->f_flags & O_DIRECT) { |
2535 | down_read(&inode->i_alloc_sem); | 2543 | down_read(&inode->i_alloc_sem); |
2536 | have_alloc_sem = 1; | 2544 | have_alloc_sem = 1; |
2545 | ocfs2_iocb_set_sem_locked(iocb); | ||
2537 | 2546 | ||
2538 | ret = ocfs2_rw_lock(inode, 0); | 2547 | ret = ocfs2_rw_lock(inode, 0); |
2539 | if (ret < 0) { | 2548 | if (ret < 0) { |
@@ -2575,8 +2584,10 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, | |||
2575 | } | 2584 | } |
2576 | 2585 | ||
2577 | bail: | 2586 | bail: |
2578 | if (have_alloc_sem) | 2587 | if (have_alloc_sem) { |
2579 | up_read(&inode->i_alloc_sem); | 2588 | up_read(&inode->i_alloc_sem); |
2589 | ocfs2_iocb_clear_sem_locked(iocb); | ||
2590 | } | ||
2580 | if (rw_level != -1) | 2591 | if (rw_level != -1) |
2581 | ocfs2_rw_unlock(inode, rw_level); | 2592 | ocfs2_rw_unlock(inode, rw_level); |
2582 | mlog_exit(ret); | 2593 | mlog_exit(ret); |