linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] FAT: Support the large partition (> 128GB) for 2.4
@ 2003-12-22 20:02 OGAWA Hirofumi
  2003-12-31  9:14 ` Erik Andersen
  0 siblings, 1 reply; 4+ messages in thread
From: OGAWA Hirofumi @ 2003-12-22 20:02 UTC (permalink / raw)
  To: linux-kernel; +Cc: Marcelo Tosatti

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(-)

diff -puN fs/fat/dir.c~fat_large-disk-2.4 fs/fat/dir.c
--- linux-2.4.24-bk1/fs/fat/dir.c~fat_large-disk-2.4	2003-12-16 02:29:29.000000000 +0900
+++ linux-2.4.24-bk1-hirofumi/fs/fat/dir.c	2003-12-16 02:29:29.000000000 +0900
@@ -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 *in
 	int 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,in
 	if (!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;
 }
 
diff -puN fs/fat/inode.c~fat_large-disk-2.4 fs/fat/inode.c
--- linux-2.4.24-bk1/fs/fat/inode.c~fat_large-disk-2.4	2003-12-16 02:29:29.000000000 +0900
+++ linux-2.4.24-bk1-hirofumi/fs/fat/inode.c	2003-12-16 02:29:29.000000000 +0900
@@ -83,17 +83,17 @@ void fat_hash_init(void)
 	}
 }
 
-static inline unsigned long fat_hash(struct super_block *sb, int i_pos)
+static inline unsigned long fat_hash(struct super_block *sb, loff_t i_pos)
 {
 	unsigned long tmp = (unsigned long)i_pos | (unsigned long) sb;
 	tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS * 2);
 	return tmp & FAT_HASH_MASK;
 }
 
-void fat_attach(struct inode *inode, int i_pos)
+void fat_attach(struct inode *inode, loff_t i_pos)
 {
 	spin_lock(&fat_inode_lock);
-	MSDOS_I(inode)->i_location = i_pos;
+	MSDOS_I(inode)->i_pos = i_pos;
 	list_add(&MSDOS_I(inode)->i_fat_hash,
 		fat_inode_hashtable + fat_hash(inode->i_sb, i_pos));
 	spin_unlock(&fat_inode_lock);
@@ -102,13 +102,13 @@ void fat_attach(struct inode *inode, int
 void fat_detach(struct inode *inode)
 {
 	spin_lock(&fat_inode_lock);
-	MSDOS_I(inode)->i_location = 0;
+	MSDOS_I(inode)->i_pos = 0;
 	list_del(&MSDOS_I(inode)->i_fat_hash);
 	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
 	spin_unlock(&fat_inode_lock);
 }
 
-struct inode *fat_iget(struct super_block *sb, int i_pos)
+struct inode *fat_iget(struct super_block *sb, loff_t i_pos)
 {
 	struct list_head *p = fat_inode_hashtable + fat_hash(sb, i_pos);
 	struct list_head *walk;
@@ -120,7 +120,7 @@ struct inode *fat_iget(struct super_bloc
 		i = list_entry(walk, struct msdos_inode_info, i_fat_hash);
 		if (i->i_fat_inode->i_sb != sb)
 			continue;
-		if (i->i_location != i_pos)
+		if (i->i_pos != i_pos)
 			continue;
 		inode = igrab(i->i_fat_inode);
 		if (inode)
@@ -133,11 +133,11 @@ struct inode *fat_iget(struct super_bloc
 static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de);
 
 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)
 {
 	struct inode *inode;
 	*res = 0;
-	inode = fat_iget(sb, ino);
+	inode = fat_iget(sb, i_pos);
 	if (inode)
 		goto out;
 	inode = new_inode(sb);
@@ -147,7 +147,7 @@ struct inode *fat_build_inode(struct sup
 	*res = 0;
 	inode->i_ino = iunique(sb, MSDOS_ROOT_INO);
 	fat_fill_inode(inode, de);
-	fat_attach(inode, ino);
+	fat_attach(inode, i_pos);
 	insert_inode_hash(inode);
 out:
 	return inode;
@@ -379,7 +379,7 @@ static void fat_read_root(struct inode *
 	int nr;
 
 	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
-	MSDOS_I(inode)->i_location = 0;
+	MSDOS_I(inode)->i_pos = 0;
 	MSDOS_I(inode)->i_fat_inode = inode;
 	inode->i_uid = sbi->options.fs_uid;
 	inode->i_gid = sbi->options.fs_gid;
@@ -421,9 +421,10 @@ static void fat_read_root(struct inode *
  *  0/  i_ino - for fast, reliable lookup if still in the cache
  *  1/  i_generation - to see if i_ino is still valid
  *          bit 0 == 0 iff directory
- *  2/  i_location - if ino has changed, but still in cache
- *  3/  i_logstart - to semi-verify inode found at i_location
- *  4/  parent->i_logstart - maybe used to hunt for the file on disc
+ *  2/  i_pos - if ino has changed, but still in cache (hi)
+ *  3/  i_pos - if ino has changed, but still in cache (low)
+ *  4/  i_logstart - to semi-verify inode found at i_location
+ *  5/  parent->i_logstart - maybe used to hunt for the file on disc
  *
  */
 struct dentry *fat_fh_to_dentry(struct super_block *sb, __u32 *fh,
@@ -435,7 +436,7 @@ struct dentry *fat_fh_to_dentry(struct s
 
 	if (fhtype != 3)
 		return ERR_PTR(-ESTALE);
-	if (len < 5)
+	if (len < 6)
 		return ERR_PTR(-ESTALE);
 	/* We cannot find the parent,
 	   It better just *be* there */
@@ -449,13 +450,15 @@ struct dentry *fat_fh_to_dentry(struct s
 		inode = NULL;
 	}
 	if (!inode) {
-		/* try 2 - see if i_location is in F-d-c
+		loff_t i_pos = ((loff_t)fh[2] << 32) | fh[3];
+
+		/* try 2 - see if i_pos is in F-d-c
 		 * require i_logstart to be the same
 		 * Will fail if you truncate and then re-write
 		 */
 
-		inode = fat_iget(sb, fh[2]);
-		if (inode && MSDOS_I(inode)->i_logstart != fh[3]) {
+		inode = fat_iget(sb, i_pos);
+		if (inode && MSDOS_I(inode)->i_logstart != fh[4]) {
 			iput(inode);
 			inode = NULL;
 		}
@@ -514,14 +517,15 @@ int fat_dentry_to_fh(struct dentry *de, 
 	int len = *lenp;
 	struct inode *inode =  de->d_inode;
 	
-	if (len < 5)
+	if (len < 6)
 		return 255; /* no room */
-	*lenp = 5;
+	*lenp = 6;
 	fh[0] = inode->i_ino;
 	fh[1] = inode->i_generation;
-	fh[2] = MSDOS_I(inode)->i_location;
-	fh[3] = MSDOS_I(inode)->i_logstart;
-	fh[4] = MSDOS_I(de->d_parent->d_inode)->i_logstart;
+	fh[2] = (__u32)(MSDOS_I(inode)->i_pos >> 32);
+	fh[3] = (__u32)MSDOS_I(inode)->i_pos;
+	fh[4] = MSDOS_I(inode)->i_logstart;
+	fh[5] = MSDOS_I(de->d_parent->d_inode)->i_logstart;
 	return 3;
 }
 
@@ -891,7 +895,7 @@ static void fat_fill_inode(struct inode 
 	int nr;
 
 	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
-	MSDOS_I(inode)->i_location = 0;
+	MSDOS_I(inode)->i_pos = 0;
 	MSDOS_I(inode)->i_fat_inode = inode;
 	inode->i_uid = sbi->options.fs_uid;
 	inode->i_gid = sbi->options.fs_gid;
@@ -906,10 +910,9 @@ static void fat_fill_inode(struct inode 
 		inode->i_fop = &fat_dir_operations;
 
 		MSDOS_I(inode)->i_start = CF_LE_W(de->start);
-		if (sbi->fat_bits == 32) {
-			MSDOS_I(inode)->i_start |=
-				(CF_LE_W(de->starthi) << 16);
-		}
+		if (sbi->fat_bits == 32)
+			MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16);
+
 		MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
 		inode->i_nlink = fat_subdirs(inode);
 		    /* includes .., compensating for "self" */
@@ -937,10 +940,9 @@ static void fat_fill_inode(struct inode 
 		    	? S_IRUGO|S_IWUGO : S_IRWXUGO)
 		    & ~sbi->options.fs_umask) | S_IFREG;
 		MSDOS_I(inode)->i_start = CF_LE_W(de->start);
-		if (sbi->fat_bits == 32) {
-			MSDOS_I(inode)->i_start |=
-				(CF_LE_W(de->starthi) << 16);
-		}
+		if (sbi->fat_bits == 32)
+			MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16);
+
 		MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
 		inode->i_size = CF_LE_L(de->size);
 	        inode->i_op = &fat_file_inode_operations;
@@ -970,22 +972,22 @@ void fat_write_inode(struct inode *inode
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *bh;
 	struct msdos_dir_entry *raw_entry;
-	unsigned int i_pos;
+	loff_t i_pos;
 
 retry:
-	i_pos = MSDOS_I(inode)->i_location;
+	i_pos = MSDOS_I(inode)->i_pos;
 	if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) {
 		return;
 	}
 	lock_kernel();
 	if (!(bh = fat_bread(sb, i_pos >> MSDOS_SB(sb)->dir_per_block_bits))) {
-		printk("dev = %s, ino = %d\n", kdevname(inode->i_dev), i_pos);
+		printk("dev = %s, i_pos = %llu\n", kdevname(inode->i_dev), i_pos);
 		fat_fs_panic(sb, "msdos_write_inode: unable to read i-node block");
 		unlock_kernel();
 		return;
 	}
 	spin_lock(&fat_inode_lock);
-	if (i_pos != MSDOS_I(inode)->i_location) {
+	if (i_pos != MSDOS_I(inode)->i_pos) {
 		spin_unlock(&fat_inode_lock);
 		fat_brelse(sb, bh);
 		unlock_kernel();
diff -puN fs/fat/misc.c~fat_large-disk-2.4 fs/fat/misc.c
--- linux-2.4.24-bk1/fs/fat/misc.c~fat_large-disk-2.4	2003-12-16 02:29:29.000000000 +0900
+++ linux-2.4.24-bk1-hirofumi/fs/fat/misc.c	2003-12-16 02:29:29.000000000 +0900
@@ -316,11 +316,12 @@ void fat_date_unix2dos(int unix_date,uns
  */
 
 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)
 {
 	struct super_block *sb = dir->i_sb;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	int sector, offset;
+	int sector;
+	loff_t offset;
 
 	while (1) {
 		offset = *pos;
@@ -343,7 +344,7 @@ int fat__get_entry(struct inode *dir, lo
 
 		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);
+		*i_pos = ((loff_t)sector << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
 
 		return 0;
 	}
@@ -383,7 +384,7 @@ int fat__get_entry(struct inode *dir, lo
     done = !IS_FREE(data[entry].name) \
       && ( \
            ( \
-             (MSDOS_SB(sb)->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \
+             (sbi->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \
            ) \
            | CF_LE_W(data[entry].start) \
          ) == *number;
@@ -400,35 +401,38 @@ int fat__get_entry(struct inode *dir, lo
 	    (*number)++; \
     }
 
-static int raw_scan_sector(struct super_block *sb,int sector,const char *name,
-    int *number,int *ino,struct buffer_head **res_bh,
-    struct msdos_dir_entry **res_de)
+static int raw_scan_sector(struct super_block *sb, int sector,
+			   const char *name, int *number, loff_t *i_pos,
+			   struct buffer_head **res_bh,
+			   struct msdos_dir_entry **res_de)
 {
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	struct buffer_head *bh;
 	struct msdos_dir_entry *data;
 	int entry,start,done;
 
-	if (!(bh = fat_bread(sb,sector)))
+	if (!(bh = fat_bread(sb, sector)))
 		return -EIO;
 	data = (struct msdos_dir_entry *) bh->b_data;
-	for (entry = 0; entry < MSDOS_SB(sb)->dir_per_block; entry++) {
+	for (entry = 0; entry < sbi->dir_per_block; entry++) {
 /* RSS_COUNT:  if (data[entry].name == name) done=true else done=false. */
 		if (name) {
 			RSS_NAME
 		} else {
-			if (!ino) RSS_COUNT
+			if (!i_pos) RSS_COUNT
 			else {
 				if (number) RSS_START
 				else RSS_FREE
 			}
 		}
 		if (done) {
-			if (ino)
-				*ino = sector * MSDOS_SB(sb)->dir_per_block + entry;
+			if (i_pos) {
+				*i_pos = ((loff_t)sector << sbi->dir_per_block_bits) + entry;
+			}
 			start = CF_LE_W(data[entry].start);
-			if (MSDOS_SB(sb)->fat_bits == 32) {
+			if (sbi->fat_bits == 32)
 				start |= (CF_LE_W(data[entry].starthi) << 16);
-			}
+
 			if (!res_bh)
 				fat_brelse(sb, bh);
 			else {
@@ -448,16 +452,19 @@ static int raw_scan_sector(struct super_
  * requested entry is found or the end of the directory is reached.
  */
 
-static int raw_scan_root(struct super_block *sb,const char *name,int *number,int *ino,
-    struct buffer_head **res_bh,struct msdos_dir_entry **res_de)
+static int raw_scan_root(struct super_block *sb, const char *name,
+			 int *number, loff_t *i_pos,
+			 struct buffer_head **res_bh,
+			 struct msdos_dir_entry **res_de)
 {
 	int count,cluster;
 
 	for (count = 0;
 	     count < MSDOS_SB(sb)->dir_entries / MSDOS_SB(sb)->dir_per_block;
 	     count++) {
-		if ((cluster = raw_scan_sector(sb,MSDOS_SB(sb)->dir_start+count,
-					       name,number,ino,res_bh,res_de)) >= 0)
+		cluster = raw_scan_sector(sb, MSDOS_SB(sb)->dir_start + count,
+					  name, number, i_pos, res_bh, res_de);
+		if (cluster >= 0)
 			return cluster;
 	}
 	return -ENOENT;
@@ -469,20 +476,24 @@ static int raw_scan_root(struct super_bl
  * requested entry is found or the end of the directory is reached.
  */
 
-static int raw_scan_nonroot(struct super_block *sb,int start,const char *name,
-    int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry
-    **res_de)
+static int raw_scan_nonroot(struct super_block *sb, int start, const char *name,
+			    int *number, loff_t *i_pos,
+			    struct buffer_head **res_bh,
+			    struct msdos_dir_entry **res_de)
 {
-	int count,cluster;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	int count, cluster, sector;
 
 #ifdef DEBUG
 	printk("raw_scan_nonroot: start=%d\n",start);
 #endif
 	do {
-		for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
-			if ((cluster = raw_scan_sector(sb,(start-2)*
-			    MSDOS_SB(sb)->cluster_size+MSDOS_SB(sb)->data_start+
-			    count,name,number,ino,res_bh,res_de)) >= 0)
+		for (count = 0; count < sbi->cluster_size; count++) {
+			sector = (start - 2) * sbi->cluster_size
+				+ count + sbi->data_start;
+			cluster = raw_scan_sector(sb, sector, name, number,
+						  i_pos, res_bh, res_de);
+			if (cluster >= 0)
 				return cluster;
 		}
 		if (!(start = fat_access(sb,start,-1))) {
@@ -506,13 +517,13 @@ static int raw_scan_nonroot(struct super
  */
 
 static int raw_scan(struct super_block *sb, int start, const char *name,
-    int *number, int *ino, struct buffer_head **res_bh,
-    struct msdos_dir_entry **res_de)
+		    loff_t *i_pos, struct buffer_head **res_bh,
+		    struct msdos_dir_entry **res_de)
 {
 	if (start)
-		return raw_scan_nonroot(sb,start,name,number,ino,res_bh,res_de);
+		return raw_scan_nonroot(sb,start,name,NULL,i_pos,res_bh,res_de);
 	else
-		return raw_scan_root(sb,name,number,ino,res_bh,res_de);
+		return raw_scan_root(sb,name,NULL,i_pos,res_bh,res_de);
 }
 
 /*
@@ -521,19 +532,21 @@ static int raw_scan(struct super_block *
  */
 int fat_subdirs(struct inode *dir)
 {
-	int count;
+	struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
+	int number;
 
-	count = 0;
-	if ((dir->i_ino == MSDOS_ROOT_INO) &&
-	    (MSDOS_SB(dir->i_sb)->fat_bits != 32)) {
-		(void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL);
-	} else {
-		if ((dir->i_ino != MSDOS_ROOT_INO) &&
-		    !MSDOS_I(dir)->i_start) return 0; /* in mkdir */
-		else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
-		    NULL,&count,NULL,NULL,NULL);
+	number = 0;
+	if ((dir->i_ino == MSDOS_ROOT_INO) && (sbi->fat_bits != 32))
+		raw_scan_root(dir->i_sb, NULL, &number, NULL, NULL, NULL);
+	else {
+		if ((dir->i_ino != MSDOS_ROOT_INO) && !MSDOS_I(dir)->i_start)
+			return 0; /* in mkdir */
+		else {
+			raw_scan_nonroot(dir->i_sb, MSDOS_I(dir)->i_start,
+					 NULL, &number, NULL, NULL, NULL);
+		}
 	}
-	return count;
+	return number;
 }
 
 
@@ -542,12 +555,12 @@ int fat_subdirs(struct inode *dir)
  * for an empty directory slot (name is NULL). Returns an error code or zero.
  */
 
-int fat_scan(struct inode *dir,const char *name,struct buffer_head **res_bh,
-    struct msdos_dir_entry **res_de,int *ino)
+int fat_scan(struct inode *dir, const char *name, struct buffer_head **res_bh,
+	     struct msdos_dir_entry **res_de, loff_t *i_pos)
 {
 	int res;
 
-	res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,
-		       name, NULL, ino, res_bh, res_de);
-	return res<0 ? res : 0;
+	res = raw_scan(dir->i_sb, MSDOS_I(dir)->i_start, name, i_pos,
+		       res_bh, res_de);
+	return (res < 0) ? res : 0;
 }
diff -puN fs/msdos/namei.c~fat_large-disk-2.4 fs/msdos/namei.c
--- linux-2.4.24-bk1/fs/msdos/namei.c~fat_large-disk-2.4	2003-12-16 02:29:29.000000000 +0900
+++ linux-2.4.24-bk1-hirofumi/fs/msdos/namei.c	2003-12-16 02:29:29.000000000 +0900
@@ -127,8 +127,9 @@ static int msdos_format_name(const char 
 }
 
 /***** Locates a directory entry.  Uses unformatted name. */
-static int msdos_find(struct inode *dir,const char *name,int len,
-    struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
+static int msdos_find(struct inode *dir, const char *name, int len,
+		      struct buffer_head **bh, struct msdos_dir_entry **de,
+		      loff_t *i_pos)
 {
 	int res;
 	char dotsOK;
@@ -138,7 +139,7 @@ static int msdos_find(struct inode *dir,
 	res = msdos_format_name(name,len, msdos_name,&MSDOS_SB(dir->i_sb)->options);
 	if (res < 0)
 		return -ENOENT;
-	res = fat_scan(dir,msdos_name,bh,de,ino);
+	res = fat_scan(dir, msdos_name, bh, de, i_pos);
 	if (!res && dotsOK) {
 		if (name[0]=='.') {
 			if (!((*de)->attr & ATTR_HIDDEN))
@@ -149,7 +150,6 @@ static int msdos_find(struct inode *dir,
 		}
 	}
 	return res;
-
 }
 
 /*
@@ -214,20 +214,20 @@ struct dentry *msdos_lookup(struct inode
 	struct inode *inode = NULL;
 	struct msdos_dir_entry *de;
 	struct buffer_head *bh = NULL;
-	int ino,res;
+	loff_t i_pos;
+	int res;
 	
 	PRINTK (("msdos_lookup\n"));
 
 	dentry->d_op = &msdos_dentry_operations;
 
 	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh,
-			&de, &ino);
-
+			 &de, &i_pos);
 	if (res == -ENOENT)
 		goto add;
 	if (res < 0)
 		goto out;
-	inode = fat_build_inode(sb, de, ino, &res);
+	inode = fat_build_inode(sb, de, i_pos, &res);
 	if (res)
 		goto out;
 add:
@@ -243,13 +243,13 @@ out:
 static int msdos_add_entry(struct inode *dir, const char *name,
 			   struct buffer_head **bh,
 			   struct msdos_dir_entry **de,
-			   int *ino,
-			   int is_dir, int is_hid)
+			   loff_t *i_pos, int is_dir, int is_hid)
 {
 	struct super_block *sb = dir->i_sb;
 	int res;
 
-	if ((res = fat_add_entries(dir, 1, bh, de, ino))<0)
+	res = fat_add_entries(dir, 1, bh, de, i_pos);
+ 	if (res < 0)
 		return res;
 	/*
 	 * XXX all times should be set by caller upon successful completion.
@@ -279,7 +279,8 @@ int msdos_create(struct inode *dir,struc
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 	struct inode *inode;
-	int ino,res,is_hid;
+	loff_t i_pos;
+	int res, is_hid;
 	char msdos_name[MSDOS_NAME];
 
 	res = msdos_format_name(dentry->d_name.name,dentry->d_name.len,
@@ -288,15 +289,15 @@ int msdos_create(struct inode *dir,struc
 		return res;
 	is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
 	/* Have to do it due to foo vs. .foo conflicts */
-	if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
+	if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) {
 		fat_brelse(sb, bh);
 		return -EINVAL;
  	}
 	inode = NULL;
-	res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 0, is_hid);
+	res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 0, is_hid);
 	if (res)
 		return res;
-	inode = fat_build_inode(dir->i_sb, de, ino, &res);
+	inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
 	fat_brelse(sb, bh);
 	if (!inode)
 		return res;
@@ -311,13 +312,14 @@ int msdos_rmdir(struct inode *dir, struc
 {
 	struct super_block *sb = dir->i_sb;
 	struct inode *inode = dentry->d_inode;
-	int res,ino;
+	loff_t i_pos;
+	int res;
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 
 	bh = NULL;
 	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
-				&bh, &de, &ino);
+			 &bh, &de, &i_pos);
 	if (res < 0)
 		goto rmdir_done;
 	/*
@@ -352,7 +354,7 @@ int msdos_mkdir(struct inode *dir,struct
 	struct inode *inode;
 	int res,is_hid;
 	char msdos_name[MSDOS_NAME];
-	int ino;
+	loff_t i_pos;
 
 	res = msdos_format_name(dentry->d_name.name,dentry->d_name.len,
 				msdos_name, &MSDOS_SB(sb)->options);
@@ -360,13 +362,13 @@ int msdos_mkdir(struct inode *dir,struct
 		return res;
 	is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
 	/* foo vs .foo situation */
-	if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0)
+	if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0)
 		goto out_exist;
 
-	res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 1, is_hid);
+	res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid);
 	if (res)
 		goto out_unlock;
-	inode = fat_build_inode(dir->i_sb, de, ino, &res);
+	inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
 	if (!inode) {
 		fat_brelse(sb, bh);
 		goto out_unlock;
@@ -412,13 +414,14 @@ int msdos_unlink( struct inode *dir, str
 {
 	struct super_block *sb = dir->i_sb;
 	struct inode *inode = dentry->d_inode;
-	int res,ino;
+	loff_t i_pos;
+	int res;
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 
 	bh = NULL;
 	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
-			&bh, &de, &ino);
+			 &bh, &de, &i_pos);
 	if (res < 0)
 		goto unlink_done;
 
@@ -439,13 +442,13 @@ static int do_msdos_rename(struct inode 
     struct dentry *old_dentry,
     struct inode *new_dir,char *new_name, struct dentry *new_dentry,
     struct buffer_head *old_bh,
-    struct msdos_dir_entry *old_de, int old_ino, int is_hid)
+    struct msdos_dir_entry *old_de, loff_t old_i_pos, int is_hid)
 {
 	struct super_block *sb = old_dir->i_sb;
 	struct buffer_head *new_bh=NULL,*dotdot_bh=NULL;
 	struct msdos_dir_entry *new_de,*dotdot_de;
 	struct inode *old_inode,*new_inode;
-	int new_ino,dotdot_ino;
+	loff_t new_i_pos, dotdot_i_pos;
 	int error;
 	int is_dir;
 
@@ -453,7 +456,8 @@ static int do_msdos_rename(struct inode 
 	new_inode = new_dentry->d_inode;
 	is_dir = S_ISDIR(old_inode->i_mode);
 
-	if (fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)>=0 &&!new_inode)
+	if (fat_scan(new_dir, new_name, &new_bh, &new_de, &new_i_pos) >= 0
+	    && !new_inode)
 		goto degenerate_case;
 	if (is_dir) {
 		if (new_inode) {
@@ -462,7 +466,7 @@ static int do_msdos_rename(struct inode 
 				goto out;
 		}
 		error = fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
-				&dotdot_de, &dotdot_ino);
+				&dotdot_de, &dotdot_i_pos);
 		if (error < 0) {
 			printk(KERN_WARNING
 				"MSDOS: %s/%s, get dotdot failed, ret=%d\n",
@@ -473,7 +477,7 @@ static int do_msdos_rename(struct inode 
 	}
 	if (!new_bh) {
 		error = msdos_add_entry(new_dir, new_name, &new_bh, &new_de,
-					&new_ino, is_dir, is_hid);
+					&new_i_pos, is_dir, is_hid);
 		if (error)
 			goto out;
 	}
@@ -486,7 +490,7 @@ static int do_msdos_rename(struct inode 
 	old_de->name[0] = DELETED_FLAG;
 	fat_mark_buffer_dirty(sb, old_bh);
 	fat_detach(old_inode);
-	fat_attach(old_inode, new_ino);
+	fat_attach(old_inode, new_i_pos);
 	if (is_hid)
 		MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
 	else
@@ -542,8 +546,8 @@ int msdos_rename(struct inode *old_dir,s
 	struct super_block *sb = old_dir->i_sb;
 	struct buffer_head *old_bh;
 	struct msdos_dir_entry *old_de;
-	int old_ino, error;
-	int is_hid,old_hid; /* if new file and old file are hidden */
+	loff_t old_i_pos;
+	int error, is_hid, old_hid; /* if new file and old file are hidden */
 	char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
 
 	error = msdos_format_name(old_dentry->d_name.name,
@@ -559,13 +563,13 @@ int msdos_rename(struct inode *old_dir,s
 
 	is_hid  = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.');
 	old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.');
-	error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_ino);
+	error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_i_pos);
 	if (error < 0)
 		goto rename_done;
 
 	error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
 				new_dir, new_msdos_name, new_dentry,
-				old_bh, old_de, (ino_t)old_ino, is_hid);
+				old_bh, old_de, old_i_pos, is_hid);
 	fat_brelse(sb, old_bh);
 
 rename_done:
diff -puN fs/vfat/namei.c~fat_large-disk-2.4 fs/vfat/namei.c
--- linux-2.4.24-bk1/fs/vfat/namei.c~fat_large-disk-2.4	2003-12-16 02:29:29.000000000 +0900
+++ linux-2.4.24-bk1-hirofumi/fs/vfat/namei.c	2003-12-16 02:29:29.000000000 +0900
@@ -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,st
 	struct 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,st
 	vfat_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;
diff -puN include/linux/msdos_fs.h~fat_large-disk-2.4 include/linux/msdos_fs.h
--- linux-2.4.24-bk1/include/linux/msdos_fs.h~fat_large-disk-2.4	2003-12-16 02:29:29.000000000 +0900
+++ linux-2.4.24-bk1-hirofumi/include/linux/msdos_fs.h	2003-12-16 02:29:29.000000000 +0900
@@ -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_di
 extern 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);
diff -puN include/linux/msdos_fs_i.h~fat_large-disk-2.4 include/linux/msdos_fs_i.h
--- linux-2.4.24-bk1/include/linux/msdos_fs_i.h~fat_large-disk-2.4	2003-12-16 02:29:29.000000000 +0900
+++ linux-2.4.24-bk1-hirofumi/include/linux/msdos_fs_i.h	2003-12-16 02:29:29.000000000 +0900
@@ -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 */
 };

_

-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] FAT: Support the large partition (> 128GB) for 2.4
  2003-12-22 20:02 [PATCH] FAT: Support the large partition (> 128GB) for 2.4 OGAWA Hirofumi
@ 2003-12-31  9:14 ` Erik Andersen
  2004-01-04  9:07   ` OGAWA Hirofumi
  0 siblings, 1 reply; 4+ messages in thread
From: Erik Andersen @ 2003-12-31  9:14 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: linux-kernel, Marcelo Tosatti

On Tue Dec 23, 2003 at 05:02:01AM +0900, OGAWA Hirofumi wrote:
> 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).

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.



diff -urN linux/fs.orig/buffer.c linux/fs/buffer.c
--- linux/fs.orig/buffer.c	2003-12-31 00:34:57.000000000 -0700
+++ linux/fs/buffer.c	2003-12-31 00:45:40.000000000 -0700
@@ -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;
diff -urN linux/fs.orig/fat/dir.c linux/fs/fat/dir.c
--- linux/fs.orig/fat/dir.c	2003-12-31 00:36:59.000000000 -0700
+++ linux/fs/fat/dir.c	2003-12-31 01:22:34.000000000 -0700
@@ -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. */
diff -urN linux/fs.orig/fat/file.c linux/fs/fat/file.c
--- linux/fs.orig/fat/file.c	2001-08-12 11:56:56.000000000 -0600
+++ linux/fs/fat/file.c	2003-12-31 01:39:20.000000000 -0700
@@ -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;
 	}
diff -urN linux/fs.orig/fat/inode.c linux/fs/fat/inode.c
--- linux/fs.orig/fat/inode.c	2003-12-31 00:36:59.000000000 -0700
+++ linux/fs/fat/inode.c	2003-12-31 01:53:02.000000000 -0700
@@ -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 =
diff -urN linux/include/linux.orig/adfs_fs_i.h linux/include/linux/adfs_fs_i.h
--- linux/include/linux.orig/adfs_fs_i.h	2000-02-13 11:45:13.000000000 -0700
+++ linux/include/linux/adfs_fs_i.h	2003-12-31 00:45:40.000000000 -0700
@@ -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		*/
diff -urN linux/include/linux.orig/affs_fs_i.h linux/include/linux/affs_fs_i.h
--- linux/include/linux.orig/affs_fs_i.h	2001-11-22 12:46:19.000000000 -0700
+++ linux/include/linux/affs_fs_i.h	2003-12-31 00:45:40.000000000 -0700
@@ -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 */
diff -urN linux/include/linux.orig/fs.h linux/include/linux/fs.h
--- linux/include/linux.orig/fs.h	2003-12-31 00:34:59.000000000 -0700
+++ linux/include/linux/fs.h	2003-12-31 00:45:40.000000000 -0700
@@ -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 *);
diff -urN linux/include/linux.orig/hfs_fs_i.h linux/include/linux/hfs_fs_i.h
--- linux/include/linux.orig/hfs_fs_i.h	2001-02-13 15:13:44.000000000 -0700
+++ linux/include/linux/hfs_fs_i.h	2003-12-31 00:45:40.000000000 -0700
@@ -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 */
diff -urN linux/include/linux.orig/hpfs_fs_i.h linux/include/linux/hpfs_fs_i.h
--- linux/include/linux.orig/hpfs_fs_i.h	2000-02-10 13:17:00.000000000 -0700
+++ linux/include/linux/hpfs_fs_i.h	2003-12-31 00:45:40.000000000 -0700
@@ -2,7 +2,7 @@
 #define _HPFS_FS_I
 
 struct 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 */
diff -urN linux/include/linux.orig/msdos_fs_i.h linux/include/linux/msdos_fs_i.h
--- linux/include/linux.orig/msdos_fs_i.h	2003-12-31 00:36:59.000000000 -0700
+++ linux/include/linux/msdos_fs_i.h	2003-12-31 00:46:21.000000000 -0700
@@ -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--

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] FAT: Support the large partition (> 128GB) for 2.4
  2003-12-31  9:14 ` Erik Andersen
