Commit 29a54a41 authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Linus Torvalds

[PATCH] HPFS fixes for 2.6.7 kernel

This contains hpfs fixes from my source ported to 2.6.7 kernel:

updates:
- allocator fragments files less
- OS/2 Warp Server filesystem can be mounted read/only
- added reschedule points so that it doesn't hog CPU

bug fixes:
- filesystem error message when syncing or fsyncing deleted file (or when
  system just writes it on its own)
- filesystem error on extremly fragmented files
- corrupted disk structures could possibly corrupt memory
parent 2c4d93fe
Read/Write HPFS 2.05
1998-2001, Mikulas Patocka
Read/Write HPFS 2.09
1998-2004, Mikulas Patocka
email: mikulas@artax.karlin.mff.cuni.cz
homepage: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
......@@ -283,6 +283,14 @@ History
2.05 Fixed crash when got mount parameters without =
Fixed crash when allocation of anode failed due to full disk
Fixed some crashes when block io or inode allocation failed
2.06 Fixed some crash on corrupted disk structures
Better allocation strategy
Reschedule points added so that it doesn't lock CPU long time
It should work in read-only mode on Warp Server
2.07 More fixes for Warp Server. Now it really works
2.08 Creating new files is not so slow on large disks
An attempt to sync deleted file does not generate filesystem error
2.09 Fixed error on extremly fragmented files
vim: set textwidth=80:
......@@ -79,11 +79,11 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne
} else {
if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) goto uls;
}
/*if (!tstbits(bmp, nr + n, n + forward)) {
if (!tstbits(bmp, nr, n + forward)) {
ret = bs + nr;
goto rt;
}
if (!tstbits(bmp, nr + 2*n, n + forward)) {
/*if (!tstbits(bmp, nr + n, n + forward)) {
ret = bs + nr + n;
goto rt;
}*/
......@@ -103,9 +103,11 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne
goto rt;
}
nr >>= 5;
for (i = nr + 1; i != nr; i++, i &= 0x1ff) {
if (!bmp[i]) continue;
if (n + forward >= 0x3f && bmp[i] != -1) continue;
/*for (i = nr + 1; i != nr; i++, i &= 0x1ff) {*/
i = nr;
do {
if (!bmp[i]) goto cont;
if (n + forward >= 0x3f && bmp[i] != -1) goto cont;
q = i<<5;
if (i > 0) {
unsigned k = bmp[i-1];
......@@ -123,7 +125,9 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne
ret = bs + q;
goto rt;
}
}
cont:
i++, i &= 0x1ff;
} while (i != nr);
rt:
if (ret) {
if (hpfs_sb(s)->sb_chk && ((ret >> 14) != (bs >> 14) || (bmp[(ret & 0x3fff) >> 5] | ~(((1 << n) - 1) << (ret & 0x1f))) != 0xffffffff)) {
......@@ -152,45 +156,56 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne
secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forward, int lock)
{
secno sec;
unsigned i;
int i;
unsigned n_bmps;
struct hpfs_sb_info *sbi = hpfs_sb(s);
int b = sbi->sb_c_bitmap;
int f_p = 0;
int near_bmp;
if (forward < 0) {
forward = -forward;
f_p = 1;
}
if (lock) hpfs_lock_creation(s);
if (near && near < sbi->sb_fs_size)
n_bmps = (sbi->sb_fs_size + 0x4000 - 1) >> 14;
if (near && near < sbi->sb_fs_size) {
if ((sec = alloc_in_bmp(s, near, n, f_p ? forward : forward/4))) goto ret;
near_bmp = near >> 14;
} else near_bmp = n_bmps / 2;
/*
if (b != -1) {
if ((sec = alloc_in_bmp(s, b<<14, n, f_p ? forward : forward/2))) {
b &= 0x0fffffff;
goto ret;
}
if (b > 0x10000000) if ((sec = alloc_in_bmp(s, (b&0xfffffff)<<14, n, f_p ? forward : 0))) goto ret;
*/
if (!f_p) if (forward > sbi->sb_max_fwd_alloc) forward = sbi->sb_max_fwd_alloc;
less_fwd:
for (i = 0; i < n_bmps; i++) {
if (near_bmp+i < n_bmps && ((sec = alloc_in_bmp(s, (near_bmp+i) << 14, n, forward)))) {
sbi->sb_c_bitmap = near_bmp+i;
goto ret;
}
n_bmps = (sbi->sb_fs_size + 0x4000 - 1) >> 14;
for (i = 0; i < n_bmps / 2; i++) {
if ((sec = alloc_in_bmp(s, (n_bmps/2+i) << 14, n, forward))) {
sbi->sb_c_bitmap = n_bmps/2+i;
if (!forward) {
if (near_bmp-i-1 >= 0 && ((sec = alloc_in_bmp(s, (near_bmp-i-1) << 14, n, forward)))) {
sbi->sb_c_bitmap = near_bmp-i-1;
goto ret;
}
if ((sec = alloc_in_bmp(s, (n_bmps/2-i-1) << 14, n, forward))) {
sbi->sb_c_bitmap = n_bmps/2-i-1;
} else {
if (near_bmp+i >= n_bmps && ((sec = alloc_in_bmp(s, (near_bmp+i-n_bmps) << 14, n, forward)))) {
sbi->sb_c_bitmap = near_bmp+i-n_bmps;
goto ret;
}
}
if ((sec = alloc_in_bmp(s, (n_bmps-1) << 14, n, forward))) {
sbi->sb_c_bitmap = n_bmps-1;
if (i == 1 && sbi->sb_c_bitmap != -1 && ((sec = alloc_in_bmp(s, (sbi->sb_c_bitmap) << 14, n, forward)))) {
goto ret;
}
}
if (!f_p) {
for (i = 0; i < n_bmps; i++)
if ((sec = alloc_in_bmp(s, i << 14, n, 0))) {
sbi->sb_c_bitmap = 0x10000000 + i;
goto ret;
if (forward) {
sbi->sb_max_fwd_alloc = forward * 3 / 4;
forward /= 2;
goto less_fwd;
}
}
sec = 0;
......@@ -262,6 +277,7 @@ void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n)
{
struct quad_buffer_head qbh;
unsigned *bmp;
struct hpfs_sb_info *sbi = hpfs_sb(s);
/*printk("2 - ");*/
if (!n) return;
if (sec < 0x12) {
......@@ -269,6 +285,8 @@ void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n)
return;
}
lock_super(s);
sbi->sb_max_fwd_alloc += n > 0xffff ? 0xffff : n;
if (sbi->sb_max_fwd_alloc > 0xffffff) sbi->sb_max_fwd_alloc = 0xffffff;
new_map:
if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "free"))) {
unlock_super(s);
......@@ -321,7 +339,7 @@ int hpfs_check_free_dnodes(struct super_block *s, int n)
}
hpfs_brelse4(&qbh);
i = 0;
if (hpfs_sb(s)->sb_c_bitmap != -1 ) {
if (hpfs_sb(s)->sb_c_bitmap != -1) {
bmp = hpfs_map_bitmap(s, b, &qbh, "chkdn1");
goto chk_bmp;
}
......
......@@ -113,7 +113,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
brelse(bh);
return -1;
}
se = node;
se = !fnod ? node : (node + 16384) & ~16383;
}
if (!(se = hpfs_alloc_sector(s, se, 1, fsecno*ALLOC_M>ALLOC_FWD_MAX ? ALLOC_FWD_MAX : fsecno*ALLOC_M<ALLOC_FWD_MIN ? ALLOC_FWD_MIN : fsecno*ALLOC_M, 1))) {
brelse(bh);
......@@ -192,7 +192,6 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
}
up = up != node ? anode->up : -1;
btree->u.internal[btree->n_used_nodes - 1].file_secno = /*fs*/-1;
if (up == -1) anode->up = ra;
mark_buffer_dirty(bh);
brelse(bh);
a = na;
......
......@@ -31,6 +31,8 @@ void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head
{
struct buffer_head *bh;
cond_resched();
*bhp = bh = sb_bread(s, secno);
if (bh != NULL)
return bh->b_data;
......@@ -47,6 +49,8 @@ void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head
struct buffer_head *bh;
/*return hpfs_map_sector(s, secno, bhp, 0);*/
cond_resched();
if ((*bhp = bh = sb_getblk(s, secno)) != NULL) {
if (!buffer_uptodate(bh)) wait_on_buffer(bh);
set_buffer_uptodate(bh);
......@@ -65,6 +69,8 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe
struct buffer_head *bh;
char *data;
cond_resched();
if (secno & 3) {
printk("HPFS: hpfs_map_4sectors: unaligned read\n");
return 0;
......@@ -116,6 +122,8 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe
void *hpfs_get_4sectors(struct super_block *s, unsigned secno,
struct quad_buffer_head *qbh)
{
cond_resched();
if (secno & 3) {
printk("HPFS: hpfs_get_4sectors: unaligned read\n");
return 0;
......
......@@ -234,7 +234,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, char *key, char *data
}
pos += ea->namelen + ea->valuelen + 5;
}
if (!fnode->ea_size_s) {
if (!fnode->ea_offs) {
/*if (fnode->ea_size_s) {
hpfs_error(s, "fnode %08x: ea_size_s == %03x, ea_offs == 0",
inode->i_ino, fnode->ea_size_s);
......@@ -242,15 +242,13 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, char *key, char *data
}*/
fnode->ea_offs = 0xc4;
}
if (fnode->ea_offs < 0xc4 || fnode->ea_offs + fnode->ea_size_s > 0x200) {
if (fnode->ea_offs < 0xc4 || fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s > 0x200) {
hpfs_error(s, "fnode %08x: ea_offs == %03x, ea_size_s == %03x",
inode->i_ino, fnode->ea_offs, fnode->ea_size_s);
return;
}
if ((fnode->ea_size_s || !fnode->ea_size_l) &&
fnode->ea_offs + fnode->ea_size_s + strlen(key) + size + 5 <= 0x200) {
/* I'm not sure ... maybe we overwrite ACL here. I have no info
on it right now :-( */
fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s + strlen(key) + size + 5 <= 0x200) {
ea = fnode_end_ea(fnode);
*(char *)ea = 0;
ea->namelen = strlen(key);
......
......@@ -408,7 +408,7 @@ struct fnode
unsigned file_size; /* file length, bytes */
unsigned n_needea; /* number of EA's with NEEDEA set */
char user_id[16]; /* unused */
unsigned ea_offs; /* offset from start of fnode
unsigned short ea_offs; /* offset from start of fnode
to first fnode-resident ea */
char dasd_limit_treshhold;
char dasd_limit_delta;
......
......@@ -87,6 +87,7 @@ struct hpfs_sb_info {
/* 128 bytes lowercasing table */
unsigned *sb_bmp_dir; /* main bitmap directory */
unsigned sb_c_bitmap; /* current bitmap */
unsigned sb_max_fwd_alloc; /* max forwad allocation */
struct semaphore hpfs_creation_de; /* when creating dirents, nobody else
can alloc blocks */
/*unsigned sb_mounting : 1;*/
......@@ -141,12 +142,12 @@ static inline struct hpfs_dirent *de_next_de (struct hpfs_dirent *de)
static inline struct extended_attribute *fnode_ea(struct fnode *fnode)
{
return (struct extended_attribute *)((char *)fnode + fnode->ea_offs);
return (struct extended_attribute *)((char *)fnode + fnode->ea_offs + fnode->acl_size_s);
}
static inline struct extended_attribute *fnode_end_ea(struct fnode *fnode)
{
return (struct extended_attribute *)((char *)fnode + fnode->ea_offs + fnode->ea_size_s);
return (struct extended_attribute *)((char *)fnode + fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s);
}
static inline struct extended_attribute *next_ea(struct extended_attribute *ea)
......
......@@ -144,11 +144,11 @@ void hpfs_read_inode(struct inode *i)
void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode)
{
struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
if (fnode->acl_size_l || fnode->acl_size_s) {
/* Some unknown structures like ACL may be in fnode,
we'd better not overwrite them */
/*if (fnode->acl_size_l || fnode->acl_size_s) {
Some unknown structures like ACL may be in fnode,
we'd better not overwrite them
hpfs_error(i->i_sb, "fnode %08x has some unknown HPFS386 stuctures", i->i_ino);
} else if (hpfs_sb(i->i_sb)->sb_eas >= 2) {
} else*/ if (hpfs_sb(i->i_sb)->sb_eas >= 2) {
u32 ea;
if ((i->i_uid != hpfs_sb(i->i_sb)->sb_uid) || hpfs_inode->i_ea_uid) {
ea = cpu_to_le32(i->i_uid);
......@@ -218,16 +218,18 @@ void hpfs_write_inode_nolock(struct inode *i)
struct hpfs_dirent *de;
if (i->i_ino == hpfs_sb(i->i_sb)->sb_root) return;
if (!(fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) return;
if (i->i_ino != hpfs_sb(i->i_sb)->sb_root) {
if (i->i_ino != hpfs_sb(i->i_sb)->sb_root && i->i_nlink) {
if (!(de = map_fnode_dirent(i->i_sb, i->i_ino, fnode, &qbh))) {
brelse(bh);
return;
}
} else de = NULL;
if (S_ISREG(i->i_mode)) {
fnode->file_size = de->file_size = i->i_size;
fnode->file_size = i->i_size;
if (de) de->file_size = i->i_size;
} else if (S_ISDIR(i->i_mode)) {
fnode->file_size = de->file_size = 0;
fnode->file_size = 0;
if (de) de->file_size = 0;
}
hpfs_write_inode_ea(i, fnode);
if (de) {
......
......@@ -142,7 +142,7 @@ struct fnode *hpfs_map_fnode(struct super_block *s, ino_t ino, struct buffer_hea
}
}
if (fnode->ea_size_s && ((signed int)fnode->ea_offs < 0xc4 ||
(signed int)fnode->ea_offs + fnode->ea_size_s > 0x200)) {
(signed int)fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s > 0x200)) {
hpfs_error(s, "bad EA info in fnode %08x: ea_offs == %04x ea_size_s == %04x",
ino, fnode->ea_offs, fnode->ea_size_s);
goto bail;
......@@ -225,14 +225,16 @@ struct dnode *hpfs_map_dnode(struct super_block *s, unsigned secno,
}
for (p = 20; p < dnode->first_free; p += d[p] + (d[p+1] << 8)) {
struct hpfs_dirent *de = (struct hpfs_dirent *)((char *)dnode + p);
if (de->length > 292 || (de->length < 32) || (de->length & 3)) {
if (de->length > 292 || (de->length < 32) || (de->length & 3) || p + de->length > 2048) {
hpfs_error(s, "bad dirent size in dnode %08x, dirent %03x, last %03x", secno, p, pp);
goto bail;
}
if (((31 + de->namelen + de->down*4 + 3) & ~3) != de->length) {
if (((31 + de->namelen + de->down*4 + 3) & ~3) < de->length && s->s_flags & MS_RDONLY) goto ok;
hpfs_error(s, "namelen does not match dirent size in dnode %08x, dirent %03x, last %03x", secno, p, pp);
goto bail;
}
ok:
if (hpfs_sb(s)->sb_chk >= 2) b |= 1 << de->down;
if (de->down) if (de_down_pointer(de) < 0x10) {
hpfs_error(s, "bad down pointer in dnode %08x, dirent %03x, last %03x", secno, p, pp);
......
......@@ -542,6 +542,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
sbi->sb_was_error = 0;
sbi->sb_cp_table = NULL;
sbi->sb_c_bitmap = -1;
sbi->sb_max_fwd_alloc = 0xffffff;
/* Load bitmap directory */
if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, superblock->bitmaps)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment