aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-03-29 11:56:46 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-03-29 11:56:46 -0400
commit75dfe3960e602e63ea42ac7a2a0520832b189ffa (patch)
tree106e8b09afcf5facfba8ba0cf3343e46d5db3ce3 /fs/btrfs
parent30ae8467483d7ab023b5e728bf7d74a575c78023 (diff)
btrfs_file_write -- first pass
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/super.c222
1 files changed, 213 insertions, 9 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 151c1002d74e..7914b31f5bcd 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -9,6 +9,8 @@
9#include <linux/smp_lock.h> 9#include <linux/smp_lock.h>
10#include <linux/backing-dev.h> 10#include <linux/backing-dev.h>
11#include <linux/mpage.h> 11#include <linux/mpage.h>
12#include <linux/swap.h>
13#include <linux/writeback.h>
12#include "ctree.h" 14#include "ctree.h"
13#include "disk-io.h" 15#include "disk-io.h"
14#include "transaction.h" 16#include "transaction.h"
@@ -755,7 +757,7 @@ printk("btrfs sync_fs\n");
755 return 0; 757 return 0;
756} 758}
757 759
758static int btrfs_get_block(struct inode *inode, sector_t iblock, 760static int btrfs_get_block_lock(struct inode *inode, sector_t iblock,
759 struct buffer_head *result, int create) 761 struct buffer_head *result, int create)
760{ 762{
761 int ret; 763 int ret;
@@ -772,7 +774,6 @@ static int btrfs_get_block(struct inode *inode, sector_t iblock,
772 struct btrfs_disk_key *found_key; 774 struct btrfs_disk_key *found_key;
773 775
774 btrfs_init_path(&path); 776 btrfs_init_path(&path);
775 mutex_lock(&root->fs_info->fs_mutex);
776 if (create) 777 if (create)
777 trans = btrfs_start_transaction(root, 1); 778 trans = btrfs_start_transaction(root, 1);
778 779
@@ -848,6 +849,16 @@ allocate:
848out: 849out:
849 if (trans) 850 if (trans)
850 btrfs_end_transaction(trans, root); 851 btrfs_end_transaction(trans, root);
852 return err;
853}
854
855static int btrfs_get_block(struct inode *inode, sector_t iblock,
856 struct buffer_head *result, int create)
857{
858 int err;
859 struct btrfs_root *root = btrfs_sb(inode->i_sb);
860 mutex_lock(&root->fs_info->fs_mutex);
861 err = btrfs_get_block_lock(inode, iblock, result, create);
851 mutex_unlock(&root->fs_info->fs_mutex); 862 mutex_unlock(&root->fs_info->fs_mutex);
852 return err; 863 return err;
853} 864}
@@ -855,8 +866,15 @@ out:
855static int btrfs_prepare_write(struct file *file, struct page *page, 866static int btrfs_prepare_write(struct file *file, struct page *page,
856 unsigned from, unsigned to) 867 unsigned from, unsigned to)
857{ 868{
869 WARN_ON(1);
858 return nobh_prepare_write(page, from, to, btrfs_get_block); 870 return nobh_prepare_write(page, from, to, btrfs_get_block);
859} 871}
872static int btrfs_commit_write(struct file *file, struct page *page,
873 unsigned from, unsigned to)
874{
875 WARN_ON(1);
876 return nobh_commit_write(file, page, from, to);
877}
860 878
861static void btrfs_write_super(struct super_block *sb) 879static void btrfs_write_super(struct super_block *sb)
862{ 880{
@@ -903,6 +921,196 @@ static void btrfs_truncate(struct inode *inode)
903 mark_inode_dirty(inode); 921 mark_inode_dirty(inode);
904} 922}
905 923
924static int btrfs_copy_from_user(loff_t pos, int num_pages, int write_bytes,
925 struct page **prepared_pages,
926 const char __user * buf)
927{
928 long page_fault = 0;
929 int i;
930 int offset = pos & (PAGE_CACHE_SIZE - 1);
931
932 for (i = 0; i < num_pages && write_bytes > 0; i++, offset = 0) {
933 size_t count = min_t(size_t,
934 PAGE_CACHE_SIZE - offset, write_bytes);
935 struct page *page = prepared_pages[i];
936 fault_in_pages_readable(buf, count);
937
938 /* Copy data from userspace to the current page */
939 kmap(page);
940 page_fault = __copy_from_user(page_address(page) + offset,
941 buf, count);
942 /* Flush processor's dcache for this page */
943 flush_dcache_page(page);
944 kunmap(page);
945 buf += count;
946 write_bytes -= count;
947
948 if (page_fault)
949 break;
950 }
951 return page_fault ? -EFAULT : 0;
952}
953
954static void btrfs_drop_pages(struct page **pages, size_t num_pages)
955{
956 size_t i;
957 for (i = 0; i < num_pages; i++) {
958 if (!pages[i])
959 break;
960 unlock_page(pages[i]);
961 mark_page_accessed(pages[i]);
962 page_cache_release(pages[i]);
963 }
964}
965static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
966 struct btrfs_root *root,
967 struct file *file,
968 struct page **pages,
969 size_t num_pages,
970 loff_t pos,
971 size_t write_bytes)
972{
973 int i;
974 int offset;
975 int err = 0;
976 int ret;
977 int this_write;
978
979 for (i = 0; i < num_pages; i++) {
980 offset = pos & (PAGE_CACHE_SIZE -1);
981 this_write = min(PAGE_CACHE_SIZE - offset, write_bytes);
982 ret = nobh_commit_write(file, pages[i], offset,
983 offset + this_write);
984 pos += this_write;
985 if (ret) {
986 err = ret;
987 goto failed;
988 }
989 WARN_ON(this_write > write_bytes);
990 write_bytes -= this_write;
991 }
992failed:
993 return err;
994}
995
996static int prepare_pages(struct btrfs_trans_handle *trans,
997 struct btrfs_root *root,
998 struct file *file,
999 struct page **pages,
1000 size_t num_pages,
1001 loff_t pos,
1002 size_t write_bytes)
1003{
1004 int i;
1005 unsigned long index = pos >> PAGE_CACHE_SHIFT;
1006 struct inode *inode = file->f_path.dentry->d_inode;
1007 int offset;
1008 int err = 0;
1009 int ret;
1010 int this_write;
1011 loff_t isize = i_size_read(inode);
1012
1013 memset(pages, 0, num_pages * sizeof(struct page *));
1014
1015 for (i = 0; i < num_pages; i++) {
1016 pages[i] = grab_cache_page(inode->i_mapping, index + i);
1017 if (!pages[i]) {
1018 err = -ENOMEM;
1019 goto failed_release;
1020 }
1021 offset = pos & (PAGE_CACHE_SIZE -1);
1022 this_write = min(PAGE_CACHE_SIZE - offset, write_bytes);
1023 ret = nobh_prepare_write(pages[i], offset,
1024 offset + this_write,
1025 btrfs_get_block_lock);
1026 pos += this_write;
1027 if (ret) {
1028 err = ret;
1029 goto failed_truncate;
1030 }
1031 WARN_ON(this_write > write_bytes);
1032 write_bytes -= this_write;
1033 }
1034 return 0;
1035
1036failed_release:
1037 btrfs_drop_pages(pages, num_pages);
1038 return err;
1039
1040failed_truncate:
1041 btrfs_drop_pages(pages, num_pages);
1042 if (pos > isize)
1043 vmtruncate(inode, isize);
1044 return err;
1045}
1046
1047static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
1048 size_t count, loff_t *ppos)
1049{
1050 loff_t pos;
1051 size_t num_written = 0;
1052 int err = 0;
1053 int ret = 0;
1054 struct btrfs_trans_handle *trans;
1055 struct inode *inode = file->f_path.dentry->d_inode;
1056 struct btrfs_root *root = btrfs_sb(inode->i_sb);
1057 struct page *pages[1];
1058
1059 if (file->f_flags & O_DIRECT)
1060 return -EINVAL;
1061 pos = *ppos;
1062
1063 vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
1064 current->backing_dev_info = inode->i_mapping->backing_dev_info;
1065 err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
1066 if (err)
1067 goto out;
1068 if (count == 0)
1069 goto out;
1070 err = remove_suid(file->f_path.dentry);
1071 if (err)
1072 goto out;
1073 file_update_time(file);
1074 mutex_lock(&inode->i_mutex);
1075 while(count > 0) {
1076 size_t offset = pos & (PAGE_CACHE_SIZE - 1);
1077 size_t write_bytes = min(count, PAGE_CACHE_SIZE - offset);
1078 size_t num_pages = (write_bytes + PAGE_CACHE_SIZE - 1) >>
1079 PAGE_CACHE_SHIFT;
1080 mutex_lock(&root->fs_info->fs_mutex);
1081 trans = btrfs_start_transaction(root, 1);
1082
1083 ret = prepare_pages(trans, root, file, pages, num_pages,
1084 pos, write_bytes);
1085 BUG_ON(ret);
1086 ret = btrfs_copy_from_user(pos, num_pages,
1087 write_bytes, pages, buf);
1088 BUG_ON(ret);
1089
1090 mutex_unlock(&root->fs_info->fs_mutex);
1091
1092 ret = dirty_and_release_pages(trans, root, file, pages,
1093 num_pages, pos, write_bytes);
1094 BUG_ON(ret);
1095 btrfs_drop_pages(pages, num_pages);
1096
1097 ret = btrfs_end_transaction(trans, root);
1098
1099 buf += write_bytes;
1100 count -= write_bytes;
1101 pos += write_bytes;
1102 num_written += write_bytes;
1103
1104 balance_dirty_pages_ratelimited(inode->i_mapping);
1105 cond_resched();
1106 }
1107 mutex_unlock(&inode->i_mutex);
1108out:
1109 *ppos = pos;
1110 current->backing_dev_info = NULL;
1111 return num_written ? num_written : err;
1112}
1113
906static int btrfs_get_sb(struct file_system_type *fs_type, 1114static int btrfs_get_sb(struct file_system_type *fs_type,
907 int flags, const char *dev_name, void *data, struct vfsmount *mnt) 1115 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
908{ 1116{
@@ -948,7 +1156,7 @@ static struct address_space_operations btrfs_aops = {
948 .writepage = btrfs_writepage, 1156 .writepage = btrfs_writepage,
949 .sync_page = block_sync_page, 1157 .sync_page = block_sync_page,
950 .prepare_write = btrfs_prepare_write, 1158 .prepare_write = btrfs_prepare_write,
951 .commit_write = nobh_commit_write, 1159 .commit_write = btrfs_commit_write,
952}; 1160};
953 1161
954static struct inode_operations btrfs_file_inode_operations = { 1162static struct inode_operations btrfs_file_inode_operations = {
@@ -958,14 +1166,10 @@ static struct inode_operations btrfs_file_inode_operations = {
958static struct file_operations btrfs_file_operations = { 1166static struct file_operations btrfs_file_operations = {
959 .llseek = generic_file_llseek, 1167 .llseek = generic_file_llseek,
960 .read = do_sync_read, 1168 .read = do_sync_read,
961 .write = do_sync_write, 1169 .aio_read = generic_file_aio_read,
962 .aio_read = generic_file_aio_read, 1170 .write = btrfs_file_write,
963 .aio_write = generic_file_aio_write,
964 .mmap = generic_file_mmap, 1171 .mmap = generic_file_mmap,
965 .open = generic_file_open, 1172 .open = generic_file_open,
966 .sendfile = generic_file_sendfile,
967 .splice_read = generic_file_splice_read,
968 .splice_write = generic_file_splice_write,
969}; 1173};
970 1174
971static int __init init_btrfs_fs(void) 1175static int __init init_btrfs_fs(void)