From: Vijay Kumar <jkumar@qualcomm.com>
To: Alan.Cox@linux.org
Cc: linux-kernel@vger.kernel.org
Subject: kernel patch support large fat partitions
Date: Thu, 03 Jan 2002 15:42:20 -0800 [thread overview]
Message-ID: <5.1.0.14.0.20020103152205.039f2008@mage.qualcomm.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1679 bytes --]
Alan,
This is regarding a change I had to make to the kernel 2.2.17-14 to support
really large drives. In our project we deal with huge drives, sometimes
drives larger than 128GB. The file system is FAT32 and only one partition
is create on any drive. During our testing we realized that linux fat
implementation doesn't support partitions larger than 128GB(actually 64GB
because of a bug in fat implementation).
This limitation is imposed by the data structures used by the linux fat
implementation to read/write directory entries. A 'long' data type is used
to access directory entries on the disk, of which only 28 bits are used to
identify the sector that contains the directory entry and the rest 4 bits
are used to specify offset of the directory entry inside the sector. Using
28 bits to identify a sector means we cannot access sectors beyond 128GB
(2^28*512), thus limiting us from creating partitions larger than 128GB on
large disk drives.
I have made changes to fat, vfat and msdos file system implementations in
the kernel to use larger data types, thus allowing us to create larger
partitions. As per the GPL I would like to make the patch available to
everyone and also in case somebody has run into the same problem(who cares
about fat in the linux world). The patch has been fairly well tested only
on our systems(p3, 700MHz with FC). I truly appreciate if you & anybody in
the kernel mailing list have any feedback about the changes.
The patch is applicable to only 2.2.17-14 kernel and may require changes to
use with other kernel versions. As far as I know none of the kernel
versions provide any fix for this problem.
Thanks,
- Vijay
[-- Attachment #2: linux-2.2.17-fat-qualcomm-128GB-limit.patch --]
[-- Type: application/octet-stream, Size: 12208 bytes --]
diff -u -r linux.orig/fs/fat/dir.c linux/fs/fat/dir.c
--- linux.orig/fs/fat/dir.c Fri Nov 9 17:07:02 2001
+++ linux/fs/fat/dir.c Fri Nov 9 18:05:29 2001
@@ -129,7 +129,8 @@
loff_t *spos, loff_t *lpos)
{
struct super_block *sb = inode->i_sb;
- int ino,i,i2,last;
+ int i,i2,last;
+ loff_t ino;
char c;
struct buffer_head *bh = NULL;
struct msdos_dir_entry *de;
@@ -292,7 +293,8 @@
int both)
{
struct super_block *sb = inode->i_sb;
- int ino,inum,i,i2,last;
+ int i,i2,last;
+ loff_t ino, inum;
char c;
struct buffer_head *bh;
struct msdos_dir_entry *de;
@@ -587,7 +589,8 @@
loff_t pos;
struct buffer_head *bh;
struct msdos_dir_entry *de;
- int ino,result = 0;
+ int result = 0;
+ loff_t ino;
pos = 0;
bh = NULL;
@@ -611,7 +614,7 @@
/* 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 *ino)
{
struct super_block *sb = dir->i_sb;
loff_t offset, curr;
diff -u -r linux.orig/fs/fat/inode.c linux/fs/fat/inode.c
--- linux.orig/fs/fat/inode.c Fri Nov 9 17:07:02 2001
+++ linux/fs/fat/inode.c Fri Nov 9 19:06:58 2001
@@ -90,7 +90,7 @@
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;
list_add(&MSDOS_I(inode)->i_fat_hash,
@@ -106,7 +106,7 @@
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;
struct msdos_inode_info *i;
@@ -127,7 +127,7 @@
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 ino, int *res)
{
struct inode *inode;
*res = 0;
@@ -839,13 +839,13 @@
struct super_block *sb = inode->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *raw_entry;
- int i_pos;
+ loff_t i_pos;
retry:
i_pos = MSDOS_I(inode)->i_location;
if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) return;
- if (!(bh = fat_bread(sb, ((unsigned int) i_pos) >> MSDOS_DPB_BITS))) {
- printk("dev = %s, ino = %d\n", kdevname(inode->i_dev), i_pos);
+ if (!(bh = fat_bread(sb, ((unsigned long long) i_pos) >> MSDOS_DPB_BITS))) {
+ printk("dev = %s, ino = %ld\n", kdevname(inode->i_dev), i_pos);
fat_fs_panic(sb, "msdos_write_inode: unable to read i-node block");
return;
}
diff -u -r linux.orig/fs/fat/misc.c linux/fs/fat/misc.c
--- linux.orig/fs/fat/misc.c Fri Nov 9 17:07:02 2001
+++ linux/fs/fat/misc.c Fri Nov 9 17:17:09 2001
@@ -341,10 +341,10 @@
*/
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 *ino)
{
struct super_block *sb = dir->i_sb;
- int sector, offset;
+ long long sector, offset;
while (1) {
offset = *pos;
@@ -420,8 +420,8 @@
(*number)++; \
}
-static int raw_scan_sector(struct super_block *sb,int sector,const char *name,
- int *number,int *ino,struct buffer_head **res_bh,
+static int raw_scan_sector(struct super_block *sb,long long sector,
+ const char *name, int *number,loff_t *ino,struct buffer_head **res_bh,
struct msdos_dir_entry **res_de)
{
struct buffer_head *bh;
@@ -467,7 +467,7 @@
* 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,
+static int raw_scan_root(struct super_block *sb,const char *name,int *number,loff_t *ino,
struct buffer_head **res_bh,struct msdos_dir_entry **res_de)
{
int count,cluster;
@@ -486,7 +486,7 @@
*/
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
+ int *number,loff_t *ino,struct buffer_head **res_bh,struct msdos_dir_entry
**res_de)
{
int count,cluster;
@@ -522,7 +522,7 @@
*/
static int raw_scan(struct super_block *sb, int start, const char *name,
- int *number, int *ino, struct buffer_head **res_bh,
+ int *number, loff_t *ino, struct buffer_head **res_bh,
struct msdos_dir_entry **res_de)
{
if (start) return raw_scan_nonroot
@@ -613,7 +613,7 @@
*/
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 *ino)
{
int res;
Only in linux/fs/msdos: .depend
diff -u -r linux.orig/fs/msdos/namei.c linux/fs/msdos/namei.c
--- linux.orig/fs/msdos/namei.c Wed Nov 14 23:17:25 2001
+++ linux/fs/msdos/namei.c Wed Nov 14 23:14:15 2001
@@ -126,7 +126,7 @@
/***** 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)
+ struct buffer_head **bh,struct msdos_dir_entry **de,loff_t *ino)
{
int res;
char dotsOK;
@@ -220,7 +220,8 @@
struct inode *inode = NULL;
struct msdos_dir_entry *de;
struct buffer_head *bh = NULL;
- int ino,res;
+ int res;
+ loff_t ino;
PRINTK (("msdos_lookup\n"));
@@ -249,7 +250,7 @@
static int msdos_add_entry(struct inode *dir, const char *name,
struct buffer_head **bh,
struct msdos_dir_entry **de,
- int *ino,
+ loff_t *ino,
int is_dir, int is_hid)
{
struct super_block *sb = dir->i_sb;
@@ -285,7 +286,8 @@
struct buffer_head *bh;
struct msdos_dir_entry *de;
struct inode *inode;
- int ino,res,is_hid;
+ int res,is_hid;
+ loff_t ino;
char msdos_name[MSDOS_NAME];
res = msdos_format_name(MSDOS_SB(sb)->options.name_check,
@@ -318,7 +320,8 @@
{
struct super_block *sb = dir->i_sb;
struct inode *inode = dentry->d_inode;
- int res,ino;
+ int res;
+ loff_t ino;
struct buffer_head *bh;
struct msdos_dir_entry *de;
@@ -365,7 +368,7 @@
char msdos_name[MSDOS_NAME];
struct buffer_head *bh1;
struct msdos_dir_entry *de1;
- int ino;
+ loff_t ino;
res = msdos_format_name(MSDOS_SB(sb)->options.name_check,
dentry->d_name.name,dentry->d_name.len,
@@ -451,7 +454,8 @@
{
struct super_block *sb = dir->i_sb;
struct inode *inode = dentry->d_inode;
- int res,ino;
+ int res;
+ loff_t ino;
struct buffer_head *bh;
struct msdos_dir_entry *de;
@@ -479,13 +483,13 @@
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_ino, 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_ino,dotdot_ino;
int error;
int is_dir;
@@ -582,7 +586,8 @@
struct super_block *sb = old_dir->i_sb;
struct buffer_head *old_bh;
struct msdos_dir_entry *old_de;
- int old_ino, error;
+ int error;
+ loff_t old_ino;
int is_hid,old_hid; /* if new file and old file are hidden */
char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
@@ -605,7 +610,7 @@
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_ino, is_hid);
fat_brelse(sb, old_bh);
rename_done:
diff -u -r linux.orig/fs/vfat/namei.c linux/fs/vfat/namei.c
--- linux.orig/fs/vfat/namei.c Fri Nov 9 17:07:07 2001
+++ linux/fs/vfat/namei.c Fri Nov 9 18:05:45 2001
@@ -419,7 +419,8 @@
{
struct msdos_dir_entry *de;
struct buffer_head *bh = NULL;
- int ino,res;
+ int res;
+ loff_t ino;
res=fat_scan(dir,name,&bh,&de,&ino);
fat_brelse(dir->i_sb, bh);
@@ -809,7 +810,7 @@
int res;
struct msdos_dir_entry *de1;
struct buffer_head *bh1;
- int ino;
+ loff_t ino;
int len;
loff_t dummy;
@@ -1020,7 +1021,8 @@
{
struct super_block *sb = dir->i_sb;
loff_t offset;
- int i,ino;
+ int i;
+ loff_t ino;
/* remove the shortname */
dir->i_mtime = CURRENT_TIME;
@@ -1145,7 +1147,7 @@
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_ino;
struct inode *old_inode, *new_inode;
int res, is_dir;
struct vfat_slot_info old_sinfo,sinfo;
diff -u -r linux.orig/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- linux.orig/include/linux/msdos_fs.h Fri Nov 9 17:33:51 2001
+++ linux/include/linux/msdos_fs.h Fri Nov 9 19:07:04 2001
@@ -167,7 +167,7 @@
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 ino; /* ino for the file */
};
/* Determine whether this FS has kB-aligned data. */
@@ -203,9 +203,9 @@
extern void fat_unlock_creation(void);
extern void fat_date_unix2dos(int unix_date,__u16 *time, __u16 *date);
extern 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 *ino);
static __inline__ int fat_get_entry(struct inode *dir,loff_t *pos,
- struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
+ struct buffer_head **bh,struct msdos_dir_entry **de,loff_t *ino)
{
/* Fast stuff first */
if (*bh && *de &&
@@ -218,7 +218,7 @@
return fat__get_entry(dir,pos,bh,de,ino);
}
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 *ino);
extern int fat_parent_ino(struct inode *dir,int locked);
extern int fat_subdirs(struct inode *dir);
void fat_clusters_flush(struct super_block *sb);
@@ -241,10 +241,10 @@
extern void fat_clear_inode(struct inode *inode);
extern void fat_delete_inode(struct inode *inode);
extern void fat_put_super(struct super_block *sb);
-extern void fat_attach(struct inode *inode, int ino);
+extern void fat_attach(struct inode *inode, loff_t ino);
extern void fat_detach(struct inode *inode);
-extern struct inode *fat_iget(struct super_block*,int);
-extern struct inode *fat_build_inode(struct super_block*,struct msdos_dir_entry*,int,int*);
+extern struct inode *fat_iget(struct super_block*,loff_t);
+extern struct inode *fat_build_inode(struct super_block*,struct msdos_dir_entry*,loff_t,int*);
extern struct super_block *fat_read_super(struct super_block *s, void *data, int silent, struct inode_operations *dir_ops);
extern void msdos_put_super(struct super_block *sb);
extern int fat_statfs(struct super_block *sb,struct statfs *buf, int);
@@ -259,7 +259,7 @@
extern int fat_dir_ioctl(struct inode * inode, struct file * filp,
unsigned int cmd, unsigned long arg);
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 *ino);
int fat_dir_empty(struct inode *dir);
/* file.c */
diff -u -r linux.orig/include/linux/msdos_fs_i.h linux/include/linux/msdos_fs_i.h
--- linux.orig/include/linux/msdos_fs_i.h Fri Nov 9 18:16:49 2001
+++ linux/include/linux/msdos_fs_i.h Fri Nov 9 18:17:20 2001
@@ -30,7 +30,7 @@
int i_attrs; /* unused attribute bits */
int i_ctime_ms; /* unused change time in milliseconds */
int i_binary; /* file contains non-text data */
- int i_location; /* on-disk position of directory entry or 0 */
+ loff_t i_location; /* 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 */
off_t i_last_pos;/* position of last lookup */
next reply other threads:[~2002-01-03 23:42 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-01-03 23:42 Vijay Kumar [this message]
2002-01-04 0:24 ` Andreas Dilger
2002-01-04 0:34 ` Vijay Kumar
2002-01-04 2:48 ` CJ
2002-01-04 18:52 ` Vijay Kumar
2002-01-05 20:40 ` H. Peter Anvin
2002-01-05 0:12 ` Vijay Kumar
2002-01-04 10:40 Randal, Phil
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5.1.0.14.0.20020103152205.039f2008@mage.qualcomm.com \
--to=jkumar@qualcomm.com \
--cc=Alan.Cox@linux.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®