Re: patch for minix fs -- need testers!

Andreas Schwab (schwab@issan.informatik.uni-dortmund.de)
26 Jan 1998 10:24:20 +0100


Bill Hawes <whawes@star.net> writes:

|> If you're using a minix filesystem, please test this patch and let me
|> know of any problems.

Ok, here is the result of my tests:

- in minix_read_super s_nzones wasn't set correctly for a V2 filesystem
- remove silly and now obsolete restriction on filesystem size.

Additionally i have included the following changes:

- inodes are counted one-based, thus an inode with the number s_inodes is
actually valid.
- count_free didn't count correctly, the bitmaps are organized in 16 bit
blocks in native byte order.
- add some extra braces that gcc 2.8 warns about.
- correctly handle file name aliases due to truncation
- properly recognize a busy directory in minix_rmdir
- V2 inodes have 16 bit link count.

--- linux-2.1.80/fs/minix/bitmap.c.~1~ Fri Jan 9 18:14:34 1998
+++ linux-2.1.80/fs/minix/bitmap.c Fri Jan 23 22:39:24 1998
@@ -36,16 +36,17 @@

if (numblocks==0 || !(bh=map[numblocks-1]))
return(0);
- i = (numbits-(numblocks-1)*BLOCK_SIZE*8)/8;
+ i = ((numbits-(numblocks-1)*BLOCK_SIZE*8)/16)*2;
for (j=0; j<i; j++) {
sum += nibblemap[bh->b_data[j] & 0xf]
+ nibblemap[(bh->b_data[j]>>4) & 0xf];
}

- i = numbits%8;
+ i = numbits%16;
if (i!=0) {
- i = bh->b_data[j] | ~((1<<i) - 1);
+ i = *(__u16 *)(&bh->b_data[j]) | ~((1<<i) - 1);
sum += nibblemap[i & 0xf] + nibblemap[(i>>4) & 0xf];
+ sum += nibblemap[(i>>8) & 0xf] + nibblemap[(i>>12) & 0xf];
}
return(sum);
}
@@ -71,11 +72,11 @@
zone = block - sb->u.minix_sb.s_firstdatazone + 1;
bit = zone & 8191;
zone >>= 13;
- bh = sb->u.minix_sb.s_zmap[zone];
- if (!bh) {
+ if (zone >= sb->u.minix_sb.s_zmap_blocks) {
printk("minix_free_block: nonexistent bitmap buffer\n");
return;
}
+ bh = sb->u.minix_sb.s_zmap[zone];
if (!minix_clear_bit(bit,bh->b_data))
printk("free_block (%s:%d): bit already cleared\n",
kdevname(sb->s_dev), block);
@@ -94,11 +95,13 @@
}
repeat:
j = 8192;
- for (i=0 ; i<64 ; i++)
- if ((bh=sb->u.minix_sb.s_zmap[i]) != NULL)
- if ((j=minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
- break;
- if (i>=64 || !bh || j>=8192)
+ bh = NULL;
+ for (i = 0; i < sb->u.minix_sb.s_zmap_blocks; i++) {
+ bh = sb->u.minix_sb.s_zmap[i];
+ if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
+ break;
+ }
+ if (!bh || j >= 8192)
return 0;
if (minix_set_bit(j,bh->b_data)) {
printk("new_block: bit already set");
@@ -134,7 +137,7 @@
int ino, block;

ino = inode->i_ino;
- if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s: %d is out of range\n",
kdevname(inode->i_dev), ino);
return 0;
@@ -162,7 +165,7 @@
int ino, block;

ino = inode->i_ino;
- if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s: %d is out of range\n",
kdevname(inode->i_dev), ino);
return 0;
@@ -218,15 +221,16 @@
printk("free_inode: inode on nonexistent device\n");
return;
}
- if (inode->i_ino < 1 || inode->i_ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("free_inode: inode 0 or nonexistent inode\n");
return;
}
ino = inode->i_ino;
- if (!(bh=inode->i_sb->u.minix_sb.s_imap[ino >> 13])) {
+ if ((ino >> 13) >= inode->i_sb->u.minix_sb.s_imap_blocks) {
printk("free_inode: nonexistent imap in superblock\n");
return;
}
+ bh = inode->i_sb->u.minix_sb.s_imap[ino >> 13];
minix_clear_inode(inode);
clear_inode(inode);
if (!minix_clear_bit(ino & 8191, bh->b_data))
@@ -247,10 +251,12 @@
inode->i_sb = sb;
inode->i_flags = inode->i_sb->s_flags;
j = 8192;
- for (i=0 ; i<8 ; i++)
- if ((bh = inode->i_sb->u.minix_sb.s_imap[i]) != NULL)
- if ((j=minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
- break;
+ bh = NULL;
+ for (i = 0; i < sb->u.minix_sb.s_imap_blocks; i++) {
+ bh = inode->i_sb->u.minix_sb.s_imap[i];
+ if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
+ break;
+ }
if (!bh || j >= 8192) {
iput(inode);
return NULL;
@@ -262,7 +268,7 @@
}
mark_buffer_dirty(bh, 1);
j += i*8192;
- if (!j || j >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!j || j > inode->i_sb->u.minix_sb.s_ninodes) {
iput(inode);
return NULL;
}
--- linux-2.1.80/fs/minix/inode.c.~2~ Fri Jan 23 19:54:14 1998
+++ linux-2.1.80/fs/minix/inode.c Fri Jan 23 23:48:06 1998
@@ -64,9 +64,9 @@
sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state;
mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
}
- for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++)
+ for (i = 0; i < sb->u.minix_sb.s_imap_blocks; i++)
brelse(sb->u.minix_sb.s_imap[i]);
- for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++)
+ for (i = 0; i < sb->u.minix_sb.s_zmap_blocks; i++)
brelse(sb->u.minix_sb.s_zmap[i]);
brelse (sb->u.minix_sb.s_sbh);
kfree(sb->u.minix_sb.s_imap);
@@ -211,27 +211,27 @@
s->u.minix_sb.s_namelen = 30;
} else if (s->s_magic == MINIX2_SUPER_MAGIC) {
s->u.minix_sb.s_version = MINIX_V2;
+ s->u.minix_sb.s_nzones = ms->s_zones;
s->u.minix_sb.s_dirsize = 16;
s->u.minix_sb.s_namelen = 14;
} else if (s->s_magic == MINIX2_SUPER_MAGIC2) {
s->u.minix_sb.s_version = MINIX_V2;
+ s->u.minix_sb.s_nzones = ms->s_zones;
s->u.minix_sb.s_dirsize = 32;
s->u.minix_sb.s_namelen = 30;
} else
goto out_no_fs;

