Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / fs / jfs / jfs_imap.c
index 6a6f147..d88cf0b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *   Copyright (C) International Business Machines Corp., 2000-2003
+ *   Copyright (C) International Business Machines Corp., 2000-2004
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
 #include <linux/pagemap.h>
+#include <linux/quotaops.h>
 #include <linux/vserver/xid.h>
 
 #include "jfs_incore.h"
+#include "jfs_inode.h"
 #include "jfs_filsys.h"
 #include "jfs_dinode.h"
 #include "jfs_dmap.h"
 #include "jfs_superblock.h"
 #include "jfs_debug.h"
 
+/*
+ * __mark_inode_dirty expects inodes to be hashed.  Since we don't want
+ * special inodes in the fileset inode space, we hash them to a dummy head
+ */
+static HLIST_HEAD(aggregate_hash);
+
 /*
  * imap locks
  */
 /* iag free list lock */
-#define IAGFREE_LOCK_INIT(imap)                init_MUTEX(&imap->im_freelock)
-#define IAGFREE_LOCK(imap)             down(&imap->im_freelock)
-#define IAGFREE_UNLOCK(imap)           up(&imap->im_freelock)
+#define IAGFREE_LOCK_INIT(imap)                mutex_init(&imap->im_freelock)
+#define IAGFREE_LOCK(imap)             mutex_lock(&imap->im_freelock)
+#define IAGFREE_UNLOCK(imap)           mutex_unlock(&imap->im_freelock)
 
 /* per ag iag list locks */
-#define AG_LOCK_INIT(imap,index)       init_MUTEX(&(imap->im_aglock[index]))
-#define AG_LOCK(imap,agno)             down(&imap->im_aglock[agno])
-#define AG_UNLOCK(imap,agno)           up(&imap->im_aglock[agno])
-
-/*
- * external references
- */
-extern struct address_space_operations jfs_aops;
+#define AG_LOCK_INIT(imap,index)       mutex_init(&(imap->im_aglock[index]))
+#define AG_LOCK(imap,agno)             mutex_lock(&imap->im_aglock[agno])
+#define AG_UNLOCK(imap,agno)           mutex_unlock(&imap->im_aglock[agno])
 
 /*
  * forward references
@@ -90,25 +93,6 @@ static int diIAGRead(struct inomap * imap, int, struct metapage **);
 static int copy_from_dinode(struct dinode *, struct inode *);
 static void copy_to_dinode(struct dinode *, struct inode *);
 
-/*
- *     debug code for double-checking inode map
- */
-/* #define     _JFS_DEBUG_IMAP 1 */
-
-#ifdef _JFS_DEBUG_IMAP
-#define DBG_DIINIT(imap)       DBGdiInit(imap)
-#define DBG_DIALLOC(imap, ino) DBGdiAlloc(imap, ino)
-#define DBG_DIFREE(imap, ino)  DBGdiFree(imap, ino)
-
-static void *DBGdiInit(struct inomap * imap);
-static void DBGdiAlloc(struct inomap * imap, ino_t ino);
-static void DBGdiFree(struct inomap * imap, ino_t ino);
-#else
-#define DBG_DIINIT(imap)
-#define DBG_DIALLOC(imap, ino)
-#define DBG_DIFREE(imap, ino)
-#endif                         /* _JFS_DEBUG_IMAP */
-
 /*
  * NAME:        diMount()
  *
@@ -131,7 +115,7 @@ int diMount(struct inode *ipimap)
        struct inomap *imap;
        struct metapage *mp;
        int index;
-       struct dinomap *dinom_le;
+       struct dinomap_disk *dinom_le;
 
        /*
         * allocate/initialize the in-memory inode map control structure
@@ -154,7 +138,7 @@ int diMount(struct inode *ipimap)
        }
 
        /* copy the on-disk version to the in-memory version. */
-       dinom_le = (struct dinomap *) mp->data;
+       dinom_le = (struct dinomap_disk *) mp->data;
        imap->im_freeiag = le32_to_cpu(dinom_le->in_freeiag);
        imap->im_nextiag = le32_to_cpu(dinom_le->in_nextiag);
        atomic_set(&imap->im_numinos, le32_to_cpu(dinom_le->in_numinos));
