diff options
| author | Martin J. Bligh <mbligh@mbligh.org> | 2007-10-17 02:30:46 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-17 11:43:02 -0400 |
| commit | a686cd898bd999fd026a51e90fb0a3410d258ddb (patch) | |
| tree | 3f0a91a70fe1a3addf9e99f3babed9e9baba4b99 | |
| parent | 369f2389e7d03022abdd25e298bffb9613cd0e54 (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.c | 1305 | ||||
| -rw-r--r-- | fs/ext2/ext2.h | 36 | ||||
| -rw-r--r-- | fs/ext2/file.c | 7 | ||||
| -rw-r--r-- | fs/ext2/ialloc.c | 5 | ||||
| -rw-r--r-- | fs/ext2/inode.c | 524 | ||||
| -rw-r--r-- | fs/ext2/ioctl.c | 45 | ||||
| -rw-r--r-- | fs/ext2/super.c | 41 | ||||
| -rw-r--r-- | fs/ext2/xattr.c | 3 | ||||
| -rw-r--r-- | include/linux/ext2_fs.h | 23 | ||||
| -rw-r--r-- | include/linux/ext2_fs_sb.h | 50 |
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 | */ | ||
| 140 | static 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 | |||
| 171 | static void release_blocks(struct super_block *sb, int count) | 136 | static 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 | ||
| 181 | static int group_reserve_blocks(struct ext2_sb_info *sbi, int group_no, | 146 | static 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 | |||
| 199 | static 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 | ||
| 184 | static 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 | |||
| 191 | restart: | ||
| 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 | */ | ||
| 249 | static int | ||
| 250 | goal_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 | |||