- if (s->u.minix_sb.s_zmap_blocks > MINIX_Z_MAP_SLOTS)
- goto out_too_big;
/*
* Allocate the buffer map to keep the superblock small.
*/
- i = (MINIX_I_MAP_SLOTS + MINIX_Z_MAP_SLOTS) * sizeof(bh);
+ i = (s->u.minix_sb.s_imap_blocks + s->u.minix_sb.s_zmap_blocks) * sizeof(bh);
map = kmalloc(i, GFP_KERNEL);
if (!map)
goto out_no_map;
memset(map, 0, i);
s->u.minix_sb.s_imap = &map[0];
- s->u.minix_sb.s_zmap = &map[MINIX_I_MAP_SLOTS];
+ s->u.minix_sb.s_zmap = &map[s->u.minix_sb.s_imap_blocks];

block=2;
for (i=0 ; i < s->u.minix_sb.s_imap_blocks ; i++) {
@@ -244,8 +244,6 @@
goto out_no_bitmap;
block++;
}
- if (block != 2+s->u.minix_sb.s_imap_blocks+s->u.minix_sb.s_zmap_blocks)
- goto out_no_bitmap;

minix_set_bit(0,s->u.minix_sb.s_imap[0]->b_data);
minix_set_bit(0,s->u.minix_sb.s_zmap[0]->b_data);
@@ -265,6 +263,8 @@
if (!s->s_root)
goto out_iput;

