FAT: Support the large partition (> 128GB) for 2.4
Subsystems (2)
OGAWA Hirofumi
maintainerPATCH 1/1 FAT: Support the large partition (> 128GB) for 2.4
Hello,
Some peoples reported the problem of fatfs on large partion (> 128GB), and fixed by the following patch.
The "directory entry pointer" is position of the directory entry in the partition. like the following,
in fs/fat/misc.c:fat__get_entry()
offset &= sb->s_blocksize - 1;
*de = (struct msdos_dir_entry *) ((*bh)->b_data + offset);
*ino = (sector << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
^^^This is used for updates (not create) of the directory entry, and overflowed by large partition (> 128GB).
fs/fat/dir.c | 31 ++++++------- fs/fat/inode.c | 72 +++++++++++++++--------------- fs/fat/misc.c | 105 +++++++++++++++++++++++++-------------------- fs/msdos/namei.c | 70 +++++++++++++++--------------- fs/vfat/namei.c | 33 +++++++------- include/linux/msdos_fs.h | 23 +++++---- include/linux/msdos_fs_i.h | 2 7 files changed, 179 insertions(+), 157 deletions(-)
fs/fat/dir.c renamed from fs/fat/dir.c~fat_large-disk-2.4 +16 -15
@@ -198,11 +198,11 @@ int fat_search_long(struct inode *inode,int uni_xlate =MSDOS_SB (sb)->options.unicode_xlate;int utf8 =MSDOS_SB (sb)->options.utf8;unsigned short opt_shortname =MSDOS_SB (sb)->options.shortname; -int ino, chl, i, j, last_u, res =0 ; -loff_t cpos =0 ; +int chl, i, j, last_u, res =0 ; +loff_t i_pos, cpos =0 ;while (1 ) { -if (fat_get_entry (inode,&cpos,&bh,&de,&ino) ==-1 ) +if (fat_get_entry (inode,&cpos,&bh,&de,&i_pos) ==-1 ) goto EODir; parse_record: long_slots =0 ;
@@ -253,7 +253,7 @@ parse_long:if (ds->id &0x40 ) { unicode[offset +13 ] =0 ; } -if (fat_get_entry (inode,&cpos,&bh,&de,&ino)<0 ) +if (fat_get_entry (inode,&cpos,&bh,&de,&i_pos)<0 ) goto EODir;if (slot ==0 )break ;
@@ -368,8 +368,9 @@ static int fat_readdirx(struct inode *inint utf8 =MSDOS_SB (sb)->options.utf8;int nocase =MSDOS_SB (sb)->options.nocase;unsigned short opt_shortname =MSDOS_SB (sb)->options.shortname; -int ino, inum, chi, chl, i, i2, j, last, last_u, dotoffset =0 ; -loff_t cpos; +unsigned long inum; +int chi, chl, i, i2, j, last, last_u, dotoffset =0 ; +loff_t i_pos, cpos; cpos = filp->f_pos;/* Fake . and .. for the root directory. */
@@ -392,7 +393,7 @@ static int fat_readdirx(struct inode *in bh =NULL ; GetNew: long_slots =0 ; -if (fat_get_entry (inode,&cpos,&bh,&de,&ino) ==-1 ) +if (fat_get_entry (inode,&cpos,&bh,&de,&i_pos) ==-1 ) goto EODir;/* Check for long filename entry */ if (isvfat) {
@@ -449,7 +450,7 @@ ParseLong:if (ds->id &0x40 ) { unicode[offset +13 ] =0 ; } -if (fat_get_entry (inode,&cpos,&bh,&de,&ino) ==-1 ) +if (fat_get_entry (inode,&cpos,&bh,&de,&i_pos) ==-1 ) goto EODir;if (slot ==0 )break ;
@@ -541,7 +542,7 @@ ParseLong:/* inum = fat_parent_ino(inode,0); */ inum = filp->f_dentry->d_parent->d_inode->i_ino; }else { -struct inode *tmp =fat_iget (sb, ino); +struct inode *tmp =fat_iget (sb, i_pos);if (tmp) { inum = tmp->i_ino;iput (tmp);
@@ -690,14 +691,14 @@ int fat_dir_ioctl(struct inode * inode,/***** See if directory is empty */ int fat_dir_empty (struct inode *dir) { -loff_t pos; +loff_t pos, i_pos;struct buffer_head *bh;struct msdos_dir_entry *de; -int ino,result =0 ; +int result =0 ; pos =0 ; bh =NULL ; -while (fat_get_entry (dir,&pos,&bh,&de,&ino) >-1 ) { +while (fat_get_entry (dir,&pos,&bh,&de,&i_pos) >-1 ) {/* Ignore vfat longname entries */ if (de->attr ==ATTR_EXT )continue ;
@@ -717,7 +718,7 @@ int fat_dir_empty(struct inode *dir)/* This assumes that size of cluster is above the 32*slots */ int fat_add_entries (struct inode *dir,int slots,struct buffer_head **bh, -struct msdos_dir_entry **de,int *ino) +struct msdos_dir_entry **de,loff_t *i_pos) {struct super_block *sb = dir->i_sb;loff_t offset, curr;
@@ -727,7 +728,7 @@ int fat_add_entries(struct inode *dir,in offset = curr =0 ; *bh =NULL ; row =0 ; -while (fat_get_entry (dir,&curr,bh,de,ino) >-1 ) { +while (fat_get_entry (dir,&curr,bh,de,i_pos) >-1 ) {if (IS_FREE ((*de)->name)) {if (++row == slots)return offset;
@@ -742,7 +743,7 @@ int fat_add_entries(struct inode *dir,inif (!new_bh)return -ENOSPC ;fat_brelse (sb, new_bh); -do fat_get_entry (dir,&curr,bh,de,ino);while (++row<slots); +do fat_get_entry (dir,&curr,bh,de,i_pos);while (++row<slots);return offset; }
fs/fat/inode.c renamed from fs/fat/inode.c~fat_large-disk-2.4 +37 -35
191 lines not on this page · raw message
fs/fat/misc.c renamed from fs/fat/misc.c~fat_large-disk-2.4 +59 -46
199 lines not on this page · raw message
fs/msdos/namei.c renamed from fs/msdos/namei.c~fat_large-disk-2.4 +37 -33
222 lines not on this page · raw message
fs/vfat/namei.c renamed from fs/vfat/namei.c~fat_large-disk-2.4 +17 -16
@@ -408,9 +408,10 @@ static int vfat_find_form(struct inode * {struct msdos_dir_entry *de;struct buffer_head *bh =NULL ; -int ino,res; +loff_t i_pos; +int res; - res=fat_scan (dir,name,&bh,&de,&ino); + res =fat_scan (dir, name, &bh, &de, &i_pos);fat_brelse (dir->i_sb, bh);if (res<0 )return -ENOENT ;
@@ -891,7 +892,7 @@ static int vfat_add_entry(struct inode *int res, len;struct msdos_dir_entry *dummy_de;struct buffer_head *dummy_bh; -int dummy_ino; +loff_t dummy_i_pos;loff_t dummy; dir_slots = (struct msdos_dir_slot *)
@@ -917,7 +918,7 @@ static int vfat_add_entry(struct inode * goto cleanup;/* build the empty directory entry of number of slots */ - offset =fat_add_entries (dir, slots, &dummy_bh, &dummy_de, &dummy_ino); + offset =fat_add_entries (dir, slots, &dummy_bh, &dummy_de, &dummy_i_pos);if (offset <0 ) { res = offset; goto cleanup;
@@ -927,7 +928,7 @@ static int vfat_add_entry(struct inode */* Now create the new entry */ *bh =NULL ;for (slot =0 ; slot < slots; slot++) { -if (fat_get_entry (dir, &offset, bh, de, &sinfo_out->ino) <0 ) { +if (fat_get_entry (dir, &offset, bh, de, &sinfo_out->i_pos) <0 ) { res = -EIO ; goto cleanup; }
@@ -972,7 +973,7 @@ static int vfat_find(struct inode *dir,s &offset,&sinfo->longname_offset);if (res>0 ) { sinfo->long_slots = res-1 ; -if (fat_get_entry (dir,&offset,last_bh,last_de,&sinfo->ino)>=0 ) +if (fat_get_entry (dir,&offset,last_bh,last_de,&sinfo->i_pos)>=0 )return 0 ; res = -EIO ; }
@@ -1001,7 +1002,7 @@ struct dentry *vfat_lookup(struct inode table++; goto error; } - inode =fat_build_inode (dir->i_sb, de, sinfo.ino, &res); + inode =fat_build_inode (dir->i_sb, de, sinfo.i_pos, &res);fat_brelse (dir->i_sb, bh);if (res)return ERR_PTR (res);
@@ -1034,7 +1035,7 @@ int vfat_create(struct inode *dir,struct res =vfat_add_entry (dir, &dentry->d_name,0 , &sinfo, &bh, &de);if (res <0 )return res; - inode =fat_build_inode (sb, de, sinfo.ino, &res); + inode =fat_build_inode (sb, de, sinfo.i_pos, &res);fat_brelse (sb, bh);if (!inode)return res;
@@ -1051,8 +1052,8 @@ static void vfat_remove_entry(struct ino struct buffer_head *bh, struct msdos_dir_entry *de) { struct super_block *sb = dir->i_sb; -loff_t offset; -int i,ino; +loff_t offset, i_pos; +int i;/* remove the shortname */ dir->i_mtime =CURRENT_TIME ;
@@ -1064,7 +1065,7 @@ static void vfat_remove_entry(struct ino/* remove the longname */ offset = sinfo->longname_offset; de =NULL ;for (i = sinfo->long_slots; i >0 ; --i) { -if (fat_get_entry (dir, &offset, &bh, &de, &ino) <0 ) +if (fat_get_entry (dir, &offset, &bh, &de, &i_pos) <0 )continue ; de->name[0 ] =DELETED_FLAG ; de->attr =0 ;
@@ -1133,7 +1134,7 @@ int vfat_mkdir(struct inode *dir,struct res =vfat_add_entry (dir, &dentry->d_name,1 , &sinfo, &bh, &de);if (res <0 )return res; - inode =fat_build_inode (sb, de, sinfo.ino, &res); + inode =fat_build_inode (sb, de, sinfo.i_pos, &res);if (!inode) goto out; inode->i_mtime = inode->i_atime = inode->i_ctime =CURRENT_TIME ;
@@ -1170,7 +1171,7 @@ int vfat_rename(struct inode *old_dir,ststruct super_block *sb = old_dir->i_sb;struct buffer_head *old_bh,*new_bh,*dotdot_bh;struct msdos_dir_entry *old_de,*new_de,*dotdot_de; -int dotdot_ino; +loff_t dotdot_i_pos;struct inode *old_inode, *new_inode;int res, is_dir;struct vfat_slot_info old_sinfo,sinfo;
@@ -1185,13 +1186,13 @@ int vfat_rename(struct inode *old_dir,st is_dir =S_ISDIR (old_inode->i_mode);if (is_dir && (res =fat_scan (old_inode,MSDOS_DOTDOT ,&dotdot_bh, - &dotdot_de,&dotdot_ino)) <0 ) + &dotdot_de,&dotdot_i_pos)) <0 ) goto rename_done;if (new_dentry->d_inode) { res =vfat_find (new_dir,&new_dentry->d_name,&sinfo,&new_bh, &new_de); -if (res <0 ||MSDOS_I (new_inode)->i_location != sinfo.ino) { +if (res <0 ||MSDOS_I (new_inode)->i_pos != sinfo.i_pos) {/* WTF??? Cry and fail. */ printk (KERN_WARNING "vfat_rename: fs corrupted\n" ); goto rename_done;
@@ -1215,7 +1216,7 @@ int vfat_rename(struct inode *old_dir,stvfat_remove_entry (old_dir,&old_sinfo,old_bh,old_de); old_bh=NULL ;fat_detach (old_inode); -fat_attach (old_inode, sinfo.ino); +fat_attach (old_inode, sinfo.i_pos);mark_inode_dirty (old_inode); old_dir->i_version = ++event;
include/linux/msdos_fs.h renamed from include/linux/msdos_fs.h~fat_large-disk-2.4 +12 -11
@@ -180,7 +180,7 @@ struct vfat_slot_info {int total_slots;/* total slots (long and short) */ loff_t longname_offset;/* dir offset for longname start */ loff_t shortname_offset;/* dir offset for shortname start */ -int ino;/* ino for the file */ +loff_t i_pos;/* on-disk position of directory entry */ };/* Determine whether this FS has kB-aligned data. */
@@ -264,7 +264,7 @@ extern int fat_dir_ioctl(struct inode * unsigned int cmd, unsigned long arg);extern int fat_dir_empty (struct inode *dir);extern int fat_add_entries (struct inode *dir,int slots,struct buffer_head **bh, -struct msdos_dir_entry **de,int *ino); +struct msdos_dir_entry **de,loff_t *i_pos);extern int fat_new_dir (struct inode *dir,struct inode *parent,int is_vfat);/* fat/file.c */
@@ -280,11 +280,11 @@ extern void fat_truncate(struct inode *i/* fat/inode.c */ extern void fat_hash_init (void ); -extern void fat_attach (struct inode *inode,int i_pos); +extern void fat_attach (struct inode *inode,loff_t i_pos);extern void fat_detach (struct inode *inode); -extern struct inode *fat_iget (struct super_block *sb,int i_pos); +extern struct inode *fat_iget (struct super_block *sb,loff_t i_pos);extern struct inode *fat_build_inode (struct super_block *sb, -struct msdos_dir_entry *de,int ino,int *res); +struct msdos_dir_entry *de,loff_t i_pos,int *res);extern void fat_delete_inode (struct inode *inode);extern void fat_clear_inode (struct inode *inode);extern void fat_put_super (struct super_block *sb);
@@ -306,26 +306,27 @@ extern struct buffer_head *fat_extend_diextern int date_dos2unix (unsigned short time,unsigned short date);extern void fat_date_unix2dos (int unix_date,unsigned short *time,unsigned short *date); -extern int fat__get_entry (struct inode *dir,loff_t *pos,struct buffer_head **bh, -struct msdos_dir_entry **de,int *ino); +extern int fat__get_entry (struct inode *dir,loff_t *pos, +struct buffer_head **bh, +struct msdos_dir_entry **de,loff_t *i_pos);static __inline__int fat_get_entry (struct inode *dir,loff_t *pos,struct buffer_head **bh, -struct msdos_dir_entry **de,int *ino) +struct msdos_dir_entry **de,loff_t *i_pos) {/* Fast stuff first */ if (*bh && *de && (*de - (struct msdos_dir_entry *)(*bh)->b_data) <MSDOS_SB (dir->i_sb)->dir_per_block -1 ) { *pos +=sizeof (struct msdos_dir_entry ); (*de)++; - (*ino)++; + (*i_pos)++;return 0 ; } -return fat__get_entry (dir,pos,bh,de,ino); +return fat__get_entry (dir, pos, bh, de, i_pos); }extern int fat_subdirs (struct inode *dir);extern int fat_scan (struct inode *dir,const char *name,struct buffer_head **res_bh, -struct msdos_dir_entry **res_de,int *ino); +struct msdos_dir_entry **res_de,loff_t *i_pos);/* msdos/namei.c - these are for Umsdos */ extern void msdos_put_super (struct super_block *sb);
include/linux/msdos_fs_i.h renamed from include/linux/msdos_fs_i.h~fat_large-disk-2.4 +1 -1
@@ -11,7 +11,7 @@ struct msdos_inode_info {int i_logstart;/* logical first cluster */ int i_attrs;/* unused attribute bits */ int i_ctime_ms;/* unused change time in milliseconds */ -int i_location;/* on-disk position of directory entry or 0 */ +loff_t i_pos;/* on-disk position of directory entry or 0 */ struct inode *i_fat_inode;/* struct inode of this one */ struct list_head i_fat_hash;/* hash by i_location */ };
_
Signature · 1 line
OGAWA Hirofumi <[email protected]>
Quoted 11 lines · OGAWA Hirofumi
Hello,
Some peoples reported the problem of fatfs on large partion (> 128GB), and fixed by the following patch.
The "directory entry pointer" is position of the directory entry in the partition. like the following,
in fs/fat/misc.c:fat__get_entry()
Quoted 7 lines
offset &= sb->s_blocksize - 1; *de = (struct msdos_dir_entry *) ((*bh)->b_data + offset); *ino = (sector << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS); ^^^This is used for updates (not create) of the directory entry, and overflowed by large partition (> 128GB).
I think this additional fat32 patch would be a good idea for 2.4.x. Could you review these changes and perhaps fold them into your patch for inclusion into 2.4.x. This patch fixes support for the full 4GB (-1 bytes) allowable fat32 file size, and should be added onto of your previous patch for large fat32 filesystems.
fs/buffer.c renamed from fs.orig/buffer.c +1 -1
@@ -1940,7 +1940,7 @@* We may have to extend the file. */ -int cont_prepare_write (struct page *page,unsigned offset,unsigned to,get_block_t *get_block,unsigned long *bytes) +int cont_prepare_write (struct page *page,unsigned offset,unsigned to,get_block_t *get_block,loff_t *bytes) {struct address_space *mapping = page->mapping;struct inode *inode = mapping->host;
fs/fat/dir.c renamed from fs.orig/fat/dir.c +2 -3
@@ -362,15 +362,14 @@unsigned char long_slots;wchar_t *unicode =NULL ;char c, work[8 ], bufname[56 ], *ptname = bufname; -unsigned long lpos, dummy, *furrfu = &lpos; +loff_t lpos, dummy, *furrfu = &lpos;int uni_xlate =MSDOS_SB (sb)->options.unicode_xlate;int isvfat =MSDOS_SB (sb)->options.isvfat;int utf8 =MSDOS_SB (sb)->options.utf8;int nocase =MSDOS_SB (sb)->options.nocase;unsigned short opt_shortname =MSDOS_SB (sb)->options.shortname; -unsigned long inum;int chi, chl, i, i2, j, last, last_u, dotoffset =0 ; -loff_t i_pos, cpos; +loff_t i_pos, inum, cpos; cpos = filp->f_pos;/* Fake . and .. for the root directory. */
fs/fat/file.c renamed from fs.orig/fat/file.c +1 -1
@@ -62,7 +62,7 @@ }if (!create)return 0 ; -if (iblock << sb->s_blocksize_bits !=MSDOS_I (inode)->mmu_private) { +if (iblock !=MSDOS_I (inode)->mmu_private >> sb->s_blocksize_bits) {BUG ();return -EIO ; }
fs/fat/inode.c renamed from fs.orig/fat/inode.c +5 -4
@@ -406,7 +406,7 @@ } inode->i_blksize =1 << sbi->cluster_bits; inode->i_blocks = ((inode->i_size + inode->i_blksize -1 ) - & ~(inode->i_blksize -1 )) >>9 ; + & ~((loff_t )inode->i_blksize -1 )) >>9 ;MSDOS_I (inode)->i_logstart =0 ;MSDOS_I (inode)->mmu_private = inode->i_size;
@@ -556,8 +556,8 @@struct fat_boot_sector *b;struct msdos_sb_info *sbi =MSDOS_SB (sb);char *p; -int logical_sector_size, hard_blksize, fat_clusters =0 ; -unsigned int total_sectors, rootdir_sectors; +int logical_sector_size, hard_blksize; +unsigned long total_sectors, rootdir_sectors, fat_clusters =0 ;int fat32, debug, error, fat, cp;struct fat_mount_options opts;char buf[50 ];
@@ -651,6 +651,7 @@ fat32 =1 ; sbi->fat_length =CF_LE_L (b->fat32_length); sbi->root_cluster =CF_LE_L (b->root_cluster); + sb->s_maxbytes =0xffffffff ; sbi->fsinfo_sector =CF_LE_W (b->info_sector);/* MC - if info_sector is 0, don't multiply by 0 */
@@ -957,7 +958,7 @@/* this is as close to the truth as we can get ... */ inode->i_blksize =1 << sbi->cluster_bits; inode->i_blocks = ((inode->i_size + inode->i_blksize -1 ) - & ~(inode->i_blksize -1 )) >>9 ; + & ~((loff_t )inode->i_blksize -1 )) >>9 ; inode->i_mtime = inode->i_atime =date_dos2unix (CF_LE_W (de->time),CF_LE_W (de->date)); inode->i_ctime =
include/linux/adfs_fs_i.h renamed from include/linux.orig/adfs_fs_i.h +1 -1
@@ -11,7 +11,7 @@* adfs file system inode data in memory */ struct adfs_inode_info { -unsigned long mmu_private; +loff_t mmu_private;unsigned long parent_id;/* object id of parent */ __u32 loadaddr;/* RISC OS load address */ __u32 execaddr;/* RISC OS exec address */
include/linux/affs_fs_i.h renamed from include/linux.orig/affs_fs_i.h +1 -1
@@ -36,7 +36,7 @@struct affs_ext_key *i_ac;/* associative cache of extended blocks */ u32 i_ext_last;/* last accessed extended block */ struct buffer_head *i_ext_bh;/* bh of last extended block */ -unsigned long mmu_private; +loff_t mmu_private;u32 i_protect;/* unused attribute bits */ u32 i_lastalloc;/* last allocated block */ int i_pa_cnt;/* number of preallocated blocks */
include/linux/fs.h renamed from include/linux.orig/fs.h +1 -1
@@ -1505,7 +1505,7 @@extern int block_read_full_page (struct page *,get_block_t *);extern int block_prepare_write (struct page *,unsigned ,unsigned ,get_block_t *);extern int cont_prepare_write (struct page *,unsigned ,unsigned ,get_block_t *, -unsigned long *); +loff_t *);extern int generic_cont_expand (struct inode *inode,loff_t size) ;extern int block_commit_write (struct page *page,unsigned from,unsigned to);extern int block_sync_page (struct page *);
include/linux/hfs_fs_i.h renamed from include/linux.orig/hfs_fs_i.h +1 -1
@@ -19,7 +19,7 @@struct hfs_inode_info {int magic;/* A magic number */ -unsigned long mmu_private; +loff_t mmu_private;struct hfs_cat_entry *entry;/* For a regular or header file */
include/linux/hpfs_fs_i.h renamed from include/linux.orig/hpfs_fs_i.h +1 -1
@@ -2,7 +2,7 @@#define _HPFS_FS_Istruct hpfs_inode_info { -unsigned long mmu_private; +loff_t mmu_private;ino_t i_parent_dir;/* (directories) gives fnode of parent dir */ unsigned i_dno;/* (directories) root dnode */ unsigned i_dpos;/* (directories) temp for readdir */
include/linux/msdos_fs_i.h renamed from include/linux.orig/msdos_fs_i.h +1 -1
@@ -6,7 +6,7 @@*/ struct msdos_inode_info { -unsigned long mmu_private; +loff_t mmu_private;int i_start;/* first cluster or 0 */ int i_logstart;/* logical first cluster */ int i_attrs;/* unused attribute bits */
-Erik
--
Erik B. Andersen http://codepoet-consulting.com/
--This message was written using 73% post-consumer electrons--
OGAWA Hirofumi
maintainerQuoted 8 lines · Erik Andersen
Quoted 2 lines
This is used for updates (not create) of the directory entry, and overflowed by large partition (> 128GB).
I think this additional fat32 patch would be a good idea for 2.4.x. Could you review these changes and perhaps fold them into your patch for inclusion into 2.4.x. This patch fixes support for the full 4GB (-1 bytes) allowable fat32 file size, and should be added onto of your previous patch for large fat32 filesystems.
Basically looks good. But it was forgetting to fix the mmu_private of some filesystems.
If previous patch was applied and someone didn't submit this stuff, I'll try it.
Thanks.
Signature · 1 line
OGAWA Hirofumi <[email protected]>
Quoted 5 lines · OGAWA Hirofumi
Quoted 3 lines · Erik Andersen
Quoted 2 lines
This is used for updates (not create) of the directory entry, and overflowed by large partition (> 128GB).
Quoted 8 lines
Quoted 5 lines
I think this additional fat32 patch would be a good idea for 2.4.x. Could you review these changes and perhaps fold them into your patch for inclusion into 2.4.x. This patch fixes support for the full 4GB (-1 bytes) allowable fat32 file size, and should be added onto of your previous patch for large fat32 filesystems.
Basically looks good. But it was forgetting to fix the
mmu_privateof some filesystems.
Yes, I suppose all filesystems should be fixed.
Quoted 2 lines
If previous patch was applied and someone didn't submit this stuff, I'll try it.
That would be great.
-Erik
--
Erik B. Andersen http://codepoet-consulting.com/
--This message was written using 73% post-consumer electrons--