i_sem-less generic_file_write for O_DIRECT & XFS
Subsystems (3)
PATCH 1/1 i_sem-less generic_file_write for O_DIRECT & XFS
There are a number of places where generic_file_write could be used if it didn't take i_sem by itself or where it doesn't need it:
(1) XFS needs to do some preparation in it's write file operation
(most notably taking it's own per-inode locks), after taking i_sem, but before calling the guts of generic_file_write.
(2) blockdevices are happy with parralel get_block() operations,
and there is nothing i_sem could protect.
This patch introduces a generic_file_write_nolock and makes the good old generic_file_write a wrapper around. The block device code is switched over to it.
fs/block_dev.c +1 -1
@@ -792,7 +792,7 @@ release: blkdev_close, llseek: block_llseek, read: generic_file_read, - write: generic_file_write, + write: generic_file_write_nolock, mmap: generic_file_mmap, fsync: block_fsync, ioctl: blkdev_ioctl,
kernel/ksyms.c +1 -0
@@ -219,6 +219,7 @@EXPORT_SYMBOL (generic_file_sendfile);EXPORT_SYMBOL (do_generic_file_read);EXPORT_SYMBOL (generic_file_write); +EXPORT_SYMBOL (generic_file_write_nolock);EXPORT_SYMBOL (generic_file_mmap);EXPORT_SYMBOL (generic_ro_fops);EXPORT_SYMBOL (file_lock_list);
include/linux/fs.h +1 -0
@@ -1239,6 +1239,7 @@extern int file_read_actor (read_descriptor_t * desc,struct page *page,unsigned long offset,unsigned long size);extern ssize_t generic_file_read (struct file *,char *,size_t ,loff_t *);extern ssize_t generic_file_write (struct file *,const char *,size_t ,loff_t *); +extern ssize_t generic_file_write_nolock (struct file *,const char *,size_t ,loff_t *);extern ssize_t generic_file_sendfile (struct file *,struct file *,loff_t *,size_t );extern void do_generic_file_read (struct file *,loff_t *,read_descriptor_t *,read_actor_t ); ssize_t generic_file_direct_IO(int rw, struct inode *inode, char *buf,
mm/filemap.c +17 -9
@@ -1821,9 +1821,8 @@* it for writing by marking it dirty. * [email protected] */ -ssize_t -generic_file_write (struct file *file,const char *buf, -size_t count,loff_t *ppos) +ssize_t generic_file_write_nolock (struct file *file,const char *buf, +size_t count,loff_t *ppos) {struct address_space * mapping = file->f_dentry->d_inode->i_mapping;struct address_space_operations *a_ops = mapping->a_ops;
@@ -1838,18 +1837,15 @@unsigned bytes;time_t time_now; -if (unlikely ((ssize_t ) count <0 )) +if (unlikely ((ssize_t )count <0 ))return -EINVAL ;if (unlikely (!access_ok (VERIFY_READ , buf, count)))return -EFAULT ; -down (&inode->i_sem); pos = *ppos; -if (unlikely (pos <0 )) { - err = -EINVAL ; - goto out; - } +if (unlikely (pos <0 )) +return -EINVAL ;if (unlikely (file->f_error)) { err = file->f_error;
@@ -2046,6 +2042,18 @@ out_status: err = written ? written : status; out: +return err; +} + +ssize_t generic_file_write (struct file *file,const char *buf, +size_t count,loff_t *ppos) +{ +struct inode *inode = file->f_dentry->d_inode->i_mapping->host; +int err; + +down (&inode->i_sem); + err =generic_file_write_nolock (file, buf, count, ppos);up (&inode->i_sem); +return err; }