Re: VFS 64-bit clean

Jakub Jelinek (jj@sunsite.ms.mff.cuni.cz)
Wed, 25 Feb 1998 17:17:33 +0100 (MET)


> > The following patch adds support for large files on EXT2 on 64bit machines.
> > Once the kernel will be able to handle large files on 32bit machines, this can
> > be easily changed.
>
> Could you also provide patches for e2fsprogs ?
>

Ok, here they are. This patch to e2fsprogs-1.10 makes all e2fsprogs
understand large files and handle them correctly.
BTW: I found an ugly bug in libe2fs... It did not count correctly blocks
of sparse files, so if your filesystem would be trashed, e.g. e2fsck could
incorrectly fix it (I think).
Ted, can you review this patch and tell your comments?
I don't know how to solve the problem of the modified ext2_fs.h. At the
moment with this patch it is only possible to compile it with the patch I've
posted for the kernel.

BTW: I've put RPMS of this modified e2fsprogs in
ftp://ultra.linux.cz/OS/Linux/Sparc/local/e2fs/

--- ./lib/ext2fs/swapfs.c.orig Tue Mar 11 04:10:54 1997
+++ ./lib/ext2fs/swapfs.c Wed Feb 25 16:00:29 1998
@@ -97,7 +97,7 @@ void ext2fs_swap_inode(ext2_filsys fs, s
}
t->i_version = ext2fs_swab32(f->i_version);
t->i_file_acl = ext2fs_swab32(f->i_file_acl);
- t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
+ t->un1.i_dir_acl = ext2fs_swab32(f->un1.i_dir_acl);
t->i_faddr = ext2fs_swab32(f->i_faddr);

switch (fs->super->s_creator_os) {
--- ./lib/ext2fs/block.c.orig Fri Apr 18 02:21:46 1997
+++ ./lib/ext2fs/block.c Wed Feb 25 16:58:42 1998
@@ -318,6 +318,7 @@ errcode_t ext2fs_block_iterate2(ext2_fil
struct ext2_inode inode;
errcode_t retval;
struct block_context ctx;
+ int limit;

EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);

@@ -358,6 +359,8 @@ errcode_t ext2fs_block_iterate2(ext2_fil
goto abort;
}
}
+
+ limit = fs->blocksize >> 2;

