diff options
| author | Christoph Hellwig <hch@infradead.org> | 2011-06-24 14:29:43 -0400 | 
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-07-20 20:47:46 -0400 | 
| commit | bd5fe6c5eb9c548d7f07fe8f89a150bb6705e8e3 (patch) | |
| tree | ef5341c7747f809aec7ae233f6e3ef90af39be5f /include/linux/fs.h | |
| parent | f9b5570d7fdedff32a2e78102bfb54cd1b12b289 (diff) | |
| download | olio-linux-3.10-bd5fe6c5eb9c548d7f07fe8f89a150bb6705e8e3.tar.xz olio-linux-3.10-bd5fe6c5eb9c548d7f07fe8f89a150bb6705e8e3.zip  | |
fs: kill i_alloc_sem
i_alloc_sem is a rather special rw_semaphore.  It's the last one that may
be released by a non-owner, and it's write side is always mirrored by
real exclusion.  It's intended use it to wait for all pending direct I/O
requests to finish before starting a truncate.
Replace it with a hand-grown construct:
 - exclusion for truncates is already guaranteed by i_mutex, so it can
   simply fall way
 - the reader side is replaced by an i_dio_count member in struct inode
   that counts the number of pending direct I/O requests.  Truncate can't
   proceed as long as it's non-zero
 - when i_dio_count reaches non-zero we wake up a pending truncate using
   wake_up_bit on a new bit in i_flags
 - new references to i_dio_count can't appear while we are waiting for
   it to read zero because the direct I/O count always needs i_mutex
   (or an equivalent like XFS's i_iolock) for starting a new operation.
This scheme is much simpler, and saves the space of a spinlock_t and a
struct list_head in struct inode (typically 160 bits on a non-debug 64-bit
system).
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'include/linux/fs.h')
| -rw-r--r-- | include/linux/fs.h | 11 | 
1 files changed, 9 insertions, 2 deletions
diff --git a/include/linux/fs.h b/include/linux/fs.h index 1393742bba9..2fe920774ab 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -779,7 +779,7 @@ struct inode {  	struct timespec		i_ctime;  	blkcnt_t		i_blocks;  	unsigned short          i_bytes; -	struct rw_semaphore	i_alloc_sem; +	atomic_t		i_dio_count;  	const struct file_operations	*i_fop;	/* former ->i_op->default_file_ops */  	struct file_lock	*i_flock;  	struct address_space	*i_mapping; @@ -1705,6 +1705,10 @@ struct super_operations {   *			set during data writeback, and cleared with a wakeup   *			on the bit address once it is done.   * + * I_REFERENCED		Marks the inode as recently references on the LRU list. + * + * I_DIO_WAKEUP		Never set.  Only used as a key for wait_on_bit(). + *   * Q: What is the difference between I_WILL_FREE and I_FREEING?   */  #define I_DIRTY_SYNC		(1 << 0) @@ -1718,6 +1722,8 @@ struct super_operations {  #define __I_SYNC		7  #define I_SYNC			(1 << __I_SYNC)  #define I_REFERENCED		(1 << 8) +#define __I_DIO_WAKEUP		9 +#define I_DIO_WAKEUP		(1 << I_DIO_WAKEUP)  #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES) @@ -1828,7 +1834,6 @@ struct file_system_type {  	struct lock_class_key i_lock_key;  	struct lock_class_key i_mutex_key;  	struct lock_class_key i_mutex_dir_key; -	struct lock_class_key i_alloc_sem_key;  };  extern struct dentry *mount_ns(struct file_system_type *fs_type, int flags, @@ -2404,6 +2409,8 @@ enum {  };  void dio_end_io(struct bio *bio, int error); +void inode_dio_wait(struct inode *inode); +void inode_dio_done(struct inode *inode);  ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,  	struct block_device *bdev, const struct iovec *iov, loff_t offset,  |