Blame view
fs/fat/fatent.c
16.5 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 |
/* * Copyright (C) 2004, OGAWA Hirofumi * Released under GPL v2. */ |
8c540a96c Let the block dev... |
5 |
#include <linux/blkdev.h> |
9e975dae2 fat: split includ... |
6 |
#include "fat.h" |
1da177e4c Linux-2.6.12-rc2 |
7 8 9 10 11 12 13 14 15 16 |
struct fatent_operations { void (*ent_blocknr)(struct super_block *, int, int *, sector_t *); void (*ent_set_ptr)(struct fat_entry *, int); int (*ent_bread)(struct super_block *, struct fat_entry *, int, sector_t); int (*ent_get)(struct fat_entry *); void (*ent_put)(struct fat_entry *, int); int (*ent_next)(struct fat_entry *); }; |
98283bb49 fat: Fix the race... |
17 |
static DEFINE_SPINLOCK(fat12_entry_lock); |
1da177e4c Linux-2.6.12-rc2 |
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
static void fat12_ent_blocknr(struct super_block *sb, int entry, int *offset, sector_t *blocknr) { struct msdos_sb_info *sbi = MSDOS_SB(sb); int bytes = entry + (entry >> 1); WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry); *offset = bytes & (sb->s_blocksize - 1); *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits); } static void fat_ent_blocknr(struct super_block *sb, int entry, int *offset, sector_t *blocknr) { struct msdos_sb_info *sbi = MSDOS_SB(sb); int bytes = (entry << sbi->fatent_shift); WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry); *offset = bytes & (sb->s_blocksize - 1); *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits); } static void fat12_ent_set_ptr(struct fat_entry *fatent, int offset) { struct buffer_head **bhs = fatent->bhs; if (fatent->nr_bhs == 1) { WARN_ON(offset >= (bhs[0]->b_size - 1)); fatent->u.ent12_p[0] = bhs[0]->b_data + offset; fatent->u.ent12_p[1] = bhs[0]->b_data + (offset + 1); } else { WARN_ON(offset != (bhs[0]->b_size - 1)); fatent->u.ent12_p[0] = bhs[0]->b_data + offset; fatent->u.ent12_p[1] = bhs[1]->b_data; } } static void fat16_ent_set_ptr(struct fat_entry *fatent, int offset) { WARN_ON(offset & (2 - 1)); fatent->u.ent16_p = (__le16 *)(fatent->bhs[0]->b_data + offset); } static void fat32_ent_set_ptr(struct fat_entry *fatent, int offset) { WARN_ON(offset & (4 - 1)); fatent->u.ent32_p = (__le32 *)(fatent->bhs[0]->b_data + offset); } static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent, int offset, sector_t blocknr) { struct buffer_head **bhs = fatent->bhs; WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); |
b522412ae Sanitize ->fsync(... |
70 |
fatent->fat_inode = MSDOS_SB(sb)->fat_inode; |
1da177e4c Linux-2.6.12-rc2 |
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
bhs[0] = sb_bread(sb, blocknr); if (!bhs[0]) goto err; if ((offset + 1) < sb->s_blocksize) fatent->nr_bhs = 1; else { /* This entry is block boundary, it needs the next block */ blocknr++; bhs[1] = sb_bread(sb, blocknr); if (!bhs[1]) goto err_brelse; fatent->nr_bhs = 2; } fat12_ent_set_ptr(fatent, offset); return 0; err_brelse: brelse(bhs[0]); err: |
869f58c0c fat: Replace all ... |
91 |
fat_msg(sb, KERN_ERR, "FAT read failed (blocknr %llu)", (llu)blocknr); |
1da177e4c Linux-2.6.12-rc2 |
92 93 94 95 96 97 |
return -EIO; } static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent, int offset, sector_t blocknr) { |
8992de4ce fat: constify fat... |
98 |
const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; |
1da177e4c Linux-2.6.12-rc2 |
99 100 |
WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); |
b522412ae Sanitize ->fsync(... |
101 |
fatent->fat_inode = MSDOS_SB(sb)->fat_inode; |
1da177e4c Linux-2.6.12-rc2 |
102 103 |
fatent->bhs[0] = sb_bread(sb, blocknr); if (!fatent->bhs[0]) { |
869f58c0c fat: Replace all ... |
104 |
fat_msg(sb, KERN_ERR, "FAT read failed (blocknr %llu)", |
c3302931d fat: i_blocks war... |
105 |
(llu)blocknr); |
1da177e4c Linux-2.6.12-rc2 |
106 107 108 109 110 111 112 113 114 115 116 |
return -EIO; } fatent->nr_bhs = 1; ops->ent_set_ptr(fatent, offset); return 0; } static int fat12_ent_get(struct fat_entry *fatent) { u8 **ent12_p = fatent->u.ent12_p; int next; |
98283bb49 fat: Fix the race... |
117 |
spin_lock(&fat12_entry_lock); |
1da177e4c Linux-2.6.12-rc2 |
118 119 120 121 |
if (fatent->entry & 1) next = (*ent12_p[0] >> 4) | (*ent12_p[1] << 4); else next = (*ent12_p[1] << 8) | *ent12_p[0]; |
98283bb49 fat: Fix the race... |
122 |
spin_unlock(&fat12_entry_lock); |
1da177e4c Linux-2.6.12-rc2 |
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
next &= 0x0fff; if (next >= BAD_FAT12) next = FAT_ENT_EOF; return next; } static int fat16_ent_get(struct fat_entry *fatent) { int next = le16_to_cpu(*fatent->u.ent16_p); WARN_ON((unsigned long)fatent->u.ent16_p & (2 - 1)); if (next >= BAD_FAT16) next = FAT_ENT_EOF; return next; } static int fat32_ent_get(struct fat_entry *fatent) { int next = le32_to_cpu(*fatent->u.ent32_p) & 0x0fffffff; WARN_ON((unsigned long)fatent->u.ent32_p & (4 - 1)); if (next >= BAD_FAT32) next = FAT_ENT_EOF; return next; } static void fat12_ent_put(struct fat_entry *fatent, int new) { u8 **ent12_p = fatent->u.ent12_p; if (new == FAT_ENT_EOF) new = EOF_FAT12; |
98283bb49 fat: Fix the race... |
153 |
spin_lock(&fat12_entry_lock); |
1da177e4c Linux-2.6.12-rc2 |
154 155 156 157 158 159 160 |
if (fatent->entry & 1) { *ent12_p[0] = (new << 4) | (*ent12_p[0] & 0x0f); *ent12_p[1] = new >> 4; } else { *ent12_p[0] = new & 0xff; *ent12_p[1] = (*ent12_p[1] & 0xf0) | (new >> 8); } |
98283bb49 fat: Fix the race... |
161 |
spin_unlock(&fat12_entry_lock); |
1da177e4c Linux-2.6.12-rc2 |
162 |
|
b522412ae Sanitize ->fsync(... |
163 |
mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); |
1da177e4c Linux-2.6.12-rc2 |
164 |
if (fatent->nr_bhs == 2) |
b522412ae Sanitize ->fsync(... |
165 |
mark_buffer_dirty_inode(fatent->bhs[1], fatent->fat_inode); |
1da177e4c Linux-2.6.12-rc2 |
166 167 168 169 170 171 172 173 |
} static void fat16_ent_put(struct fat_entry *fatent, int new) { if (new == FAT_ENT_EOF) new = EOF_FAT16; *fatent->u.ent16_p = cpu_to_le16(new); |
b522412ae Sanitize ->fsync(... |
174 |
mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); |
1da177e4c Linux-2.6.12-rc2 |
175 176 177 178 |
} static void fat32_ent_put(struct fat_entry *fatent, int new) { |
1da177e4c Linux-2.6.12-rc2 |
179 180 181 |
WARN_ON(new & 0xf0000000); new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff; *fatent->u.ent32_p = cpu_to_le32(new); |
b522412ae Sanitize ->fsync(... |
182 |
mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); |
1da177e4c Linux-2.6.12-rc2 |
183 184 185 186 187 188 189 190 191 192 |
} static int fat12_ent_next(struct fat_entry *fatent) { u8 **ent12_p = fatent->u.ent12_p; struct buffer_head **bhs = fatent->bhs; u8 *nextp = ent12_p[1] + 1 + (fatent->entry & 1); fatent->entry++; if (fatent->nr_bhs == 1) { |
441dff34a fs/fat: fix check... |
193 194 195 196 |
WARN_ON(ent12_p[0] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 2))); WARN_ON(ent12_p[1] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))); |
1da177e4c Linux-2.6.12-rc2 |
197 198 199 200 201 202 |
if (nextp < (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))) { ent12_p[0] = nextp - 1; ent12_p[1] = nextp; return 1; } } else { |
441dff34a fs/fat: fix check... |
203 204 |
WARN_ON(ent12_p[0] != (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))); |
1da177e4c Linux-2.6.12-rc2 |
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
WARN_ON(ent12_p[1] != (u8 *)bhs[1]->b_data); ent12_p[0] = nextp - 1; ent12_p[1] = nextp; brelse(bhs[0]); bhs[0] = bhs[1]; fatent->nr_bhs = 1; return 1; } ent12_p[0] = NULL; ent12_p[1] = NULL; return 0; } static int fat16_ent_next(struct fat_entry *fatent) { const struct buffer_head *bh = fatent->bhs[0]; fatent->entry++; if (fatent->u.ent16_p < (__le16 *)(bh->b_data + (bh->b_size - 2))) { fatent->u.ent16_p++; return 1; } fatent->u.ent16_p = NULL; return 0; } static int fat32_ent_next(struct fat_entry *fatent) { const struct buffer_head *bh = fatent->bhs[0]; fatent->entry++; if (fatent->u.ent32_p < (__le32 *)(bh->b_data + (bh->b_size - 4))) { fatent->u.ent32_p++; return 1; } fatent->u.ent32_p = NULL; return 0; } |
8992de4ce fat: constify fat... |
241 |
static const struct fatent_operations fat12_ops = { |
1da177e4c Linux-2.6.12-rc2 |
242 243 244 245 246 247 248 |
.ent_blocknr = fat12_ent_blocknr, .ent_set_ptr = fat12_ent_set_ptr, .ent_bread = fat12_ent_bread, .ent_get = fat12_ent_get, .ent_put = fat12_ent_put, .ent_next = fat12_ent_next, }; |
8992de4ce fat: constify fat... |
249 |
static const struct fatent_operations fat16_ops = { |
1da177e4c Linux-2.6.12-rc2 |
250 251 252 253 254 255 256 |
.ent_blocknr = fat_ent_blocknr, .ent_set_ptr = fat16_ent_set_ptr, .ent_bread = fat_ent_bread, .ent_get = fat16_ent_get, .ent_put = fat16_ent_put, .ent_next = fat16_ent_next, }; |
8992de4ce fat: constify fat... |
257 |
static const struct fatent_operations fat32_ops = { |
1da177e4c Linux-2.6.12-rc2 |
258 259 260 261 262 263 264 265 266 267 |
.ent_blocknr = fat_ent_blocknr, .ent_set_ptr = fat32_ent_set_ptr, .ent_bread = fat_ent_bread, .ent_get = fat32_ent_get, .ent_put = fat32_ent_put, .ent_next = fat32_ent_next, }; static inline void lock_fat(struct msdos_sb_info *sbi) { |
6b9438e13 [PATCH] fat_lock ... |
268 |
mutex_lock(&sbi->fat_lock); |
1da177e4c Linux-2.6.12-rc2 |
269 270 271 272 |
} static inline void unlock_fat(struct msdos_sb_info *sbi) { |
6b9438e13 [PATCH] fat_lock ... |
273 |
mutex_unlock(&sbi->fat_lock); |
1da177e4c Linux-2.6.12-rc2 |
274 275 276 277 278 |
} void fat_ent_access_init(struct super_block *sb) { struct msdos_sb_info *sbi = MSDOS_SB(sb); |
6b9438e13 [PATCH] fat_lock ... |
279 |
mutex_init(&sbi->fat_lock); |
1da177e4c Linux-2.6.12-rc2 |
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
switch (sbi->fat_bits) { case 32: sbi->fatent_shift = 2; sbi->fatent_ops = &fat32_ops; break; case 16: sbi->fatent_shift = 1; sbi->fatent_ops = &fat16_ops; break; case 12: sbi->fatent_shift = -1; sbi->fatent_ops = &fat12_ops; break; } } |
90b436657 fat: introduce ma... |
296 297 |
static void mark_fsinfo_dirty(struct super_block *sb) { |
78491189d fat: switch to fs... |
298 299 300 301 302 303 |
struct msdos_sb_info *sbi = MSDOS_SB(sb); if (sb->s_flags & MS_RDONLY || sbi->fat_bits != 32) return; __mark_inode_dirty(sbi->fsinfo_inode, I_DIRTY_SYNC); |
90b436657 fat: introduce ma... |
304 |
} |
1da177e4c Linux-2.6.12-rc2 |
305 306 307 308 309 |
static inline int fat_ent_update_ptr(struct super_block *sb, struct fat_entry *fatent, int offset, sector_t blocknr) { struct msdos_sb_info *sbi = MSDOS_SB(sb); |
8992de4ce fat: constify fat... |
310 |
const struct fatent_operations *ops = sbi->fatent_ops; |
1da177e4c Linux-2.6.12-rc2 |
311 312 313 314 315 |
struct buffer_head **bhs = fatent->bhs; /* Is this fatent's blocks including this entry? */ if (!fatent->nr_bhs || bhs[0]->b_blocknr != blocknr) return 0; |
5e35dd465 fat: Fix fat_ent_... |
316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
if (sbi->fat_bits == 12) { if ((offset + 1) < sb->s_blocksize) { /* This entry is on bhs[0]. */ if (fatent->nr_bhs == 2) { brelse(bhs[1]); fatent->nr_bhs = 1; } } else { /* This entry needs the next block. */ if (fatent->nr_bhs != 2) return 0; if (bhs[1]->b_blocknr != (blocknr + 1)) return 0; } |
1da177e4c Linux-2.6.12-rc2 |
330 331 332 333 334 335 336 337 338 |
} ops->ent_set_ptr(fatent, offset); return 1; } int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry) { struct super_block *sb = inode->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); |
8992de4ce fat: constify fat... |
339 |
const struct fatent_operations *ops = sbi->fatent_ops; |
1da177e4c Linux-2.6.12-rc2 |
340 341 342 343 344 |
int err, offset; sector_t blocknr; if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { fatent_brelse(fatent); |
85c785919 FAT: add 'errors'... |
345 |
fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry); |
1da177e4c Linux-2.6.12-rc2 |
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
return -EIO; } fatent_set_entry(fatent, entry); ops->ent_blocknr(sb, entry, &offset, &blocknr); if (!fat_ent_update_ptr(sb, fatent, offset, blocknr)) { fatent_brelse(fatent); err = ops->ent_bread(sb, fatent, offset, blocknr); if (err) return err; } return ops->ent_get(fatent); } /* FIXME: We can write the blocks as more big chunk. */ static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs, int nr_bhs) { struct msdos_sb_info *sbi = MSDOS_SB(sb); struct buffer_head *c_bh; int err, n, copy; err = 0; for (copy = 1; copy < sbi->fats; copy++) { sector_t backup_fat = sbi->fat_length * copy; for (n = 0; n < nr_bhs; n++) { c_bh = sb_getblk(sb, backup_fat + bhs[n]->b_blocknr); if (!c_bh) { err = -ENOMEM; goto error; } memcpy(c_bh->b_data, bhs[n]->b_data, sb->s_blocksize); set_buffer_uptodate(c_bh); |
b522412ae Sanitize ->fsync(... |
381 |
mark_buffer_dirty_inode(c_bh, sbi->fat_inode); |
1da177e4c Linux-2.6.12-rc2 |
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
if (sb->s_flags & MS_SYNCHRONOUS) err = sync_dirty_buffer(c_bh); brelse(c_bh); if (err) goto error; } } error: return err; } int fat_ent_write(struct inode *inode, struct fat_entry *fatent, int new, int wait) { struct super_block *sb = inode->i_sb; |
8992de4ce fat: constify fat... |
397 |
const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; |
1da177e4c Linux-2.6.12-rc2 |
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 |
int err; ops->ent_put(fatent, new); if (wait) { err = fat_sync_bhs(fatent->bhs, fatent->nr_bhs); if (err) return err; } return fat_mirror_bhs(sb, fatent->bhs, fatent->nr_bhs); } static inline int fat_ent_next(struct msdos_sb_info *sbi, struct fat_entry *fatent) { if (sbi->fatent_ops->ent_next(fatent)) { if (fatent->entry < sbi->max_cluster) return 1; } return 0; } static inline int fat_ent_read_block(struct super_block *sb, struct fat_entry *fatent) { |
8992de4ce fat: constify fat... |
422 |
const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; |
1da177e4c Linux-2.6.12-rc2 |
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
sector_t blocknr; int offset; fatent_brelse(fatent); ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr); return ops->ent_bread(sb, fatent, offset, blocknr); } static void fat_collect_bhs(struct buffer_head **bhs, int *nr_bhs, struct fat_entry *fatent) { int n, i; for (n = 0; n < fatent->nr_bhs; n++) { for (i = 0; i < *nr_bhs; i++) { if (fatent->bhs[n] == bhs[i]) break; } if (i == *nr_bhs) { get_bh(fatent->bhs[n]); bhs[i] = fatent->bhs[n]; (*nr_bhs)++; } } } int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster) { struct super_block *sb = inode->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(sb); |
8992de4ce fat: constify fat... |
453 |
const struct fatent_operations *ops = sbi->fatent_ops; |
1da177e4c Linux-2.6.12-rc2 |
454 455 456 457 458 459 460 |
struct fat_entry fatent, prev_ent; struct buffer_head *bhs[MAX_BUF_PER_PAGE]; int i, count, err, nr_bhs, idx_clus; BUG_ON(nr_cluster > (MAX_BUF_PER_PAGE / 2)); /* fixed limit */ lock_fat(sbi); |
606e423e4 fat: Update free_... |
461 462 |
if (sbi->free_clusters != -1 && sbi->free_clus_valid && sbi->free_clusters < nr_cluster) { |
1da177e4c Linux-2.6.12-rc2 |
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 |
unlock_fat(sbi); return -ENOSPC; } err = nr_bhs = idx_clus = 0; count = FAT_START_ENT; fatent_init(&prev_ent); fatent_init(&fatent); fatent_set_entry(&fatent, sbi->prev_free + 1); while (count < sbi->max_cluster) { if (fatent.entry >= sbi->max_cluster) fatent.entry = FAT_START_ENT; fatent_set_entry(&fatent, fatent.entry); err = fat_ent_read_block(sb, &fatent); if (err) goto out; /* Find the free entries in a block */ do { if (ops->ent_get(&fatent) == FAT_ENT_FREE) { int entry = fatent.entry; /* make the cluster chain */ ops->ent_put(&fatent, FAT_ENT_EOF); if (prev_ent.nr_bhs) ops->ent_put(&prev_ent, entry); fat_collect_bhs(bhs, &nr_bhs, &fatent); sbi->prev_free = entry; if (sbi->free_clusters != -1) sbi->free_clusters--; cluster[idx_clus] = entry; idx_clus++; if (idx_clus == nr_cluster) goto out; /* * fat_collect_bhs() gets ref-count of bhs, * so we can still use the prev_ent. */ prev_ent = fatent; } count++; if (count == sbi->max_cluster) break; } while (fat_ent_next(sbi, &fatent)); } /* Couldn't allocate the free entries */ sbi->free_clusters = 0; |
606e423e4 fat: Update free_... |
515 |
sbi->free_clus_valid = 1; |
1da177e4c Linux-2.6.12-rc2 |
516 517 518 519 |
err = -ENOSPC; out: unlock_fat(sbi); |
330fe3c4c fat: mark superbl... |
520 |
mark_fsinfo_dirty(sb); |
1da177e4c Linux-2.6.12-rc2 |
521 522 523 524 525 526 527 528 529 |
fatent_brelse(&fatent); if (!err) { if (inode_needs_sync(inode)) err = fat_sync_bhs(bhs, nr_bhs); if (!err) err = fat_mirror_bhs(sb, bhs, nr_bhs); } for (i = 0; i < nr_bhs; i++) brelse(bhs[i]); |
1da177e4c Linux-2.6.12-rc2 |
530 531 532 533 534 535 536 537 538 539 540 |
if (err && idx_clus) fat_free_clusters(inode, cluster[0]); return err; } int fat_free_clusters(struct inode *inode, int cluster) { struct super_block *sb = inode->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(sb); |
8992de4ce fat: constify fat... |
541 |
const struct fatent_operations *ops = sbi->fatent_ops; |
1da177e4c Linux-2.6.12-rc2 |
542 543 544 |
struct fat_entry fatent; struct buffer_head *bhs[MAX_BUF_PER_PAGE]; int i, err, nr_bhs; |
330fe3c4c fat: mark superbl... |
545 |
int first_cl = cluster, dirty_fsinfo = 0; |
1da177e4c Linux-2.6.12-rc2 |
546 547 548 549 550 551 552 553 554 555 |
nr_bhs = 0; fatent_init(&fatent); lock_fat(sbi); do { cluster = fat_ent_read(inode, &fatent, cluster); if (cluster < 0) { err = cluster; goto error; } else if (cluster == FAT_ENT_FREE) { |
85c785919 FAT: add 'errors'... |
556 |
fat_fs_error(sb, "%s: deleting FAT entry beyond EOF", |
8e24eea72 fs: replace remai... |
557 |
__func__); |
1da177e4c Linux-2.6.12-rc2 |
558 559 560 |
err = -EIO; goto error; } |
681142f92 fat: make discard... |
561 562 563 564 565 566 567 568 569 570 571 |
if (sbi->options.discard) { /* * Issue discard for the sectors we no longer * care about, batching contiguous clusters * into one request */ if (cluster != fatent.entry + 1) { int nr_clus = fatent.entry - first_cl + 1; sb_issue_discard(sb, fat_clus_to_blknr(sbi, first_cl), |
2cf6d26a3 block: pass gfp_m... |
572 |
nr_clus * sbi->sec_per_clus, |
dd3932edd block: remove BLK... |
573 |
GFP_NOFS, 0); |
681142f92 fat: make discard... |
574 575 576 |
first_cl = cluster; } |
8c540a96c Let the block dev... |
577 |
} |
1da177e4c Linux-2.6.12-rc2 |
578 |
ops->ent_put(&fatent, FAT_ENT_FREE); |
a6bf6b211 [PATCH] fat: move... |
579 |
if (sbi->free_clusters != -1) { |
1da177e4c Linux-2.6.12-rc2 |
580 |
sbi->free_clusters++; |
330fe3c4c fat: mark superbl... |
581 |
dirty_fsinfo = 1; |
a6bf6b211 [PATCH] fat: move... |
582 |
} |
1da177e4c Linux-2.6.12-rc2 |
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 |
if (nr_bhs + fatent.nr_bhs > MAX_BUF_PER_PAGE) { if (sb->s_flags & MS_SYNCHRONOUS) { err = fat_sync_bhs(bhs, nr_bhs); if (err) goto error; } err = fat_mirror_bhs(sb, bhs, nr_bhs); if (err) goto error; for (i = 0; i < nr_bhs; i++) brelse(bhs[i]); nr_bhs = 0; } fat_collect_bhs(bhs, &nr_bhs, &fatent); } while (cluster != FAT_ENT_EOF); if (sb->s_flags & MS_SYNCHRONOUS) { err = fat_sync_bhs(bhs, nr_bhs); if (err) goto error; } err = fat_mirror_bhs(sb, bhs, nr_bhs); error: fatent_brelse(&fatent); for (i = 0; i < nr_bhs; i++) brelse(bhs[i]); unlock_fat(sbi); |
330fe3c4c fat: mark superbl... |
611 612 |
if (dirty_fsinfo) mark_fsinfo_dirty(sb); |
1da177e4c Linux-2.6.12-rc2 |
613 |
|
1da177e4c Linux-2.6.12-rc2 |
614 615 |
return err; } |
7c709d00d [PATCH] fat: s/EX... |
616 |
EXPORT_SYMBOL_GPL(fat_free_clusters); |
1da177e4c Linux-2.6.12-rc2 |
617 |
|
9f966be89 fat: optimize fat... |
618 619 620 621 622 623 |
/* 128kb is the whole sectors for FAT12 and FAT16 */ #define FAT_READA_SIZE (128 * 1024) static void fat_ent_reada(struct super_block *sb, struct fat_entry *fatent, unsigned long reada_blocks) { |
8992de4ce fat: constify fat... |
624 |
const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; |
9f966be89 fat: optimize fat... |
625 626 627 628 629 630 631 632 |
sector_t blocknr; int i, offset; ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr); for (i = 0; i < reada_blocks; i++) sb_breadahead(sb, blocknr + i); } |
1da177e4c Linux-2.6.12-rc2 |
633 634 635 |
int fat_count_free_clusters(struct super_block *sb) { struct msdos_sb_info *sbi = MSDOS_SB(sb); |
8992de4ce fat: constify fat... |
636 |
const struct fatent_operations *ops = sbi->fatent_ops; |
1da177e4c Linux-2.6.12-rc2 |
637 |
struct fat_entry fatent; |
9f966be89 fat: optimize fat... |
638 |
unsigned long reada_blocks, reada_mask, cur_block; |
1da177e4c Linux-2.6.12-rc2 |
639 640 641 |
int err = 0, free; lock_fat(sbi); |
606e423e4 fat: Update free_... |
642 |
if (sbi->free_clusters != -1 && sbi->free_clus_valid) |
1da177e4c Linux-2.6.12-rc2 |
643 |
goto out; |
9f966be89 fat: optimize fat... |
644 645 646 |
reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits; reada_mask = reada_blocks - 1; cur_block = 0; |
1da177e4c Linux-2.6.12-rc2 |
647 648 649 650 |
free = 0; fatent_init(&fatent); fatent_set_entry(&fatent, FAT_START_ENT); while (fatent.entry < sbi->max_cluster) { |
9f966be89 fat: optimize fat... |
651 652 653 654 655 656 |
/* readahead of fat blocks */ if ((cur_block & reada_mask) == 0) { unsigned long rest = sbi->fat_length - cur_block; fat_ent_reada(sb, &fatent, min(reada_blocks, rest)); } cur_block++; |
1da177e4c Linux-2.6.12-rc2 |
657 658 659 660 661 662 663 664 665 666 |
err = fat_ent_read_block(sb, &fatent); if (err) goto out; do { if (ops->ent_get(&fatent) == FAT_ENT_FREE) free++; } while (fat_ent_next(sbi, &fatent)); } sbi->free_clusters = free; |
606e423e4 fat: Update free_... |
667 |
sbi->free_clus_valid = 1; |
90b436657 fat: introduce ma... |
668 |
mark_fsinfo_dirty(sb); |
1da177e4c Linux-2.6.12-rc2 |
669 670 671 672 673 |
fatent_brelse(&fatent); out: unlock_fat(sbi); return err; } |