@ 2004-01-04  9:07   ` OGAWA Hirofumi
  2004-01-04  9:25     ` Erik Andersen
  0 siblings, 1 reply; 4+ messages in thread
From: OGAWA Hirofumi @ 2004-01-04  9:07 UTC (permalink / raw)
  To: andersen; +Cc: linux-kernel, Marcelo Tosatti

Erik Andersen <andersen@codepoet.org> writes:

> > 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.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] FAT: Support the large partition (> 128GB) for 2.4
  2004-01-04  9:07   ` OGAWA Hirofumi
@ 2004-01-04  9:25     ` Erik Andersen
  0 siblings, 0 replies; 4+ messages in thread
From: Erik Andersen @ 2004-01-04  9:25 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: linux-kernel, Marcelo Tosatti

On Sun Jan 04, 2004 at 06:07:35PM +0900, OGAWA Hirofumi wrote:
> Erik Andersen <andersen@codepoet.org> writes:
> 
> > > 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.

Yes, I suppose all filesystems should be fixed.

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

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2004-01-04  9:25 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-12-22 20:02 [PATCH] FAT: Support the large partition (> 128GB) for 2.4 OGAWA Hirofumi
2003-12-31  9:14 ` Erik Andersen
2004-01-04  9:07   ` OGAWA Hirofumi
2004-01-04  9:25     ` Erik Andersen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).