diff options
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 510dba785db4..eb4ddfeeeedc 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -3036,11 +3036,18 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, | |||
3036 | 3036 | ||
3037 | BUG_ON(iocb->private == NULL); | 3037 | BUG_ON(iocb->private == NULL); |
3038 | 3038 | ||
3039 | /* | ||
3040 | * Make all waiters for direct IO properly wait also for extent | ||
3041 | * conversion. This also disallows race between truncate() and | ||
3042 | * overwrite DIO as i_dio_count needs to be incremented under i_mutex. | ||
3043 | */ | ||
3044 | if (rw == WRITE) | ||
3045 | atomic_inc(&inode->i_dio_count); | ||
3046 | |||
3039 | /* If we do a overwrite dio, i_mutex locking can be released */ | 3047 | /* If we do a overwrite dio, i_mutex locking can be released */ |
3040 | overwrite = *((int *)iocb->private); | 3048 | overwrite = *((int *)iocb->private); |
3041 | 3049 | ||
3042 | if (overwrite) { | 3050 | if (overwrite) { |
3043 | atomic_inc(&inode->i_dio_count); | ||
3044 | down_read(&EXT4_I(inode)->i_data_sem); | 3051 | down_read(&EXT4_I(inode)->i_data_sem); |
3045 | mutex_unlock(&inode->i_mutex); | 3052 | mutex_unlock(&inode->i_mutex); |
3046 | } | 3053 | } |
@@ -3143,9 +3150,10 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, | |||
3143 | } | 3150 | } |
3144 | 3151 | ||
3145 | retake_lock: | 3152 | retake_lock: |
3153 | if (rw == WRITE) | ||
3154 | inode_dio_done(inode); | ||
3146 | /* take i_mutex locking again if we do a ovewrite dio */ | 3155 | /* take i_mutex locking again if we do a ovewrite dio */ |
3147 | if (overwrite) { | 3156 | if (overwrite) { |
3148 | inode_dio_done(inode); | ||
3149 | up_read(&EXT4_I(inode)->i_data_sem); | 3157 | up_read(&EXT4_I(inode)->i_data_sem); |
3150 | mutex_lock(&inode->i_mutex); | 3158 | mutex_lock(&inode->i_mutex); |
3151 | } | 3159 | } |