@@ -192,8 +176,6 @@ int diMount(struct inode *ipimap)
        imap->im_ipimap = ipimap;
        JFS_IP(ipimap)->i_imap = imap;
 
-//      DBG_DIINIT(imap);
-
        return (0);
 }
 
@@ -242,7 +224,7 @@ int diUnmount(struct inode *ipimap, int mounterror)
  */
 int diSync(struct inode *ipimap)
 {
-       struct dinomap *dinom_le;
+       struct dinomap_disk *dinom_le;
        struct inomap *imp = JFS_IP(ipimap)->i_imap;
        struct metapage *mp;
        int index;
@@ -260,7 +242,7 @@ int diSync(struct inode *ipimap)
        }
 
        /* copy the in-memory version to the on-disk version */
-       dinom_le = (struct dinomap *) mp->data;
+       dinom_le = (struct dinomap_disk *) mp->data;
        dinom_le->in_freeiag = cpu_to_le32(imp->im_freeiag);
        dinom_le->in_nextiag = cpu_to_le32(imp->im_nextiag);
        dinom_le->in_numinos = cpu_to_le32(atomic_read(&imp->im_numinos));
@@ -284,8 +266,7 @@ int diSync(struct inode *ipimap)
        /*
         * write out dirty pages of imap
         */
-       filemap_fdatawrite(ipimap->i_mapping);
-       filemap_fdatawait(ipimap->i_mapping);
+       filemap_write_and_wait(ipimap->i_mapping);
 
        diWriteSpecial(ipimap, 0);
 
@@ -502,9 +483,12 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
 
        }
 
-       ip->i_mapping->a_ops = &jfs_aops;
+       ip->i_mapping->a_ops = &jfs_metapage_aops;
        mapping_set_gfp_mask(ip->i_mapping, GFP_NOFS);
 
+       /* Allocations to metadata inodes should not affect quotas */
+       ip->i_flags |= S_NOQUOTA;
+
        if ((inum == FILESYSTEM_I) && (JFS_IP(ip)->ipimap == sbi->ipaimap)) {
                sbi->gengen = le32_to_cpu(dp->di_gengen);
                sbi->inostamp = le32_to_cpu(dp->di_inostamp);
@@ -513,6 +497,8 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
        /* release the page */
        release_metapage(mp);
 
+       hlist_add_head(&ip->i_hash, &aggregate_hash);
+
        return (ip);
 }
 
@@ -536,8 +522,6 @@ void diWriteSpecial(struct inode *ip, int secondary)
        ino_t inum = ip->i_ino;
        struct metapage *mp;
 
-       ip->i_state &= ~I_DIRTY;
-
        if (secondary)
                address = addressPXD(&sbi->ait2) >> sbi->l2nbperpage;
        else
@@ -581,8 +565,7 @@ void diFreeSpecial(struct inode *ip)
                jfs_err("diFreeSpecial called with NULL ip!");
                return;
        }
-       filemap_fdatawrite(ip->i_mapping);
-       filemap_fdatawait(ip->i_mapping);
+       filemap_write_and_wait(ip->i_mapping);
        truncate_inode_pages(ip->i_mapping, 0);
        iput(ip);
 }
@@ -1024,7 +1007,7 @@ int diFree(struct inode *ip)
                         */
                        iagp->inofreefwd =
                            cpu_to_le32(imap->im_agctl[agno].inofree);
-                       iagp->inofreeback = -1;
+                       iagp->inofreeback = cpu_to_le32(-1);
                        imap->im_agctl[agno].inofree = iagno;
                }
                IREAD_UNLOCK(ipimap);
@@ -1034,7 +1017,7 @@ int diFree(struct inode *ip)
                 * inodes (i.e., the inode being freed is the first free 
                 * inode of extent),
                 */
-               if (iagp->wmap[extno] == ONES) {
+               if (iagp->wmap[extno] == cpu_to_le32(ONES)) {
                        sword = extno >> L2EXTSPERSUM;
                        bitno = extno & (EXTSPERSUM - 1);
                        iagp->inosmap[sword] &=
@@ -1044,7 +1027,6 @@ int diFree(struct inode *ip)
                /* update the bitmap.
                 */
                iagp->wmap[extno] = cpu_to_le32(bitmap);
-               DBG_DIFREE(imap, inum);
 
                /* update the free inode counts at the iag, ag and
                 * map level.
@@ -1182,7 +1164,7 @@ int diFree(struct inode *ip)
 
                iagp->extfreefwd =
                    cpu_to_le32(imap->im_agctl[agno].extfree);
-               iagp->extfreeback = -1;
+               iagp->extfreeback = cpu_to_le32(-1);
                imap->im_agctl[agno].extfree = iagno;
        } else {
                /* remove the iag from the ag extent list if all extents
@@ -1198,7 +1180,7 @@ int diFree(struct inode *ip)
                                imap->im_agctl[agno].extfree =
                                    le32_to_cpu(iagp->extfreefwd);
 
-                       iagp->extfreefwd = iagp->extfreeback = -1;
+                       iagp->extfreefwd = iagp->extfreeback = cpu_to_le32(-1);
 
                        IAGFREE_LOCK(imap);
                        iagp->iagfree = cpu_to_le32(imap->im_freeiag);
@@ -1220,7 +1202,7 @@ int diFree(struct inode *ip)
                        imap->im_agctl[agno].inofree =
                            le32_to_cpu(iagp->inofreefwd);
 
-               iagp->inofreefwd = iagp->inofreeback = -1;
+               iagp->inofreefwd = iagp->inofreeback = cpu_to_le32(-1);
        }
 
        /* update the inode extent address and working map 
@@ -1232,7 +1214,6 @@ int diFree(struct inode *ip)
                jfs_error(ip->i_sb, "diFree: the pmap does not show inode free");
        }
        iagp->wmap[extno] = 0;
-       DBG_DIFREE(imap, inum);
        PXDlength(&iagp->inoext[extno], 0);
        PXDaddress(&iagp->inoext[extno], 0);
 
@@ -1281,7 +1262,7 @@ int diFree(struct inode *ip)
         * to be freed by the transaction;  
         */
        tid = txBegin(ipimap->i_sb, COMMIT_FORCE);
-       down(&JFS_IP(ipimap)->commit_sem);
+       mutex_lock(&JFS_IP(ipimap)->commit_mutex);
 
        /* acquire tlock of the iag page of the freed ixad 
         * to force the page NOHOMEOK (even though no data is
@@ -1314,7 +1295,7 @@ int diFree(struct inode *ip)
        rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
 
        txEnd(tid);
-       up(&JFS_IP(ipimap)->commit_sem);
+       mutex_unlock(&JFS_IP(ipimap)->commit_mutex);
 
        /* unlock the AG inode map information */
        AG_UNLOCK(imap, agno);
@@ -1351,7 +1332,6 @@ diInitInode(struct inode *ip, int iagno, int ino, int extno, struct iag * iagp)
        struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 
        ip->i_ino = (iagno << L2INOSPERIAG) + ino;
-       DBG_DIALLOC(JFS_IP(ipimap)->i_imap, ip->i_ino);
        jfs_ip->ixpxd = iagp->inoext[extno];
        jfs_ip->agno = BLKTOAG(le64_to_cpu(iagp->agstart), sbi);
        jfs_ip->active_ag = -1;
@@ -2128,7 +2108,7 @@ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
         * allocated.  if so, update the free inode summary
         * map to reflect this.
         */
-       if (iagp->wmap[extno] == ONES) {
+       if (iagp->wmap[extno] == cpu_to_le32(ONES)) {
                sword = extno >> L2EXTSPERSUM;
                bitno = extno & (EXTSPERSUM - 1);
                iagp->inosmap[sword] |= cpu_to_le32(HIGHORDER >> bitno);
@@ -2150,7 +2130,7 @@ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
                        imap->im_agctl[agno].inofree =
                            le32_to_cpu(iagp->inofreefwd);
                }
-               iagp->inofreefwd = iagp->inofreeback = -1;
+               iagp->inofreefwd = iagp->inofreeback = cpu_to_le32(-1);
        }
 
        /* update the free inode count at the iag, ag, inode
@@ -2359,7 +2339,7 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
                        imap->im_agctl[agno].extfree =
                            le32_to_cpu(iagp->extfreefwd);
 
-               iagp->extfreefwd = iagp->extfreeback = -1;
+               iagp->extfreefwd = iagp->extfreeback = cpu_to_le32(-1);
        } else {
                /* if the iag has all free extents (newly allocated iag),
                 * add the iag to the ag free extent list.
@@ -2369,7 +2349,7 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
                                aiagp->extfreeback = cpu_to_le32(iagno);
 
                        iagp->extfreefwd = cpu_to_le32(fwd);
-                       iagp->extfreeback = -1;
+                       iagp->extfreeback = cpu_to_le32(-1);
                        imap->im_agctl[agno].extfree = iagno;
                }
        }
@@ -2383,7 +2363,7 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
 
                iagp->inofreefwd =
                    cpu_to_le32(imap->im_agctl[agno].inofree);
-               iagp->inofreeback = -1;
+               iagp->inofreeback = cpu_to_le32(-1);
                imap->im_agctl[agno].inofree = iagno;
        }
 
@@ -2570,9 +2550,18 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
                        goto out;
                }
 
-               /* assign a buffer for the page */
-               mp = get_metapage(ipimap, xaddr, PSIZE, 1);
-               if (!mp) {
+               /*
+                * start transaction of update of the inode map
+                * addressing structure pointing to the new iag page;
+                */
+               tid = txBegin(sb, COMMIT_FORCE);
+               mutex_lock(&JFS_IP(ipimap)->commit_mutex);
+
+               /* update the inode map addressing structure to point to it */
+               if ((rc =
+                    xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) {
+                       txEnd(tid);
+                       mutex_unlock(&JFS_IP(ipimap)->commit_mutex);
                        /* Free the blocks allocated for the iag since it was
                         * not successfully added to the inode map
                         */
@@ -2581,6 +2570,29 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
                        /* release the inode map lock */
                        IWRITE_UNLOCK(ipimap);
 
+                       goto out;
+               }
+
+               /* update the inode map's inode to reflect the extension */
+               ipimap->i_size += PSIZE;
+               inode_add_bytes(ipimap, PSIZE);
+
+               /* assign a buffer for the page */
+               mp = get_metapage(ipimap, blkno, PSIZE, 0);
+               if (!mp) {
+                       /*
+                        * This is very unlikely since we just created the
+                        * extent, but let's try to handle it correctly
+                        */
+                       xtTruncate(tid, ipimap, ipimap->i_size - PSIZE,
+                                  COMMIT_PWMAP);
+
+                       txAbort(tid, 0);
+                       txEnd(tid);
+
+                       /* release the inode map lock */
+                       IWRITE_UNLOCK(ipimap);
+
                        rc = -EIO;
                        goto out;
                }
@@ -2589,9 +2601,9 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
                /* init the iag */
                memset(iagp, 0, sizeof(struct iag));
                iagp->iagnum = cpu_to_le32(iagno);
-               iagp->inofreefwd = iagp->inofreeback = -1;
-               iagp->extfreefwd = iagp->extfreeback = -1;
-               iagp->iagfree = -1;
+               iagp->inofreefwd = iagp->inofreeback = cpu_to_le32(-1);
+               iagp->extfreefwd = iagp->extfreeback = cpu_to_le32(-1);
+               iagp->iagfree = cpu_to_le32(-1);
                iagp->nfreeinos = 0;
                iagp->nfreeexts = cpu_to_le32(EXTSPERIAG);
 
@@ -2599,53 +2611,12 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
                 * summary map initialization handled by bzero).
                 */
                for (i = 0; i < SMAPSZ; i++)
-                       iagp->inosmap[i] = ONES;
-
-               flush_metapage(mp);
-#ifdef _STILL_TO_PORT
-               /* synchronously write the iag page */
-               if (bmWrite(bp)) {
-                       /* Free the blocks allocated for the iag since it was
-                        * not successfully added to the inode map
-                        */
-                       dbFree(ipimap, xaddr, (s64) xlen);
-
-                       /* release the inode map lock */
-                       IWRITE_UNLOCK(ipimap);
-
-                       rc = -EIO;
-                       goto out;
-               }
-
-               /* Now the iag is on disk */
+                       iagp->inosmap[i] = cpu_to_le32(ONES);
 
                /*
-                * start tyransaction of update of the inode map
-                * addressing structure pointing to the new iag page;
+                * Write and sync the metapage
                 */
-#endif                         /*  _STILL_TO_PORT */
-               tid = txBegin(sb, COMMIT_FORCE);
-               down(&JFS_IP(ipimap)->commit_sem);
-
-               /* update the inode map addressing structure to point to it */
-               if ((rc =
-                    xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) {
-                       txEnd(tid);
-                       up(&JFS_IP(ipimap)->commit_sem);
-                       /* Free the blocks allocated for the iag since it was
-                        * not successfully added to the inode map
-                        */
-                       dbFree(ipimap, xaddr, (s64) xlen);
-
-                       /* release the inode map lock */
-                       IWRITE_UNLOCK(ipimap);
-
-                       goto out;
-               }
-
-               /* update the inode map's inode to reflect the extension */
-               ipimap->i_size += PSIZE;
-               ipimap->i_blocks += LBLK2PBLK(sb, xlen);
+               flush_metapage(mp);
 
                /*
                 * txCommit(COMMIT_FORCE) will synchronously write address 
@@ -2656,7 +2627,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
                rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
 
                txEnd(tid);
-               up(&JFS_IP(ipimap)->commit_sem);
+               mutex_unlock(&JFS_IP(ipimap)->commit_mutex);
 
                duplicateIXtree(sb, blkno, xlen, &xaddr);
 
@@ -2690,7 +2661,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
 
        /* remove the iag from the iag free list */
        imap->im_freeiag = le32_to_cpu(iagp->iagfree);
-       iagp->iagfree = -1;
+       iagp->iagfree = cpu_to_le32(-1);
 
        /* set the return iag number and buffer pointer */
        *iagnop = iagno;
@@ -2797,6 +2768,7 @@ diUpdatePMap(struct inode *ipimap,
        u32 mask;
        struct jfs_log *log;
        int lsn, difft, diffp;
+       unsigned long flags;
 
        imap = JFS_IP(ipimap)->i_imap;
        /* get the iag number containing the inode */
@@ -2813,6 +2785,7 @@ diUpdatePMap(struct inode *ipimap,
        IREAD_UNLOCK(ipimap);
        if (rc)
                return (rc);
+       metapage_wait_for_io(mp);
        iagp = (struct iag *) mp->data;
        /* get the inode number and extent number of the inode within
         * the iag and the inode number within the extent.
@@ -2872,6 +2845,7 @@ diUpdatePMap(struct inode *ipimap,
         */
        lsn = tblk->lsn;
        log = JFS_SBI(tblk->sb)->log;
+       LOGSYNC_LOCK(log, flags);
        if (mp->lsn != 0) {
                /* inherit older/smaller lsn */
                logdiff(difft, lsn, log);
@@ -2879,28 +2853,23 @@ diUpdatePMap(struct inode *ipimap,
                if (difft < diffp) {
                        mp->lsn = lsn;
                        /* move mp after tblock in logsync list */
-                       LOGSYNC_LOCK(log);
                        list_move(&mp->synclist, &tblk->synclist);
-                       LOGSYNC_UNLOCK(log);
                }
                /* inherit younger/larger clsn */
-               LOGSYNC_LOCK(log);
                assert(mp->clsn);
                logdiff(difft, tblk->clsn, log);
                logdiff(diffp, mp->clsn, log);
                if (difft > diffp)
                        mp->clsn = tblk->clsn;
-               LOGSYNC_UNLOCK(log);
        } else {
                mp->log = log;
                mp->lsn = lsn;
                /* insert mp after tblock in logsync list */
-               LOGSYNC_LOCK(log);
                log->count++;
                list_add(&mp->synclist, &tblk->synclist);
                mp->clsn = tblk->clsn;
-               LOGSYNC_UNLOCK(log);
        }
+       LOGSYNC_UNLOCK(log, flags);
        write_metapage(mp);
        return (0);
 }
@@ -2938,8 +2907,8 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
 
        /* init per AG control information im_agctl[] */
        for (i = 0; i < MAXAG; i++) {
-               imap->im_agctl[i].inofree = -1; /* free inode list */
-               imap->im_agctl[i].extfree = -1; /* free extent list */
+               imap->im_agctl[i].inofree = -1;
+               imap->im_agctl[i].extfree = -1;
                imap->im_agctl[i].numinos = 0;  /* number of backed inodes */
                imap->im_agctl[i].numfree = 0;  /* number of free backed inodes */
        }
@@ -2984,18 +2953,18 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
 
                /* if any backed free inodes, insert at AG free inode list */
                if ((int) le32_to_cpu(iagp->nfreeinos) > 0) {
-                       if ((head = imap->im_agctl[n].inofree) == -1)
-                               iagp->inofreefwd = iagp->inofreeback = -1;
-                       else {
+                       if ((head = imap->im_agctl[n].inofree) == -1) {
+                               iagp->inofreefwd = cpu_to_le32(-1);
+                               iagp->inofreeback = cpu_to_le32(-1);
+                       } else {
                                if ((rc = diIAGRead(imap, head, &hbp))) {
                                        rcx = rc;
                                        goto nextiag;
                                }
                                hiagp = (struct iag *) hbp->data;
-                               hiagp->inofreeback =
-                                   le32_to_cpu(iagp->iagnum);
+                               hiagp->inofreeback = iagp->iagnum;
                                iagp->inofreefwd = cpu_to_le32(head);
-                               iagp->inofreeback = -1;
+                               iagp->inofreeback = cpu_to_le32(-1);
                                write_metapage(hbp);
                        }
 
@@ -3010,9 +2979,10 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
 
                /* if any free extents, insert at AG free extent list */
                if (le32_to_cpu(iagp->nfreeexts) > 0) {
-                       if ((head = imap->im_agctl[n].extfree) == -1)
-                               iagp->extfreefwd = iagp->extfreeback = -1;
-                       else {
+                       if ((head = imap->im_agctl[n].extfree) == -1) {
+                               iagp->extfreefwd = cpu_to_le32(-1);
+                               iagp->extfreeback = cpu_to_le32(-1);
+                       } else {
                                if ((rc = diIAGRead(imap, head, &hbp))) {
                                        rcx = rc;
                                        goto nextiag;
@@ -3020,7 +2990,7 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
                                hiagp = (struct iag *) hbp->data;
                                hiagp->extfreeback = iagp->iagnum;
                                iagp->extfreefwd = cpu_to_le32(head);
-                               iagp->extfreeback = -1;
+                               iagp->extfreeback = cpu_to_le32(-1);
                                write_metapage(hbp);
                        }
 
@@ -3067,7 +3037,7 @@ static void duplicateIXtree(struct super_block *sb, s64 blkno,
                if (readSuper(sb, &bh))
                        return;
                j_sb = (struct jfs_superblock *)bh->b_data;
-               j_sb->s_flag |= JFS_BAD_SAIT;
+               j_sb->s_flag |= cpu_to_le32(JFS_BAD_SAIT);
 
                mark_buffer_dirty(bh);
                sync_dirty_buffer(bh);
@@ -3086,7 +3056,7 @@ static void duplicateIXtree(struct super_block *sb, s64 blkno,
        }
        /* update the inode map's inode to reflect the extension */
        ip->i_size += PSIZE;
-       ip->i_blocks += LBLK2PBLK(sb, xlen);
+       inode_add_bytes(ip, PSIZE);
        txCommit(tid, 1, &ip, COMMIT_FORCE);
       cleanup:
        txEnd(tid);
@@ -3105,6 +3075,7 @@ static void duplicateIXtree(struct super_block *sb, s64 blkno,
 static int copy_from_dinode(struct dinode * dip, struct inode *ip)
 {
        struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+       struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
        uid_t uid;
        gid_t gid;
 
@@ -3112,14 +3083,38 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip)
        jfs_ip->mode2 = le32_to_cpu(dip->di_mode);
 
        ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff;
+       if (sbi->umask != -1) {
+               ip->i_mode = (ip->i_mode & ~0777) | (0777 & ~sbi->umask);
+               /* For directories, add x permission if r is allowed by umask */
+               if (S_ISDIR(ip->i_mode)) {
+                       if (ip->i_mode & 0400)
+                               ip->i_mode |= 0100;
+                       if (ip->i_mode & 0040)
+                               ip->i_mode |= 0010;
+                       if (ip->i_mode & 0004)
+                               ip->i_mode |= 0001;
+               }
+       }
        ip->i_nlink = le32_to_cpu(dip->di_nlink);
 
        uid = le32_to_cpu(dip->di_uid);
        gid = le32_to_cpu(dip->di_gid);
-       ip->i_uid = INOXID_UID(XID_TAG(ip), uid, gid);
-       ip->i_gid = INOXID_GID(XID_TAG(ip), uid, gid);
        ip->i_xid = INOXID_XID(XID_TAG(ip), uid, gid, 0);
-       
+
+       jfs_ip->saved_uid = INOXID_UID(XID_TAG(ip), uid, gid);
+       if (sbi->uid == -1)
+               ip->i_uid = jfs_ip->saved_uid;
+       else {
+               ip->i_uid = sbi->uid;
+       }
+
+       jfs_ip->saved_gid = INOXID_GID(XID_TAG(ip), uid, gid);
+       if (sbi->gid == -1)
+               ip->i_gid = jfs_ip->saved_gid;
+       else {
+               ip->i_gid = sbi->gid;
+       }
+
        ip->i_size = le64_to_cpu(dip->di_size);
        ip->i_atime.tv_sec = le32_to_cpu(dip->di_atime.tv_sec);
        ip->i_atime.tv_nsec = le32_to_cpu(dip->di_atime.tv_nsec);
@@ -3170,26 +3165,31 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip)
 static void copy_to_dinode(struct dinode * dip, struct inode *ip)
 {
        struct jfs_inode_info *jfs_ip = JFS_IP(ip);
-       uid_t uid;
-       gid_t gid;
+       struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
 
        dip->di_fileset = cpu_to_le32(jfs_ip->fileset);
-       dip->di_inostamp = cpu_to_le32(JFS_SBI(ip->i_sb)->inostamp);
+       dip->di_inostamp = cpu_to_le32(sbi->inostamp);
        dip->di_number = cpu_to_le32(ip->i_ino);
        dip->di_gen = cpu_to_le32(ip->i_generation);
        dip->di_size = cpu_to_le64(ip->i_size);
        dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks));
        dip->di_nlink = cpu_to_le32(ip->i_nlink);
 
-       uid = XIDINO_UID(XID_TAG(ip), ip->i_uid, ip->i_xid);
-       gid = XIDINO_GID(XID_TAG(ip), ip->i_gid, ip->i_xid);
-       dip->di_uid = cpu_to_le32(uid);
-       dip->di_gid = cpu_to_le32(gid);
+       dip->di_uid = cpu_to_le32(XIDINO_UID(XID_TAG(ip),
+               (sbi->uid == -1) ? ip->i_uid : jfs_ip->saved_uid, ip->i_xid));
+       dip->di_gid = cpu_to_le32(XIDINO_GID(XID_TAG(ip),
+               (sbi->gid == -1) ? ip->i_gid : jfs_ip->saved_gid, ip->i_xid));
+
        /*
         * mode2 is only needed for storing the higher order bits.
         * Trust i_mode for the lower order ones
         */
-       dip->di_mode = cpu_to_le32((jfs_ip->mode2 & 0xffff0000) | ip->i_mode);
+       if (sbi->umask == -1)
+               dip->di_mode = cpu_to_le32((jfs_ip->mode2 & 0xffff0000) |
+                                          ip->i_mode);
+       else /* Leave the original permissions alone */
+               dip->di_mode = cpu_to_le32(jfs_ip->mode2);
+
        dip->di_atime.tv_sec = cpu_to_le32(ip->i_atime.tv_sec);
        dip->di_atime.tv_nsec = cpu_to_le32(ip->i_atime.tv_nsec);
        dip->di_ctime.tv_sec = cpu_to_le32(ip->i_ctime.tv_sec);
@@ -3206,84 +3206,3 @@ static void copy_to_dinode(struct dinode * dip, struct inode *ip)
        if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode))
                dip->di_rdev = cpu_to_le32(jfs_ip->dev);
 }
-
-#ifdef _JFS_DEBUG_IMAP
-/*
- *     DBGdiInit()
- */
-static void *DBGdiInit(struct inomap * imap)
-{
-       u32 *dimap;
-       int size;
-       size = 64 * 1024;
-       if ((dimap = (u32 *) xmalloc(size, L2PSIZE, kernel_heap)) == NULL)
-               assert(0);
-       bzero((void *) dimap, size);
-       imap->im_DBGdimap = dimap;
-}
-
-/*
- *     DBGdiAlloc()
- */
-static void DBGdiAlloc(struct inomap * imap, ino_t ino)
-{
-       u32 *dimap = imap->im_DBGdimap;
-       int w, b;
-       u32 m;
-       w = ino >> 5;
-       b = ino & 31;
-       m = 0x80000000 >> b;
-       assert(w < 64 * 256);
-       if (dimap[w] & m) {
-               printk("DEBUG diAlloc: duplicate alloc ino:0x%x\n", ino);
-       }
-       dimap[w] |= m;
-}
-
-/*
- *     DBGdiFree()
- */
-static void DBGdiFree(struct inomap * imap, ino_t ino)
-{
-       u32 *dimap = imap->im_DBGdimap;
-       int w, b;
-       u32 m;
-       w = ino >> 5;
-       b = ino & 31;
-       m = 0x80000000 >> b;
-       assert(w < 64 * 256);
-       if ((dimap[w] & m) == 0) {
-               printk("DEBUG diFree: duplicate free ino:0x%x\n", ino);
-       }
-       dimap[w] &= ~m;
-}
-
-static void dump_cp(struct inomap * ipimap, char *function, int line)
-{
-       printk("\n* ********* *\nControl Page %s %d\n", function, line);
-       printk("FreeIAG %d\tNextIAG %d\n", ipimap->im_freeiag,
-              ipimap->im_nextiag);
-       printk("NumInos %d\tNumFree %d\n",
-              atomic_read(&ipimap->im_numinos),
-              atomic_read(&ipimap->im_numfree));
-       printk("AG InoFree %d\tAG ExtFree %d\n",
-              ipimap->im_agctl[0].inofree, ipimap->im_agctl[0].extfree);
-       printk("AG NumInos %d\tAG NumFree %d\n",
-              ipimap->im_agctl[0].numinos, ipimap->im_agctl[0].numfree);
-}
-
-static void dump_iag(struct iag * iag, char *function, int line)
-{
-       printk("\n* ********* *\nIAG %s %d\n", function, line);
-       printk("IagNum %d\tIAG Free %d\n", le32_to_cpu(iag->iagnum),
-              le32_to_cpu(iag->iagfree));
-       printk("InoFreeFwd %d\tInoFreeBack %d\n",
-              le32_to_cpu(iag->inofreefwd),
-              le32_to_cpu(iag->inofreeback));
-       printk("ExtFreeFwd %d\tExtFreeBack %d\n",
-              le32_to_cpu(iag->extfreefwd),
-              le32_to_cpu(iag->extfreeback));
-       printk("NFreeInos %d\tNFreeExts %d\n", le32_to_cpu(iag->nfreeinos),
-              le32_to_cpu(iag->nfreeexts));
-}
-#endif                         /* _JFS_DEBUG_IMAP */