aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/super.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-03-29 15:15:27 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-03-29 15:15:27 -0400
commitf254e52c1ce550fdaa0d31f5e068f0d67c2485d4 (patch)
tree1232b7e16b6f0b1b1b150c5df396452cac5e3853 /fs/btrfs/super.c
parent75dfe3960e602e63ea42ac7a2a0520832b189ffa (diff)
Btrfs: verify csums on read
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r--fs/btrfs/super.c184
1 files changed, 155 insertions, 29 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 7914b31f5bcd..04428137d75f 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -249,15 +249,16 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
249 struct btrfs_key key; 249 struct btrfs_key key;
250 struct btrfs_disk_key *found_key; 250 struct btrfs_disk_key *found_key;
251 struct btrfs_leaf *leaf; 251 struct btrfs_leaf *leaf;
252 struct btrfs_file_extent_item *fi; 252 struct btrfs_file_extent_item *fi = NULL;
253 u64 extent_start; 253 u64 extent_start = 0;
254 u64 extent_num_blocks; 254 u64 extent_num_blocks = 0;
255 int found_extent;
255 256
256 /* FIXME, add redo link to tree so we don't leak on crash */ 257 /* FIXME, add redo link to tree so we don't leak on crash */
257 key.objectid = inode->i_ino; 258 key.objectid = inode->i_ino;
258 key.offset = (u64)-1; 259 key.offset = (u64)-1;
259 key.flags = 0; 260 key.flags = 0;
260 btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY); 261 btrfs_set_key_type(&key, BTRFS_CSUM_ITEM_KEY);
261 while(1) { 262 while(1) {
262 btrfs_init_path(&path); 263 btrfs_init_path(&path);
263 ret = btrfs_search_slot(trans, root, &key, &path, -1, 1); 264 ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
@@ -273,25 +274,32 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
273 found_key = &leaf->items[path.slots[0]].key; 274 found_key = &leaf->items[path.slots[0]].key;
274 if (btrfs_disk_key_objectid(found_key) != inode->i_ino) 275 if (btrfs_disk_key_objectid(found_key) != inode->i_ino)
275 break; 276 break;
276 if (btrfs_disk_key_type(found_key) != BTRFS_EXTENT_DATA_KEY) 277 if (btrfs_disk_key_type(found_key) != BTRFS_CSUM_ITEM_KEY &&
278 btrfs_disk_key_type(found_key) != BTRFS_EXTENT_DATA_KEY)
277 break; 279 break;
278 if (btrfs_disk_key_offset(found_key) < inode->i_size) 280 if (btrfs_disk_key_offset(found_key) < inode->i_size)
279 break; 281 break;
280 fi = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), 282 if (btrfs_disk_key_type(found_key) == BTRFS_EXTENT_DATA_KEY) {
281 path.slots[0], 283 fi = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]),
282 struct btrfs_file_extent_item); 284 path.slots[0],
283 extent_start = btrfs_file_extent_disk_blocknr(fi); 285 struct btrfs_file_extent_item);
284 extent_num_blocks = btrfs_file_extent_disk_num_blocks(fi); 286 extent_start = btrfs_file_extent_disk_blocknr(fi);
285 key.offset = btrfs_disk_key_offset(found_key) - 1; 287 extent_num_blocks =
288 btrfs_file_extent_disk_num_blocks(fi);
289 inode->i_blocks -=
290 btrfs_file_extent_num_blocks(fi) >> 9;
291 found_extent = 1;
292 } else {
293 found_extent = 0;
294 }
286 ret = btrfs_del_item(trans, root, &path); 295 ret = btrfs_del_item(trans, root, &path);
287 BUG_ON(ret); 296 BUG_ON(ret);
288 inode->i_blocks -= btrfs_file_extent_num_blocks(fi) >> 9;
289 btrfs_release_path(root, &path); 297 btrfs_release_path(root, &path);
290 ret = btrfs_free_extent(trans, root, extent_start, 298 if (found_extent) {
291 extent_num_blocks, 0); 299 ret = btrfs_free_extent(trans, root, extent_start,
292 BUG_ON(ret); 300 extent_num_blocks, 0);
293 if (key.offset + 1 == 0) 301 BUG_ON(ret);
294 break; 302 }
295 } 303 }
296 btrfs_release_path(root, &path); 304 btrfs_release_path(root, &path);
297 ret = 0; 305 ret = 0;
@@ -975,10 +983,24 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
975 int err = 0; 983 int err = 0;
976 int ret; 984 int ret;
977 int this_write; 985 int this_write;
986 struct inode *inode = file->f_path.dentry->d_inode;
978 987
979 for (i = 0; i < num_pages; i++) { 988 for (i = 0; i < num_pages; i++) {
980 offset = pos & (PAGE_CACHE_SIZE -1); 989 offset = pos & (PAGE_CACHE_SIZE -1);
981 this_write = min(PAGE_CACHE_SIZE - offset, write_bytes); 990 this_write = min(PAGE_CACHE_SIZE - offset, write_bytes);
991 /* FIXME, one block at a time */
992
993 mutex_lock(&root->fs_info->fs_mutex);
994 trans = btrfs_start_transaction(root, 1);
995 btrfs_csum_file_block(trans, root, inode->i_ino,
996 pages[i]->index << PAGE_CACHE_SHIFT,
997 kmap(pages[i]), PAGE_CACHE_SIZE);
998 kunmap(pages[i]);
999 SetPageChecked(pages[i]);
1000 ret = btrfs_end_transaction(trans, root);
1001 BUG_ON(ret);
1002 mutex_unlock(&root->fs_info->fs_mutex);
1003
982 ret = nobh_commit_write(file, pages[i], offset, 1004 ret = nobh_commit_write(file, pages[i], offset,
983 offset + this_write); 1005 offset + this_write);
984 pos += this_write; 1006 pos += this_write;
@@ -1022,7 +1044,7 @@ static int prepare_pages(struct btrfs_trans_handle *trans,
1022 this_write = min(PAGE_CACHE_SIZE - offset, write_bytes); 1044 this_write = min(PAGE_CACHE_SIZE - offset, write_bytes);
1023 ret = nobh_prepare_write(pages[i], offset, 1045 ret = nobh_prepare_write(pages[i], offset,
1024 offset + this_write, 1046 offset + this_write,
1025 btrfs_get_block_lock); 1047 btrfs_get_block);
1026 pos += this_write; 1048 pos += this_write;
1027 if (ret) { 1049 if (ret) {
1028 err = ret; 1050 err = ret;
@@ -1051,7 +1073,6 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
1051 size_t num_written = 0; 1073 size_t num_written = 0;
1052 int err = 0; 1074 int err = 0;
1053 int ret = 0; 1075 int ret = 0;
1054 struct btrfs_trans_handle *trans;
1055 struct inode *inode = file->f_path.dentry->d_inode; 1076 struct inode *inode = file->f_path.dentry->d_inode;
1056 struct btrfs_root *root = btrfs_sb(inode->i_sb); 1077 struct btrfs_root *root = btrfs_sb(inode->i_sb);
1057 struct page *pages[1]; 1078 struct page *pages[1];
@@ -1077,25 +1098,18 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
1077 size_t write_bytes = min(count, PAGE_CACHE_SIZE - offset); 1098 size_t write_bytes = min(count, PAGE_CACHE_SIZE - offset);
1078 size_t num_pages = (write_bytes + PAGE_CACHE_SIZE - 1) >> 1099 size_t num_pages = (write_bytes + PAGE_CACHE_SIZE - 1) >>
1079 PAGE_CACHE_SHIFT; 1100 PAGE_CACHE_SHIFT;
1080 mutex_lock(&root->fs_info->fs_mutex); 1101 ret = prepare_pages(NULL, root, file, pages, num_pages,
1081 trans = btrfs_start_transaction(root, 1);
1082
1083 ret = prepare_pages(trans, root, file, pages, num_pages,
1084 pos, write_bytes); 1102 pos, write_bytes);
1085 BUG_ON(ret); 1103 BUG_ON(ret);
1086 ret = btrfs_copy_from_user(pos, num_pages, 1104 ret = btrfs_copy_from_user(pos, num_pages,
1087 write_bytes, pages, buf); 1105 write_bytes, pages, buf);
1088 BUG_ON(ret); 1106 BUG_ON(ret);
1089 1107
1090 mutex_unlock(&root->fs_info->fs_mutex); 1108 ret = dirty_and_release_pages(NULL, root, file, pages,
1091
1092 ret = dirty_and_release_pages(trans, root, file, pages,
1093 num_pages, pos, write_bytes); 1109 num_pages, pos, write_bytes);
1094 BUG_ON(ret); 1110 BUG_ON(ret);
1095 btrfs_drop_pages(pages, num_pages); 1111 btrfs_drop_pages(pages, num_pages);
1096 1112
1097 ret = btrfs_end_transaction(trans, root);
1098
1099 buf += write_bytes; 1113 buf += write_bytes;
1100 count -= write_bytes; 1114 count -= write_bytes;
1101 pos += write_bytes; 1115 pos += write_bytes;
@@ -1111,6 +1125,118 @@ out:
1111 return num_written ? num_written : err; 1125 return num_written ? num_written : err;
1112} 1126}
1113 1127
1128static int btrfs_read_actor(read_descriptor_t *desc, struct page *page,
1129 unsigned long offset, unsigned long size)
1130{
1131 char *kaddr;
1132 unsigned long left, count = desc->count;
1133
1134 if (size > count)
1135 size = count;
1136
1137 if (!PageChecked(page)) {
1138 /* FIXME, do it per block */
1139 struct btrfs_root *root = btrfs_sb(page->mapping->host->i_sb);
1140 int ret = btrfs_csum_verify_file_block(root,
1141 page->mapping->host->i_ino,
1142 page->index << PAGE_CACHE_SHIFT,
1143 kmap(page), PAGE_CACHE_SIZE);
1144 if (ret) {
1145 printk("failed to verify ino %lu page %lu\n",
1146 page->mapping->host->i_ino,
1147 page->index);
1148 memset(page_address(page), 0, PAGE_CACHE_SIZE);
1149 }
1150 SetPageChecked(page);
1151 kunmap(page);
1152 }
1153 /*
1154 * Faults on the destination of a read are common, so do it before
1155 * taking the kmap.
1156 */
1157 if (!fault_in_pages_writeable(desc->arg.buf, size)) {
1158 kaddr = kmap_atomic(page, KM_USER0);
1159 left = __copy_to_user_inatomic(desc->arg.buf,
1160 kaddr + offset, size);
1161 kunmap_atomic(kaddr, KM_USER0);
1162 if (left == 0)
1163 goto success;
1164 }
1165
1166 /* Do it the slow way */
1167 kaddr = kmap(page);
1168 left = __copy_to_user(desc->arg.buf, kaddr + offset, size);
1169 kunmap(page);
1170
1171 if (left) {
1172 size -= left;
1173 desc->error = -EFAULT;
1174 }
1175success:
1176 desc->count = count - size;
1177 desc->written += size;
1178 desc->arg.buf += size;
1179 return size;
1180}
1181
1182/**
1183 * btrfs_file_aio_read - filesystem read routine
1184 * @iocb: kernel I/O control block
1185 * @iov: io vector request
1186 * @nr_segs: number of segments in the iovec
1187 * @pos: current file position
1188 */
1189static ssize_t btrfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
1190 unsigned long nr_segs, loff_t pos)
1191{
1192 struct file *filp = iocb->ki_filp;
1193 ssize_t retval;
1194 unsigned long seg;
1195 size_t count;
1196 loff_t *ppos = &iocb->ki_pos;
1197
1198 count = 0;
1199 for (seg = 0; seg < nr_segs; seg++) {
1200 const struct iovec *iv = &iov[seg];
1201
1202 /*
1203 * If any segment has a negative length, or the cumulative
1204 * length ever wraps negative then return -EINVAL.
1205 */
1206 count += iv->iov_len;
1207 if (unlikely((ssize_t)(count|iv->iov_len) < 0))
1208 return -EINVAL;
1209 if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len))
1210 continue;
1211 if (seg == 0)
1212 return -EFAULT;
1213 nr_segs = seg;
1214 count -= iv->iov_len; /* This segment is no good */
1215 break;
1216 }
1217 retval = 0;
1218 if (count) {
1219 for (seg = 0; seg < nr_segs; seg++) {
1220 read_descriptor_t desc;
1221
1222 desc.written = 0;
1223 desc.arg.buf = iov[seg].iov_base;
1224 desc.count = iov[seg].iov_len;
1225 if (desc.count == 0)
1226 continue;
1227 desc.error = 0;
1228 do_generic_file_read(filp, ppos, &desc,
1229 btrfs_read_actor);
1230 retval += desc.written;
1231 if (desc.error) {
1232 retval = retval ?: desc.error;
1233 break;
1234 }
1235 }
1236 }
1237 return retval;
1238}
1239
1114static int btrfs_get_sb(struct file_system_type *fs_type, 1240static int btrfs_get_sb(struct file_system_type *fs_type,
1115 int flags, const char *dev_name, void *data, struct vfsmount *mnt) 1241 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
1116{ 1242{
@@ -1166,7 +1292,7 @@ static struct inode_operations btrfs_file_inode_operations = {
1166static struct file_operations btrfs_file_operations = { 1292static struct file_operations btrfs_file_operations = {
1167 .llseek = generic_file_llseek, 1293 .llseek = generic_file_llseek,
1168 .read = do_sync_read, 1294 .read = do_sync_read,
1169 .aio_read = generic_file_aio_read, 1295 .aio_read = btrfs_file_aio_read,
1170 .write = btrfs_file_write, 1296 .write = btrfs_file_write,
1171 .mmap = generic_file_mmap, 1297 .mmap = generic_file_mmap,
1172 .open = generic_file_open, 1298 .open = generic_file_open,