Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ee10a44 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://oss.sgi.com:8090/oss/git/rc-fixes:
  Fix a direct I/O locking issue revealed by the new mutex code.
parents a488edc9 3fb962bd
Loading
Loading
Loading
Loading
+12 −9
Original line number Original line Diff line number Diff line
@@ -1155,15 +1155,16 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
 * For writes, i_mutex is not held on entry; it is never taken.
 * For writes, i_mutex is not held on entry; it is never taken.
 *
 *
 * DIO_LOCKING (simple locking for regular files)
 * DIO_LOCKING (simple locking for regular files)
 * For writes we are called under i_mutex and return with i_mutex held, even though
 * For writes we are called under i_mutex and return with i_mutex held, even
 * it is internally dropped.
 * though it is internally dropped.
 * For reads, i_mutex is not held on entry, but it is taken and dropped before
 * For reads, i_mutex is not held on entry, but it is taken and dropped before
 * returning.
 * returning.
 *
 *
 * DIO_OWN_LOCKING (filesystem provides synchronisation and handling of
 * DIO_OWN_LOCKING (filesystem provides synchronisation and handling of
 *	uninitialised data, allowing parallel direct readers and writers)
 *	uninitialised data, allowing parallel direct readers and writers)
 * For writes we are called without i_mutex, return without it, never touch it.
 * For writes we are called without i_mutex, return without it, never touch it.
 * For reads, i_mutex is held on entry and will be released before returning.
 * For reads we are called under i_mutex and return with i_mutex held, even
 * though it may be internally dropped.
 *
 *
 * Additional i_alloc_sem locking requirements described inline below.
 * Additional i_alloc_sem locking requirements described inline below.
 */
 */
@@ -1182,7 +1183,8 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
	ssize_t retval = -EINVAL;
	ssize_t retval = -EINVAL;
	loff_t end = offset;
	loff_t end = offset;
	struct dio *dio;
	struct dio *dio;
	int reader_with_isem = (rw == READ && dio_lock_type == DIO_OWN_LOCKING);
	int release_i_mutex = 0;
	int acquire_i_mutex = 0;


	if (rw & WRITE)
	if (rw & WRITE)
		current->flags |= PF_SYNCWRITE;
		current->flags |= PF_SYNCWRITE;
@@ -1225,7 +1227,6 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
	 *	writers need to grab i_alloc_sem only (i_mutex is already held)
	 *	writers need to grab i_alloc_sem only (i_mutex is already held)
	 * For regular files using DIO_OWN_LOCKING,
	 * For regular files using DIO_OWN_LOCKING,
	 *	neither readers nor writers take any locks here
	 *	neither readers nor writers take any locks here
	 *	(i_mutex is already held and release for writers here)
	 */
	 */
	dio->lock_type = dio_lock_type;
	dio->lock_type = dio_lock_type;
	if (dio_lock_type != DIO_NO_LOCKING) {
	if (dio_lock_type != DIO_NO_LOCKING) {
@@ -1236,7 +1237,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
			mapping = iocb->ki_filp->f_mapping;
			mapping = iocb->ki_filp->f_mapping;
			if (dio_lock_type != DIO_OWN_LOCKING) {
			if (dio_lock_type != DIO_OWN_LOCKING) {
				mutex_lock(&inode->i_mutex);
				mutex_lock(&inode->i_mutex);
				reader_with_isem = 1;
				release_i_mutex = 1;
			}
			}


			retval = filemap_write_and_wait_range(mapping, offset,
			retval = filemap_write_and_wait_range(mapping, offset,
@@ -1248,7 +1249,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,


			if (dio_lock_type == DIO_OWN_LOCKING) {
			if (dio_lock_type == DIO_OWN_LOCKING) {
				mutex_unlock(&inode->i_mutex);
				mutex_unlock(&inode->i_mutex);
				reader_with_isem = 0;
				acquire_i_mutex = 1;
			}
			}
		}
		}


@@ -1269,11 +1270,13 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
				nr_segs, blkbits, get_blocks, end_io, dio);
				nr_segs, blkbits, get_blocks, end_io, dio);


	if (rw == READ && dio_lock_type == DIO_LOCKING)
	if (rw == READ && dio_lock_type == DIO_LOCKING)
		reader_with_isem = 0;
		release_i_mutex = 0;


out:
out:
	if (reader_with_isem)
	if (release_i_mutex)
		mutex_unlock(&inode->i_mutex);
		mutex_unlock(&inode->i_mutex);
	else if (acquire_i_mutex)
		mutex_lock(&inode->i_mutex);
	if (rw & WRITE)
	if (rw & WRITE)
		current->flags &= ~PF_SYNCWRITE;
		current->flags &= ~PF_SYNCWRITE;
	return retval;
	return retval;