aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin J. Bligh <mbligh@mbligh.org>2007-10-17 02:30:46 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-17 11:43:02 -0400
commita686cd898bd999fd026a51e90fb0a3410d258ddb (patch)
tree3f0a91a70fe1a3addf9e99f3babed9e9baba4b99
parent369f2389e7d03022abdd25e298bffb9613cd0e54 (diff)
ext2 reservations
Val's cross-port of the ext3 reservations code into ext2. [mbligh@mbligh.org: Small type error for printk [akpm@linux-foundation.org: fix types, sync with ext3] [mbligh@mbligh.org: Bring ext2 reservations code in line with latest ext3] [akpm@linux-foundation.org: kill noisy printk] [akpm@linux-foundation.org: remember to dirty the gdp's block] [akpm@linux-foundation.org: cross-port the missed 5dea5176e5c32ef9f0d1a41d28427b3bf6881b3a] [akpm@linux-foundation.org: cross-port e6022603b9aa7d61d20b392e69edcdbbc1789969] [akpm@linux-foundation.org: Port the omitted 08fb306fe63d98eb86e3b16f4cc21816fa47f18e] [akpm@linux-foundation.org: Backport the missed 20acaa18d0c002fec180956f87adeb3f11f635a6] [akpm@linux-foundation.org: fixes] [cmm@us.ibm.com: fix reservation extension] [bunk@stusta.de: make ext2_get_blocks() static] [hugh@veritas.com: fix hang] [hugh@veritas.com: ext2_new_blocks should reset the reservation window size] [hugh@veritas.com: ext2 balloc: fix off-by-one against rsv_end] [hugh@veritas.com: grp_goal 0 is a genuine goal (unlike -1), so ext2_try_to_allocate_with_rsv should treat it as such] [hugh@veritas.com: rbtree usage cleanup] [pbadari@us.ibm.com: Fix for ext2 reservation] [bunk@kernel.org: remove fs/ext2/balloc.c:reserve_blocks()] [hugh@veritas.com: ext2 balloc: use io_error label] Cc: "Martin J. Bligh" <mbligh@mbligh.org> Cc: Valerie Henson <val_henson@linux.intel.com> Cc: Mingming Cao <cmm@us.ibm.com> Cc: Mel Gorman <mel@csn.ul.ie> Cc: Hugh Dickins <hugh@veritas.com> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Hugh Dickins <hugh@veritas.com> Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com> Signed-off-by: Adrian Bunk <bunk@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/ext2/balloc.c1305
-rw-r--r--fs/ext2/ext2.h36
-rw-r--r--fs/ext2/file.c7
-rw-r--r--fs/ext2/ialloc.c5
-rw-r--r--fs/ext2/inode.c524
-rw-r--r--fs/ext2/ioctl.c45
-rw-r--r--fs/ext2/super.c41
-rw-r--r--fs/ext2/xattr.c3
-rw-r--r--include/linux/ext2_fs.h23
-rw-r--r--include/linux/ext2_fs_sb.h50
10 files changed, 1554 insertions, 485 deletions
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index ffaa6d845442..18a42de25b55 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -133,41 +133,6 @@ error_out:
133 return NULL; 133 return NULL;
134} 134}
135 135
136/*
137 * Set sb->s_dirt here because the superblock was "logically" altered. We
138 * need to recalculate its free blocks count and flush it out.
139 */
140static int reserve_blocks(struct super_block *sb, int count)
141{
142 struct ext2_sb_info *sbi = EXT2_SB(sb);
143 struct ext2_super_block *es = sbi->s_es;
144 unsigned free_blocks;
145 unsigned root_blocks;
146
147 free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
148 root_blocks = le32_to_cpu(es->s_r_blocks_count);
149
150 if (free_blocks < count)
151 count = free_blocks;
152
153 if (free_blocks < root_blocks + count && !capable(CAP_SYS_RESOURCE) &&
154 sbi->s_resuid != current->fsuid &&
155 (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
156 /*
157 * We are too close to reserve and we are not privileged.
158 * Can we allocate anything at all?
159 */
160 if (free_blocks > root_blocks)
161 count = free_blocks - root_blocks;
162 else
163 return 0;
164 }
165
166 percpu_counter_sub(&sbi->s_freeblocks_counter, count);
167 sb->s_dirt = 1;
168 return count;
169}
170
171static void release_blocks(struct super_block *sb, int count) 136static void release_blocks(struct super_block *sb, int count)
172{ 137{
173 if (count) { 138 if (count) {
@@ -178,25 +143,7 @@ static void release_blocks(struct super_block *sb, int count)
178 } 143 }
179} 144}
180 145
181static int group_reserve_blocks(struct ext2_sb_info *sbi, int group_no, 146static void group_adjust_blocks(struct super_block *sb, int group_no,
182 struct ext2_group_desc *desc, struct buffer_head *bh, int count)
183{
184 unsigned free_blocks;
185
186 if (!desc->bg_free_blocks_count)
187 return 0;
188
189 spin_lock(sb_bgl_lock(sbi, group_no));
190 free_blocks = le16_to_cpu(desc->bg_free_blocks_count);
191 if (free_blocks < count)
192 count = free_blocks;
193 desc->bg_free_blocks_count = cpu_to_le16(free_blocks - count);
194 spin_unlock(sb_bgl_lock(sbi, group_no));
195 mark_buffer_dirty(bh);
196 return count;
197}
198
199static void group_release_blocks(struct super_block *sb, int group_no,
200 struct ext2_group_desc *desc, struct buffer_head *bh, int count) 147 struct ext2_group_desc *desc, struct buffer_head *bh, int count)
201{ 148{
202 if (count) { 149 if (count) {
@@ -212,7 +159,306 @@ static void group_release_blocks(struct super_block *sb, int group_no,
212 } 159 }
213} 160}
214 161
215/* Free given blocks, update quota and i_blocks field */ 162/*
163 * The reservation window structure operations
164 * --------------------------------------------
165 * Operations include:
166 * dump, find, add, remove, is_empty, find_next_reservable_window, etc.
167 *
168 * We use a red-black tree to represent per-filesystem reservation
169 * windows.
170 *
171 */
172
173/**
174 * __rsv_window_dump() -- Dump the filesystem block allocation reservation map
175 * @rb_root: root of per-filesystem reservation rb tree
176 * @verbose: verbose mode
177 * @fn: function which wishes to dump the reservation map
178 *
179 * If verbose is turned on, it will print the whole block reservation
180 * windows(start, end). Otherwise, it will only print out the "bad" windows,
181 * those windows that overlap with their immediate neighbors.
182 */
183#if 1
184static void __rsv_window_dump(struct rb_root *root, int verbose,
185 const char *fn)
186{
187 struct rb_node *n;
188 struct ext2_reserve_window_node *rsv, *prev;
189 int bad;
190
191restart:
192 n = rb_first(root);
193 bad = 0;
194 prev = NULL;
195
196 printk("Block Allocation Reservation Windows Map (%s):\n", fn);
197 while (n) {
198 rsv = rb_entry(n, struct ext2_reserve_window_node, rsv_node);
199 if (verbose)
200 printk("reservation window 0x%p "
201 "start: %lu, end: %lu\n",
202 rsv, rsv->rsv_start, rsv->rsv_end);
203 if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) {
204 printk("Bad reservation %p (start >= end)\n",
205 rsv);
206 bad = 1;
207 }
208 if (prev && prev->rsv_end >= rsv->rsv_start) {
209 printk("Bad reservation %p (prev->end >= start)\n",
210 rsv);
211 bad = 1;
212 }
213 if (bad) {
214 if (!verbose) {
215 printk("Restarting reservation walk in verbose mode\n");
216 verbose = 1;
217 goto restart;
218 }
219 }
220 n = rb_next(n);
221 prev = rsv;
222 }
223 printk("Window map complete.\n");
224 if (bad)
225 BUG();
226}
227#define rsv_window_dump(root, verbose) \
228 __rsv_window_dump((root), (verbose), __FUNCTION__)
229#else
230#define rsv_window_dump(root, verbose) do {} while (0)
231#endif
232
233/**
234 * goal_in_my_reservation()
235 * @rsv: inode's reservation window
236 * @grp_goal: given goal block relative to the allocation block group
237 * @group: the current allocation block group
238 * @sb: filesystem super block
239 *
240 * Test if the given goal block (group relative) is within the file's
241 * own block reservation window range.
242 *
243 * If the reservation window is outside the goal allocation group, return 0;
244 * grp_goal (given goal block) could be -1, which means no specific
245 * goal block. In this case, always return 1.
246 * If the goal block is within the reservation window, return 1;
247 * otherwise, return 0;
248 */
249static int
250goal_in_my_reservation(struct ext2_reserve_window *rsv, ext2_grpblk_t grp_goal,
251 unsigned int group, struct super_block * sb)
252{
253 ext2_fsblk_t group_first_block, group_last_block;
254
255 group_first_block = ext2_group_first_block_no(sb, group);
256 group_last_block = group_first_block + EXT2_BLOCKS_PER_GROUP(sb) - 1;
257
258 if ((rsv->_rsv_start > group_last_block) ||
259 (rsv->_rsv_end < group_first_block))
260 return 0;
261 if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start)
262