+ s->s_root->d_op = &minix_dentry_operations;
+
if (!(s->s_flags & MS_RDONLY)) {
ms->s_state &= ~MINIX_VALID_FS;
mark_buffer_dirty(bh, 1);
@@ -294,9 +294,9 @@
out_no_bitmap:
printk("MINIX-fs: bad superblock or unable to read bitmaps\n");
out_freemap:
- for(i=0;i<MINIX_I_MAP_SLOTS;i++)
+ for (i = 0; i < s->u.minix_sb.s_imap_blocks; i++)
brelse(s->u.minix_sb.s_imap[i]);
- for(i=0;i<MINIX_Z_MAP_SLOTS;i++)
+ for (i = 0; i < s->u.minix_sb.s_zmap_blocks; i++)
brelse(s->u.minix_sb.s_zmap[i]);
kfree(s->u.minix_sb.s_imap);
goto out_release;
@@ -306,11 +306,6 @@
printk ("MINIX-fs: can't allocate map\n");
goto out_release;

-out_too_big:
- if (!silent)
- printk ("MINIX-fs: filesystem too big\n");
- goto out_release;
-
out_no_fs:
if (!silent)
printk("VFS: Can't find a minix or minix V2 filesystem on dev "
@@ -731,7 +726,7 @@
ino = inode->i_ino;
inode->i_op = NULL;
inode->i_mode = 0;
- if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
@@ -785,7 +780,7 @@
ino = inode->i_ino;
inode->i_op = NULL;
inode->i_mode = 0;
- if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
@@ -850,7 +845,7 @@
int ino, block;

ino = inode->i_ino;
- if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
@@ -888,7 +883,7 @@
int ino, block;

ino = inode->i_ino;
- if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
--- linux-2.1.80/fs/minix/namei.c.~1~ Wed Jan 14 20:40:31 1998
+++ linux-2.1.80/fs/minix/namei.c Sat Jan 24 00:29:45 1998
@@ -23,34 +23,12 @@
static inline int namecompare(int len, int maxlen,
const char * name, const char * buffer)
{
- if (len > maxlen)
- return 0;
if (len < maxlen && buffer[len])
return 0;
return !memcmp(name, buffer, len);
}

/*
- * ok, we cannot use strncmp, as the name is not in our data space.
- * Thus we'll have to use minix_match. No big problem. Match also makes
- * some sanity tests.
- *
- * NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure.
- */
-static int minix_match(int len, const char * name,
- struct buffer_head * bh, unsigned long * offset,
- struct minix_sb_info * info)
-{
- struct minix_dir_entry * de;
-
- de = (struct minix_dir_entry *) (bh->b_data + *offset);
- *offset += info->s_dirsize;
- if (!de->inode || len > info->s_namelen)
- return 0;
- return namecompare(len,info->s_namelen,name,de->name);
-}
-
-/*
* minix_find_entry()
*
* finds an entry in the specified directory with the wanted name. It
@@ -64,6 +42,7 @@
unsigned long block, offset;
struct buffer_head * bh;
struct minix_sb_info * info;
+ struct minix_dir_entry *de;

*res_dir = NULL;
if (!dir || !dir->i_sb)
@@ -86,9 +65,12 @@
continue;
}
}
- *res_dir = (struct minix_dir_entry *) (bh->b_data + offset);
- if (minix_match(namelen,name,bh,&offset,info))
+ de = (struct minix_dir_entry *) (bh->b_data + offset);
+ offset += info->s_dirsize;
+ if (de->inode && namecompare(namelen,info->s_namelen,name,de->name)) {
+ *res_dir = de;
return bh;
+ }
if (offset < bh->b_size)
continue;
brelse(bh);
@@ -97,16 +79,52 @@
block++;
}
brelse(bh);
- *res_dir = NULL;
return NULL;
}

+#ifndef NO_TRUNCATE
+
+static int minix_hash(struct dentry *dentry, struct qstr *qstr)
+{
+ unsigned long hash;
+ int i;
+ const char *name;
+
+ i = dentry->d_inode->i_sb->u.minix_sb.s_namelen;
+ if (i >= qstr->len)
+ return 0;
+ /* Truncate the name in place, avoids having to define a compare
+ function. */
+ qstr->len = i;
+ name = qstr->name;
+ hash = init_name_hash();
+ while (i--)
+ hash = partial_name_hash(*name++, hash);
+ qstr->hash = end_name_hash(hash);
+ return 0;
+}
+
+#endif
+
+struct dentry_operations minix_dentry_operations = {
+ 0, /* revalidate */
+#ifndef NO_TRUNCATE
+ minix_hash,
+#else
+ 0,
+#endif
+ 0 /* compare */
+};
+
int minix_lookup(struct inode * dir, struct dentry *dentry)
{
struct inode * inode = NULL;
struct minix_dir_entry * de;
struct buffer_head * bh;

+#ifndef NO_TRUNCATE
+ dentry->d_op = &minix_dentry_operations;
+#endif
bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
if (bh) {
int ino = de->inode;
@@ -296,7 +314,8 @@
brelse(bh);
return -EEXIST;
}
- if (dir->i_nlink >= MINIX_LINK_MAX)
+ if (dir->i_nlink >= (INODE_VERSION(dir) == MINIX_V1 ?
+ MINIX_LINK_MAX : MINIX2_LINK_MAX))
return -EMLINK;
inode = minix_new_inode(dir);
if (!inode)
@@ -434,7 +453,7 @@
retval = -ENOENT;
goto end_rmdir;
}
- if (inode->i_count > 1) {
+ if (dentry->d_count > 1) {
retval = -EBUSY;
goto end_rmdir;
}
@@ -573,7 +592,8 @@
if (S_ISDIR(inode->i_mode))
return -EPERM;

- if (inode->i_nlink >= MINIX_LINK_MAX)
+ if (inode->i_nlink >= (INODE_VERSION(inode) == MINIX_V1 ?
+ MINIX_LINK_MAX : MINIX2_LINK_MAX))
return -EMLINK;

bh = minix_find_entry(dir, dentry->d_name.name,
@@ -707,7 +727,9 @@
if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
goto end_rename;
retval = -EMLINK;
- if (!new_inode && new_dir->i_nlink >= MINIX_LINK_MAX)
+ if (!new_inode &&
+ new_dir->i_nlink >= (INODE_VERSION(new_dir) == MINIX_V1 ?
+ MINIX_LINK_MAX : MINIX2_LINK_MAX))
goto end_rename;
}
if (!new_bh) {
--- linux-2.1.80/fs/minix/truncate.c.~1~ Fri Jul 18 19:18:54 1997
+++ linux-2.1.80/fs/minix/truncate.c Fri Jan 23 23:08:12 1998
@@ -117,7 +117,7 @@
for (i = 0; i < 512; i++)
if (*(ind++))
break;
- if (i >= 512)
+ if (i >= 512) {
if (ind_bh->b_count != 1)
retry = 1;
else {
@@ -125,6 +125,7 @@
*p = 0;
minix_free_block(inode->i_sb,tmp);
}
+ }
brelse(ind_bh);
return retry;
}
@@ -161,7 +162,7 @@
for (i = 0; i < 512; i++)
if (*(dind++))
break;
- if (i >= 512)
+ if (i >= 512) {
if (dind_bh->b_count != 1)
retry = 1;
else {
@@ -170,6 +171,7 @@
mark_inode_dirty(inode);
minix_free_block(inode->i_sb,tmp);
}
+ }
brelse(dind_bh);
return retry;
}
@@ -279,7 +281,7 @@
for (i = 0; i < 256; i++)
if (*(ind++))
break;
- if (i >= 256)
+ if (i >= 256) {
if (ind_bh->b_count != 1)
retry = 1;
else {
@@ -287,6 +289,7 @@
*p = 0;
minix_free_block(inode->i_sb,tmp);
}
+ }
brelse(ind_bh);
return retry;
}
@@ -323,7 +326,7 @@
for (i = 0; i < 256; i++)
if (*(dind++))
break;
- if (i >= 256)
+ if (i >= 256) {
if (dind_bh->b_count != 1)
retry = 1;
else {
@@ -332,6 +335,7 @@
mark_inode_dirty(inode);
minix_free_block(inode->i_sb,tmp);
}
+ }
brelse(dind_bh);
return retry;
}
@@ -368,7 +372,7 @@
for (i = 0; i < 256; i++)
if (*(tind++))
break;
- if (i >= 256)
+ if (i >= 256) {
if (tind_bh->b_count != 1)
retry = 1;
else {
@@ -377,6 +381,7 @@
mark_inode_dirty(inode);
minix_free_block(inode->i_sb,tmp);
}
+ }
brelse(tind_bh);
return retry;
}
--- linux-2.1.80/include/linux/minix_fs.h.~1~ Wed Jan 14 20:41:30 1998
+++ linux-2.1.80/include/linux/minix_fs.h Fri Jan 23 23:57:05 1998
@@ -15,6 +15,7 @@

/* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
#define MINIX_LINK_MAX 250
+#define MINIX2_LINK_MAX 65530

#define MINIX_I_MAP_SLOTS 8
#define MINIX_Z_MAP_SLOTS 64
@@ -126,6 +127,7 @@
extern struct inode_operations minix_file_inode_operations;
extern struct inode_operations minix_dir_inode_operations;
extern struct inode_operations minix_symlink_inode_operations;
+extern struct dentry_operations minix_dentry_operations;

#endif /* __KERNEL__ */

-- 
Andreas Schwab                                      "And now for something
schwab@issan.informatik.uni-dortmund.de              completely different"
schwab@gnu.org