aboutsummaryrefslogtreecommitdiffstats
path: root/fs/bfs/file.c
diff options
context:
space:
mode:
authorDmitri Vorobiev <dmitri.vorobiev@gmail.com>2007-11-14 19:59:47 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-11-14 21:45:40 -0500
commitf433dc56344cb72cc3de5ba0819021cec3aef807 (patch)
tree19fa9052a2787c84417dc306eda1eae8b02f14f2 /fs/bfs/file.c
parentcfb5285660aad4931b2ebbfa902ea48a37dfffa1 (diff)
Fixes to the BFS filesystem driver
I found a few bugs in the BFS driver. Detailed description of the bugs as well as the steps to reproduce the errors are given in the kernel bugzilla. Please follow these links for more information: http://bugzilla.kernel.org/show_bug.cgi?id=9363 http://bugzilla.kernel.org/show_bug.cgi?id=9364 http://bugzilla.kernel.org/show_bug.cgi?id=9365 http://bugzilla.kernel.org/show_bug.cgi?id=9366 This patch fixes the bugs described above. Besides, the patch introduces coding style changes to make the BFS driver conform to the requirements specified for Linux kernel code. Finally, I made a few cosmetic changes such as removal of trivial debug output. Also, the patch removes the fields `si_lf_ioff' and `si_lf_sblk' of the in-core superblock structure. These fields are initialized but never actually used. If you are wondering why I need BFS, here is the answer: I am using this driver in the context of Linux kernel classes I am teaching in the Moscow State University and in the International Institute of Information Technology in Pune, India. Signed-off-by: Dmitri Vorobiev <dmitri.vorobiev@gmail.com> Cc: Tigran Aivazian <tigran@veritas.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/bfs/file.c')
-rw-r--r--fs/bfs/file.c62
1 files changed, 41 insertions, 21 deletions
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index 911b4ccf470f..b11e63e8fbcd 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -2,6 +2,11 @@
2 * fs/bfs/file.c 2 * fs/bfs/file.c
3 * BFS file operations. 3 * BFS file operations.
4 * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com> 4 * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com>
5 *
6 * Make the file block allocation algorithm understand the size
7 * of the underlying block device.
8 * Copyright (C) 2007 Dmitri Vorobiev <dmitri.vorobiev@gmail.com>
9 *
5 */ 10 */
6 11
7#include <linux/fs.h> 12#include <linux/fs.h>
@@ -27,7 +32,8 @@ const struct file_operations bfs_file_operations = {
27 .splice_read = generic_file_splice_read, 32 .splice_read = generic_file_splice_read,
28}; 33};
29 34
30static int bfs_move_block(unsigned long from, unsigned long to, struct super_block *sb) 35static int bfs_move_block(unsigned long from, unsigned long to,
36 struct super_block *sb)
31{ 37{
32 struct buffer_head *bh, *new; 38 struct buffer_head *bh, *new;
33 39
@@ -43,21 +49,22 @@ static int bfs_move_block(unsigned long from, unsigned long to, struct super_blo
43} 49}
44 50
45static int bfs_move_blocks(struct super_block *sb, unsigned long start, 51static int bfs_move_blocks(struct super_block *sb, unsigned long start,
46 unsigned long end, unsigned long where) 52 unsigned long end, unsigned long where)
47{ 53{
48 unsigned long i; 54 unsigned long i;
49 55
50 dprintf("%08lx-%08lx->%08lx\n", start, end, where); 56 dprintf("%08lx-%08lx->%08lx\n", start, end, where);
51 for (i = start; i <= end; i++) 57 for (i = start; i <= end; i++)
52 if(bfs_move_block(i, where + i, sb)) { 58 if(bfs_move_block(i, where + i, sb)) {
53 dprintf("failed to move block %08lx -> %08lx\n", i, where + i); 59 dprintf("failed to move block %08lx -> %08lx\n", i,
60 where + i);
54 return -EIO; 61 return -EIO;
55 } 62 }
56 return 0; 63 return 0;
57} 64}
58 65
59static int bfs_get_block(struct inode * inode, sector_t block, 66static int bfs_get_block(struct inode *inode, sector_t block,
60 struct buffer_head * bh_result, int create) 67 struct buffer_head *bh_result, int create)
61{ 68{
62 unsigned long phys; 69 unsigned long phys;
63 int err; 70 int err;
@@ -66,9 +73,6 @@ static int bfs_get_block(struct inode * inode, sector_t block,
66 struct bfs_inode_info *bi = BFS_I(inode); 73 struct bfs_inode_info *bi = BFS_I(inode);
67 struct buffer_head *sbh = info->si_sbh; 74 struct buffer_head *sbh = info->si_sbh;
68 75
69 if (block > info->si_blocks)
70 return -EIO;
71
72 phys = bi->i_sblock + block; 76 phys = bi->i_sblock + block;
73 if (!create) { 77 if (!create) {
74 if (phys <= bi->i_eblock) { 78 if (phys <= bi->i_eblock) {
@@ -79,21 +83,29 @@ static int bfs_get_block(struct inode * inode, sector_t block,
79 return 0; 83 return 0;
80 } 84 }
81 85
82 /* if the file is not empty and the requested block is within the range 86 /*
83 of blocks allocated for this file, we can grant it */ 87 * If the file is not empty and the requested block is within the
84 if (inode->i_size && phys <= bi->i_eblock) { 88 * range of blocks allocated for this file, we can grant it.
89 */
90 if (bi->i_sblock && (phys <= bi->i_eblock)) {
85 dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", 91 dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n",
86 create, (unsigned long)block, phys); 92 create, (unsigned long)block, phys);
87 map_bh(bh_result, sb, phys); 93 map_bh(bh_result, sb, phys);
88 return 0; 94 return 0;
89 } 95 }
90 96
91 /* the rest has to be protected against itself */ 97 /* The file will be extended, so let's see if there is enough space. */
98 if (phys >= info->si_blocks)
99 return -ENOSPC;
100
101 /* The rest has to be protected against itself. */
92 lock_kernel(); 102 lock_kernel();
93 103
94 /* if the last data block for this file is the last allocated 104 /*
95 block, we can extend the file trivially, without moving it 105 * If the last data block for this file is the last allocated
96 anywhere */ 106 * block, we can extend the file trivially, without moving it
107 * anywhere.
108 */
97 if (bi->i_eblock == info->si_lf_eblk) { 109 if (bi->i_eblock == info->si_lf_eblk) {
98 dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", 110 dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n",
99 create, (unsigned long)block, phys); 111 create, (unsigned long)block, phys);
@@ -106,13 +118,19 @@ static int bfs_get_block(struct inode * inode, sector_t block,
106 goto out; 118 goto out;
107 } 119 }
108 120
109 /* Ok, we have to move this entire file to the next free block */ 121 /* Ok, we have to move this entire file to the next free block. */
110 phys = info->si_lf_eblk + 1; 122 phys = info->si_lf_eblk + 1;
111 if (bi->i_sblock) { /* if data starts on block 0 then there is no data */ 123 if (phys + block >= info->si_blocks) {
124 err = -ENOSPC;
125 goto out;
126 }
127
128 if (bi->i_sblock) {
112 err = bfs_move_blocks(inode->i_sb, bi->i_sblock, 129 err = bfs_move_blocks(inode->i_sb, bi->i_sblock,
113 bi->i_eblock, phys); 130 bi->i_eblock, phys);
114 if (err) { 131 if (err) {
115 dprintf("failed to move ino=%08lx -> fs corruption\n", inode->i_ino); 132 dprintf("failed to move ino=%08lx -> fs corruption\n",
133 inode->i_ino);
116 goto out; 134 goto out;
117 } 135 }
118 } else 136 } else
@@ -124,8 +142,10 @@ static int bfs_get_block(struct inode * inode, sector_t block,
124 phys += block; 142 phys += block;
125 info->si_lf_eblk = bi->i_eblock = phys; 143 info->si_lf_eblk = bi->i_eblock = phys;
126 144
127 /* this assumes nothing can write the inode back while we are here 145 /*
128 * and thus update inode->i_blocks! (XXX)*/ 146 * This assumes nothing can write the inode back while we are here
147 * and thus update inode->i_blocks! (XXX)
148 */
129 info->si_freeb -= bi->i_eblock - bi->i_sblock + 1 - inode->i_blocks; 149 info->si_freeb -= bi->i_eblock - bi->i_sblock + 1 - inode->i_blocks;
130 mark_inode_dirty(inode); 150 mark_inode_dirty(inode);
131 mark_buffer_dirty(sbh); 151 mark_buffer_dirty(sbh);