X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=fs%2Ffat%2Ffatent.c;h=302e95c4af7e0c517704d987932411066c129d86;hb=9e975dae2970d22557662761c8505ce9fd165684;hp=ab171ea8e869b2cc9da6369abad3a83c970d2a96;hpb=be9bf30c73184e0f1e4e0a50fb193d2a551bf75e;p=linux-2.6-omap-h63xx.git diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index ab171ea8e86..5b5f49061b7 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include "fat.h" struct fatent_operations { void (*ent_blocknr)(struct super_block *, int, int *, sector_t *); @@ -17,6 +19,8 @@ struct fatent_operations { int (*ent_next)(struct fat_entry *); }; +static DEFINE_SPINLOCK(fat12_entry_lock); + static void fat12_ent_blocknr(struct super_block *sb, int entry, int *offset, sector_t *blocknr) { @@ -116,10 +120,13 @@ static int fat12_ent_get(struct fat_entry *fatent) u8 **ent12_p = fatent->u.ent12_p; int next; + spin_lock(&fat12_entry_lock); if (fatent->entry & 1) next = (*ent12_p[0] >> 4) | (*ent12_p[1] << 4); else next = (*ent12_p[1] << 8) | *ent12_p[0]; + spin_unlock(&fat12_entry_lock); + next &= 0x0fff; if (next >= BAD_FAT12) next = FAT_ENT_EOF; @@ -151,6 +158,7 @@ static void fat12_ent_put(struct fat_entry *fatent, int new) if (new == FAT_ENT_EOF) new = EOF_FAT12; + spin_lock(&fat12_entry_lock); if (fatent->entry & 1) { *ent12_p[0] = (new << 4) | (*ent12_p[0] & 0x0f); *ent12_p[1] = new >> 4; @@ -158,6 +166,7 @@ static void fat12_ent_put(struct fat_entry *fatent, int new) *ent12_p[0] = new & 0xff; *ent12_p[1] = (*ent12_p[1] & 0xf0) | (new >> 8); } + spin_unlock(&fat12_entry_lock); mark_buffer_dirty(fatent->bhs[0]); if (fatent->nr_bhs == 2) @@ -443,7 +452,8 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster) BUG_ON(nr_cluster > (MAX_BUF_PER_PAGE / 2)); /* fixed limit */ lock_fat(sbi); - if (sbi->free_clusters != -1 && sbi->free_clusters < nr_cluster) { + if (sbi->free_clusters != -1 && sbi->free_clus_valid && + sbi->free_clusters < nr_cluster) { unlock_fat(sbi); return -ENOSPC; } @@ -497,6 +507,7 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster) /* Couldn't allocate the free entries */ sbi->free_clusters = 0; + sbi->free_clus_valid = 1; sb->s_dirt = 1; err = -ENOSPC; @@ -526,6 +537,7 @@ int fat_free_clusters(struct inode *inode, int cluster) struct fat_entry fatent; struct buffer_head *bhs[MAX_BUF_PER_PAGE]; int i, err, nr_bhs; + int first_cl = cluster; nr_bhs = 0; fatent_init(&fatent); @@ -537,11 +549,23 @@ int fat_free_clusters(struct inode *inode, int cluster) goto error; } else if (cluster == FAT_ENT_FREE) { fat_fs_panic(sb, "%s: deleting FAT entry beyond EOF", - __FUNCTION__); + __func__); err = -EIO; goto error; } + /* + * 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), + nr_clus * sbi->sec_per_clus); + first_cl = cluster; + } + ops->ent_put(&fatent, FAT_ENT_FREE); if (sbi->free_clusters != -1) { sbi->free_clusters++; @@ -576,28 +600,54 @@ error: brelse(bhs[i]); unlock_fat(sbi); - fat_clusters_flush(sb); - return err; } EXPORT_SYMBOL_GPL(fat_free_clusters); +/* 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) +{ + struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; + 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); +} + int fat_count_free_clusters(struct super_block *sb) { struct msdos_sb_info *sbi = MSDOS_SB(sb); struct fatent_operations *ops = sbi->fatent_ops; struct fat_entry fatent; + unsigned long reada_blocks, reada_mask, cur_block; int err = 0, free; lock_fat(sbi); - if (sbi->free_clusters != -1) + if (sbi->free_clusters != -1 && sbi->free_clus_valid) goto out; + reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits; + reada_mask = reada_blocks - 1; + cur_block = 0; + free = 0; fatent_init(&fatent); fatent_set_entry(&fatent, FAT_START_ENT); while (fatent.entry < sbi->max_cluster) { + /* 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++; + err = fat_ent_read_block(sb, &fatent); if (err) goto out; @@ -608,6 +658,7 @@ int fat_count_free_clusters(struct super_block *sb) } while (fat_ent_next(sbi, &fatent)); } sbi->free_clusters = free; + sbi->free_clus_valid = 1; sb->s_dirt = 1; fatent_brelse(&fatent); out: