[2.6 PATCH] ufs2_frag_map_fix : fixes wrong content reading in ufs2code

From: Niraj Kumar
Date: Mon Apr 12 2004 - 06:09:59 EST


Andrew,

This is in continuation of the ufs2 read-only code that went into 2.6.5.

This patch fixes a bug where wrong content was being read off the disk
after around 4 MB mark.


Patch is also located at
http://ufs-linux.sourceforge.net/ufs2/2.6.5/ufs2_frag_map_fix.txt

Regards
Niraj


diff -ur linux-2.6.5/fs/ufs/dir.c linux-2.6.5-ufs2/fs/ufs/dir.c
--- linux-2.6.5/fs/ufs/dir.c 2004-04-04 09:07:44.000000000 +0530
+++ linux-2.6.5-ufs2/fs/ufs/dir.c 2004-04-05 14:00:37.000000000 +0530
@@ -56,13 +56,14 @@
{
struct inode *inode = filp->f_dentry->d_inode;
int error = 0;
- unsigned long offset, lblk, blk;
+ unsigned long offset, lblk;
int i, stored;
struct buffer_head * bh;
struct ufs_dir_entry * de;
struct super_block * sb;
int de_reclen;
unsigned flags;
+ u64 blk= 0L;

lock_kernel();

diff -ur linux-2.6.5/fs/ufs/inode.c linux-2.6.5-ufs2/fs/ufs/inode.c
--- linux-2.6.5/fs/ufs/inode.c 2004-04-04 09:06:26.000000000 +0530
+++ linux-2.6.5-ufs2/fs/ufs/inode.c 2004-04-12 15:02:28.000000000 +0530
@@ -50,7 +50,7 @@
#define UFSD(x)
#endif

-static int ufs_block_to_path(struct inode *inode, long i_block, int offsets[4])
+static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t offsets[4])
{
struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi;
int ptrs = uspi->s_apb;
@@ -60,6 +60,8 @@
double_blocks = (1 << (ptrs_bits * 2));
int n = 0;

+ UFSD(("ptrs=uspi->s_apb = %d,double_blocks=%d \n",ptrs,double_blocks));
if (i_block < 0) {
ufs_warning(inode->i_sb, "ufs_block_to_path", "block < 0");
} else if (i_block < direct_blocks) {
@@ -87,20 +89,23 @@
* the begining of the filesystem.
*/

-u64 ufs_frag_map(struct inode *inode, int frag)
+u64 ufs_frag_map(struct inode *inode, sector_t frag)
{
struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block *sb = inode->i_sb;
struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
- int mask = uspi->s_apbmask>>uspi->s_fpbshift;
+ u64 mask = (u64) uspi->s_apbmask>>uspi->s_fpbshift;
int shift = uspi->s_apbshift-uspi->s_fpbshift;
- int offsets[4], *p;
+ sector_t offsets[4], *p;
int depth = ufs_block_to_path(inode, frag >> uspi->s_fpbshift, offsets);
- int ret = 0;
+ u64 ret = 0L;
u32 block;
- u64 u2_block = 0;
+ u64 u2_block = 0L;
unsigned flags = UFS_SB(sb)->s_flags;
- u64 temp = 0;
+ u64 temp = 0L;
+
+ UFSD((": frag = %lu depth = %d\n",frag,depth));
+ UFSD((": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",uspi->s_fpbshift,uspi->s_apbmask,mask));

if (depth == 0)
return 0;
@@ -116,7 +121,7 @@
goto out;
while (--depth) {
struct buffer_head *bh;
- int n = *p++;
+ sector_t n = *p++;

bh = sb_bread(sb, uspi->s_sbbase + fs32_to_cpu(sb, block)+(n>>shift));
if (!bh)
@@ -126,20 +131,21 @@
if (!block)
goto out;
}
- ret = uspi->s_sbbase + fs32_to_cpu(sb, block) + (frag & uspi->s_fpbmask);
+ ret = (u64) (uspi->s_sbbase + fs32_to_cpu(sb, block) + (frag & uspi->s_fpbmask));
goto out;
ufs2:
u2_block = ufsi->i_u1.u2_i_data[*p++];
if (!u2_block)
goto out;

- temp = (u64)uspi->s_sbbase + fs64_to_cpu(sb, u2_block);

while (--depth) {
struct buffer_head *bh;
- u64 n = *p++;
+ sector_t n = *p++;

- bh = sb_bread(sb, temp +(n>>shift));
+
+ temp = (u64)(uspi->s_sbbase) + fs64_to_cpu(sb, u2_block);
+ bh = sb_bread(sb, temp +(u64) (n>>shift));
if (!bh)
goto out;
u2_block = ((u64*)bh->b_data)[n & mask];
@@ -147,7 +153,8 @@
if (!u2_block)
goto out;
}
- ret = temp + (frag & uspi->s_fpbmask);
+ temp = (u64)uspi->s_sbbase + fs64_to_cpu(sb, u2_block);
+ ret = temp + (u64) (frag & uspi->s_fpbmask);

out:
unlock_kernel();
@@ -379,6 +386,7 @@

if (!create) {
phys64 = ufs_frag_map(inode, fragment);
+ UFSD(("phys64 = %lu \n",phys64));
if (phys64)
map_bh(bh_result, sb, phys64);
return 0;
diff -ur linux-2.6.5/fs/ufs/super.c linux-2.6.5-ufs2/fs/ufs/super.c
--- linux-2.6.5/fs/ufs/super.c 2004-04-04 09:06:11.000000000 +0530
+++ linux-2.6.5-ufs2/fs/ufs/super.c 2004-04-12 15:03:25.000000000 +0530
@@ -93,6 +93,8 @@
#undef UFS_SUPER_DEBUG
#undef UFS_SUPER_DEBUG_MORE

+
+#undef UFS_SUPER_DEBUG_MORE
#ifdef UFS_SUPER_DEBUG
#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
#else
@@ -157,6 +159,8 @@
printk(" magic: 0x%x\n", fs32_to_cpu(sb, usb->fs_magic));
printk(" fs_size: %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size));
printk(" fs_dsize: %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize));
+ printk(" bsize: %u\n", fs32_to_cpu(usb, usb->fs_bsize));
+ printk(" fsize: %u\n", fs32_to_cpu(usb, usb->fs_fsize));
printk(" fs_volname: %s\n", usb->fs_u11.fs_u2.fs_volname);
printk(" fs_fsmnt: %s\n", usb->fs_u11.fs_u2.fs_fsmnt);
printk(" fs_sblockloc: %u\n",fs64_to_cpu(sb,
@@ -897,6 +901,8 @@
uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask);
uspi->s_bshift = fs32_to_cpu(sb, usb1->fs_bshift);
uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift);
+ UFSD(("uspi->s_bshift = %d,uspi->s_fshift = %d", uspi->s_bshift,
+ uspi->s_fshift));
uspi->s_fpbshift = fs32_to_cpu(sb, usb1->fs_fragshift);
uspi->s_fsbtodb = fs32_to_cpu(sb, usb1->fs_fsbtodb);
/* s_sbsize already set */
@@ -929,7 +935,12 @@
* Compute another frequently used values
*/
uspi->s_fpbmask = uspi->s_fpb - 1;
- uspi->s_apbshift = uspi->s_bshift - 2;
+ if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+ uspi->s_apbshift = uspi->s_bshift - 3;
+ }
+ else {
+ uspi->s_apbshift = uspi->s_bshift - 2;
+ }
uspi->s_2apbshift = uspi->s_apbshift * 2;
uspi->s_3apbshift = uspi->s_apbshift * 3;
uspi->s_apb = 1 << uspi->s_apbshift;
diff -ur linux-2.6.5/include/linux/ufs_fs.h linux-2.6.5-ufs2/include/linux/ufs_fs.h
--- linux-2.6.5/include/linux/ufs_fs.h 2004-04-04 09:07:43.000000000 +0530
+++ linux-2.6.5-ufs2/include/linux/ufs_fs.h 2004-04-05 14:00:42.000000000 +0530
@@ -896,7 +896,7 @@
extern struct inode * ufs_new_inode (struct inode *, int);

/* inode.c */
-extern u64 ufs_frag_map (struct inode *, int);
+extern u64 ufs_frag_map (struct inode *, sector_t);
extern void ufs_read_inode (struct inode *);
extern void ufs_put_inode (struct inode *);
extern void ufs_write_inode (struct inode *, int);