X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fjfs%2Fjfs_imap.c;h=dcd9f7e7731b6009951ed5c3f8e1e5cdd3423e62;hb=a2f44b27303a5353859d77a3e96a1d3f33f56ab7;hp=9c483a635ec510f830441b97970a481f8d6b054f;hpb=5167311cae6aa3a5ff5afd39f88c32a435c969ef;p=linux-2.6.git diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index 9c483a635..dcd9f7e77 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -3,16 +3,16 @@ * * 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 - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -45,10 +45,10 @@ #include #include #include -#include -#include +#include #include "jfs_incore.h" +#include "jfs_inode.h" #include "jfs_filsys.h" #include "jfs_dinode.h" #include "jfs_dmap.h" @@ -57,29 +57,30 @@ #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 */ -static int diAllocAG(struct inomap *, int, boolean_t, struct inode *); -static int diAllocAny(struct inomap *, int, boolean_t, struct inode *); +static int diAllocAG(struct inomap *, int, bool, struct inode *); +static int diAllocAny(struct inomap *, int, bool, struct inode *); static int diAllocBit(struct inomap *, struct iag *, int); static int diAllocExt(struct inomap *, int, struct inode *); static int diAllocIno(struct inomap *, int, struct inode *); @@ -92,32 +93,13 @@ 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() * * FUNCTION: initialize the incore inode map control structures for * a fileset or aggregate init time. * - * the inode map's control structure (dinomap) is + * the inode map's control structure (dinomap) is * brought in from disk and placed in virtual memory. * * PARAMETERS: @@ -126,7 +108,7 @@ static void DBGdiFree(struct inomap * imap, ino_t ino); * RETURN VALUES: * 0 - success * -ENOMEM - insufficient free virtual memory. - * -EIO - i/o error. + * -EIO - i/o error. */ int diMount(struct inode *ipimap) { @@ -139,7 +121,7 @@ int diMount(struct inode *ipimap) * allocate/initialize the in-memory inode map control structure */ /* allocate the in-memory inode map control structure. */ - imap = (struct inomap *) kmalloc(sizeof(struct inomap), GFP_KERNEL); + imap = kmalloc(sizeof(struct inomap), GFP_KERNEL); if (imap == NULL) { jfs_err("diMount: kmalloc returned NULL!"); return -ENOMEM; @@ -194,8 +176,6 @@ int diMount(struct inode *ipimap) imap->im_ipimap = ipimap; JFS_IP(ipimap)->i_imap = imap; -// DBG_DIINIT(imap); - return (0); } @@ -212,7 +192,7 @@ int diMount(struct inode *ipimap) * RETURN VALUES: * 0 - success * -ENOMEM - insufficient free virtual memory. - * -EIO - i/o error. + * -EIO - i/o error. */ int diUnmount(struct inode *ipimap, int mounterror) { @@ -286,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); @@ -303,7 +282,7 @@ int diSync(struct inode *ipimap) * on entry, the specifed incore inode should itself * specify the disk inode number corresponding to the * incore inode (i.e. i_number should be initialized). - * + * * this routine handles incore inode initialization for * both "special" and "regular" inodes. special inodes * are those required early in the mount process and @@ -311,7 +290,7 @@ int diSync(struct inode *ipimap) * is not yet initialized. these "special" inodes are * identified by a NULL inode map inode pointer and are * actually initialized by a call to diReadSpecial(). - * + * * for regular inodes, the iag describing the disk inode * is read from disk to determine the inode extent address * for the disk inode. with the inode extent address in @@ -324,9 +303,9 @@ int diSync(struct inode *ipimap) * * RETURN VALUES: * 0 - success - * -EIO - i/o error. + * -EIO - i/o error. * -ENOMEM - insufficient memory - * + * */ int diRead(struct inode *ip) { @@ -340,7 +319,7 @@ int diRead(struct inode *ip) struct inomap *imap; int block_offset; int inodes_left; - uint pageno; + unsigned long pageno; int rel_inode; jfs_info("diRead: ino = %ld", ip->i_ino); @@ -504,7 +483,7 @@ 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 */ @@ -518,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); } @@ -541,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 @@ -586,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); } @@ -609,14 +587,14 @@ void diFreeSpecial(struct inode *ip) * page of the extent that contains the disk inode is * read and the disk inode portion of the incore inode * is copied to the disk inode. - * + * * PARAMETERS: * tid - transacation id * ip - pointer to incore inode to be written to the inode extent. * * RETURN VALUES: * 0 - success - * -EIO - i/o error. + * -EIO - i/o error. */ int diWrite(tid_t tid, struct inode *ip) { @@ -629,7 +607,7 @@ int diWrite(tid_t tid, struct inode *ip) int block_offset; int inodes_left; struct metapage *mp; - uint pageno; + unsigned long pageno; int rel_inode; int dioffset; struct inode *ipimap; @@ -699,11 +677,11 @@ int diWrite(tid_t tid, struct inode *ip) * copy btree root from in-memory inode to on-disk inode * * (tlock is taken from inline B+-tree root in in-memory - * inode when the B+-tree root is updated, which is pointed + * inode when the B+-tree root is updated, which is pointed * by jfs_ip->blid as well as being on tx tlock list) * - * further processing of btree root is based on the copy - * in in-memory inode, where txLog() will log from, and, + * further processing of btree root is based on the copy + * in in-memory inode, where txLog() will log from, and, * for xtree root, txUpdateMap() will update map and reset * XAD_NEW bit; */ @@ -847,7 +825,7 @@ int diWrite(tid_t tid, struct inode *ip) memcpy(&dp->di_DASD, &ip->i_DASD, sizeof(struct dasd)); #endif /* _JFS_FASTDASD */ - /* release the buffer holding the updated on-disk inode. + /* release the buffer holding the updated on-disk inode. * the buffer will be later written by commit processing. */ write_metapage(mp); @@ -865,7 +843,7 @@ int diWrite(tid_t tid, struct inode *ip) * if the inode to be freed represents the first (only) * free inode within the iag, the iag will be placed on * the ag free inode list. - * + * * freeing the inode will cause the inode extent to be * freed if the inode is the only allocated inode within * the extent. in this case all the disk resource backing @@ -888,11 +866,11 @@ int diWrite(tid_t tid, struct inode *ip) * any updates and are held until all updates are complete. * * PARAMETERS: - * ip - inode to be freed. + * ip - inode to be freed. * * RETURN VALUES: * 0 - success - * -EIO - i/o error. + * -EIO - i/o error. */ int diFree(struct inode *ip) { @@ -921,7 +899,7 @@ int diFree(struct inode *ip) */ iagno = INOTOIAG(inum); - /* make sure that the iag is contained within + /* make sure that the iag is contained within * the map. */ if (iagno >= imap->im_nextiag) { @@ -1036,7 +1014,7 @@ int diFree(struct inode *ip) /* update the free inode summary map for the extent if * freeing the inode means the extent will now have free - * inodes (i.e., the inode being freed is the first free + * inodes (i.e., the inode being freed is the first free * inode of extent), */ if (iagp->wmap[extno] == cpu_to_le32(ONES)) { @@ -1049,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. @@ -1228,22 +1205,21 @@ int diFree(struct inode *ip) iagp->inofreefwd = iagp->inofreeback = cpu_to_le32(-1); } - /* update the inode extent address and working map + /* update the inode extent address and working map * to reflect the free extent. - * the permanent map should have been updated already + * the permanent map should have been updated already * for the inode being freed. */ if (iagp->pmap[extno] != 0) { 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); /* update the free extent and free inode summary maps * to reflect the freed extent. - * the inode summary map is marked to indicate no inodes + * the inode summary map is marked to indicate no inodes * available for the freed extent. */ sword = extno >> L2EXTSPERSUM; @@ -1280,17 +1256,17 @@ int diFree(struct inode *ip) * start transaction to update block allocation map * for the inode extent freed; * - * N.B. AG_LOCK is released and iag will be released below, and + * N.B. AG_LOCK is released and iag will be released below, and * other thread may allocate inode from/reusing the ixad freed - * BUT with new/different backing inode extent from the extent - * to be freed by the transaction; + * BUT with new/different backing inode extent from the extent + * 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 + /* acquire tlock of the iag page of the freed ixad * to force the page NOHOMEOK (even though no data is - * logged from the iag page) until NOREDOPAGE|FREEXTENT log + * logged from the iag page) until NOREDOPAGE|FREEXTENT log * for the free of the extent is committed; * write FREEXTENT|NOREDOPAGE log record * N.B. linelock is overlaid as freed extent descriptor; @@ -1309,8 +1285,8 @@ int diFree(struct inode *ip) * logredo needs the IAG number and IAG extent index in order * to ensure that the IMap is consistent. The least disruptive * way to pass these values through to the transaction manager - * is in the iplist array. - * + * is in the iplist array. + * * It's not pretty, but it works. */ iplist[1] = (struct inode *) (size_t)iagno; @@ -1319,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); @@ -1356,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; @@ -1366,20 +1341,20 @@ diInitInode(struct inode *ip, int iagno, int ino, int extno, struct iag * iagp) /* * NAME: diAlloc(pip,dir,ip) * - * FUNCTION: allocate a disk inode from the inode working map + * FUNCTION: allocate a disk inode from the inode working map * for a fileset or aggregate. * * PARAMETERS: - * pip - pointer to incore inode for the parent inode. - * dir - TRUE if the new disk inode is for a directory. - * ip - pointer to a new inode + * pip - pointer to incore inode for the parent inode. + * dir - 'true' if the new disk inode is for a directory. + * ip - pointer to a new inode * * RETURN VALUES: * 0 - success. * -ENOSPC - insufficient disk resources. - * -EIO - i/o error. + * -EIO - i/o error. */ -int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) +int diAlloc(struct inode *pip, bool dir, struct inode *ip) { int rc, ino, iagno, addext, extno, bitno, sword; int nwords, rem, i, agno; @@ -1398,10 +1373,10 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) JFS_IP(ip)->ipimap = ipimap; JFS_IP(ip)->fileset = FILESYSTEM_I; - /* for a directory, the allocation policy is to start + /* for a directory, the allocation policy is to start * at the ag level using the preferred ag. */ - if (dir == TRUE) { + if (dir) { agno = dbNextAG(JFS_SBI(pip->i_sb)->ipbmap); AG_LOCK(imap, agno); goto tryag; @@ -1461,7 +1436,7 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) /* * try to allocate from the IAG */ - /* check if the inode may be allocated from the iag + /* check if the inode may be allocated from the iag * (i.e. the inode has free inodes or new extent can be added). */ if (iagp->nfreeinos || addext) { @@ -1516,7 +1491,7 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) * hint or, if appropriate (i.e. addext is true), allocate * an extent of free inodes at or following the extent * containing the hint. - * + * * the free inode and free extent summary maps are used * here, so determine the starting summary map position * and the number of words we'll have to examine. again, @@ -1667,7 +1642,7 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) * inodes should be added for the allocation group, with * the current request satisfied from this extent. if this * is the case, an attempt will be made to do just that. if - * this attempt fails or it has been determined that a new + * this attempt fails or it has been determined that a new * extent should not be added, an attempt is made to satisfy * the request by allocating an existing (backed) free inode * from the allocation group. @@ -1675,24 +1650,24 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) * PRE CONDITION: Already have the AG lock for this AG. * * PARAMETERS: - * imap - pointer to inode map control structure. - * agno - allocation group to allocate from. - * dir - TRUE if the new disk inode is for a directory. - * ip - pointer to the new inode to be filled in on successful return + * imap - pointer to inode map control structure. + * agno - allocation group to allocate from. + * dir - 'true' if the new disk inode is for a directory. + * ip - pointer to the new inode to be filled in on successful return * with the disk inode number allocated, its extent address * and the start of the ag. * * RETURN VALUES: * 0 - success. * -ENOSPC - insufficient disk resources. - * -EIO - i/o error. + * -EIO - i/o error. */ static int -diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) +diAllocAG(struct inomap * imap, int agno, bool dir, struct inode *ip) { int rc, addext, numfree, numinos; - /* get the number of free and the number of backed disk + /* get the number of free and the number of backed disk * inodes currently within the ag. */ numfree = imap->im_agctl[agno].numfree; @@ -1708,7 +1683,7 @@ diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) * if there are a small number of free inodes or number of free * inodes is a small percentage of the number of backed inodes. */ - if (dir == TRUE) + if (dir) addext = (numfree < 64 || (numfree < 256 && ((numfree * 100) / numinos) <= 20)); @@ -1745,26 +1720,26 @@ diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) * specified primary group. * * PARAMETERS: - * imap - pointer to inode map control structure. - * agno - primary allocation group (to avoid). - * dir - TRUE if the new disk inode is for a directory. - * ip - pointer to a new inode to be filled in on successful return + * imap - pointer to inode map control structure. + * agno - primary allocation group (to avoid). + * dir - 'true' if the new disk inode is for a directory. + * ip - pointer to a new inode to be filled in on successful return * with the disk inode number allocated, its extent address * and the start of the ag. * * RETURN VALUES: * 0 - success. * -ENOSPC - insufficient disk resources. - * -EIO - i/o error. + * -EIO - i/o error. */ static int -diAllocAny(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) +diAllocAny(struct inomap * imap, int agno, bool dir, struct inode *ip) { int ag, rc; int maxag = JFS_SBI(imap->im_ipimap->i_sb)->bmap->db_maxag; - /* try to allocate from the ags following agno up to + /* try to allocate from the ags following agno up to * the maximum ag number. */ for (ag = agno + 1; ag <= maxag; ag++) { @@ -1806,21 +1781,21 @@ diAllocAny(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) * * allocation occurs from the first iag on the list using * the iag's free inode summary map to find the leftmost - * free inode in the iag. - * + * free inode in the iag. + * * PRE CONDITION: Already have AG lock for this AG. - * + * * PARAMETERS: - * imap - pointer to inode map control structure. - * agno - allocation group. - * ip - pointer to new inode to be filled in on successful return + * imap - pointer to inode map control structure. + * agno - allocation group. + * ip - pointer to new inode to be filled in on successful return * with the disk inode number allocated, its extent address * and the start of the ag. * * RETURN VALUES: * 0 - success. * -ENOSPC - insufficient disk resources. - * -EIO - i/o error. + * -EIO - i/o error. */ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip) { @@ -1893,7 +1868,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip) return -EIO; } - /* compute the inode number within the iag. + /* compute the inode number within the iag. */ ino = (extno << L2INOSPEREXT) + rem; @@ -1918,17 +1893,17 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip) /* * NAME: diAllocExt(imap,agno,ip) * - * FUNCTION: add a new extent of free inodes to an iag, allocating - * an inode from this extent to satisfy the current allocation - * request. - * + * FUNCTION: add a new extent of free inodes to an iag, allocating + * an inode from this extent to satisfy the current allocation + * request. + * * this routine first tries to find an existing iag with free * extents through the ag free extent list. if list is not * empty, the head of the list will be selected as the home * of the new extent of free inodes. otherwise (the list is * empty), a new iag will be allocated for the ag to contain * the extent. - * + * * once an iag has been selected, the free extent summary map * is used to locate a free extent within the iag and diNewExt() * is called to initialize the extent, with initialization @@ -1936,16 +1911,16 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip) * for the purpose of satisfying this request. * * PARAMETERS: - * imap - pointer to inode map control structure. - * agno - allocation group number. - * ip - pointer to new inode to be filled in on successful return + * imap - pointer to inode map control structure. + * agno - allocation group number. + * ip - pointer to new inode to be filled in on successful return * with the disk inode number allocated, its extent address * and the start of the ag. * * RETURN VALUES: * 0 - success. * -ENOSPC - insufficient disk resources. - * -EIO - i/o error. + * -EIO - i/o error. */ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip) { @@ -2038,7 +2013,7 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip) /* * NAME: diAllocBit(imap,iagp,ino) * - * FUNCTION: allocate a backed inode from an iag. + * FUNCTION: allocate a backed inode from an iag. * * this routine performs the mechanics of allocating a * specified inode from a backed extent. @@ -2051,19 +2026,19 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip) * in the face of updates to multiple buffers. under this * approach, all required buffers are obtained before making * any updates and are held all are updates are complete. - * + * * PRE CONDITION: Already have buffer lock on iagp. Already have AG lock on * this AG. Must have read lock on imap inode. * * PARAMETERS: - * imap - pointer to inode map control structure. - * iagp - pointer to iag. - * ino - inode number to be allocated within the iag. + * imap - pointer to inode map control structure. + * iagp - pointer to iag. + * ino - inode number to be allocated within the iag. * * RETURN VALUES: * 0 - success. * -ENOSPC - insufficient disk resources. - * -EIO - i/o error. + * -EIO - i/o error. */ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino) { @@ -2198,19 +2173,19 @@ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino) * buffers. under this approach, all required buffers are * obtained before making any updates and are held until all * updates are complete. - * + * * PRE CONDITION: Already have buffer lock on iagp. Already have AG lock on * this AG. Must have read lock on imap inode. * * PARAMETERS: - * imap - pointer to inode map control structure. - * iagp - pointer to iag. - * extno - extent number. + * imap - pointer to inode map control structure. + * iagp - pointer to iag. + * extno - extent number. * * RETURN VALUES: * 0 - success. * -ENOSPC - insufficient disk resources. - * -EIO - i/o error. + * -EIO - i/o error. */ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno) { @@ -2458,34 +2433,34 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno) /* * NAME: diNewIAG(imap,iagnop,agno) * - * FUNCTION: allocate a new iag for an allocation group. - * - * first tries to allocate the iag from the inode map - * iagfree list: - * if the list has free iags, the head of the list is removed + * FUNCTION: allocate a new iag for an allocation group. + * + * first tries to allocate the iag from the inode map + * iagfree list: + * if the list has free iags, the head of the list is removed * and returned to satisfy the request. * if the inode map's iag free list is empty, the inode map * is extended to hold a new iag. this new iag is initialized * and returned to satisfy the request. * * PARAMETERS: - * imap - pointer to inode map control structure. - * iagnop - pointer to an iag number set with the number of the + * imap - pointer to inode map control structure. + * iagnop - pointer to an iag number set with the number of the * newly allocated iag upon successful return. - * agno - allocation group number. + * agno - allocation group number. * bpp - Buffer pointer to be filled in with new IAG's buffer * * RETURN VALUES: * 0 - success. * -ENOSPC - insufficient disk resources. - * -EIO - i/o error. + * -EIO - i/o error. * - * serialization: + * serialization: * AG lock held on entry/exit; * write lock on the map is held inside; * read lock on the map is held on successful completion; * - * note: new iag transaction: + * note: new iag transaction: * . synchronously write iag; * . write log of xtree and inode of imap; * . commit; @@ -2520,7 +2495,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) /* acquire the free iag lock */ IAGFREE_LOCK(imap); - /* if there are any iags on the inode map free iag list, + /* if there are any iags on the inode map free iag list, * allocate the iag from the head of the list. */ if (imap->im_freeiag >= 0) { @@ -2575,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 */ @@ -2586,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; } @@ -2606,45 +2613,21 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) for (i = 0; i < SMAPSZ; i++) iagp->inosmap[i] = cpu_to_le32(ONES); - flush_metapage(mp); - /* - * start tyransaction of update of the inode map - * addressing structure pointing to the new iag page; + * Write and sync the metapage */ - 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; - inode_add_bytes(ipimap, PSIZE); + flush_metapage(mp); /* - * txCommit(COMMIT_FORCE) will synchronously write address - * index pages and inode after commit in careful update order + * txCommit(COMMIT_FORCE) will synchronously write address + * index pages and inode after commit in careful update order * of address index pages (right to left, bottom up); */ iplist[0] = ipimap; 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); @@ -2696,11 +2679,11 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) * * FUNCTION: get the buffer for the specified iag within a fileset * or aggregate inode map. - * + * * PARAMETERS: - * imap - pointer to inode map control structure. - * iagno - iag number. - * bpp - point to buffer pointer to be filled in on successful + * imap - pointer to inode map control structure. + * iagno - iag number. + * bpp - point to buffer pointer to be filled in on successful * exit. * * SERIALIZATION: @@ -2710,7 +2693,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) * * RETURN VALUES: * 0 - success. - * -EIO - i/o error. + * -EIO - i/o error. */ static int diIAGRead(struct inomap * imap, int iagno, struct metapage ** mpp) { @@ -2736,8 +2719,8 @@ static int diIAGRead(struct inomap * imap, int iagno, struct metapage ** mpp) * the specified bit position. * * PARAMETERS: - * word - word to be examined. - * start - starting bit position. + * word - word to be examined. + * start - starting bit position. * * RETURN VALUES: * bit position of first free bit in the word or 32 if @@ -2758,24 +2741,24 @@ static int diFindFree(u32 word, int start) /* * NAME: diUpdatePMap() - * - * FUNCTION: Update the persistent map in an IAG for the allocation or + * + * FUNCTION: Update the persistent map in an IAG for the allocation or * freeing of the specified inode. - * + * * PRE CONDITIONS: Working map has already been updated for allocate. * * PARAMETERS: * ipimap - Incore inode map inode * inum - Number of inode to mark in permanent map - * is_free - If TRUE indicates inode should be marked freed, otherwise + * is_free - If 'true' indicates inode should be marked freed, otherwise * indicates inode should be marked allocated. * - * RETURN VALUES: + * RETURN VALUES: * 0 for success */ int diUpdatePMap(struct inode *ipimap, - unsigned long inum, boolean_t is_free, struct tblock * tblk) + unsigned long inum, bool is_free, struct tblock * tblk) { int rc; struct iag *iagp; @@ -2785,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 */ @@ -2801,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. @@ -2809,17 +2794,17 @@ diUpdatePMap(struct inode *ipimap, extno = ino >> L2INOSPEREXT; bitno = ino & (INOSPEREXT - 1); mask = HIGHORDER >> bitno; - /* + /* * mark the inode free in persistent map: */ - if (is_free == TRUE) { + if (is_free) { /* The inode should have been allocated both in working * map and in persistent map; * the inode will be freed from working map at the release * of last reference release; */ if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) { - jfs_error(ipimap->i_sb, + jfs_error(ipimap->i_sb, "diUpdatePMap: inode %ld not marked as " "allocated in wmap!", inum); } @@ -2860,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); @@ -2867,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); } @@ -2897,8 +2878,8 @@ diUpdatePMap(struct inode *ipimap, * diExtendFS() * * function: update imap for extendfs(); - * - * note: AG size has been increased s.t. each k old contiguous AGs are + * + * note: AG size has been increased s.t. each k old contiguous AGs are * coalesced into a new AG; */ int diExtendFS(struct inode *ipimap, struct inode *ipbmap) @@ -2917,7 +2898,7 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap) atomic_read(&imap->im_numfree)); /* - * reconstruct imap + * reconstruct imap * * coalesce contiguous k (newAGSize/oldAGSize) AGs; * i.e., (AGi, ..., AGj) where i = k*n and j = k*(n+1) - 1 to AGn; @@ -2951,7 +2932,7 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap) } /* leave free iag in the free iag list */ - if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) { + if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) { release_metapage(bp); continue; } @@ -3094,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; @@ -3101,13 +3083,37 @@ 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); + ip->i_tag = INOTAG_TAG(DX_TAG(ip), uid, gid, 0); + + jfs_ip->saved_uid = INOTAG_UID(DX_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 = INOTAG_GID(DX_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); @@ -3116,7 +3122,6 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip) ip->i_mtime.tv_nsec = le32_to_cpu(dip->di_mtime.tv_nsec); ip->i_ctime.tv_sec = le32_to_cpu(dip->di_ctime.tv_sec); ip->i_ctime.tv_nsec = le32_to_cpu(dip->di_ctime.tv_nsec); - ip->i_blksize = ip->i_sb->s_blocksize; ip->i_blocks = LBLK2PBLK(ip->i_sb, le64_to_cpu(dip->di_nblocks)); ip->i_generation = le32_to_cpu(dip->di_gen); @@ -3159,26 +3164,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(TAGINO_UID(DX_TAG(ip), + (sbi->uid == -1) ? ip->i_uid : jfs_ip->saved_uid, ip->i_tag)); + dip->di_gid = cpu_to_le32(TAGINO_GID(DX_TAG(ip), + (sbi->gid == -1) ? ip->i_gid : jfs_ip->saved_gid, ip->i_tag)); + /* * 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); @@ -3195,84 +3205,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 */