cregit-Linux how code gets into the kernel

Release 4.11 fs/fat/fatent.c

Directory: fs/fat
/*
 * Copyright (C) 2004, OGAWA Hirofumi
 * Released under GPL v2.
 */

#include <linux/blkdev.h>
#include "fat.h"


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 *);
};

static DEFINE_SPINLOCK(fat12_entry_lock);


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); }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa84100.00%2100.00%
Total84100.00%2100.00%


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); }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa84100.00%2100.00%
Total84100.00%2100.00%


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; } }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa143100.00%2100.00%
Total143100.00%2100.00%


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); }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa48100.00%2100.00%
Total48100.00%2100.00%


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); }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa48100.00%2100.00%
Total48100.00%2100.00%


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); fatent->fat_inode = MSDOS_SB(sb)->fat_inode; 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: fat_msg(sb, KERN_ERR, "FAT read failed (blocknr %llu)", (llu)blocknr); return -EIO; }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa15690.70%360.00%
Al Viro116.40%120.00%
Alexey Fisher52.91%120.00%
Total172100.00%5100.00%


static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent, int offset, sector_t blocknr) { const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); fatent->fat_inode = MSDOS_SB(sb)->fat_inode; fatent->bhs[0] = sb_bread(sb, blocknr); if (!fatent->bhs[0]) { fat_msg(sb, KERN_ERR, "FAT read failed (blocknr %llu)", (llu)blocknr); return -EIO; } fatent->nr_bhs = 1; ops->ent_set_ptr(fatent, offset); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa10385.83%350.00%
Al Viro119.17%116.67%
Alexey Fisher54.17%116.67%
Julia Lawall10.83%116.67%
Total120100.00%6100.00%


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; return next; }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa103100.00%2100.00%
Total103100.00%2100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa56100.00%2100.00%
Total56100.00%2100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa58100.00%2100.00%
Total58100.00%2100.00%


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; spin_lock(&fat12_entry_lock); 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); } spin_unlock(&fat12_entry_lock); mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); if (fatent->nr_bhs == 2) mark_buffer_dirty_inode(fatent->bhs[1], fatent->fat_inode); }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa15093.75%266.67%
Al Viro106.25%133.33%
Total160100.00%3100.00%


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); mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa4590.00%150.00%
Al Viro510.00%150.00%
Total50100.00%2100.00%


static void fat32_ent_put(struct fat_entry *fatent, int new) { WARN_ON(new & 0xf0000000); new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff; *fatent->u.ent32_p = cpu_to_le32(new); mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa5791.94%266.67%
Al Viro58.06%133.33%
Total62100.00%3100.00%


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) { 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))); if (nextp < (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))) { ent12_p[0] = nextp - 1; ent12_p[1] = nextp; return 1; } } else { WARN_ON(ent12_p[0] != (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))); 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; }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa293100.00%2100.00%
Total293100.00%2100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa78100.00%2100.00%
Total78100.00%2100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa78100.00%2100.00%
Total78100.00%2100.00%

static const struct fatent_operations fat12_ops = { .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, }; static const struct fatent_operations fat16_ops = { .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, }; static const struct fatent_operations fat32_ops = { .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) { mutex_lock(&sbi->fat_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa1995.00%150.00%
Arjan van de Ven15.00%150.00%
Total20100.00%2100.00%


static inline void unlock_fat(struct msdos_sb_info *sbi) { mutex_unlock(&sbi->fat_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa1995.00%150.00%
Arjan van de Ven15.00%150.00%
Total20100.00%2100.00%


void fat_ent_access_init(struct super_block *sb) { struct msdos_sb_info *sbi = MSDOS_SB(sb); mutex_init(&sbi->fat_lock); 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; } }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa8798.86%150.00%
Arjan van de Ven11.14%150.00%
Total88100.00%2100.00%


static void mark_fsinfo_dirty(struct super_block *sb) { 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); }

Contributors

PersonTokensPropCommitsCommitProp
Artem B. Bityutskiy45100.00%2100.00%
Total45100.00%2100.00%


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); const struct fatent_operations *ops = sbi->fatent_ops; 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; 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; } } ops->ent_set_ptr(fatent, offset); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa16699.40%266.67%
Julia Lawall10.60%133.33%
Total167100.00%3100.00%


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); const struct fatent_operations *ops = sbi->fatent_ops; int err, offset; sector_t blocknr; if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { fatent_brelse(fatent); fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry); 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); }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa16098.77%133.33%
Julia Lawall10.62%133.33%
Denis Karpov10.62%133.33%
Total162100.00%3100.00%

/* 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); mark_buffer_dirty_inode(c_bh, sbi->fat_inode); if (sb->s_flags & MS_SYNCHRONOUS) err = sync_dirty_buffer(c_bh); brelse(c_bh); if (err) goto error; } } error: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa17797.25%150.00%
Al Viro52.75%150.00%
Total182100.00%2100.00%


int fat_ent_write(struct inode *inode, struct fat_entry *fatent, int new, int wait) { struct super_block *sb = inode->i_sb; const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; 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); }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa9498.95%150.00%
Julia Lawall11.05%150.00%
Total95100.00%2100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa46100.00%1100.00%
Total46100.00%1100.00%


static inline int fat_ent_read_block(struct super_block *sb, struct fat_entry *fatent) { const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; sector_t blocknr; int offset; fatent_brelse(fatent); ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr); return ops->ent_bread(sb, fatent, offset, blocknr); }

Contributors

PersonTokensPropCommitsCommitProp
Hirofumi Ogawa7198.61%150.00%
Julia Lawall11.39%150.00%
Total72100.00%2100.00%


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]