aboutsummaryrefslogtreecommitdiffstats
path: root/fs/bfs/file.c
diff options
context:
space:
mode:
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);