/*
* Iterate over normal data blocks
@@ -375,13 +378,15 @@ errcode_t ext2fs_block_iterate2(ext2_fil
0, 0, &ctx);
if (ret & BLOCK_ABORT)
goto abort;
- }
+ } else
+ ctx.bcount += limit;
if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
0, 0, &ctx);
if (ret & BLOCK_ABORT)
goto abort;
- }
+ } else
+ ctx.bcount += limit * limit;
if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
0, 0, &ctx);
--- ./debugfs/debugfs.c.orig Fri Apr 11 05:48:16 1997
+++ ./debugfs/debugfs.c Wed Feb 25 16:00:29 1998
@@ -306,16 +306,23 @@ static void dump_inode(ino_t inode_num,
fprintf(out, "Inode: %ld Type: %s ", inode_num, i_type);
fprintf(out, "Mode: %04o Flags: 0x%x Version: %d\n",
inode.i_mode & 0777, inode.i_flags, inode.i_version);
- fprintf(out, "User: %5d Group: %5d Size: %d\n",
- inode.i_uid, inode.i_gid, inode.i_size);
+ fprintf(out, "User: %5d Group: %5d Size: ",
+ inode.i_uid, inode.i_gid);
+ if (LINUX_S_ISDIR(inode.i_mode))
+ fprintf(out, "%d\n", inode.i_size);
+ else {
+ unsigned long long i_size = inode.i_size | ((unsigned long long)inode.un1.i_size_high << 32);
+
+ fprintf(out, "%lld\n", i_size);
+ }
if (current_fs->super->s_creator_os == EXT2_OS_HURD)
fprintf(out,
"File ACL: %d Directory ACL: %d Translator: %d\n",
- inode.i_file_acl, inode.i_dir_acl,
+ inode.i_file_acl, LINUX_S_ISDIR(inode.i_mode) ? inode.un1.i_dir_acl : 0,
inode.osd1.hurd1.h_i_translator);
else
fprintf(out, "File ACL: %d Directory ACL: %d\n",
- inode.i_file_acl, inode.i_dir_acl);
+ inode.i_file_acl, LINUX_S_ISDIR(inode.i_mode) ? inode.un1.i_dir_acl : 0);
fprintf(out, "Links: %d Blockcount: %d\n", inode.i_links_count,
inode.i_blocks);
switch (os) {
@@ -681,7 +688,10 @@ void do_modify_inode(int argc, char *arg
modify_u32(argv[0], "Reserved1", decimal_format, &inode.i_reserved1);
#endif
modify_u32(argv[0], "File acl", decimal_format, &inode.i_file_acl);
- modify_u32(argv[0], "Directory acl", decimal_format, &inode.i_dir_acl);
+ if (LINUX_S_ISDIR(inode.i_mode))
+ modify_u32(argv[0], "Directory acl", decimal_format, &inode.un1.i_dir_acl);
+ else
+ modify_u32(argv[0], "High 32bits of size", decimal_format, &inode.un1.i_size_high);

if (current_fs->super->s_creator_os == EXT2_OS_HURD)
modify_u32(argv[0], "Translator Block",
--- ./debugfs/dump.c.orig Sat Sep 7 23:08:29 1996
+++ ./debugfs/dump.c Wed Feb 25 16:00:29 1998
@@ -133,6 +133,12 @@ static void dump_file(char *cmdname, ino
rec.errcode = 0;
rec.buf = malloc(current_fs->blocksize);
rec.left = inode.i_size;
+
+ if (!S_ISDIR(inode.i_mode) && inode.un1.i_size_high) {
+ com_err(cmdname, EFBIG,
+ "dumping of files larger than 4G not supported");
+ return;
+ }

if (rec.buf == 0) {
com_err(cmdname, ENOMEM,
--- ./debugfs/ls.c.orig Thu Apr 10 22:58:43 1997
+++ ./debugfs/ls.c Wed Feb 25 16:03:13 1998
@@ -51,8 +51,13 @@ static void ls_l_file(struct list_dir_st
sprintf(datestr, "%2d-%s-%2d %02d:%02d",
tm_p->tm_mday, monstr[tm_p->tm_mon], tm_p->tm_year,
tm_p->tm_hour, tm_p->tm_min);
- fprintf(ls->f, "%6d %6o %5d %5d %5d %s %s\n", ino, inode.i_mode,
- inode.i_uid, inode.i_gid, inode.i_size, datestr, name);
+ fprintf(ls->f, "%6d %6o %5d %5d ", ino, inode.i_mode,
+ inode.i_uid, inode.i_gid);
+ if (LINUX_S_ISDIR(inode.i_mode))
+ fprintf(ls->f, "%5d", inode.i_size);
+ else
+ fprintf(ls->f, "%5lld", inode.i_size | ((unsigned long long)inode.un1.i_size_high << 32));
+ fprintf (ls->f, " %s %s\n", datestr, name);
}

static void ls_file(struct list_dir_struct *ls, char *name,
--- ./debugfs/lsdel.c.orig Thu Jan 2 05:53:24 1997
+++ ./debugfs/lsdel.c Wed Feb 25 16:00:29 1998
@@ -23,7 +23,7 @@ struct deleted_info {
ino_t ino;
unsigned short mode;
unsigned short uid;
- unsigned long size;
+ unsigned long long size;
time_t dtime;
int num_blocks;
int free_blocks;
@@ -148,6 +148,9 @@ void do_lsdel(int argc, char **argv)
delarray[num_delarray].mode = inode.i_mode;
delarray[num_delarray].uid = inode.i_uid;
delarray[num_delarray].size = inode.i_size;
+ if (!LINUX_S_ISDIR(inode.i_mode))
+ delarray[num_delarray].size |=
+ ((unsigned long long)inode.un1.i_size_high << 32);
delarray[num_delarray].dtime = inode.i_dtime;
delarray[num_delarray].num_blocks = lsd.num_blocks;
delarray[num_delarray].free_blocks = lsd.free_blocks;
@@ -170,7 +173,7 @@ void do_lsdel(int argc, char **argv)
deleted_info_compare);

for (i = 0; i < num_delarray; i++) {
- printf("%6lu %6d %6o %6lu %4d/%4d %s", delarray[i].ino,
+ printf("%6lu %6d %6o %6llu %4d/%4d %s", delarray[i].ino,
delarray[i].uid, delarray[i].mode, delarray[i].size,
delarray[i].free_blocks, delarray[i].num_blocks,
time_to_string(delarray[i].dtime));
--- ./e2fsck/message.c.orig Fri Mar 7 19:35:39 1997
+++ ./e2fsck/message.c Wed Feb 25 16:00:29 1998
@@ -182,7 +182,11 @@ static _INLINE_ void expand_inode_expres

switch (ch) {
case 's':
- printf("%u", inode->i_size);
+ if (LINUX_S_ISDIR(inode->i_mode))
+ printf("%u", inode->i_size);
+ else
+ printf("%llu", inode->i_size |
+ ((unsigned long long)inode->un1.i_size_high << 32));
break;
case 'b':
printf("%u", inode->i_blocks);
@@ -205,7 +209,10 @@ static _INLINE_ void expand_inode_expres
printf("%u", inode->i_file_acl);
break;
case 'd':
- printf("%u", inode->i_dir_acl);
+ if (LINUX_S_ISDIR(inode->i_mode))
+ printf("%u", inode->un1.i_dir_acl);
+ else
+ printf("0");
break;
default:
no_inode:
@@ -276,7 +283,7 @@ static _INLINE_ void expand_percent_expr
printf("%lu", ctx->ino2);
break;
case 'N':
- printf("%u", ctx->num);
+ printf("%llu", ctx->num);
break;
case 'p':
print_pathname(fs, ctx->ino, 0);
--- ./e2fsck/pass1.c.orig Thu Apr 10 14:49:38 1997
+++ ./e2fsck/pass1.c Wed Feb 25 17:00:39 1998
@@ -103,6 +103,7 @@ struct process_block_struct {
int last_block;
int num_illegal_blocks;
blk_t previous_block;
+ unsigned long long i_size;
struct ext2_inode *inode;
struct problem_context *pctx;
};
@@ -276,6 +277,7 @@ void pass1(ext2_filsys fs)
pb.num_illegal_blocks = 0;
pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
pb.fragmented = 0;
+ pb.i_size = inode.i_size;
pb.inode = &inode;
pb.pctx = &pctx;
retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
@@ -390,7 +392,8 @@ void pass1(ext2_filsys fs)
}

if (inode.i_faddr || frag || fsize
- || inode.i_file_acl || inode.i_dir_acl) {
+ || inode.i_file_acl ||
+ (LINUX_S_ISDIR(inode.i_mode) && inode.un1.i_dir_acl)) {
if (!inode_bad_map)
alloc_bad_map(fs);
ext2fs_mark_inode_bitmap(inode_bad_map, ino);
@@ -636,6 +639,10 @@ static void check_blocks(ext2_filsys fs,
pb.is_dir = LINUX_S_ISDIR(pctx->inode->i_mode);
pb.inode = inode;
pb.pctx = pctx;
+ if (pb.is_dir)
+ pb.i_size = inode->i_size;
+ else
+ pb.i_size = inode->i_size | ((unsigned long long)inode->un1.i_size_high << 32);
retval = ext2fs_block_iterate2(fs, ino,
pb.is_dir ? BLOCK_FLAG_HOLE : 0,
block_buf, process_block, &pb);
@@ -671,8 +678,8 @@ static void check_blocks(ext2_filsys fs,

pb.num_blocks *= (fs->blocksize / 512);
#if 0
- printf("inode %u, i_size = %lu, last_block = %lu, i_blocks=%lu, num_blocks = %lu\n",
- ino, inode->i_size, pb.last_block, inode->i_blocks,
+ printf("inode %u, i_size = %llu, last_block = %lu, i_blocks=%lu, num_blocks = %lu\n",
+ ino, pb.i_size, pb.last_block, inode->i_blocks,
pb.num_blocks);
#endif
if (!pb.num_blocks && pb.is_dir) {
@@ -687,12 +694,17 @@ static void check_blocks(ext2_filsys fs,
pb.is_dir = 0;
}
}
- if ((pb.is_dir && (inode->i_size !=
+ if ((pb.is_dir && (pb.i_size !=
(pb.last_block + 1) * fs->blocksize)) ||
- (inode->i_size < pb.last_block * fs->blocksize)) {
- pctx->num = (pb.last_block+1) * fs->blocksize;
+ (pb.i_size < (unsigned long long)pb.last_block * fs->blocksize)) {
+ pctx->num = ((unsigned long long)(pb.last_block+1)) * fs->blocksize;
if (fix_problem(fs, PR_1_BAD_I_SIZE, pctx)) {
- inode->i_size = pctx->num;
+ if (pb.is_dir)
+ inode->i_size = pctx->num;
+ else {
+ inode->i_size = pctx->num;
+ inode->un1.i_size_high = pctx->num >> 32;
+ }
e2fsck_write_inode(fs, ino, inode, "check_blocks");
}
pctx->num = 0;
@@ -792,7 +804,7 @@ int process_block(ext2_filsys fs,
}
if (blockcnt < 0)
return 0;
- if (blockcnt * fs->blocksize < p->inode->i_size) {
+ if ((long long)blockcnt * fs->blocksize < p->i_size) {
#if 0
printf("Missing block (#%d) in directory inode %lu!\n",
blockcnt, p->ino);
--- ./e2fsck/problem.h.orig Sun Apr 6 16:17:13 1997
+++ ./e2fsck/problem.h Wed Feb 25 16:00:29 1998
@@ -15,7 +15,7 @@ struct problem_context {
struct ext2_dir_entry *dirent;
blk_t blk;
int blkcount, group;
- __u32 num;
+ unsigned long long num;
};

struct e2fsck_problem {
--- ./e2fsck/pass2.c.orig Fri Apr 4 17:55:20 1997
+++ ./e2fsck/pass2.c Wed Feb 25 16:00:29 1998
@@ -595,9 +595,10 @@ static int process_bad_inode(ext2_filsys
inode.i_file_acl = 0;
inode_modified++;
}
- if (inode.i_dir_acl &&
+ if (LINUX_S_ISDIR(inode.i_mode) &&
+ inode.un1.i_dir_acl &&
fix_problem(fs, PR_2_DIR_ACL_ZERO, &pctx)) {
- inode.i_dir_acl = 0;
+ inode.un1.i_dir_acl = 0;
inode_modified++;
}
if (inode_modified)
@@ -620,6 +621,7 @@ static int allocate_dir_block(ext2_filsy
char *block;
struct ext2_inode inode;
errcode_t retval;
+ unsigned long long i_size;

if (fix_problem(fs, PR_2_DIRECTORY_HOLE, pctx) == 0)
return 1;
@@ -671,8 +673,17 @@ static int allocate_dir_block(ext2_filsy
*/
e2fsck_read_inode(fs, db->ino, &inode, "allocate_dir_block");
inode.i_blocks += fs->blocksize / 512;
- if (inode.i_size < (db->blockcnt+1) * fs->blocksize)
- inode.i_size = (db->blockcnt+1) * fs->blocksize;
+ if (LINUX_S_ISDIR(inode.i_mode))
+ i_size = inode.i_size;
+ else
+ i_size = inode.i_size |
+ ((unsigned long long)inode.un1.i_size_high << 32);
+ if (i_size < ((unsigned long long)db->blockcnt+1) * fs->blocksize) {
+ i_size = ((unsigned long long)db->blockcnt+1) * fs->blocksize;
+ inode.i_size = i_size;
+ if ((i_size >> 32) && !LINUX_S_ISDIR(inode.i_mode))
+ inode.un1.i_size_high = i_size >> 32;
+ }
e2fsck_write_inode(fs, db->ino, &inode, "allocate_dir_block");

/*
--- ./include/linux/ext2_fs.h.orig Sun Apr 6 18:30:40 1997
+++ ./include/linux/ext2_fs.h Wed Feb 25 16:00:29 1998
@@ -229,7 +229,10 @@ struct ext2_inode {
__u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
__u32 i_version; /* File version (for NFS) */
__u32 i_file_acl; /* File ACL */
- __u32 i_dir_acl; /* Directory ACL */
+ union {
+ __u32 i_dir_acl; /* Directory ACL */
+ __u32 i_size_high; /* High 32bits of size */
+ } un1;
__u32 i_faddr; /* Fragment address */
union {
struct {

Cheers,
Jakub
___________________________________________________________________
Jakub Jelinek | jj@sunsite.mff.cuni.cz | http://sunsite.mff.cuni.cz
Administrator of SunSITE Czech Republic, MFF, Charles University
___________________________________________________________________
Ultralinux - first 64bit OS to take full power of the UltraSparc
Linux version 2.1.88 on a sparc64 machine (498.80 BogoMips).
___________________________________________________________________

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu