Commit 8c0b388a authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Linus Torvalds

[PATCH] 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.
parent 630986cd
...@@ -874,7 +874,7 @@ struct file_operations def_blk_fops = { ...@@ -874,7 +874,7 @@ struct file_operations def_blk_fops = {
release: blkdev_close, release: blkdev_close,
llseek: block_llseek, llseek: block_llseek,
read: generic_file_read, read: generic_file_read,
write: generic_file_write, write: generic_file_write_nolock,
mmap: generic_file_mmap, mmap: generic_file_mmap,
fsync: block_fsync, fsync: block_fsync,
ioctl: blkdev_ioctl, ioctl: blkdev_ioctl,
......
...@@ -1241,6 +1241,7 @@ extern int generic_file_mmap(struct file *, struct vm_area_struct *); ...@@ -1241,6 +1241,7 @@ extern int generic_file_mmap(struct file *, struct vm_area_struct *);
extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size); 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_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(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 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); 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, ssize_t generic_file_direct_IO(int rw, struct inode *inode, char *buf,
......
...@@ -222,6 +222,7 @@ EXPORT_SYMBOL(generic_file_read); ...@@ -222,6 +222,7 @@ EXPORT_SYMBOL(generic_file_read);
EXPORT_SYMBOL(generic_file_sendfile); EXPORT_SYMBOL(generic_file_sendfile);
EXPORT_SYMBOL(do_generic_file_read); EXPORT_SYMBOL(do_generic_file_read);
EXPORT_SYMBOL(generic_file_write); EXPORT_SYMBOL(generic_file_write);
EXPORT_SYMBOL(generic_file_write_nolock);
EXPORT_SYMBOL(generic_file_mmap); EXPORT_SYMBOL(generic_file_mmap);
EXPORT_SYMBOL(generic_ro_fops); EXPORT_SYMBOL(generic_ro_fops);
EXPORT_SYMBOL(file_lock_list); EXPORT_SYMBOL(file_lock_list);
......
...@@ -1812,9 +1812,8 @@ inline void remove_suid(struct dentry *dentry) ...@@ -1812,9 +1812,8 @@ inline void remove_suid(struct dentry *dentry)
* it for writing by marking it dirty. * it for writing by marking it dirty.
* okir@monad.swb.de * okir@monad.swb.de
*/ */
ssize_t ssize_t generic_file_write_nolock(struct file *file, const char *buf,
generic_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
size_t count, loff_t *ppos)
{ {
struct address_space * mapping = file->f_dentry->d_inode->i_mapping; struct address_space * mapping = file->f_dentry->d_inode->i_mapping;
struct address_space_operations *a_ops = mapping->a_ops; struct address_space_operations *a_ops = mapping->a_ops;
...@@ -1829,18 +1828,15 @@ generic_file_write(struct file *file, const char *buf, ...@@ -1829,18 +1828,15 @@ generic_file_write(struct file *file, const char *buf,
unsigned bytes; unsigned bytes;
time_t time_now; time_t time_now;
if (unlikely((ssize_t) count < 0)) if (unlikely((ssize_t)count < 0))
return -EINVAL; return -EINVAL;
if (unlikely(!access_ok(VERIFY_READ, buf, count))) if (unlikely(!access_ok(VERIFY_READ, buf, count)))
return -EFAULT; return -EFAULT;
down(&inode->i_sem);
pos = *ppos; pos = *ppos;
if (unlikely(pos < 0)) { if (unlikely(pos < 0))
err = -EINVAL; return -EINVAL;
goto out;
}
if (unlikely(file->f_error)) { if (unlikely(file->f_error)) {
err = file->f_error; err = file->f_error;
...@@ -2037,6 +2033,18 @@ generic_file_write(struct file *file, const char *buf, ...@@ -2037,6 +2033,18 @@ generic_file_write(struct file *file, const char *buf,
out_status: out_status:
err = written ? written : status; err = written ? written : status;
out: 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); up(&inode->i_sem);
return err; return err;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment