18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *   Copyright (C) International Business Machines Corp., 2000-2004
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci/*
78c2ecf20Sopenharmony_ci *	jfs_imap.c: inode allocation map manager
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Serialization:
108c2ecf20Sopenharmony_ci *   Each AG has a simple lock which is used to control the serialization of
118c2ecf20Sopenharmony_ci *	the AG level lists.  This lock should be taken first whenever an AG
128c2ecf20Sopenharmony_ci *	level list will be modified or accessed.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *   Each IAG is locked by obtaining the buffer for the IAG page.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci *   There is also a inode lock for the inode map inode.  A read lock needs to
178c2ecf20Sopenharmony_ci *	be taken whenever an IAG is read from the map or the global level
188c2ecf20Sopenharmony_ci *	information is read.  A write lock needs to be taken whenever the global
198c2ecf20Sopenharmony_ci *	level information is modified or an atomic operation needs to be used.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci *	If more than one IAG is read at one time, the read lock may not
228c2ecf20Sopenharmony_ci *	be given up until all of the IAG's are read.  Otherwise, a deadlock
238c2ecf20Sopenharmony_ci *	may occur when trying to obtain the read lock while another thread
248c2ecf20Sopenharmony_ci *	holding the read lock is waiting on the IAG already being held.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci *   The control page of the inode map is read into memory by diMount().
278c2ecf20Sopenharmony_ci *	Thereafter it should only be modified in memory and then it will be
288c2ecf20Sopenharmony_ci *	written out when the filesystem is unmounted by diUnmount().
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <linux/fs.h>
328c2ecf20Sopenharmony_ci#include <linux/buffer_head.h>
338c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
348c2ecf20Sopenharmony_ci#include <linux/quotaops.h>
358c2ecf20Sopenharmony_ci#include <linux/slab.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include "jfs_incore.h"
388c2ecf20Sopenharmony_ci#include "jfs_inode.h"
398c2ecf20Sopenharmony_ci#include "jfs_filsys.h"
408c2ecf20Sopenharmony_ci#include "jfs_dinode.h"
418c2ecf20Sopenharmony_ci#include "jfs_dmap.h"
428c2ecf20Sopenharmony_ci#include "jfs_imap.h"
438c2ecf20Sopenharmony_ci#include "jfs_metapage.h"
448c2ecf20Sopenharmony_ci#include "jfs_superblock.h"
458c2ecf20Sopenharmony_ci#include "jfs_debug.h"
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/*
488c2ecf20Sopenharmony_ci * imap locks
498c2ecf20Sopenharmony_ci */
508c2ecf20Sopenharmony_ci/* iag free list lock */
518c2ecf20Sopenharmony_ci#define IAGFREE_LOCK_INIT(imap)		mutex_init(&imap->im_freelock)
528c2ecf20Sopenharmony_ci#define IAGFREE_LOCK(imap)		mutex_lock(&imap->im_freelock)
538c2ecf20Sopenharmony_ci#define IAGFREE_UNLOCK(imap)		mutex_unlock(&imap->im_freelock)
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* per ag iag list locks */
568c2ecf20Sopenharmony_ci#define AG_LOCK_INIT(imap,index)	mutex_init(&(imap->im_aglock[index]))
578c2ecf20Sopenharmony_ci#define AG_LOCK(imap,agno)		mutex_lock(&imap->im_aglock[agno])
588c2ecf20Sopenharmony_ci#define AG_UNLOCK(imap,agno)		mutex_unlock(&imap->im_aglock[agno])
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/*
618c2ecf20Sopenharmony_ci * forward references
628c2ecf20Sopenharmony_ci */
638c2ecf20Sopenharmony_cistatic int diAllocAG(struct inomap *, int, bool, struct inode *);
648c2ecf20Sopenharmony_cistatic int diAllocAny(struct inomap *, int, bool, struct inode *);
658c2ecf20Sopenharmony_cistatic int diAllocBit(struct inomap *, struct iag *, int);
668c2ecf20Sopenharmony_cistatic int diAllocExt(struct inomap *, int, struct inode *);
678c2ecf20Sopenharmony_cistatic int diAllocIno(struct inomap *, int, struct inode *);
688c2ecf20Sopenharmony_cistatic int diFindFree(u32, int);
698c2ecf20Sopenharmony_cistatic int diNewExt(struct inomap *, struct iag *, int);
708c2ecf20Sopenharmony_cistatic int diNewIAG(struct inomap *, int *, int, struct metapage **);
718c2ecf20Sopenharmony_cistatic void duplicateIXtree(struct super_block *, s64, int, s64 *);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic int diIAGRead(struct inomap * imap, int, struct metapage **);
748c2ecf20Sopenharmony_cistatic int copy_from_dinode(struct dinode *, struct inode *);
758c2ecf20Sopenharmony_cistatic void copy_to_dinode(struct dinode *, struct inode *);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/*
788c2ecf20Sopenharmony_ci * NAME:	diMount()
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci * FUNCTION:	initialize the incore inode map control structures for
818c2ecf20Sopenharmony_ci *		a fileset or aggregate init time.
828c2ecf20Sopenharmony_ci *
838c2ecf20Sopenharmony_ci *		the inode map's control structure (dinomap) is
848c2ecf20Sopenharmony_ci *		brought in from disk and placed in virtual memory.
858c2ecf20Sopenharmony_ci *
868c2ecf20Sopenharmony_ci * PARAMETERS:
878c2ecf20Sopenharmony_ci *	ipimap	- pointer to inode map inode for the aggregate or fileset.
888c2ecf20Sopenharmony_ci *
898c2ecf20Sopenharmony_ci * RETURN VALUES:
908c2ecf20Sopenharmony_ci *	0	- success
918c2ecf20Sopenharmony_ci *	-ENOMEM	- insufficient free virtual memory.
928c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
938c2ecf20Sopenharmony_ci */
948c2ecf20Sopenharmony_ciint diMount(struct inode *ipimap)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	struct inomap *imap;
978c2ecf20Sopenharmony_ci	struct metapage *mp;
988c2ecf20Sopenharmony_ci	int index;
998c2ecf20Sopenharmony_ci	struct dinomap_disk *dinom_le;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	/*
1028c2ecf20Sopenharmony_ci	 * allocate/initialize the in-memory inode map control structure
1038c2ecf20Sopenharmony_ci	 */
1048c2ecf20Sopenharmony_ci	/* allocate the in-memory inode map control structure. */
1058c2ecf20Sopenharmony_ci	imap = kmalloc(sizeof(struct inomap), GFP_KERNEL);
1068c2ecf20Sopenharmony_ci	if (imap == NULL) {
1078c2ecf20Sopenharmony_ci		jfs_err("diMount: kmalloc returned NULL!");
1088c2ecf20Sopenharmony_ci		return -ENOMEM;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/* read the on-disk inode map control structure. */
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	mp = read_metapage(ipimap,
1148c2ecf20Sopenharmony_ci			   IMAPBLKNO << JFS_SBI(ipimap->i_sb)->l2nbperpage,
1158c2ecf20Sopenharmony_ci			   PSIZE, 0);
1168c2ecf20Sopenharmony_ci	if (mp == NULL) {
1178c2ecf20Sopenharmony_ci		kfree(imap);
1188c2ecf20Sopenharmony_ci		return -EIO;
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* copy the on-disk version to the in-memory version. */
1228c2ecf20Sopenharmony_ci	dinom_le = (struct dinomap_disk *) mp->data;
1238c2ecf20Sopenharmony_ci	imap->im_freeiag = le32_to_cpu(dinom_le->in_freeiag);
1248c2ecf20Sopenharmony_ci	imap->im_nextiag = le32_to_cpu(dinom_le->in_nextiag);
1258c2ecf20Sopenharmony_ci	atomic_set(&imap->im_numinos, le32_to_cpu(dinom_le->in_numinos));
1268c2ecf20Sopenharmony_ci	atomic_set(&imap->im_numfree, le32_to_cpu(dinom_le->in_numfree));
1278c2ecf20Sopenharmony_ci	imap->im_nbperiext = le32_to_cpu(dinom_le->in_nbperiext);
1288c2ecf20Sopenharmony_ci	imap->im_l2nbperiext = le32_to_cpu(dinom_le->in_l2nbperiext);
1298c2ecf20Sopenharmony_ci	for (index = 0; index < MAXAG; index++) {
1308c2ecf20Sopenharmony_ci		imap->im_agctl[index].inofree =
1318c2ecf20Sopenharmony_ci		    le32_to_cpu(dinom_le->in_agctl[index].inofree);
1328c2ecf20Sopenharmony_ci		imap->im_agctl[index].extfree =
1338c2ecf20Sopenharmony_ci		    le32_to_cpu(dinom_le->in_agctl[index].extfree);
1348c2ecf20Sopenharmony_ci		imap->im_agctl[index].numinos =
1358c2ecf20Sopenharmony_ci		    le32_to_cpu(dinom_le->in_agctl[index].numinos);
1368c2ecf20Sopenharmony_ci		imap->im_agctl[index].numfree =
1378c2ecf20Sopenharmony_ci		    le32_to_cpu(dinom_le->in_agctl[index].numfree);
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	/* release the buffer. */
1418c2ecf20Sopenharmony_ci	release_metapage(mp);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	/*
1448c2ecf20Sopenharmony_ci	 * allocate/initialize inode allocation map locks
1458c2ecf20Sopenharmony_ci	 */
1468c2ecf20Sopenharmony_ci	/* allocate and init iag free list lock */
1478c2ecf20Sopenharmony_ci	IAGFREE_LOCK_INIT(imap);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	/* allocate and init ag list locks */
1508c2ecf20Sopenharmony_ci	for (index = 0; index < MAXAG; index++) {
1518c2ecf20Sopenharmony_ci		AG_LOCK_INIT(imap, index);
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/* bind the inode map inode and inode map control structure
1558c2ecf20Sopenharmony_ci	 * to each other.
1568c2ecf20Sopenharmony_ci	 */
1578c2ecf20Sopenharmony_ci	imap->im_ipimap = ipimap;
1588c2ecf20Sopenharmony_ci	JFS_IP(ipimap)->i_imap = imap;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	return (0);
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/*
1658c2ecf20Sopenharmony_ci * NAME:	diUnmount()
1668c2ecf20Sopenharmony_ci *
1678c2ecf20Sopenharmony_ci * FUNCTION:	write to disk the incore inode map control structures for
1688c2ecf20Sopenharmony_ci *		a fileset or aggregate at unmount time.
1698c2ecf20Sopenharmony_ci *
1708c2ecf20Sopenharmony_ci * PARAMETERS:
1718c2ecf20Sopenharmony_ci *	ipimap	- pointer to inode map inode for the aggregate or fileset.
1728c2ecf20Sopenharmony_ci *
1738c2ecf20Sopenharmony_ci * RETURN VALUES:
1748c2ecf20Sopenharmony_ci *	0	- success
1758c2ecf20Sopenharmony_ci *	-ENOMEM	- insufficient free virtual memory.
1768c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
1778c2ecf20Sopenharmony_ci */
1788c2ecf20Sopenharmony_ciint diUnmount(struct inode *ipimap, int mounterror)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	struct inomap *imap = JFS_IP(ipimap)->i_imap;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	/*
1838c2ecf20Sopenharmony_ci	 * update the on-disk inode map control structure
1848c2ecf20Sopenharmony_ci	 */
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (!(mounterror || isReadOnly(ipimap)))
1878c2ecf20Sopenharmony_ci		diSync(ipimap);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	/*
1908c2ecf20Sopenharmony_ci	 * Invalidate the page cache buffers
1918c2ecf20Sopenharmony_ci	 */
1928c2ecf20Sopenharmony_ci	truncate_inode_pages(ipimap->i_mapping, 0);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	/*
1958c2ecf20Sopenharmony_ci	 * free in-memory control structure
1968c2ecf20Sopenharmony_ci	 */
1978c2ecf20Sopenharmony_ci	kfree(imap);
1988c2ecf20Sopenharmony_ci	JFS_IP(ipimap)->i_imap = NULL;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	return (0);
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci/*
2058c2ecf20Sopenharmony_ci *	diSync()
2068c2ecf20Sopenharmony_ci */
2078c2ecf20Sopenharmony_ciint diSync(struct inode *ipimap)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	struct dinomap_disk *dinom_le;
2108c2ecf20Sopenharmony_ci	struct inomap *imp = JFS_IP(ipimap)->i_imap;
2118c2ecf20Sopenharmony_ci	struct metapage *mp;
2128c2ecf20Sopenharmony_ci	int index;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	/*
2158c2ecf20Sopenharmony_ci	 * write imap global conrol page
2168c2ecf20Sopenharmony_ci	 */
2178c2ecf20Sopenharmony_ci	/* read the on-disk inode map control structure */
2188c2ecf20Sopenharmony_ci	mp = get_metapage(ipimap,
2198c2ecf20Sopenharmony_ci			  IMAPBLKNO << JFS_SBI(ipimap->i_sb)->l2nbperpage,
2208c2ecf20Sopenharmony_ci			  PSIZE, 0);
2218c2ecf20Sopenharmony_ci	if (mp == NULL) {
2228c2ecf20Sopenharmony_ci		jfs_err("diSync: get_metapage failed!");
2238c2ecf20Sopenharmony_ci		return -EIO;
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	/* copy the in-memory version to the on-disk version */
2278c2ecf20Sopenharmony_ci	dinom_le = (struct dinomap_disk *) mp->data;
2288c2ecf20Sopenharmony_ci	dinom_le->in_freeiag = cpu_to_le32(imp->im_freeiag);
2298c2ecf20Sopenharmony_ci	dinom_le->in_nextiag = cpu_to_le32(imp->im_nextiag);
2308c2ecf20Sopenharmony_ci	dinom_le->in_numinos = cpu_to_le32(atomic_read(&imp->im_numinos));
2318c2ecf20Sopenharmony_ci	dinom_le->in_numfree = cpu_to_le32(atomic_read(&imp->im_numfree));
2328c2ecf20Sopenharmony_ci	dinom_le->in_nbperiext = cpu_to_le32(imp->im_nbperiext);
2338c2ecf20Sopenharmony_ci	dinom_le->in_l2nbperiext = cpu_to_le32(imp->im_l2nbperiext);
2348c2ecf20Sopenharmony_ci	for (index = 0; index < MAXAG; index++) {
2358c2ecf20Sopenharmony_ci		dinom_le->in_agctl[index].inofree =
2368c2ecf20Sopenharmony_ci		    cpu_to_le32(imp->im_agctl[index].inofree);
2378c2ecf20Sopenharmony_ci		dinom_le->in_agctl[index].extfree =
2388c2ecf20Sopenharmony_ci		    cpu_to_le32(imp->im_agctl[index].extfree);
2398c2ecf20Sopenharmony_ci		dinom_le->in_agctl[index].numinos =
2408c2ecf20Sopenharmony_ci		    cpu_to_le32(imp->im_agctl[index].numinos);
2418c2ecf20Sopenharmony_ci		dinom_le->in_agctl[index].numfree =
2428c2ecf20Sopenharmony_ci		    cpu_to_le32(imp->im_agctl[index].numfree);
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/* write out the control structure */
2468c2ecf20Sopenharmony_ci	write_metapage(mp);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	/*
2498c2ecf20Sopenharmony_ci	 * write out dirty pages of imap
2508c2ecf20Sopenharmony_ci	 */
2518c2ecf20Sopenharmony_ci	filemap_write_and_wait(ipimap->i_mapping);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	diWriteSpecial(ipimap, 0);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	return (0);
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci/*
2608c2ecf20Sopenharmony_ci * NAME:	diRead()
2618c2ecf20Sopenharmony_ci *
2628c2ecf20Sopenharmony_ci * FUNCTION:	initialize an incore inode from disk.
2638c2ecf20Sopenharmony_ci *
2648c2ecf20Sopenharmony_ci *		on entry, the specifed incore inode should itself
2658c2ecf20Sopenharmony_ci *		specify the disk inode number corresponding to the
2668c2ecf20Sopenharmony_ci *		incore inode (i.e. i_number should be initialized).
2678c2ecf20Sopenharmony_ci *
2688c2ecf20Sopenharmony_ci *		this routine handles incore inode initialization for
2698c2ecf20Sopenharmony_ci *		both "special" and "regular" inodes.  special inodes
2708c2ecf20Sopenharmony_ci *		are those required early in the mount process and
2718c2ecf20Sopenharmony_ci *		require special handling since much of the file system
2728c2ecf20Sopenharmony_ci *		is not yet initialized.  these "special" inodes are
2738c2ecf20Sopenharmony_ci *		identified by a NULL inode map inode pointer and are
2748c2ecf20Sopenharmony_ci *		actually initialized by a call to diReadSpecial().
2758c2ecf20Sopenharmony_ci *
2768c2ecf20Sopenharmony_ci *		for regular inodes, the iag describing the disk inode
2778c2ecf20Sopenharmony_ci *		is read from disk to determine the inode extent address
2788c2ecf20Sopenharmony_ci *		for the disk inode.  with the inode extent address in
2798c2ecf20Sopenharmony_ci *		hand, the page of the extent that contains the disk
2808c2ecf20Sopenharmony_ci *		inode is read and the disk inode is copied to the
2818c2ecf20Sopenharmony_ci *		incore inode.
2828c2ecf20Sopenharmony_ci *
2838c2ecf20Sopenharmony_ci * PARAMETERS:
2848c2ecf20Sopenharmony_ci *	ip	-  pointer to incore inode to be initialized from disk.
2858c2ecf20Sopenharmony_ci *
2868c2ecf20Sopenharmony_ci * RETURN VALUES:
2878c2ecf20Sopenharmony_ci *	0	- success
2888c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
2898c2ecf20Sopenharmony_ci *	-ENOMEM	- insufficient memory
2908c2ecf20Sopenharmony_ci *
2918c2ecf20Sopenharmony_ci */
2928c2ecf20Sopenharmony_ciint diRead(struct inode *ip)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
2958c2ecf20Sopenharmony_ci	int iagno, ino, extno, rc;
2968c2ecf20Sopenharmony_ci	struct inode *ipimap;
2978c2ecf20Sopenharmony_ci	struct dinode *dp;
2988c2ecf20Sopenharmony_ci	struct iag *iagp;
2998c2ecf20Sopenharmony_ci	struct metapage *mp;
3008c2ecf20Sopenharmony_ci	s64 blkno, agstart;
3018c2ecf20Sopenharmony_ci	struct inomap *imap;
3028c2ecf20Sopenharmony_ci	int block_offset;
3038c2ecf20Sopenharmony_ci	int inodes_left;
3048c2ecf20Sopenharmony_ci	unsigned long pageno;
3058c2ecf20Sopenharmony_ci	int rel_inode;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	jfs_info("diRead: ino = %ld", ip->i_ino);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	ipimap = sbi->ipimap;
3108c2ecf20Sopenharmony_ci	JFS_IP(ip)->ipimap = ipimap;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	/* determine the iag number for this inode (number) */
3138c2ecf20Sopenharmony_ci	iagno = INOTOIAG(ip->i_ino);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	/* read the iag */
3168c2ecf20Sopenharmony_ci	imap = JFS_IP(ipimap)->i_imap;
3178c2ecf20Sopenharmony_ci	IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
3188c2ecf20Sopenharmony_ci	rc = diIAGRead(imap, iagno, &mp);
3198c2ecf20Sopenharmony_ci	IREAD_UNLOCK(ipimap);
3208c2ecf20Sopenharmony_ci	if (rc) {
3218c2ecf20Sopenharmony_ci		jfs_err("diRead: diIAGRead returned %d", rc);
3228c2ecf20Sopenharmony_ci		return (rc);
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	iagp = (struct iag *) mp->data;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* determine inode extent that holds the disk inode */
3288c2ecf20Sopenharmony_ci	ino = ip->i_ino & (INOSPERIAG - 1);
3298c2ecf20Sopenharmony_ci	extno = ino >> L2INOSPEREXT;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	if ((lengthPXD(&iagp->inoext[extno]) != imap->im_nbperiext) ||
3328c2ecf20Sopenharmony_ci	    (addressPXD(&iagp->inoext[extno]) == 0)) {
3338c2ecf20Sopenharmony_ci		release_metapage(mp);
3348c2ecf20Sopenharmony_ci		return -ESTALE;
3358c2ecf20Sopenharmony_ci	}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	/* get disk block number of the page within the inode extent
3388c2ecf20Sopenharmony_ci	 * that holds the disk inode.
3398c2ecf20Sopenharmony_ci	 */
3408c2ecf20Sopenharmony_ci	blkno = INOPBLK(&iagp->inoext[extno], ino, sbi->l2nbperpage);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/* get the ag for the iag */
3438c2ecf20Sopenharmony_ci	agstart = le64_to_cpu(iagp->agstart);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	release_metapage(mp);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	rel_inode = (ino & (INOSPERPAGE - 1));
3488c2ecf20Sopenharmony_ci	pageno = blkno >> sbi->l2nbperpage;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if ((block_offset = ((u32) blkno & (sbi->nbperpage - 1)))) {
3518c2ecf20Sopenharmony_ci		/*
3528c2ecf20Sopenharmony_ci		 * OS/2 didn't always align inode extents on page boundaries
3538c2ecf20Sopenharmony_ci		 */
3548c2ecf20Sopenharmony_ci		inodes_left =
3558c2ecf20Sopenharmony_ci		     (sbi->nbperpage - block_offset) << sbi->l2niperblk;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci		if (rel_inode < inodes_left)
3588c2ecf20Sopenharmony_ci			rel_inode += block_offset << sbi->l2niperblk;
3598c2ecf20Sopenharmony_ci		else {
3608c2ecf20Sopenharmony_ci			pageno += 1;
3618c2ecf20Sopenharmony_ci			rel_inode -= inodes_left;
3628c2ecf20Sopenharmony_ci		}
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	/* read the page of disk inode */
3668c2ecf20Sopenharmony_ci	mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
3678c2ecf20Sopenharmony_ci	if (!mp) {
3688c2ecf20Sopenharmony_ci		jfs_err("diRead: read_metapage failed");
3698c2ecf20Sopenharmony_ci		return -EIO;
3708c2ecf20Sopenharmony_ci	}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	/* locate the disk inode requested */
3738c2ecf20Sopenharmony_ci	dp = (struct dinode *) mp->data;
3748c2ecf20Sopenharmony_ci	dp += rel_inode;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	if (ip->i_ino != le32_to_cpu(dp->di_number)) {
3778c2ecf20Sopenharmony_ci		jfs_error(ip->i_sb, "i_ino != di_number\n");
3788c2ecf20Sopenharmony_ci		rc = -EIO;
3798c2ecf20Sopenharmony_ci	} else if (le32_to_cpu(dp->di_nlink) == 0)
3808c2ecf20Sopenharmony_ci		rc = -ESTALE;
3818c2ecf20Sopenharmony_ci	else
3828c2ecf20Sopenharmony_ci		/* copy the disk inode to the in-memory inode */
3838c2ecf20Sopenharmony_ci		rc = copy_from_dinode(dp, ip);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	release_metapage(mp);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/* set the ag for the inode */
3888c2ecf20Sopenharmony_ci	JFS_IP(ip)->agstart = agstart;
3898c2ecf20Sopenharmony_ci	JFS_IP(ip)->active_ag = -1;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	return (rc);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci/*
3968c2ecf20Sopenharmony_ci * NAME:	diReadSpecial()
3978c2ecf20Sopenharmony_ci *
3988c2ecf20Sopenharmony_ci * FUNCTION:	initialize a 'special' inode from disk.
3998c2ecf20Sopenharmony_ci *
4008c2ecf20Sopenharmony_ci *		this routines handles aggregate level inodes.  The
4018c2ecf20Sopenharmony_ci *		inode cache cannot differentiate between the
4028c2ecf20Sopenharmony_ci *		aggregate inodes and the filesystem inodes, so we
4038c2ecf20Sopenharmony_ci *		handle these here.  We don't actually use the aggregate
4048c2ecf20Sopenharmony_ci *		inode map, since these inodes are at a fixed location
4058c2ecf20Sopenharmony_ci *		and in some cases the aggregate inode map isn't initialized
4068c2ecf20Sopenharmony_ci *		yet.
4078c2ecf20Sopenharmony_ci *
4088c2ecf20Sopenharmony_ci * PARAMETERS:
4098c2ecf20Sopenharmony_ci *	sb - filesystem superblock
4108c2ecf20Sopenharmony_ci *	inum - aggregate inode number
4118c2ecf20Sopenharmony_ci *	secondary - 1 if secondary aggregate inode table
4128c2ecf20Sopenharmony_ci *
4138c2ecf20Sopenharmony_ci * RETURN VALUES:
4148c2ecf20Sopenharmony_ci *	new inode	- success
4158c2ecf20Sopenharmony_ci *	NULL		- i/o error.
4168c2ecf20Sopenharmony_ci */
4178c2ecf20Sopenharmony_cistruct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	struct jfs_sb_info *sbi = JFS_SBI(sb);
4208c2ecf20Sopenharmony_ci	uint address;
4218c2ecf20Sopenharmony_ci	struct dinode *dp;
4228c2ecf20Sopenharmony_ci	struct inode *ip;
4238c2ecf20Sopenharmony_ci	struct metapage *mp;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	ip = new_inode(sb);
4268c2ecf20Sopenharmony_ci	if (ip == NULL) {
4278c2ecf20Sopenharmony_ci		jfs_err("diReadSpecial: new_inode returned NULL!");
4288c2ecf20Sopenharmony_ci		return ip;
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	if (secondary) {
4328c2ecf20Sopenharmony_ci		address = addressPXD(&sbi->ait2) >> sbi->l2nbperpage;
4338c2ecf20Sopenharmony_ci		JFS_IP(ip)->ipimap = sbi->ipaimap2;
4348c2ecf20Sopenharmony_ci	} else {
4358c2ecf20Sopenharmony_ci		address = AITBL_OFF >> L2PSIZE;
4368c2ecf20Sopenharmony_ci		JFS_IP(ip)->ipimap = sbi->ipaimap;
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	ASSERT(inum < INOSPEREXT);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	ip->i_ino = inum;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	address += inum >> 3;	/* 8 inodes per 4K page */
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	/* read the page of fixed disk inode (AIT) in raw mode */
4468c2ecf20Sopenharmony_ci	mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1);
4478c2ecf20Sopenharmony_ci	if (mp == NULL) {
4488c2ecf20Sopenharmony_ci		set_nlink(ip, 1);	/* Don't want iput() deleting it */
4498c2ecf20Sopenharmony_ci		iput(ip);
4508c2ecf20Sopenharmony_ci		return (NULL);
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* get the pointer to the disk inode of interest */
4548c2ecf20Sopenharmony_ci	dp = (struct dinode *) (mp->data);
4558c2ecf20Sopenharmony_ci	dp += inum % 8;		/* 8 inodes per 4K page */
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	/* copy on-disk inode to in-memory inode */
4588c2ecf20Sopenharmony_ci	if ((copy_from_dinode(dp, ip)) != 0) {
4598c2ecf20Sopenharmony_ci		/* handle bad return by returning NULL for ip */
4608c2ecf20Sopenharmony_ci		set_nlink(ip, 1);	/* Don't want iput() deleting it */
4618c2ecf20Sopenharmony_ci		iput(ip);
4628c2ecf20Sopenharmony_ci		/* release the page */
4638c2ecf20Sopenharmony_ci		release_metapage(mp);
4648c2ecf20Sopenharmony_ci		return (NULL);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	ip->i_mapping->a_ops = &jfs_metapage_aops;
4698c2ecf20Sopenharmony_ci	mapping_set_gfp_mask(ip->i_mapping, GFP_NOFS);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	/* Allocations to metadata inodes should not affect quotas */
4728c2ecf20Sopenharmony_ci	ip->i_flags |= S_NOQUOTA;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	if ((inum == FILESYSTEM_I) && (JFS_IP(ip)->ipimap == sbi->ipaimap)) {
4758c2ecf20Sopenharmony_ci		sbi->gengen = le32_to_cpu(dp->di_gengen);
4768c2ecf20Sopenharmony_ci		sbi->inostamp = le32_to_cpu(dp->di_inostamp);
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	/* release the page */
4808c2ecf20Sopenharmony_ci	release_metapage(mp);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	inode_fake_hash(ip);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	return (ip);
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci/*
4888c2ecf20Sopenharmony_ci * NAME:	diWriteSpecial()
4898c2ecf20Sopenharmony_ci *
4908c2ecf20Sopenharmony_ci * FUNCTION:	Write the special inode to disk
4918c2ecf20Sopenharmony_ci *
4928c2ecf20Sopenharmony_ci * PARAMETERS:
4938c2ecf20Sopenharmony_ci *	ip - special inode
4948c2ecf20Sopenharmony_ci *	secondary - 1 if secondary aggregate inode table
4958c2ecf20Sopenharmony_ci *
4968c2ecf20Sopenharmony_ci * RETURN VALUES: none
4978c2ecf20Sopenharmony_ci */
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_civoid diWriteSpecial(struct inode *ip, int secondary)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
5028c2ecf20Sopenharmony_ci	uint address;
5038c2ecf20Sopenharmony_ci	struct dinode *dp;
5048c2ecf20Sopenharmony_ci	ino_t inum = ip->i_ino;
5058c2ecf20Sopenharmony_ci	struct metapage *mp;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	if (secondary)
5088c2ecf20Sopenharmony_ci		address = addressPXD(&sbi->ait2) >> sbi->l2nbperpage;
5098c2ecf20Sopenharmony_ci	else
5108c2ecf20Sopenharmony_ci		address = AITBL_OFF >> L2PSIZE;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	ASSERT(inum < INOSPEREXT);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	address += inum >> 3;	/* 8 inodes per 4K page */
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	/* read the page of fixed disk inode (AIT) in raw mode */
5178c2ecf20Sopenharmony_ci	mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1);
5188c2ecf20Sopenharmony_ci	if (mp == NULL) {
5198c2ecf20Sopenharmony_ci		jfs_err("diWriteSpecial: failed to read aggregate inode extent!");
5208c2ecf20Sopenharmony_ci		return;
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	/* get the pointer to the disk inode of interest */
5248c2ecf20Sopenharmony_ci	dp = (struct dinode *) (mp->data);
5258c2ecf20Sopenharmony_ci	dp += inum % 8;		/* 8 inodes per 4K page */
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	/* copy on-disk inode to in-memory inode */
5288c2ecf20Sopenharmony_ci	copy_to_dinode(dp, ip);
5298c2ecf20Sopenharmony_ci	memcpy(&dp->di_xtroot, &JFS_IP(ip)->i_xtroot, 288);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	if (inum == FILESYSTEM_I)
5328c2ecf20Sopenharmony_ci		dp->di_gengen = cpu_to_le32(sbi->gengen);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	/* write the page */
5358c2ecf20Sopenharmony_ci	write_metapage(mp);
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci/*
5398c2ecf20Sopenharmony_ci * NAME:	diFreeSpecial()
5408c2ecf20Sopenharmony_ci *
5418c2ecf20Sopenharmony_ci * FUNCTION:	Free allocated space for special inode
5428c2ecf20Sopenharmony_ci */
5438c2ecf20Sopenharmony_civoid diFreeSpecial(struct inode *ip)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	if (ip == NULL) {
5468c2ecf20Sopenharmony_ci		jfs_err("diFreeSpecial called with NULL ip!");
5478c2ecf20Sopenharmony_ci		return;
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci	filemap_write_and_wait(ip->i_mapping);
5508c2ecf20Sopenharmony_ci	truncate_inode_pages(ip->i_mapping, 0);
5518c2ecf20Sopenharmony_ci	iput(ip);
5528c2ecf20Sopenharmony_ci}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci/*
5578c2ecf20Sopenharmony_ci * NAME:	diWrite()
5588c2ecf20Sopenharmony_ci *
5598c2ecf20Sopenharmony_ci * FUNCTION:	write the on-disk inode portion of the in-memory inode
5608c2ecf20Sopenharmony_ci *		to its corresponding on-disk inode.
5618c2ecf20Sopenharmony_ci *
5628c2ecf20Sopenharmony_ci *		on entry, the specifed incore inode should itself
5638c2ecf20Sopenharmony_ci *		specify the disk inode number corresponding to the
5648c2ecf20Sopenharmony_ci *		incore inode (i.e. i_number should be initialized).
5658c2ecf20Sopenharmony_ci *
5668c2ecf20Sopenharmony_ci *		the inode contains the inode extent address for the disk
5678c2ecf20Sopenharmony_ci *		inode.  with the inode extent address in hand, the
5688c2ecf20Sopenharmony_ci *		page of the extent that contains the disk inode is
5698c2ecf20Sopenharmony_ci *		read and the disk inode portion of the incore inode
5708c2ecf20Sopenharmony_ci *		is copied to the disk inode.
5718c2ecf20Sopenharmony_ci *
5728c2ecf20Sopenharmony_ci * PARAMETERS:
5738c2ecf20Sopenharmony_ci *	tid -  transacation id
5748c2ecf20Sopenharmony_ci *	ip  -  pointer to incore inode to be written to the inode extent.
5758c2ecf20Sopenharmony_ci *
5768c2ecf20Sopenharmony_ci * RETURN VALUES:
5778c2ecf20Sopenharmony_ci *	0	- success
5788c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
5798c2ecf20Sopenharmony_ci */
5808c2ecf20Sopenharmony_ciint diWrite(tid_t tid, struct inode *ip)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
5838c2ecf20Sopenharmony_ci	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
5848c2ecf20Sopenharmony_ci	int rc = 0;
5858c2ecf20Sopenharmony_ci	s32 ino;
5868c2ecf20Sopenharmony_ci	struct dinode *dp;
5878c2ecf20Sopenharmony_ci	s64 blkno;
5888c2ecf20Sopenharmony_ci	int block_offset;
5898c2ecf20Sopenharmony_ci	int inodes_left;
5908c2ecf20Sopenharmony_ci	struct metapage *mp;
5918c2ecf20Sopenharmony_ci	unsigned long pageno;
5928c2ecf20Sopenharmony_ci	int rel_inode;
5938c2ecf20Sopenharmony_ci	int dioffset;
5948c2ecf20Sopenharmony_ci	struct inode *ipimap;
5958c2ecf20Sopenharmony_ci	uint type;
5968c2ecf20Sopenharmony_ci	lid_t lid;
5978c2ecf20Sopenharmony_ci	struct tlock *ditlck, *tlck;
5988c2ecf20Sopenharmony_ci	struct linelock *dilinelock, *ilinelock;
5998c2ecf20Sopenharmony_ci	struct lv *lv;
6008c2ecf20Sopenharmony_ci	int n;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	ipimap = jfs_ip->ipimap;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	ino = ip->i_ino & (INOSPERIAG - 1);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	if (!addressPXD(&(jfs_ip->ixpxd)) ||
6078c2ecf20Sopenharmony_ci	    (lengthPXD(&(jfs_ip->ixpxd)) !=
6088c2ecf20Sopenharmony_ci	     JFS_IP(ipimap)->i_imap->im_nbperiext)) {
6098c2ecf20Sopenharmony_ci		jfs_error(ip->i_sb, "ixpxd invalid\n");
6108c2ecf20Sopenharmony_ci		return -EIO;
6118c2ecf20Sopenharmony_ci	}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	/*
6148c2ecf20Sopenharmony_ci	 * read the page of disk inode containing the specified inode:
6158c2ecf20Sopenharmony_ci	 */
6168c2ecf20Sopenharmony_ci	/* compute the block address of the page */
6178c2ecf20Sopenharmony_ci	blkno = INOPBLK(&(jfs_ip->ixpxd), ino, sbi->l2nbperpage);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	rel_inode = (ino & (INOSPERPAGE - 1));
6208c2ecf20Sopenharmony_ci	pageno = blkno >> sbi->l2nbperpage;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if ((block_offset = ((u32) blkno & (sbi->nbperpage - 1)))) {
6238c2ecf20Sopenharmony_ci		/*
6248c2ecf20Sopenharmony_ci		 * OS/2 didn't always align inode extents on page boundaries
6258c2ecf20Sopenharmony_ci		 */
6268c2ecf20Sopenharmony_ci		inodes_left =
6278c2ecf20Sopenharmony_ci		    (sbi->nbperpage - block_offset) << sbi->l2niperblk;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci		if (rel_inode < inodes_left)
6308c2ecf20Sopenharmony_ci			rel_inode += block_offset << sbi->l2niperblk;
6318c2ecf20Sopenharmony_ci		else {
6328c2ecf20Sopenharmony_ci			pageno += 1;
6338c2ecf20Sopenharmony_ci			rel_inode -= inodes_left;
6348c2ecf20Sopenharmony_ci		}
6358c2ecf20Sopenharmony_ci	}
6368c2ecf20Sopenharmony_ci	/* read the page of disk inode */
6378c2ecf20Sopenharmony_ci      retry:
6388c2ecf20Sopenharmony_ci	mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
6398c2ecf20Sopenharmony_ci	if (!mp)
6408c2ecf20Sopenharmony_ci		return -EIO;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	/* get the pointer to the disk inode */
6438c2ecf20Sopenharmony_ci	dp = (struct dinode *) mp->data;
6448c2ecf20Sopenharmony_ci	dp += rel_inode;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	dioffset = (ino & (INOSPERPAGE - 1)) << L2DISIZE;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	/*
6498c2ecf20Sopenharmony_ci	 * acquire transaction lock on the on-disk inode;
6508c2ecf20Sopenharmony_ci	 * N.B. tlock is acquired on ipimap not ip;
6518c2ecf20Sopenharmony_ci	 */
6528c2ecf20Sopenharmony_ci	if ((ditlck =
6538c2ecf20Sopenharmony_ci	     txLock(tid, ipimap, mp, tlckINODE | tlckENTRY)) == NULL)
6548c2ecf20Sopenharmony_ci		goto retry;
6558c2ecf20Sopenharmony_ci	dilinelock = (struct linelock *) & ditlck->lock;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	/*
6588c2ecf20Sopenharmony_ci	 * copy btree root from in-memory inode to on-disk inode
6598c2ecf20Sopenharmony_ci	 *
6608c2ecf20Sopenharmony_ci	 * (tlock is taken from inline B+-tree root in in-memory
6618c2ecf20Sopenharmony_ci	 * inode when the B+-tree root is updated, which is pointed
6628c2ecf20Sopenharmony_ci	 * by jfs_ip->blid as well as being on tx tlock list)
6638c2ecf20Sopenharmony_ci	 *
6648c2ecf20Sopenharmony_ci	 * further processing of btree root is based on the copy
6658c2ecf20Sopenharmony_ci	 * in in-memory inode, where txLog() will log from, and,
6668c2ecf20Sopenharmony_ci	 * for xtree root, txUpdateMap() will update map and reset
6678c2ecf20Sopenharmony_ci	 * XAD_NEW bit;
6688c2ecf20Sopenharmony_ci	 */
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	if (S_ISDIR(ip->i_mode) && (lid = jfs_ip->xtlid)) {
6718c2ecf20Sopenharmony_ci		/*
6728c2ecf20Sopenharmony_ci		 * This is the special xtree inside the directory for storing
6738c2ecf20Sopenharmony_ci		 * the directory table
6748c2ecf20Sopenharmony_ci		 */
6758c2ecf20Sopenharmony_ci		xtpage_t *p, *xp;
6768c2ecf20Sopenharmony_ci		xad_t *xad;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci		jfs_ip->xtlid = 0;
6798c2ecf20Sopenharmony_ci		tlck = lid_to_tlock(lid);
6808c2ecf20Sopenharmony_ci		assert(tlck->type & tlckXTREE);
6818c2ecf20Sopenharmony_ci		tlck->type |= tlckBTROOT;
6828c2ecf20Sopenharmony_ci		tlck->mp = mp;
6838c2ecf20Sopenharmony_ci		ilinelock = (struct linelock *) & tlck->lock;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		/*
6868c2ecf20Sopenharmony_ci		 * copy xtree root from inode to dinode:
6878c2ecf20Sopenharmony_ci		 */
6888c2ecf20Sopenharmony_ci		p = &jfs_ip->i_xtroot;
6898c2ecf20Sopenharmony_ci		xp = (xtpage_t *) &dp->di_dirtable;
6908c2ecf20Sopenharmony_ci		lv = ilinelock->lv;
6918c2ecf20Sopenharmony_ci		for (n = 0; n < ilinelock->index; n++, lv++) {
6928c2ecf20Sopenharmony_ci			memcpy(&xp->xad[lv->offset], &p->xad[lv->offset],
6938c2ecf20Sopenharmony_ci			       lv->length << L2XTSLOTSIZE);
6948c2ecf20Sopenharmony_ci		}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci		/* reset on-disk (metadata page) xtree XAD_NEW bit */
6978c2ecf20Sopenharmony_ci		xad = &xp->xad[XTENTRYSTART];
6988c2ecf20Sopenharmony_ci		for (n = XTENTRYSTART;
6998c2ecf20Sopenharmony_ci		     n < le16_to_cpu(xp->header.nextindex); n++, xad++)
7008c2ecf20Sopenharmony_ci			if (xad->flag & (XAD_NEW | XAD_EXTENDED))
7018c2ecf20Sopenharmony_ci				xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
7028c2ecf20Sopenharmony_ci	}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	if ((lid = jfs_ip->blid) == 0)
7058c2ecf20Sopenharmony_ci		goto inlineData;
7068c2ecf20Sopenharmony_ci	jfs_ip->blid = 0;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	tlck = lid_to_tlock(lid);
7098c2ecf20Sopenharmony_ci	type = tlck->type;
7108c2ecf20Sopenharmony_ci	tlck->type |= tlckBTROOT;
7118c2ecf20Sopenharmony_ci	tlck->mp = mp;
7128c2ecf20Sopenharmony_ci	ilinelock = (struct linelock *) & tlck->lock;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	/*
7158c2ecf20Sopenharmony_ci	 *	regular file: 16 byte (XAD slot) granularity
7168c2ecf20Sopenharmony_ci	 */
7178c2ecf20Sopenharmony_ci	if (type & tlckXTREE) {
7188c2ecf20Sopenharmony_ci		xtpage_t *p, *xp;
7198c2ecf20Sopenharmony_ci		xad_t *xad;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci		/*
7228c2ecf20Sopenharmony_ci		 * copy xtree root from inode to dinode:
7238c2ecf20Sopenharmony_ci		 */
7248c2ecf20Sopenharmony_ci		p = &jfs_ip->i_xtroot;
7258c2ecf20Sopenharmony_ci		xp = &dp->di_xtroot;
7268c2ecf20Sopenharmony_ci		lv = ilinelock->lv;
7278c2ecf20Sopenharmony_ci		for (n = 0; n < ilinelock->index; n++, lv++) {
7288c2ecf20Sopenharmony_ci			memcpy(&xp->xad[lv->offset], &p->xad[lv->offset],
7298c2ecf20Sopenharmony_ci			       lv->length << L2XTSLOTSIZE);
7308c2ecf20Sopenharmony_ci		}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci		/* reset on-disk (metadata page) xtree XAD_NEW bit */
7338c2ecf20Sopenharmony_ci		xad = &xp->xad[XTENTRYSTART];
7348c2ecf20Sopenharmony_ci		for (n = XTENTRYSTART;
7358c2ecf20Sopenharmony_ci		     n < le16_to_cpu(xp->header.nextindex); n++, xad++)
7368c2ecf20Sopenharmony_ci			if (xad->flag & (XAD_NEW | XAD_EXTENDED))
7378c2ecf20Sopenharmony_ci				xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci	/*
7408c2ecf20Sopenharmony_ci	 *	directory: 32 byte (directory entry slot) granularity
7418c2ecf20Sopenharmony_ci	 */
7428c2ecf20Sopenharmony_ci	else if (type & tlckDTREE) {
7438c2ecf20Sopenharmony_ci		dtpage_t *p, *xp;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci		/*
7468c2ecf20Sopenharmony_ci		 * copy dtree root from inode to dinode:
7478c2ecf20Sopenharmony_ci		 */
7488c2ecf20Sopenharmony_ci		p = (dtpage_t *) &jfs_ip->i_dtroot;
7498c2ecf20Sopenharmony_ci		xp = (dtpage_t *) & dp->di_dtroot;
7508c2ecf20Sopenharmony_ci		lv = ilinelock->lv;
7518c2ecf20Sopenharmony_ci		for (n = 0; n < ilinelock->index; n++, lv++) {
7528c2ecf20Sopenharmony_ci			memcpy(&xp->slot[lv->offset], &p->slot[lv->offset],
7538c2ecf20Sopenharmony_ci			       lv->length << L2DTSLOTSIZE);
7548c2ecf20Sopenharmony_ci		}
7558c2ecf20Sopenharmony_ci	} else {
7568c2ecf20Sopenharmony_ci		jfs_err("diWrite: UFO tlock");
7578c2ecf20Sopenharmony_ci	}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci      inlineData:
7608c2ecf20Sopenharmony_ci	/*
7618c2ecf20Sopenharmony_ci	 * copy inline symlink from in-memory inode to on-disk inode
7628c2ecf20Sopenharmony_ci	 */
7638c2ecf20Sopenharmony_ci	if (S_ISLNK(ip->i_mode) && ip->i_size < IDATASIZE) {
7648c2ecf20Sopenharmony_ci		lv = & dilinelock->lv[dilinelock->index];
7658c2ecf20Sopenharmony_ci		lv->offset = (dioffset + 2 * 128) >> L2INODESLOTSIZE;
7668c2ecf20Sopenharmony_ci		lv->length = 2;
7678c2ecf20Sopenharmony_ci		memcpy(&dp->di_fastsymlink, jfs_ip->i_inline, IDATASIZE);
7688c2ecf20Sopenharmony_ci		dilinelock->index++;
7698c2ecf20Sopenharmony_ci	}
7708c2ecf20Sopenharmony_ci	/*
7718c2ecf20Sopenharmony_ci	 * copy inline data from in-memory inode to on-disk inode:
7728c2ecf20Sopenharmony_ci	 * 128 byte slot granularity
7738c2ecf20Sopenharmony_ci	 */
7748c2ecf20Sopenharmony_ci	if (test_cflag(COMMIT_Inlineea, ip)) {
7758c2ecf20Sopenharmony_ci		lv = & dilinelock->lv[dilinelock->index];
7768c2ecf20Sopenharmony_ci		lv->offset = (dioffset + 3 * 128) >> L2INODESLOTSIZE;
7778c2ecf20Sopenharmony_ci		lv->length = 1;
7788c2ecf20Sopenharmony_ci		memcpy(&dp->di_inlineea, jfs_ip->i_inline_ea, INODESLOTSIZE);
7798c2ecf20Sopenharmony_ci		dilinelock->index++;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci		clear_cflag(COMMIT_Inlineea, ip);
7828c2ecf20Sopenharmony_ci	}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	/*
7858c2ecf20Sopenharmony_ci	 *	lock/copy inode base: 128 byte slot granularity
7868c2ecf20Sopenharmony_ci	 */
7878c2ecf20Sopenharmony_ci	lv = & dilinelock->lv[dilinelock->index];
7888c2ecf20Sopenharmony_ci	lv->offset = dioffset >> L2INODESLOTSIZE;
7898c2ecf20Sopenharmony_ci	copy_to_dinode(dp, ip);
7908c2ecf20Sopenharmony_ci	if (test_and_clear_cflag(COMMIT_Dirtable, ip)) {
7918c2ecf20Sopenharmony_ci		lv->length = 2;
7928c2ecf20Sopenharmony_ci		memcpy(&dp->di_dirtable, &jfs_ip->i_dirtable, 96);
7938c2ecf20Sopenharmony_ci	} else
7948c2ecf20Sopenharmony_ci		lv->length = 1;
7958c2ecf20Sopenharmony_ci	dilinelock->index++;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	/* release the buffer holding the updated on-disk inode.
7988c2ecf20Sopenharmony_ci	 * the buffer will be later written by commit processing.
7998c2ecf20Sopenharmony_ci	 */
8008c2ecf20Sopenharmony_ci	write_metapage(mp);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	return (rc);
8038c2ecf20Sopenharmony_ci}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci/*
8078c2ecf20Sopenharmony_ci * NAME:	diFree(ip)
8088c2ecf20Sopenharmony_ci *
8098c2ecf20Sopenharmony_ci * FUNCTION:	free a specified inode from the inode working map
8108c2ecf20Sopenharmony_ci *		for a fileset or aggregate.
8118c2ecf20Sopenharmony_ci *
8128c2ecf20Sopenharmony_ci *		if the inode to be freed represents the first (only)
8138c2ecf20Sopenharmony_ci *		free inode within the iag, the iag will be placed on
8148c2ecf20Sopenharmony_ci *		the ag free inode list.
8158c2ecf20Sopenharmony_ci *
8168c2ecf20Sopenharmony_ci *		freeing the inode will cause the inode extent to be
8178c2ecf20Sopenharmony_ci *		freed if the inode is the only allocated inode within
8188c2ecf20Sopenharmony_ci *		the extent.  in this case all the disk resource backing
8198c2ecf20Sopenharmony_ci *		up the inode extent will be freed. in addition, the iag
8208c2ecf20Sopenharmony_ci *		will be placed on the ag extent free list if the extent
8218c2ecf20Sopenharmony_ci *		is the first free extent in the iag.  if freeing the
8228c2ecf20Sopenharmony_ci *		extent also means that no free inodes will exist for
8238c2ecf20Sopenharmony_ci *		the iag, the iag will also be removed from the ag free
8248c2ecf20Sopenharmony_ci *		inode list.
8258c2ecf20Sopenharmony_ci *
8268c2ecf20Sopenharmony_ci *		the iag describing the inode will be freed if the extent
8278c2ecf20Sopenharmony_ci *		is to be freed and it is the only backed extent within
8288c2ecf20Sopenharmony_ci *		the iag.  in this case, the iag will be removed from the
8298c2ecf20Sopenharmony_ci *		ag free extent list and ag free inode list and placed on
8308c2ecf20Sopenharmony_ci *		the inode map's free iag list.
8318c2ecf20Sopenharmony_ci *
8328c2ecf20Sopenharmony_ci *		a careful update approach is used to provide consistency
8338c2ecf20Sopenharmony_ci *		in the face of updates to multiple buffers.  under this
8348c2ecf20Sopenharmony_ci *		approach, all required buffers are obtained before making
8358c2ecf20Sopenharmony_ci *		any updates and are held until all updates are complete.
8368c2ecf20Sopenharmony_ci *
8378c2ecf20Sopenharmony_ci * PARAMETERS:
8388c2ecf20Sopenharmony_ci *	ip	- inode to be freed.
8398c2ecf20Sopenharmony_ci *
8408c2ecf20Sopenharmony_ci * RETURN VALUES:
8418c2ecf20Sopenharmony_ci *	0	- success
8428c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
8438c2ecf20Sopenharmony_ci */
8448c2ecf20Sopenharmony_ciint diFree(struct inode *ip)
8458c2ecf20Sopenharmony_ci{
8468c2ecf20Sopenharmony_ci	int rc;
8478c2ecf20Sopenharmony_ci	ino_t inum = ip->i_ino;
8488c2ecf20Sopenharmony_ci	struct iag *iagp, *aiagp, *biagp, *ciagp, *diagp;
8498c2ecf20Sopenharmony_ci	struct metapage *mp, *amp, *bmp, *cmp, *dmp;
8508c2ecf20Sopenharmony_ci	int iagno, ino, extno, bitno, sword, agno;
8518c2ecf20Sopenharmony_ci	int back, fwd;
8528c2ecf20Sopenharmony_ci	u32 bitmap, mask;
8538c2ecf20Sopenharmony_ci	struct inode *ipimap = JFS_SBI(ip->i_sb)->ipimap;
8548c2ecf20Sopenharmony_ci	struct inomap *imap = JFS_IP(ipimap)->i_imap;
8558c2ecf20Sopenharmony_ci	pxd_t freepxd;
8568c2ecf20Sopenharmony_ci	tid_t tid;
8578c2ecf20Sopenharmony_ci	struct inode *iplist[3];
8588c2ecf20Sopenharmony_ci	struct tlock *tlck;
8598c2ecf20Sopenharmony_ci	struct pxd_lock *pxdlock;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	/*
8628c2ecf20Sopenharmony_ci	 * This is just to suppress compiler warnings.  The same logic that
8638c2ecf20Sopenharmony_ci	 * references these variables is used to initialize them.
8648c2ecf20Sopenharmony_ci	 */
8658c2ecf20Sopenharmony_ci	aiagp = biagp = ciagp = diagp = NULL;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	/* get the iag number containing the inode.
8688c2ecf20Sopenharmony_ci	 */
8698c2ecf20Sopenharmony_ci	iagno = INOTOIAG(inum);
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	/* make sure that the iag is contained within
8728c2ecf20Sopenharmony_ci	 * the map.
8738c2ecf20Sopenharmony_ci	 */
8748c2ecf20Sopenharmony_ci	if (iagno >= imap->im_nextiag) {
8758c2ecf20Sopenharmony_ci		print_hex_dump(KERN_ERR, "imap: ", DUMP_PREFIX_ADDRESS, 16, 4,
8768c2ecf20Sopenharmony_ci			       imap, 32, 0);
8778c2ecf20Sopenharmony_ci		jfs_error(ip->i_sb, "inum = %d, iagno = %d, nextiag = %d\n",
8788c2ecf20Sopenharmony_ci			  (uint) inum, iagno, imap->im_nextiag);
8798c2ecf20Sopenharmony_ci		return -EIO;
8808c2ecf20Sopenharmony_ci	}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	/* get the allocation group for this ino.
8838c2ecf20Sopenharmony_ci	 */
8848c2ecf20Sopenharmony_ci	agno = BLKTOAG(JFS_IP(ip)->agstart, JFS_SBI(ip->i_sb));
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	/* Lock the AG specific inode map information
8878c2ecf20Sopenharmony_ci	 */
8888c2ecf20Sopenharmony_ci	AG_LOCK(imap, agno);
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	/* Obtain read lock in imap inode.  Don't release it until we have
8918c2ecf20Sopenharmony_ci	 * read all of the IAG's that we are going to.
8928c2ecf20Sopenharmony_ci	 */
8938c2ecf20Sopenharmony_ci	IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	/* read the iag.
8968c2ecf20Sopenharmony_ci	 */
8978c2ecf20Sopenharmony_ci	if ((rc = diIAGRead(imap, iagno, &mp))) {
8988c2ecf20Sopenharmony_ci		IREAD_UNLOCK(ipimap);
8998c2ecf20Sopenharmony_ci		AG_UNLOCK(imap, agno);
9008c2ecf20Sopenharmony_ci		return (rc);
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci	iagp = (struct iag *) mp->data;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	/* get the inode number and extent number of the inode within
9058c2ecf20Sopenharmony_ci	 * the iag and the inode number within the extent.
9068c2ecf20Sopenharmony_ci	 */
9078c2ecf20Sopenharmony_ci	ino = inum & (INOSPERIAG - 1);
9088c2ecf20Sopenharmony_ci	extno = ino >> L2INOSPEREXT;
9098c2ecf20Sopenharmony_ci	bitno = ino & (INOSPEREXT - 1);
9108c2ecf20Sopenharmony_ci	mask = HIGHORDER >> bitno;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
9138c2ecf20Sopenharmony_ci		jfs_error(ip->i_sb, "wmap shows inode already free\n");
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	if (!addressPXD(&iagp->inoext[extno])) {
9178c2ecf20Sopenharmony_ci		release_metapage(mp);
9188c2ecf20Sopenharmony_ci		IREAD_UNLOCK(ipimap);
9198c2ecf20Sopenharmony_ci		AG_UNLOCK(imap, agno);
9208c2ecf20Sopenharmony_ci		jfs_error(ip->i_sb, "invalid inoext\n");
9218c2ecf20Sopenharmony_ci		return -EIO;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	/* compute the bitmap for the extent reflecting the freed inode.
9258c2ecf20Sopenharmony_ci	 */
9268c2ecf20Sopenharmony_ci	bitmap = le32_to_cpu(iagp->wmap[extno]) & ~mask;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	if (imap->im_agctl[agno].numfree > imap->im_agctl[agno].numinos) {
9298c2ecf20Sopenharmony_ci		release_metapage(mp);
9308c2ecf20Sopenharmony_ci		IREAD_UNLOCK(ipimap);
9318c2ecf20Sopenharmony_ci		AG_UNLOCK(imap, agno);
9328c2ecf20Sopenharmony_ci		jfs_error(ip->i_sb, "numfree > numinos\n");
9338c2ecf20Sopenharmony_ci		return -EIO;
9348c2ecf20Sopenharmony_ci	}
9358c2ecf20Sopenharmony_ci	/*
9368c2ecf20Sopenharmony_ci	 *	inode extent still has some inodes or below low water mark:
9378c2ecf20Sopenharmony_ci	 *	keep the inode extent;
9388c2ecf20Sopenharmony_ci	 */
9398c2ecf20Sopenharmony_ci	if (bitmap ||
9408c2ecf20Sopenharmony_ci	    imap->im_agctl[agno].numfree < 96 ||
9418c2ecf20Sopenharmony_ci	    (imap->im_agctl[agno].numfree < 288 &&
9428c2ecf20Sopenharmony_ci	     (((imap->im_agctl[agno].numfree * 100) /
9438c2ecf20Sopenharmony_ci	       imap->im_agctl[agno].numinos) <= 25))) {
9448c2ecf20Sopenharmony_ci		/* if the iag currently has no free inodes (i.e.,
9458c2ecf20Sopenharmony_ci		 * the inode being freed is the first free inode of iag),
9468c2ecf20Sopenharmony_ci		 * insert the iag at head of the inode free list for the ag.
9478c2ecf20Sopenharmony_ci		 */
9488c2ecf20Sopenharmony_ci		if (iagp->nfreeinos == 0) {
9498c2ecf20Sopenharmony_ci			/* check if there are any iags on the ag inode
9508c2ecf20Sopenharmony_ci			 * free list.  if so, read the first one so that
9518c2ecf20Sopenharmony_ci			 * we can link the current iag onto the list at
9528c2ecf20Sopenharmony_ci			 * the head.
9538c2ecf20Sopenharmony_ci			 */
9548c2ecf20Sopenharmony_ci			if ((fwd = imap->im_agctl[agno].inofree) >= 0) {
9558c2ecf20Sopenharmony_ci				/* read the iag that currently is the head
9568c2ecf20Sopenharmony_ci				 * of the list.
9578c2ecf20Sopenharmony_ci				 */
9588c2ecf20Sopenharmony_ci				if ((rc = diIAGRead(imap, fwd, &amp))) {
9598c2ecf20Sopenharmony_ci					IREAD_UNLOCK(ipimap);
9608c2ecf20Sopenharmony_ci					AG_UNLOCK(imap, agno);
9618c2ecf20Sopenharmony_ci					release_metapage(mp);
9628c2ecf20Sopenharmony_ci					return (rc);
9638c2ecf20Sopenharmony_ci				}
9648c2ecf20Sopenharmony_ci				aiagp = (struct iag *) amp->data;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci				/* make current head point back to the iag.
9678c2ecf20Sopenharmony_ci				 */
9688c2ecf20Sopenharmony_ci				aiagp->inofreeback = cpu_to_le32(iagno);
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci				write_metapage(amp);
9718c2ecf20Sopenharmony_ci			}
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci			/* iag points forward to current head and iag
9748c2ecf20Sopenharmony_ci			 * becomes the new head of the list.
9758c2ecf20Sopenharmony_ci			 */
9768c2ecf20Sopenharmony_ci			iagp->inofreefwd =
9778c2ecf20Sopenharmony_ci			    cpu_to_le32(imap->im_agctl[agno].inofree);
9788c2ecf20Sopenharmony_ci			iagp->inofreeback = cpu_to_le32(-1);
9798c2ecf20Sopenharmony_ci			imap->im_agctl[agno].inofree = iagno;
9808c2ecf20Sopenharmony_ci		}
9818c2ecf20Sopenharmony_ci		IREAD_UNLOCK(ipimap);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci		/* update the free inode summary map for the extent if
9848c2ecf20Sopenharmony_ci		 * freeing the inode means the extent will now have free
9858c2ecf20Sopenharmony_ci		 * inodes (i.e., the inode being freed is the first free
9868c2ecf20Sopenharmony_ci		 * inode of extent),
9878c2ecf20Sopenharmony_ci		 */
9888c2ecf20Sopenharmony_ci		if (iagp->wmap[extno] == cpu_to_le32(ONES)) {
9898c2ecf20Sopenharmony_ci			sword = extno >> L2EXTSPERSUM;
9908c2ecf20Sopenharmony_ci			bitno = extno & (EXTSPERSUM - 1);
9918c2ecf20Sopenharmony_ci			iagp->inosmap[sword] &=
9928c2ecf20Sopenharmony_ci			    cpu_to_le32(~(HIGHORDER >> bitno));
9938c2ecf20Sopenharmony_ci		}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci		/* update the bitmap.
9968c2ecf20Sopenharmony_ci		 */
9978c2ecf20Sopenharmony_ci		iagp->wmap[extno] = cpu_to_le32(bitmap);
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci		/* update the free inode counts at the iag, ag and
10008c2ecf20Sopenharmony_ci		 * map level.
10018c2ecf20Sopenharmony_ci		 */
10028c2ecf20Sopenharmony_ci		le32_add_cpu(&iagp->nfreeinos, 1);
10038c2ecf20Sopenharmony_ci		imap->im_agctl[agno].numfree += 1;
10048c2ecf20Sopenharmony_ci		atomic_inc(&imap->im_numfree);
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci		/* release the AG inode map lock
10078c2ecf20Sopenharmony_ci		 */
10088c2ecf20Sopenharmony_ci		AG_UNLOCK(imap, agno);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci		/* write the iag */
10118c2ecf20Sopenharmony_ci		write_metapage(mp);
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci		return (0);
10148c2ecf20Sopenharmony_ci	}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	/*
10188c2ecf20Sopenharmony_ci	 *	inode extent has become free and above low water mark:
10198c2ecf20Sopenharmony_ci	 *	free the inode extent;
10208c2ecf20Sopenharmony_ci	 */
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	/*
10238c2ecf20Sopenharmony_ci	 *	prepare to update iag list(s) (careful update step 1)
10248c2ecf20Sopenharmony_ci	 */
10258c2ecf20Sopenharmony_ci	amp = bmp = cmp = dmp = NULL;
10268c2ecf20Sopenharmony_ci	fwd = back = -1;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	/* check if the iag currently has no free extents.  if so,
10298c2ecf20Sopenharmony_ci	 * it will be placed on the head of the ag extent free list.
10308c2ecf20Sopenharmony_ci	 */
10318c2ecf20Sopenharmony_ci	if (iagp->nfreeexts == 0) {
10328c2ecf20Sopenharmony_ci		/* check if the ag extent free list has any iags.
10338c2ecf20Sopenharmony_ci		 * if so, read the iag at the head of the list now.
10348c2ecf20Sopenharmony_ci		 * this (head) iag will be updated later to reflect
10358c2ecf20Sopenharmony_ci		 * the addition of the current iag at the head of
10368c2ecf20Sopenharmony_ci		 * the list.
10378c2ecf20Sopenharmony_ci		 */
10388c2ecf20Sopenharmony_ci		if ((fwd = imap->im_agctl[agno].extfree) >= 0) {
10398c2ecf20Sopenharmony_ci			if ((rc = diIAGRead(imap, fwd, &amp)))
10408c2ecf20Sopenharmony_ci				goto error_out;
10418c2ecf20Sopenharmony_ci			aiagp = (struct iag *) amp->data;
10428c2ecf20Sopenharmony_ci		}
10438c2ecf20Sopenharmony_ci	} else {
10448c2ecf20Sopenharmony_ci		/* iag has free extents. check if the addition of a free
10458c2ecf20Sopenharmony_ci		 * extent will cause all extents to be free within this
10468c2ecf20Sopenharmony_ci		 * iag.  if so, the iag will be removed from the ag extent
10478c2ecf20Sopenharmony_ci		 * free list and placed on the inode map's free iag list.
10488c2ecf20Sopenharmony_ci		 */
10498c2ecf20Sopenharmony_ci		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG - 1)) {
10508c2ecf20Sopenharmony_ci			/* in preparation for removing the iag from the
10518c2ecf20Sopenharmony_ci			 * ag extent free list, read the iags preceding
10528c2ecf20Sopenharmony_ci			 * and following the iag on the ag extent free
10538c2ecf20Sopenharmony_ci			 * list.
10548c2ecf20Sopenharmony_ci			 */
10558c2ecf20Sopenharmony_ci			if ((fwd = le32_to_cpu(iagp->extfreefwd)) >= 0) {
10568c2ecf20Sopenharmony_ci				if ((rc = diIAGRead(imap, fwd, &amp)))
10578c2ecf20Sopenharmony_ci					goto error_out;
10588c2ecf20Sopenharmony_ci				aiagp = (struct iag *) amp->data;
10598c2ecf20Sopenharmony_ci			}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci			if ((back = le32_to_cpu(iagp->extfreeback)) >= 0) {
10628c2ecf20Sopenharmony_ci				if ((rc = diIAGRead(imap, back, &bmp)))
10638c2ecf20Sopenharmony_ci					goto error_out;
10648c2ecf20Sopenharmony_ci				biagp = (struct iag *) bmp->data;
10658c2ecf20Sopenharmony_ci			}
10668c2ecf20Sopenharmony_ci		}
10678c2ecf20Sopenharmony_ci	}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	/* remove the iag from the ag inode free list if freeing
10708c2ecf20Sopenharmony_ci	 * this extent cause the iag to have no free inodes.
10718c2ecf20Sopenharmony_ci	 */
10728c2ecf20Sopenharmony_ci	if (iagp->nfreeinos == cpu_to_le32(INOSPEREXT - 1)) {
10738c2ecf20Sopenharmony_ci		int inofreeback = le32_to_cpu(iagp->inofreeback);
10748c2ecf20Sopenharmony_ci		int inofreefwd = le32_to_cpu(iagp->inofreefwd);
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci		/* in preparation for removing the iag from the
10778c2ecf20Sopenharmony_ci		 * ag inode free list, read the iags preceding
10788c2ecf20Sopenharmony_ci		 * and following the iag on the ag inode free
10798c2ecf20Sopenharmony_ci		 * list.  before reading these iags, we must make
10808c2ecf20Sopenharmony_ci		 * sure that we already don't have them in hand
10818c2ecf20Sopenharmony_ci		 * from up above, since re-reading an iag (buffer)
10828c2ecf20Sopenharmony_ci		 * we are currently holding would cause a deadlock.
10838c2ecf20Sopenharmony_ci		 */
10848c2ecf20Sopenharmony_ci		if (inofreefwd >= 0) {
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci			if (inofreefwd == fwd)
10878c2ecf20Sopenharmony_ci				ciagp = (struct iag *) amp->data;
10888c2ecf20Sopenharmony_ci			else if (inofreefwd == back)
10898c2ecf20Sopenharmony_ci				ciagp = (struct iag *) bmp->data;
10908c2ecf20Sopenharmony_ci			else {
10918c2ecf20Sopenharmony_ci				if ((rc =
10928c2ecf20Sopenharmony_ci				     diIAGRead(imap, inofreefwd, &cmp)))
10938c2ecf20Sopenharmony_ci					goto error_out;
10948c2ecf20Sopenharmony_ci				ciagp = (struct iag *) cmp->data;
10958c2ecf20Sopenharmony_ci			}
10968c2ecf20Sopenharmony_ci			assert(ciagp != NULL);
10978c2ecf20Sopenharmony_ci		}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci		if (inofreeback >= 0) {
11008c2ecf20Sopenharmony_ci			if (inofreeback == fwd)
11018c2ecf20Sopenharmony_ci				diagp = (struct iag *) amp->data;
11028c2ecf20Sopenharmony_ci			else if (inofreeback == back)
11038c2ecf20Sopenharmony_ci				diagp = (struct iag *) bmp->data;
11048c2ecf20Sopenharmony_ci			else {
11058c2ecf20Sopenharmony_ci				if ((rc =
11068c2ecf20Sopenharmony_ci				     diIAGRead(imap, inofreeback, &dmp)))
11078c2ecf20Sopenharmony_ci					goto error_out;
11088c2ecf20Sopenharmony_ci				diagp = (struct iag *) dmp->data;
11098c2ecf20Sopenharmony_ci			}
11108c2ecf20Sopenharmony_ci			assert(diagp != NULL);
11118c2ecf20Sopenharmony_ci		}
11128c2ecf20Sopenharmony_ci	}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	IREAD_UNLOCK(ipimap);
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	/*
11178c2ecf20Sopenharmony_ci	 * invalidate any page of the inode extent freed from buffer cache;
11188c2ecf20Sopenharmony_ci	 */
11198c2ecf20Sopenharmony_ci	freepxd = iagp->inoext[extno];
11208c2ecf20Sopenharmony_ci	invalidate_pxd_metapages(ip, freepxd);
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	/*
11238c2ecf20Sopenharmony_ci	 *	update iag list(s) (careful update step 2)
11248c2ecf20Sopenharmony_ci	 */
11258c2ecf20Sopenharmony_ci	/* add the iag to the ag extent free list if this is the
11268c2ecf20Sopenharmony_ci	 * first free extent for the iag.
11278c2ecf20Sopenharmony_ci	 */
11288c2ecf20Sopenharmony_ci	if (iagp->nfreeexts == 0) {
11298c2ecf20Sopenharmony_ci		if (fwd >= 0)
11308c2ecf20Sopenharmony_ci			aiagp->extfreeback = cpu_to_le32(iagno);
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci		iagp->extfreefwd =
11338c2ecf20Sopenharmony_ci		    cpu_to_le32(imap->im_agctl[agno].extfree);
11348c2ecf20Sopenharmony_ci		iagp->extfreeback = cpu_to_le32(-1);
11358c2ecf20Sopenharmony_ci		imap->im_agctl[agno].extfree = iagno;
11368c2ecf20Sopenharmony_ci	} else {
11378c2ecf20Sopenharmony_ci		/* remove the iag from the ag extent list if all extents
11388c2ecf20Sopenharmony_ci		 * are now free and place it on the inode map iag free list.
11398c2ecf20Sopenharmony_ci		 */
11408c2ecf20Sopenharmony_ci		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG - 1)) {
11418c2ecf20Sopenharmony_ci			if (fwd >= 0)
11428c2ecf20Sopenharmony_ci				aiagp->extfreeback = iagp->extfreeback;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci			if (back >= 0)
11458c2ecf20Sopenharmony_ci				biagp->extfreefwd = iagp->extfreefwd;
11468c2ecf20Sopenharmony_ci			else
11478c2ecf20Sopenharmony_ci				imap->im_agctl[agno].extfree =
11488c2ecf20Sopenharmony_ci				    le32_to_cpu(iagp->extfreefwd);
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci			iagp->extfreefwd = iagp->extfreeback = cpu_to_le32(-1);
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci			IAGFREE_LOCK(imap);
11538c2ecf20Sopenharmony_ci			iagp->iagfree = cpu_to_le32(imap->im_freeiag);
11548c2ecf20Sopenharmony_ci			imap->im_freeiag = iagno;
11558c2ecf20Sopenharmony_ci			IAGFREE_UNLOCK(imap);
11568c2ecf20Sopenharmony_ci		}
11578c2ecf20Sopenharmony_ci	}
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	/* remove the iag from the ag inode free list if freeing
11608c2ecf20Sopenharmony_ci	 * this extent causes the iag to have no free inodes.
11618c2ecf20Sopenharmony_ci	 */
11628c2ecf20Sopenharmony_ci	if (iagp->nfreeinos == cpu_to_le32(INOSPEREXT - 1)) {
11638c2ecf20Sopenharmony_ci		if ((int) le32_to_cpu(iagp->inofreefwd) >= 0)
11648c2ecf20Sopenharmony_ci			ciagp->inofreeback = iagp->inofreeback;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci		if ((int) le32_to_cpu(iagp->inofreeback) >= 0)
11678c2ecf20Sopenharmony_ci			diagp->inofreefwd = iagp->inofreefwd;
11688c2ecf20Sopenharmony_ci		else
11698c2ecf20Sopenharmony_ci			imap->im_agctl[agno].inofree =
11708c2ecf20Sopenharmony_ci			    le32_to_cpu(iagp->inofreefwd);
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci		iagp->inofreefwd = iagp->inofreeback = cpu_to_le32(-1);
11738c2ecf20Sopenharmony_ci	}
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	/* update the inode extent address and working map
11768c2ecf20Sopenharmony_ci	 * to reflect the free extent.
11778c2ecf20Sopenharmony_ci	 * the permanent map should have been updated already
11788c2ecf20Sopenharmony_ci	 * for the inode being freed.
11798c2ecf20Sopenharmony_ci	 */
11808c2ecf20Sopenharmony_ci	if (iagp->pmap[extno] != 0) {
11818c2ecf20Sopenharmony_ci		jfs_error(ip->i_sb, "the pmap does not show inode free\n");
11828c2ecf20Sopenharmony_ci	}
11838c2ecf20Sopenharmony_ci	iagp->wmap[extno] = 0;
11848c2ecf20Sopenharmony_ci	PXDlength(&iagp->inoext[extno], 0);
11858c2ecf20Sopenharmony_ci	PXDaddress(&iagp->inoext[extno], 0);
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	/* update the free extent and free inode summary maps
11888c2ecf20Sopenharmony_ci	 * to reflect the freed extent.
11898c2ecf20Sopenharmony_ci	 * the inode summary map is marked to indicate no inodes
11908c2ecf20Sopenharmony_ci	 * available for the freed extent.
11918c2ecf20Sopenharmony_ci	 */
11928c2ecf20Sopenharmony_ci	sword = extno >> L2EXTSPERSUM;
11938c2ecf20Sopenharmony_ci	bitno = extno & (EXTSPERSUM - 1);
11948c2ecf20Sopenharmony_ci	mask = HIGHORDER >> bitno;
11958c2ecf20Sopenharmony_ci	iagp->inosmap[sword] |= cpu_to_le32(mask);
11968c2ecf20Sopenharmony_ci	iagp->extsmap[sword] &= cpu_to_le32(~mask);
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	/* update the number of free inodes and number of free extents
11998c2ecf20Sopenharmony_ci	 * for the iag.
12008c2ecf20Sopenharmony_ci	 */
12018c2ecf20Sopenharmony_ci	le32_add_cpu(&iagp->nfreeinos, -(INOSPEREXT - 1));
12028c2ecf20Sopenharmony_ci	le32_add_cpu(&iagp->nfreeexts, 1);
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	/* update the number of free inodes and backed inodes
12058c2ecf20Sopenharmony_ci	 * at the ag and inode map level.
12068c2ecf20Sopenharmony_ci	 */
12078c2ecf20Sopenharmony_ci	imap->im_agctl[agno].numfree -= (INOSPEREXT - 1);
12088c2ecf20Sopenharmony_ci	imap->im_agctl[agno].numinos -= INOSPEREXT;
12098c2ecf20Sopenharmony_ci	atomic_sub(INOSPEREXT - 1, &imap->im_numfree);
12108c2ecf20Sopenharmony_ci	atomic_sub(INOSPEREXT, &imap->im_numinos);
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	if (amp)
12138c2ecf20Sopenharmony_ci		write_metapage(amp);
12148c2ecf20Sopenharmony_ci	if (bmp)
12158c2ecf20Sopenharmony_ci		write_metapage(bmp);
12168c2ecf20Sopenharmony_ci	if (cmp)
12178c2ecf20Sopenharmony_ci		write_metapage(cmp);
12188c2ecf20Sopenharmony_ci	if (dmp)
12198c2ecf20Sopenharmony_ci		write_metapage(dmp);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	/*
12228c2ecf20Sopenharmony_ci	 * start transaction to update block allocation map
12238c2ecf20Sopenharmony_ci	 * for the inode extent freed;
12248c2ecf20Sopenharmony_ci	 *
12258c2ecf20Sopenharmony_ci	 * N.B. AG_LOCK is released and iag will be released below, and
12268c2ecf20Sopenharmony_ci	 * other thread may allocate inode from/reusing the ixad freed
12278c2ecf20Sopenharmony_ci	 * BUT with new/different backing inode extent from the extent
12288c2ecf20Sopenharmony_ci	 * to be freed by the transaction;
12298c2ecf20Sopenharmony_ci	 */
12308c2ecf20Sopenharmony_ci	tid = txBegin(ipimap->i_sb, COMMIT_FORCE);
12318c2ecf20Sopenharmony_ci	mutex_lock(&JFS_IP(ipimap)->commit_mutex);
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	/* acquire tlock of the iag page of the freed ixad
12348c2ecf20Sopenharmony_ci	 * to force the page NOHOMEOK (even though no data is
12358c2ecf20Sopenharmony_ci	 * logged from the iag page) until NOREDOPAGE|FREEXTENT log
12368c2ecf20Sopenharmony_ci	 * for the free of the extent is committed;
12378c2ecf20Sopenharmony_ci	 * write FREEXTENT|NOREDOPAGE log record
12388c2ecf20Sopenharmony_ci	 * N.B. linelock is overlaid as freed extent descriptor;
12398c2ecf20Sopenharmony_ci	 */
12408c2ecf20Sopenharmony_ci	tlck = txLock(tid, ipimap, mp, tlckINODE | tlckFREE);
12418c2ecf20Sopenharmony_ci	pxdlock = (struct pxd_lock *) & tlck->lock;
12428c2ecf20Sopenharmony_ci	pxdlock->flag = mlckFREEPXD;
12438c2ecf20Sopenharmony_ci	pxdlock->pxd = freepxd;
12448c2ecf20Sopenharmony_ci	pxdlock->index = 1;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	write_metapage(mp);
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	iplist[0] = ipimap;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	/*
12518c2ecf20Sopenharmony_ci	 * logredo needs the IAG number and IAG extent index in order
12528c2ecf20Sopenharmony_ci	 * to ensure that the IMap is consistent.  The least disruptive
12538c2ecf20Sopenharmony_ci	 * way to pass these values through  to the transaction manager
12548c2ecf20Sopenharmony_ci	 * is in the iplist array.
12558c2ecf20Sopenharmony_ci	 *
12568c2ecf20Sopenharmony_ci	 * It's not pretty, but it works.
12578c2ecf20Sopenharmony_ci	 */
12588c2ecf20Sopenharmony_ci	iplist[1] = (struct inode *) (size_t)iagno;
12598c2ecf20Sopenharmony_ci	iplist[2] = (struct inode *) (size_t)extno;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	txEnd(tid);
12648c2ecf20Sopenharmony_ci	mutex_unlock(&JFS_IP(ipimap)->commit_mutex);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	/* unlock the AG inode map information */
12678c2ecf20Sopenharmony_ci	AG_UNLOCK(imap, agno);
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci	return (0);
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci      error_out:
12728c2ecf20Sopenharmony_ci	IREAD_UNLOCK(ipimap);
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	if (amp)
12758c2ecf20Sopenharmony_ci		release_metapage(amp);
12768c2ecf20Sopenharmony_ci	if (bmp)
12778c2ecf20Sopenharmony_ci		release_metapage(bmp);
12788c2ecf20Sopenharmony_ci	if (cmp)
12798c2ecf20Sopenharmony_ci		release_metapage(cmp);
12808c2ecf20Sopenharmony_ci	if (dmp)
12818c2ecf20Sopenharmony_ci		release_metapage(dmp);
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	AG_UNLOCK(imap, agno);
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci	release_metapage(mp);
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	return (rc);
12888c2ecf20Sopenharmony_ci}
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci/*
12918c2ecf20Sopenharmony_ci * There are several places in the diAlloc* routines where we initialize
12928c2ecf20Sopenharmony_ci * the inode.
12938c2ecf20Sopenharmony_ci */
12948c2ecf20Sopenharmony_cistatic inline void
12958c2ecf20Sopenharmony_cidiInitInode(struct inode *ip, int iagno, int ino, int extno, struct iag * iagp)
12968c2ecf20Sopenharmony_ci{
12978c2ecf20Sopenharmony_ci	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	ip->i_ino = (iagno << L2INOSPERIAG) + ino;
13008c2ecf20Sopenharmony_ci	jfs_ip->ixpxd = iagp->inoext[extno];
13018c2ecf20Sopenharmony_ci	jfs_ip->agstart = le64_to_cpu(iagp->agstart);
13028c2ecf20Sopenharmony_ci	jfs_ip->active_ag = -1;
13038c2ecf20Sopenharmony_ci}
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci/*
13078c2ecf20Sopenharmony_ci * NAME:	diAlloc(pip,dir,ip)
13088c2ecf20Sopenharmony_ci *
13098c2ecf20Sopenharmony_ci * FUNCTION:	allocate a disk inode from the inode working map
13108c2ecf20Sopenharmony_ci *		for a fileset or aggregate.
13118c2ecf20Sopenharmony_ci *
13128c2ecf20Sopenharmony_ci * PARAMETERS:
13138c2ecf20Sopenharmony_ci *	pip	- pointer to incore inode for the parent inode.
13148c2ecf20Sopenharmony_ci *	dir	- 'true' if the new disk inode is for a directory.
13158c2ecf20Sopenharmony_ci *	ip	- pointer to a new inode
13168c2ecf20Sopenharmony_ci *
13178c2ecf20Sopenharmony_ci * RETURN VALUES:
13188c2ecf20Sopenharmony_ci *	0	- success.
13198c2ecf20Sopenharmony_ci *	-ENOSPC	- insufficient disk resources.
13208c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
13218c2ecf20Sopenharmony_ci */
13228c2ecf20Sopenharmony_ciint diAlloc(struct inode *pip, bool dir, struct inode *ip)
13238c2ecf20Sopenharmony_ci{
13248c2ecf20Sopenharmony_ci	int rc, ino, iagno, addext, extno, bitno, sword;
13258c2ecf20Sopenharmony_ci	int nwords, rem, i, agno, dn_numag;
13268c2ecf20Sopenharmony_ci	u32 mask, inosmap, extsmap;
13278c2ecf20Sopenharmony_ci	struct inode *ipimap;
13288c2ecf20Sopenharmony_ci	struct metapage *mp;
13298c2ecf20Sopenharmony_ci	ino_t inum;
13308c2ecf20Sopenharmony_ci	struct iag *iagp;
13318c2ecf20Sopenharmony_ci	struct inomap *imap;
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	/* get the pointers to the inode map inode and the
13348c2ecf20Sopenharmony_ci	 * corresponding imap control structure.
13358c2ecf20Sopenharmony_ci	 */
13368c2ecf20Sopenharmony_ci	ipimap = JFS_SBI(pip->i_sb)->ipimap;
13378c2ecf20Sopenharmony_ci	imap = JFS_IP(ipimap)->i_imap;
13388c2ecf20Sopenharmony_ci	JFS_IP(ip)->ipimap = ipimap;
13398c2ecf20Sopenharmony_ci	JFS_IP(ip)->fileset = FILESYSTEM_I;
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	/* for a directory, the allocation policy is to start
13428c2ecf20Sopenharmony_ci	 * at the ag level using the preferred ag.
13438c2ecf20Sopenharmony_ci	 */
13448c2ecf20Sopenharmony_ci	if (dir) {
13458c2ecf20Sopenharmony_ci		agno = dbNextAG(JFS_SBI(pip->i_sb)->ipbmap);
13468c2ecf20Sopenharmony_ci		AG_LOCK(imap, agno);
13478c2ecf20Sopenharmony_ci		goto tryag;
13488c2ecf20Sopenharmony_ci	}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	/* for files, the policy starts off by trying to allocate from
13518c2ecf20Sopenharmony_ci	 * the same iag containing the parent disk inode:
13528c2ecf20Sopenharmony_ci	 * try to allocate the new disk inode close to the parent disk
13538c2ecf20Sopenharmony_ci	 * inode, using parent disk inode number + 1 as the allocation
13548c2ecf20Sopenharmony_ci	 * hint.  (we use a left-to-right policy to attempt to avoid
13558c2ecf20Sopenharmony_ci	 * moving backward on the disk.)  compute the hint within the
13568c2ecf20Sopenharmony_ci	 * file system and the iag.
13578c2ecf20Sopenharmony_ci	 */
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	/* get the ag number of this iag */
13608c2ecf20Sopenharmony_ci	agno = BLKTOAG(JFS_IP(pip)->agstart, JFS_SBI(pip->i_sb));
13618c2ecf20Sopenharmony_ci	dn_numag = JFS_SBI(pip->i_sb)->bmap->db_numag;
13628c2ecf20Sopenharmony_ci	if (agno < 0 || agno > dn_numag)
13638c2ecf20Sopenharmony_ci		return -EIO;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	if (atomic_read(&JFS_SBI(pip->i_sb)->bmap->db_active[agno])) {
13668c2ecf20Sopenharmony_ci		/*
13678c2ecf20Sopenharmony_ci		 * There is an open file actively growing.  We want to
13688c2ecf20Sopenharmony_ci		 * allocate new inodes from a different ag to avoid
13698c2ecf20Sopenharmony_ci		 * fragmentation problems.
13708c2ecf20Sopenharmony_ci		 */
13718c2ecf20Sopenharmony_ci		agno = dbNextAG(JFS_SBI(pip->i_sb)->ipbmap);
13728c2ecf20Sopenharmony_ci		AG_LOCK(imap, agno);
13738c2ecf20Sopenharmony_ci		goto tryag;
13748c2ecf20Sopenharmony_ci	}
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	inum = pip->i_ino + 1;
13778c2ecf20Sopenharmony_ci	ino = inum & (INOSPERIAG - 1);
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	/* back off the hint if it is outside of the iag */
13808c2ecf20Sopenharmony_ci	if (ino == 0)
13818c2ecf20Sopenharmony_ci		inum = pip->i_ino;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	/* lock the AG inode map information */
13848c2ecf20Sopenharmony_ci	AG_LOCK(imap, agno);
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	/* Get read lock on imap inode */
13878c2ecf20Sopenharmony_ci	IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	/* get the iag number and read the iag */
13908c2ecf20Sopenharmony_ci	iagno = INOTOIAG(inum);
13918c2ecf20Sopenharmony_ci	if ((rc = diIAGRead(imap, iagno, &mp))) {
13928c2ecf20Sopenharmony_ci		IREAD_UNLOCK(ipimap);
13938c2ecf20Sopenharmony_ci		AG_UNLOCK(imap, agno);
13948c2ecf20Sopenharmony_ci		return (rc);
13958c2ecf20Sopenharmony_ci	}
13968c2ecf20Sopenharmony_ci	iagp = (struct iag *) mp->data;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	/* determine if new inode extent is allowed to be added to the iag.
13998c2ecf20Sopenharmony_ci	 * new inode extent can be added to the iag if the ag
14008c2ecf20Sopenharmony_ci	 * has less than 32 free disk inodes and the iag has free extents.
14018c2ecf20Sopenharmony_ci	 */
14028c2ecf20Sopenharmony_ci	addext = (imap->im_agctl[agno].numfree < 32 && iagp->nfreeexts);
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	/*
14058c2ecf20Sopenharmony_ci	 *	try to allocate from the IAG
14068c2ecf20Sopenharmony_ci	 */
14078c2ecf20Sopenharmony_ci	/* check if the inode may be allocated from the iag
14088c2ecf20Sopenharmony_ci	 * (i.e. the inode has free inodes or new extent can be added).
14098c2ecf20Sopenharmony_ci	 */
14108c2ecf20Sopenharmony_ci	if (iagp->nfreeinos || addext) {
14118c2ecf20Sopenharmony_ci		/* determine the extent number of the hint.
14128c2ecf20Sopenharmony_ci		 */
14138c2ecf20Sopenharmony_ci		extno = ino >> L2INOSPEREXT;
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci		/* check if the extent containing the hint has backed
14168c2ecf20Sopenharmony_ci		 * inodes.  if so, try to allocate within this extent.
14178c2ecf20Sopenharmony_ci		 */
14188c2ecf20Sopenharmony_ci		if (addressPXD(&iagp->inoext[extno])) {
14198c2ecf20Sopenharmony_ci			bitno = ino & (INOSPEREXT - 1);
14208c2ecf20Sopenharmony_ci			if ((bitno =
14218c2ecf20Sopenharmony_ci			     diFindFree(le32_to_cpu(iagp->wmap[extno]),
14228c2ecf20Sopenharmony_ci					bitno))
14238c2ecf20Sopenharmony_ci			    < INOSPEREXT) {
14248c2ecf20Sopenharmony_ci				ino = (extno << L2INOSPEREXT) + bitno;
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci				/* a free inode (bit) was found within this
14278c2ecf20Sopenharmony_ci				 * extent, so allocate it.
14288c2ecf20Sopenharmony_ci				 */
14298c2ecf20Sopenharmony_ci				rc = diAllocBit(imap, iagp, ino);
14308c2ecf20Sopenharmony_ci				IREAD_UNLOCK(ipimap);
14318c2ecf20Sopenharmony_ci				if (rc) {
14328c2ecf20Sopenharmony_ci					assert(rc == -EIO);
14338c2ecf20Sopenharmony_ci				} else {
14348c2ecf20Sopenharmony_ci					/* set the results of the allocation
14358c2ecf20Sopenharmony_ci					 * and write the iag.
14368c2ecf20Sopenharmony_ci					 */
14378c2ecf20Sopenharmony_ci					diInitInode(ip, iagno, ino, extno,
14388c2ecf20Sopenharmony_ci						    iagp);
14398c2ecf20Sopenharmony_ci					mark_metapage_dirty(mp);
14408c2ecf20Sopenharmony_ci				}
14418c2ecf20Sopenharmony_ci				release_metapage(mp);
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci				/* free the AG lock and return.
14448c2ecf20Sopenharmony_ci				 */
14458c2ecf20Sopenharmony_ci				AG_UNLOCK(imap, agno);
14468c2ecf20Sopenharmony_ci				return (rc);
14478c2ecf20Sopenharmony_ci			}
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci			if (!addext)
14508c2ecf20Sopenharmony_ci				extno =
14518c2ecf20Sopenharmony_ci				    (extno ==
14528c2ecf20Sopenharmony_ci				     EXTSPERIAG - 1) ? 0 : extno + 1;
14538c2ecf20Sopenharmony_ci		}
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci		/*
14568c2ecf20Sopenharmony_ci		 * no free inodes within the extent containing the hint.
14578c2ecf20Sopenharmony_ci		 *
14588c2ecf20Sopenharmony_ci		 * try to allocate from the backed extents following
14598c2ecf20Sopenharmony_ci		 * hint or, if appropriate (i.e. addext is true), allocate
14608c2ecf20Sopenharmony_ci		 * an extent of free inodes at or following the extent
14618c2ecf20Sopenharmony_ci		 * containing the hint.
14628c2ecf20Sopenharmony_ci		 *
14638c2ecf20Sopenharmony_ci		 * the free inode and free extent summary maps are used
14648c2ecf20Sopenharmony_ci		 * here, so determine the starting summary map position
14658c2ecf20Sopenharmony_ci		 * and the number of words we'll have to examine.  again,
14668c2ecf20Sopenharmony_ci		 * the approach is to allocate following the hint, so we
14678c2ecf20Sopenharmony_ci		 * might have to initially ignore prior bits of the summary
14688c2ecf20Sopenharmony_ci		 * map that represent extents prior to the extent containing
14698c2ecf20Sopenharmony_ci		 * the hint and later revisit these bits.
14708c2ecf20Sopenharmony_ci		 */
14718c2ecf20Sopenharmony_ci		bitno = extno & (EXTSPERSUM - 1);
14728c2ecf20Sopenharmony_ci		nwords = (bitno == 0) ? SMAPSZ : SMAPSZ + 1;
14738c2ecf20Sopenharmony_ci		sword = extno >> L2EXTSPERSUM;
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci		/* mask any prior bits for the starting words of the
14768c2ecf20Sopenharmony_ci		 * summary map.
14778c2ecf20Sopenharmony_ci		 */
14788c2ecf20Sopenharmony_ci		mask = (bitno == 0) ? 0 : (ONES << (EXTSPERSUM - bitno));
14798c2ecf20Sopenharmony_ci		inosmap = le32_to_cpu(iagp->inosmap[sword]) | mask;
14808c2ecf20Sopenharmony_ci		extsmap = le32_to_cpu(iagp->extsmap[sword]) | mask;
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci		/* scan the free inode and free extent summary maps for
14838c2ecf20Sopenharmony_ci		 * free resources.
14848c2ecf20Sopenharmony_ci		 */
14858c2ecf20Sopenharmony_ci		for (i = 0; i < nwords; i++) {
14868c2ecf20Sopenharmony_ci			/* check if this word of the free inode summary
14878c2ecf20Sopenharmony_ci			 * map describes an extent with free inodes.
14888c2ecf20Sopenharmony_ci			 */
14898c2ecf20Sopenharmony_ci			if (~inosmap) {
14908c2ecf20Sopenharmony_ci				/* an extent with free inodes has been
14918c2ecf20Sopenharmony_ci				 * found. determine the extent number
14928c2ecf20Sopenharmony_ci				 * and the inode number within the extent.
14938c2ecf20Sopenharmony_ci				 */
14948c2ecf20Sopenharmony_ci				rem = diFindFree(inosmap, 0);
14958c2ecf20Sopenharmony_ci				extno = (sword << L2EXTSPERSUM) + rem;
14968c2ecf20Sopenharmony_ci				rem = diFindFree(le32_to_cpu(iagp->wmap[extno]),
14978c2ecf20Sopenharmony_ci						 0);
14988c2ecf20Sopenharmony_ci				if (rem >= INOSPEREXT) {
14998c2ecf20Sopenharmony_ci					IREAD_UNLOCK(ipimap);
15008c2ecf20Sopenharmony_ci					release_metapage(mp);
15018c2ecf20Sopenharmony_ci					AG_UNLOCK(imap, agno);
15028c2ecf20Sopenharmony_ci					jfs_error(ip->i_sb,
15038c2ecf20Sopenharmony_ci						  "can't find free bit in wmap\n");
15048c2ecf20Sopenharmony_ci					return -EIO;
15058c2ecf20Sopenharmony_ci				}
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci				/* determine the inode number within the
15088c2ecf20Sopenharmony_ci				 * iag and allocate the inode from the
15098c2ecf20Sopenharmony_ci				 * map.
15108c2ecf20Sopenharmony_ci				 */
15118c2ecf20Sopenharmony_ci				ino = (extno << L2INOSPEREXT) + rem;
15128c2ecf20Sopenharmony_ci				rc = diAllocBit(imap, iagp, ino);
15138c2ecf20Sopenharmony_ci				IREAD_UNLOCK(ipimap);
15148c2ecf20Sopenharmony_ci				if (rc)
15158c2ecf20Sopenharmony_ci					assert(rc == -EIO);
15168c2ecf20Sopenharmony_ci				else {
15178c2ecf20Sopenharmony_ci					/* set the results of the allocation
15188c2ecf20Sopenharmony_ci					 * and write the iag.
15198c2ecf20Sopenharmony_ci					 */
15208c2ecf20Sopenharmony_ci					diInitInode(ip, iagno, ino, extno,
15218c2ecf20Sopenharmony_ci						    iagp);
15228c2ecf20Sopenharmony_ci					mark_metapage_dirty(mp);
15238c2ecf20Sopenharmony_ci				}
15248c2ecf20Sopenharmony_ci				release_metapage(mp);
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci				/* free the AG lock and return.
15278c2ecf20Sopenharmony_ci				 */
15288c2ecf20Sopenharmony_ci				AG_UNLOCK(imap, agno);
15298c2ecf20Sopenharmony_ci				return (rc);
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci			}
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci			/* check if we may allocate an extent of free
15348c2ecf20Sopenharmony_ci			 * inodes and whether this word of the free
15358c2ecf20Sopenharmony_ci			 * extents summary map describes a free extent.
15368c2ecf20Sopenharmony_ci			 */
15378c2ecf20Sopenharmony_ci			if (addext && ~extsmap) {
15388c2ecf20Sopenharmony_ci				/* a free extent has been found.  determine
15398c2ecf20Sopenharmony_ci				 * the extent number.
15408c2ecf20Sopenharmony_ci				 */
15418c2ecf20Sopenharmony_ci				rem = diFindFree(extsmap, 0);
15428c2ecf20Sopenharmony_ci				extno = (sword << L2EXTSPERSUM) + rem;
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci				/* allocate an extent of free inodes.
15458c2ecf20Sopenharmony_ci				 */
15468c2ecf20Sopenharmony_ci				if ((rc = diNewExt(imap, iagp, extno))) {
15478c2ecf20Sopenharmony_ci					/* if there is no disk space for a
15488c2ecf20Sopenharmony_ci					 * new extent, try to allocate the
15498c2ecf20Sopenharmony_ci					 * disk inode from somewhere else.
15508c2ecf20Sopenharmony_ci					 */
15518c2ecf20Sopenharmony_ci					if (rc == -ENOSPC)
15528c2ecf20Sopenharmony_ci						break;
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci					assert(rc == -EIO);
15558c2ecf20Sopenharmony_ci				} else {
15568c2ecf20Sopenharmony_ci					/* set the results of the allocation
15578c2ecf20Sopenharmony_ci					 * and write the iag.
15588c2ecf20Sopenharmony_ci					 */
15598c2ecf20Sopenharmony_ci					diInitInode(ip, iagno,
15608c2ecf20Sopenharmony_ci						    extno << L2INOSPEREXT,
15618c2ecf20Sopenharmony_ci						    extno, iagp);
15628c2ecf20Sopenharmony_ci					mark_metapage_dirty(mp);
15638c2ecf20Sopenharmony_ci				}
15648c2ecf20Sopenharmony_ci				release_metapage(mp);
15658c2ecf20Sopenharmony_ci				/* free the imap inode & the AG lock & return.
15668c2ecf20Sopenharmony_ci				 */
15678c2ecf20Sopenharmony_ci				IREAD_UNLOCK(ipimap);
15688c2ecf20Sopenharmony_ci				AG_UNLOCK(imap, agno);
15698c2ecf20Sopenharmony_ci				return (rc);
15708c2ecf20Sopenharmony_ci			}
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci			/* move on to the next set of summary map words.
15738c2ecf20Sopenharmony_ci			 */
15748c2ecf20Sopenharmony_ci			sword = (sword == SMAPSZ - 1) ? 0 : sword + 1;
15758c2ecf20Sopenharmony_ci			inosmap = le32_to_cpu(iagp->inosmap[sword]);
15768c2ecf20Sopenharmony_ci			extsmap = le32_to_cpu(iagp->extsmap[sword]);
15778c2ecf20Sopenharmony_ci		}
15788c2ecf20Sopenharmony_ci	}
15798c2ecf20Sopenharmony_ci	/* unlock imap inode */
15808c2ecf20Sopenharmony_ci	IREAD_UNLOCK(ipimap);
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	/* nothing doing in this iag, so release it. */
15838c2ecf20Sopenharmony_ci	release_metapage(mp);
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci      tryag:
15868c2ecf20Sopenharmony_ci	/*
15878c2ecf20Sopenharmony_ci	 * try to allocate anywhere within the same AG as the parent inode.
15888c2ecf20Sopenharmony_ci	 */
15898c2ecf20Sopenharmony_ci	rc = diAllocAG(imap, agno, dir, ip);
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	AG_UNLOCK(imap, agno);
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	if (rc != -ENOSPC)
15948c2ecf20Sopenharmony_ci		return (rc);
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci	/*
15978c2ecf20Sopenharmony_ci	 * try to allocate in any AG.
15988c2ecf20Sopenharmony_ci	 */
15998c2ecf20Sopenharmony_ci	return (diAllocAny(imap, agno, dir, ip));
16008c2ecf20Sopenharmony_ci}
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci/*
16048c2ecf20Sopenharmony_ci * NAME:	diAllocAG(imap,agno,dir,ip)
16058c2ecf20Sopenharmony_ci *
16068c2ecf20Sopenharmony_ci * FUNCTION:	allocate a disk inode from the allocation group.
16078c2ecf20Sopenharmony_ci *
16088c2ecf20Sopenharmony_ci *		this routine first determines if a new extent of free
16098c2ecf20Sopenharmony_ci *		inodes should be added for the allocation group, with
16108c2ecf20Sopenharmony_ci *		the current request satisfied from this extent. if this
16118c2ecf20Sopenharmony_ci *		is the case, an attempt will be made to do just that.  if
16128c2ecf20Sopenharmony_ci *		this attempt fails or it has been determined that a new
16138c2ecf20Sopenharmony_ci *		extent should not be added, an attempt is made to satisfy
16148c2ecf20Sopenharmony_ci *		the request by allocating an existing (backed) free inode
16158c2ecf20Sopenharmony_ci *		from the allocation group.
16168c2ecf20Sopenharmony_ci *
16178c2ecf20Sopenharmony_ci * PRE CONDITION: Already have the AG lock for this AG.
16188c2ecf20Sopenharmony_ci *
16198c2ecf20Sopenharmony_ci * PARAMETERS:
16208c2ecf20Sopenharmony_ci *	imap	- pointer to inode map control structure.
16218c2ecf20Sopenharmony_ci *	agno	- allocation group to allocate from.
16228c2ecf20Sopenharmony_ci *	dir	- 'true' if the new disk inode is for a directory.
16238c2ecf20Sopenharmony_ci *	ip	- pointer to the new inode to be filled in on successful return
16248c2ecf20Sopenharmony_ci *		  with the disk inode number allocated, its extent address
16258c2ecf20Sopenharmony_ci *		  and the start of the ag.
16268c2ecf20Sopenharmony_ci *
16278c2ecf20Sopenharmony_ci * RETURN VALUES:
16288c2ecf20Sopenharmony_ci *	0	- success.
16298c2ecf20Sopenharmony_ci *	-ENOSPC	- insufficient disk resources.
16308c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
16318c2ecf20Sopenharmony_ci */
16328c2ecf20Sopenharmony_cistatic int
16338c2ecf20Sopenharmony_cidiAllocAG(struct inomap * imap, int agno, bool dir, struct inode *ip)
16348c2ecf20Sopenharmony_ci{
16358c2ecf20Sopenharmony_ci	int rc, addext, numfree, numinos;
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci	/* get the number of free and the number of backed disk
16388c2ecf20Sopenharmony_ci	 * inodes currently within the ag.
16398c2ecf20Sopenharmony_ci	 */
16408c2ecf20Sopenharmony_ci	numfree = imap->im_agctl[agno].numfree;
16418c2ecf20Sopenharmony_ci	numinos = imap->im_agctl[agno].numinos;
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	if (numfree > numinos) {
16448c2ecf20Sopenharmony_ci		jfs_error(ip->i_sb, "numfree > numinos\n");
16458c2ecf20Sopenharmony_ci		return -EIO;
16468c2ecf20Sopenharmony_ci	}
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	/* determine if we should allocate a new extent of free inodes
16498c2ecf20Sopenharmony_ci	 * within the ag: for directory inodes, add a new extent
16508c2ecf20Sopenharmony_ci	 * if there are a small number of free inodes or number of free
16518c2ecf20Sopenharmony_ci	 * inodes is a small percentage of the number of backed inodes.
16528c2ecf20Sopenharmony_ci	 */
16538c2ecf20Sopenharmony_ci	if (dir)
16548c2ecf20Sopenharmony_ci		addext = (numfree < 64 ||
16558c2ecf20Sopenharmony_ci			  (numfree < 256
16568c2ecf20Sopenharmony_ci			   && ((numfree * 100) / numinos) <= 20));
16578c2ecf20Sopenharmony_ci	else
16588c2ecf20Sopenharmony_ci		addext = (numfree == 0);
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	/*
16618c2ecf20Sopenharmony_ci	 * try to allocate a new extent of free inodes.
16628c2ecf20Sopenharmony_ci	 */
16638c2ecf20Sopenharmony_ci	if (addext) {
16648c2ecf20Sopenharmony_ci		/* if free space is not available for this new extent, try
16658c2ecf20Sopenharmony_ci		 * below to allocate a free and existing (already backed)
16668c2ecf20Sopenharmony_ci		 * inode from the ag.
16678c2ecf20Sopenharmony_ci		 */
16688c2ecf20Sopenharmony_ci		if ((rc = diAllocExt(imap, agno, ip)) != -ENOSPC)
16698c2ecf20Sopenharmony_ci			return (rc);
16708c2ecf20Sopenharmony_ci	}
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	/*
16738c2ecf20Sopenharmony_ci	 * try to allocate an existing free inode from the ag.
16748c2ecf20Sopenharmony_ci	 */
16758c2ecf20Sopenharmony_ci	return (diAllocIno(imap, agno, ip));
16768c2ecf20Sopenharmony_ci}
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci/*
16808c2ecf20Sopenharmony_ci * NAME:	diAllocAny(imap,agno,dir,iap)
16818c2ecf20Sopenharmony_ci *
16828c2ecf20Sopenharmony_ci * FUNCTION:	allocate a disk inode from any other allocation group.
16838c2ecf20Sopenharmony_ci *
16848c2ecf20Sopenharmony_ci *		this routine is called when an allocation attempt within
16858c2ecf20Sopenharmony_ci *		the primary allocation group has failed. if attempts to
16868c2ecf20Sopenharmony_ci *		allocate an inode from any allocation group other than the
16878c2ecf20Sopenharmony_ci *		specified primary group.
16888c2ecf20Sopenharmony_ci *
16898c2ecf20Sopenharmony_ci * PARAMETERS:
16908c2ecf20Sopenharmony_ci *	imap	- pointer to inode map control structure.
16918c2ecf20Sopenharmony_ci *	agno	- primary allocation group (to avoid).
16928c2ecf20Sopenharmony_ci *	dir	- 'true' if the new disk inode is for a directory.
16938c2ecf20Sopenharmony_ci *	ip	- pointer to a new inode to be filled in on successful return
16948c2ecf20Sopenharmony_ci *		  with the disk inode number allocated, its extent address
16958c2ecf20Sopenharmony_ci *		  and the start of the ag.
16968c2ecf20Sopenharmony_ci *
16978c2ecf20Sopenharmony_ci * RETURN VALUES:
16988c2ecf20Sopenharmony_ci *	0	- success.
16998c2ecf20Sopenharmony_ci *	-ENOSPC	- insufficient disk resources.
17008c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
17018c2ecf20Sopenharmony_ci */
17028c2ecf20Sopenharmony_cistatic int
17038c2ecf20Sopenharmony_cidiAllocAny(struct inomap * imap, int agno, bool dir, struct inode *ip)
17048c2ecf20Sopenharmony_ci{
17058c2ecf20Sopenharmony_ci	int ag, rc;
17068c2ecf20Sopenharmony_ci	int maxag = JFS_SBI(imap->im_ipimap->i_sb)->bmap->db_maxag;
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	/* try to allocate from the ags following agno up to
17108c2ecf20Sopenharmony_ci	 * the maximum ag number.
17118c2ecf20Sopenharmony_ci	 */
17128c2ecf20Sopenharmony_ci	for (ag = agno + 1; ag <= maxag; ag++) {
17138c2ecf20Sopenharmony_ci		AG_LOCK(imap, ag);
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci		rc = diAllocAG(imap, ag, dir, ip);
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci		AG_UNLOCK(imap, ag);
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci		if (rc != -ENOSPC)
17208c2ecf20Sopenharmony_ci			return (rc);
17218c2ecf20Sopenharmony_ci	}
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	/* try to allocate from the ags in front of agno.
17248c2ecf20Sopenharmony_ci	 */
17258c2ecf20Sopenharmony_ci	for (ag = 0; ag < agno; ag++) {
17268c2ecf20Sopenharmony_ci		AG_LOCK(imap, ag);
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci		rc = diAllocAG(imap, ag, dir, ip);
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci		AG_UNLOCK(imap, ag);
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci		if (rc != -ENOSPC)
17338c2ecf20Sopenharmony_ci			return (rc);
17348c2ecf20Sopenharmony_ci	}
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	/* no free disk inodes.
17378c2ecf20Sopenharmony_ci	 */
17388c2ecf20Sopenharmony_ci	return -ENOSPC;
17398c2ecf20Sopenharmony_ci}
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci/*
17438c2ecf20Sopenharmony_ci * NAME:	diAllocIno(imap,agno,ip)
17448c2ecf20Sopenharmony_ci *
17458c2ecf20Sopenharmony_ci * FUNCTION:	allocate a disk inode from the allocation group's free
17468c2ecf20Sopenharmony_ci *		inode list, returning an error if this free list is
17478c2ecf20Sopenharmony_ci *		empty (i.e. no iags on the list).
17488c2ecf20Sopenharmony_ci *
17498c2ecf20Sopenharmony_ci *		allocation occurs from the first iag on the list using
17508c2ecf20Sopenharmony_ci *		the iag's free inode summary map to find the leftmost
17518c2ecf20Sopenharmony_ci *		free inode in the iag.
17528c2ecf20Sopenharmony_ci *
17538c2ecf20Sopenharmony_ci * PRE CONDITION: Already have AG lock for this AG.
17548c2ecf20Sopenharmony_ci *
17558c2ecf20Sopenharmony_ci * PARAMETERS:
17568c2ecf20Sopenharmony_ci *	imap	- pointer to inode map control structure.
17578c2ecf20Sopenharmony_ci *	agno	- allocation group.
17588c2ecf20Sopenharmony_ci *	ip	- pointer to new inode to be filled in on successful return
17598c2ecf20Sopenharmony_ci *		  with the disk inode number allocated, its extent address
17608c2ecf20Sopenharmony_ci *		  and the start of the ag.
17618c2ecf20Sopenharmony_ci *
17628c2ecf20Sopenharmony_ci * RETURN VALUES:
17638c2ecf20Sopenharmony_ci *	0	- success.
17648c2ecf20Sopenharmony_ci *	-ENOSPC	- insufficient disk resources.
17658c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
17668c2ecf20Sopenharmony_ci */
17678c2ecf20Sopenharmony_cistatic int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
17688c2ecf20Sopenharmony_ci{
17698c2ecf20Sopenharmony_ci	int iagno, ino, rc, rem, extno, sword;
17708c2ecf20Sopenharmony_ci	struct metapage *mp;
17718c2ecf20Sopenharmony_ci	struct iag *iagp;
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	/* check if there are iags on the ag's free inode list.
17748c2ecf20Sopenharmony_ci	 */
17758c2ecf20Sopenharmony_ci	if ((iagno = imap->im_agctl[agno].inofree) < 0)
17768c2ecf20Sopenharmony_ci		return -ENOSPC;
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci	/* obtain read lock on imap inode */
17798c2ecf20Sopenharmony_ci	IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP);
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	/* read the iag at the head of the list.
17828c2ecf20Sopenharmony_ci	 */
17838c2ecf20Sopenharmony_ci	if ((rc = diIAGRead(imap, iagno, &mp))) {
17848c2ecf20Sopenharmony_ci		IREAD_UNLOCK(imap->im_ipimap);
17858c2ecf20Sopenharmony_ci		return (rc);
17868c2ecf20Sopenharmony_ci	}
17878c2ecf20Sopenharmony_ci	iagp = (struct iag *) mp->data;
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci	/* better be free inodes in this iag if it is on the
17908c2ecf20Sopenharmony_ci	 * list.
17918c2ecf20Sopenharmony_ci	 */
17928c2ecf20Sopenharmony_ci	if (!iagp->nfreeinos) {
17938c2ecf20Sopenharmony_ci		IREAD_UNLOCK(imap->im_ipimap);
17948c2ecf20Sopenharmony_ci		release_metapage(mp);
17958c2ecf20Sopenharmony_ci		jfs_error(ip->i_sb, "nfreeinos = 0, but iag on freelist\n");
17968c2ecf20Sopenharmony_ci		return -EIO;
17978c2ecf20Sopenharmony_ci	}
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci	/* scan the free inode summary map to find an extent
18008c2ecf20Sopenharmony_ci	 * with free inodes.
18018c2ecf20Sopenharmony_ci	 */
18028c2ecf20Sopenharmony_ci	for (sword = 0;; sword++) {
18038c2ecf20Sopenharmony_ci		if (sword >= SMAPSZ) {
18048c2ecf20Sopenharmony_ci			IREAD_UNLOCK(imap->im_ipimap);
18058c2ecf20Sopenharmony_ci			release_metapage(mp);
18068c2ecf20Sopenharmony_ci			jfs_error(ip->i_sb,
18078c2ecf20Sopenharmony_ci				  "free inode not found in summary map\n");
18088c2ecf20Sopenharmony_ci			return -EIO;
18098c2ecf20Sopenharmony_ci		}
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci		if (~iagp->inosmap[sword])
18128c2ecf20Sopenharmony_ci			break;
18138c2ecf20Sopenharmony_ci	}
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	/* found a extent with free inodes. determine
18168c2ecf20Sopenharmony_ci	 * the extent number.
18178c2ecf20Sopenharmony_ci	 */
18188c2ecf20Sopenharmony_ci	rem = diFindFree(le32_to_cpu(iagp->inosmap[sword]), 0);
18198c2ecf20Sopenharmony_ci	if (rem >= EXTSPERSUM) {
18208c2ecf20Sopenharmony_ci		IREAD_UNLOCK(imap->im_ipimap);
18218c2ecf20Sopenharmony_ci		release_metapage(mp);
18228c2ecf20Sopenharmony_ci		jfs_error(ip->i_sb, "no free extent found\n");
18238c2ecf20Sopenharmony_ci		return -EIO;
18248c2ecf20Sopenharmony_ci	}
18258c2ecf20Sopenharmony_ci	extno = (sword << L2EXTSPERSUM) + rem;
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	/* find the first free inode in the extent.
18288c2ecf20Sopenharmony_ci	 */
18298c2ecf20Sopenharmony_ci	rem = diFindFree(le32_to_cpu(iagp->wmap[extno]), 0);
18308c2ecf20Sopenharmony_ci	if (rem >= INOSPEREXT) {
18318c2ecf20Sopenharmony_ci		IREAD_UNLOCK(imap->im_ipimap);
18328c2ecf20Sopenharmony_ci		release_metapage(mp);
18338c2ecf20Sopenharmony_ci		jfs_error(ip->i_sb, "free inode not found\n");
18348c2ecf20Sopenharmony_ci		return -EIO;
18358c2ecf20Sopenharmony_ci	}
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	/* compute the inode number within the iag.
18388c2ecf20Sopenharmony_ci	 */
18398c2ecf20Sopenharmony_ci	ino = (extno << L2INOSPEREXT) + rem;
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	/* allocate the inode.
18428c2ecf20Sopenharmony_ci	 */
18438c2ecf20Sopenharmony_ci	rc = diAllocBit(imap, iagp, ino);
18448c2ecf20Sopenharmony_ci	IREAD_UNLOCK(imap->im_ipimap);
18458c2ecf20Sopenharmony_ci	if (rc) {
18468c2ecf20Sopenharmony_ci		release_metapage(mp);
18478c2ecf20Sopenharmony_ci		return (rc);
18488c2ecf20Sopenharmony_ci	}
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci	/* set the results of the allocation and write the iag.
18518c2ecf20Sopenharmony_ci	 */
18528c2ecf20Sopenharmony_ci	diInitInode(ip, iagno, ino, extno, iagp);
18538c2ecf20Sopenharmony_ci	write_metapage(mp);
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	return (0);
18568c2ecf20Sopenharmony_ci}
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci/*
18608c2ecf20Sopenharmony_ci * NAME:	diAllocExt(imap,agno,ip)
18618c2ecf20Sopenharmony_ci *
18628c2ecf20Sopenharmony_ci * FUNCTION:	add a new extent of free inodes to an iag, allocating
18638c2ecf20Sopenharmony_ci *		an inode from this extent to satisfy the current allocation
18648c2ecf20Sopenharmony_ci *		request.
18658c2ecf20Sopenharmony_ci *
18668c2ecf20Sopenharmony_ci *		this routine first tries to find an existing iag with free
18678c2ecf20Sopenharmony_ci *		extents through the ag free extent list.  if list is not
18688c2ecf20Sopenharmony_ci *		empty, the head of the list will be selected as the home
18698c2ecf20Sopenharmony_ci *		of the new extent of free inodes.  otherwise (the list is
18708c2ecf20Sopenharmony_ci *		empty), a new iag will be allocated for the ag to contain
18718c2ecf20Sopenharmony_ci *		the extent.
18728c2ecf20Sopenharmony_ci *
18738c2ecf20Sopenharmony_ci *		once an iag has been selected, the free extent summary map
18748c2ecf20Sopenharmony_ci *		is used to locate a free extent within the iag and diNewExt()
18758c2ecf20Sopenharmony_ci *		is called to initialize the extent, with initialization
18768c2ecf20Sopenharmony_ci *		including the allocation of the first inode of the extent
18778c2ecf20Sopenharmony_ci *		for the purpose of satisfying this request.
18788c2ecf20Sopenharmony_ci *
18798c2ecf20Sopenharmony_ci * PARAMETERS:
18808c2ecf20Sopenharmony_ci *	imap	- pointer to inode map control structure.
18818c2ecf20Sopenharmony_ci *	agno	- allocation group number.
18828c2ecf20Sopenharmony_ci *	ip	- pointer to new inode to be filled in on successful return
18838c2ecf20Sopenharmony_ci *		  with the disk inode number allocated, its extent address
18848c2ecf20Sopenharmony_ci *		  and the start of the ag.
18858c2ecf20Sopenharmony_ci *
18868c2ecf20Sopenharmony_ci * RETURN VALUES:
18878c2ecf20Sopenharmony_ci *	0	- success.
18888c2ecf20Sopenharmony_ci *	-ENOSPC	- insufficient disk resources.
18898c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
18908c2ecf20Sopenharmony_ci */
18918c2ecf20Sopenharmony_cistatic int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
18928c2ecf20Sopenharmony_ci{
18938c2ecf20Sopenharmony_ci	int rem, iagno, sword, extno, rc;
18948c2ecf20Sopenharmony_ci	struct metapage *mp;
18958c2ecf20Sopenharmony_ci	struct iag *iagp;
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	/* check if the ag has any iags with free extents.  if not,
18988c2ecf20Sopenharmony_ci	 * allocate a new iag for the ag.
18998c2ecf20Sopenharmony_ci	 */
19008c2ecf20Sopenharmony_ci	if ((iagno = imap->im_agctl[agno].extfree) < 0) {
19018c2ecf20Sopenharmony_ci		/* If successful, diNewIAG will obtain the read lock on the
19028c2ecf20Sopenharmony_ci		 * imap inode.
19038c2ecf20Sopenharmony_ci		 */
19048c2ecf20Sopenharmony_ci		if ((rc = diNewIAG(imap, &iagno, agno, &mp))) {
19058c2ecf20Sopenharmony_ci			return (rc);
19068c2ecf20Sopenharmony_ci		}
19078c2ecf20Sopenharmony_ci		iagp = (struct iag *) mp->data;
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci		/* set the ag number if this a brand new iag
19108c2ecf20Sopenharmony_ci		 */
19118c2ecf20Sopenharmony_ci		iagp->agstart =
19128c2ecf20Sopenharmony_ci		    cpu_to_le64(AGTOBLK(agno, imap->im_ipimap));
19138c2ecf20Sopenharmony_ci	} else {
19148c2ecf20Sopenharmony_ci		/* read the iag.
19158c2ecf20Sopenharmony_ci		 */
19168c2ecf20Sopenharmony_ci		IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP);
19178c2ecf20Sopenharmony_ci		if ((rc = diIAGRead(imap, iagno, &mp))) {
19188c2ecf20Sopenharmony_ci			IREAD_UNLOCK(imap->im_ipimap);
19198c2ecf20Sopenharmony_ci			jfs_error(ip->i_sb, "error reading iag\n");
19208c2ecf20Sopenharmony_ci			return rc;
19218c2ecf20Sopenharmony_ci		}
19228c2ecf20Sopenharmony_ci		iagp = (struct iag *) mp->data;
19238c2ecf20Sopenharmony_ci	}
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	/* using the free extent summary map, find a free extent.
19268c2ecf20Sopenharmony_ci	 */
19278c2ecf20Sopenharmony_ci	for (sword = 0;; sword++) {
19288c2ecf20Sopenharmony_ci		if (sword >= SMAPSZ) {
19298c2ecf20Sopenharmony_ci			release_metapage(mp);
19308c2ecf20Sopenharmony_ci			IREAD_UNLOCK(imap->im_ipimap);
19318c2ecf20Sopenharmony_ci			jfs_error(ip->i_sb, "free ext summary map not found\n");
19328c2ecf20Sopenharmony_ci			return -EIO;
19338c2ecf20Sopenharmony_ci		}
19348c2ecf20Sopenharmony_ci		if (~iagp->extsmap[sword])
19358c2ecf20Sopenharmony_ci			break;
19368c2ecf20Sopenharmony_ci	}
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	/* determine the extent number of the free extent.
19398c2ecf20Sopenharmony_ci	 */
19408c2ecf20Sopenharmony_ci	rem = diFindFree(le32_to_cpu(iagp->extsmap[sword]), 0);
19418c2ecf20Sopenharmony_ci	if (rem >= EXTSPERSUM) {
19428c2ecf20Sopenharmony_ci		release_metapage(mp);
19438c2ecf20Sopenharmony_ci		IREAD_UNLOCK(imap->im_ipimap);
19448c2ecf20Sopenharmony_ci		jfs_error(ip->i_sb, "free extent not found\n");
19458c2ecf20Sopenharmony_ci		return -EIO;
19468c2ecf20Sopenharmony_ci	}
19478c2ecf20Sopenharmony_ci	extno = (sword << L2EXTSPERSUM) + rem;
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	/* initialize the new extent.
19508c2ecf20Sopenharmony_ci	 */
19518c2ecf20Sopenharmony_ci	rc = diNewExt(imap, iagp, extno);
19528c2ecf20Sopenharmony_ci	IREAD_UNLOCK(imap->im_ipimap);
19538c2ecf20Sopenharmony_ci	if (rc) {
19548c2ecf20Sopenharmony_ci		/* something bad happened.  if a new iag was allocated,
19558c2ecf20Sopenharmony_ci		 * place it back on the inode map's iag free list, and
19568c2ecf20Sopenharmony_ci		 * clear the ag number information.
19578c2ecf20Sopenharmony_ci		 */
19588c2ecf20Sopenharmony_ci		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
19598c2ecf20Sopenharmony_ci			IAGFREE_LOCK(imap);
19608c2ecf20Sopenharmony_ci			iagp->iagfree = cpu_to_le32(imap->im_freeiag);
19618c2ecf20Sopenharmony_ci			imap->im_freeiag = iagno;
19628c2ecf20Sopenharmony_ci			IAGFREE_UNLOCK(imap);
19638c2ecf20Sopenharmony_ci		}
19648c2ecf20Sopenharmony_ci		write_metapage(mp);
19658c2ecf20Sopenharmony_ci		return (rc);
19668c2ecf20Sopenharmony_ci	}
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci	/* set the results of the allocation and write the iag.
19698c2ecf20Sopenharmony_ci	 */
19708c2ecf20Sopenharmony_ci	diInitInode(ip, iagno, extno << L2INOSPEREXT, extno, iagp);
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci	write_metapage(mp);
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci	return (0);
19758c2ecf20Sopenharmony_ci}
19768c2ecf20Sopenharmony_ci
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci/*
19798c2ecf20Sopenharmony_ci * NAME:	diAllocBit(imap,iagp,ino)
19808c2ecf20Sopenharmony_ci *
19818c2ecf20Sopenharmony_ci * FUNCTION:	allocate a backed inode from an iag.
19828c2ecf20Sopenharmony_ci *
19838c2ecf20Sopenharmony_ci *		this routine performs the mechanics of allocating a
19848c2ecf20Sopenharmony_ci *		specified inode from a backed extent.
19858c2ecf20Sopenharmony_ci *
19868c2ecf20Sopenharmony_ci *		if the inode to be allocated represents the last free
19878c2ecf20Sopenharmony_ci *		inode within the iag, the iag will be removed from the
19888c2ecf20Sopenharmony_ci *		ag free inode list.
19898c2ecf20Sopenharmony_ci *
19908c2ecf20Sopenharmony_ci *		a careful update approach is used to provide consistency
19918c2ecf20Sopenharmony_ci *		in the face of updates to multiple buffers.  under this
19928c2ecf20Sopenharmony_ci *		approach, all required buffers are obtained before making
19938c2ecf20Sopenharmony_ci *		any updates and are held all are updates are complete.
19948c2ecf20Sopenharmony_ci *
19958c2ecf20Sopenharmony_ci * PRE CONDITION: Already have buffer lock on iagp.  Already have AG lock on
19968c2ecf20Sopenharmony_ci *	this AG.  Must have read lock on imap inode.
19978c2ecf20Sopenharmony_ci *
19988c2ecf20Sopenharmony_ci * PARAMETERS:
19998c2ecf20Sopenharmony_ci *	imap	- pointer to inode map control structure.
20008c2ecf20Sopenharmony_ci *	iagp	- pointer to iag.
20018c2ecf20Sopenharmony_ci *	ino	- inode number to be allocated within the iag.
20028c2ecf20Sopenharmony_ci *
20038c2ecf20Sopenharmony_ci * RETURN VALUES:
20048c2ecf20Sopenharmony_ci *	0	- success.
20058c2ecf20Sopenharmony_ci *	-ENOSPC	- insufficient disk resources.
20068c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
20078c2ecf20Sopenharmony_ci */
20088c2ecf20Sopenharmony_cistatic int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
20098c2ecf20Sopenharmony_ci{
20108c2ecf20Sopenharmony_ci	int extno, bitno, agno, sword, rc;
20118c2ecf20Sopenharmony_ci	struct metapage *amp = NULL, *bmp = NULL;
20128c2ecf20Sopenharmony_ci	struct iag *aiagp = NULL, *biagp = NULL;
20138c2ecf20Sopenharmony_ci	u32 mask;
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ci	/* check if this is the last free inode within the iag.
20168c2ecf20Sopenharmony_ci	 * if so, it will have to be removed from the ag free
20178c2ecf20Sopenharmony_ci	 * inode list, so get the iags preceding and following
20188c2ecf20Sopenharmony_ci	 * it on the list.
20198c2ecf20Sopenharmony_ci	 */
20208c2ecf20Sopenharmony_ci	if (iagp->nfreeinos == cpu_to_le32(1)) {
20218c2ecf20Sopenharmony_ci		if ((int) le32_to_cpu(iagp->inofreefwd) >= 0) {
20228c2ecf20Sopenharmony_ci			if ((rc =
20238c2ecf20Sopenharmony_ci			     diIAGRead(imap, le32_to_cpu(iagp->inofreefwd),
20248c2ecf20Sopenharmony_ci				       &amp)))
20258c2ecf20Sopenharmony_ci				return (rc);
20268c2ecf20Sopenharmony_ci			aiagp = (struct iag *) amp->data;
20278c2ecf20Sopenharmony_ci		}
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci		if ((int) le32_to_cpu(iagp->inofreeback) >= 0) {
20308c2ecf20Sopenharmony_ci			if ((rc =
20318c2ecf20Sopenharmony_ci			     diIAGRead(imap,
20328c2ecf20Sopenharmony_ci				       le32_to_cpu(iagp->inofreeback),
20338c2ecf20Sopenharmony_ci				       &bmp))) {
20348c2ecf20Sopenharmony_ci				if (amp)
20358c2ecf20Sopenharmony_ci					release_metapage(amp);
20368c2ecf20Sopenharmony_ci				return (rc);
20378c2ecf20Sopenharmony_ci			}
20388c2ecf20Sopenharmony_ci			biagp = (struct iag *) bmp->data;
20398c2ecf20Sopenharmony_ci		}
20408c2ecf20Sopenharmony_ci	}
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	/* get the ag number, extent number, inode number within
20438c2ecf20Sopenharmony_ci	 * the extent.
20448c2ecf20Sopenharmony_ci	 */
20458c2ecf20Sopenharmony_ci	agno = BLKTOAG(le64_to_cpu(iagp->agstart), JFS_SBI(imap->im_ipimap->i_sb));
20468c2ecf20Sopenharmony_ci	extno = ino >> L2INOSPEREXT;
20478c2ecf20Sopenharmony_ci	bitno = ino & (INOSPEREXT - 1);
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci	/* compute the mask for setting the map.
20508c2ecf20Sopenharmony_ci	 */
20518c2ecf20Sopenharmony_ci	mask = HIGHORDER >> bitno;
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	/* the inode should be free and backed.
20548c2ecf20Sopenharmony_ci	 */
20558c2ecf20Sopenharmony_ci	if (((le32_to_cpu(iagp->pmap[extno]) & mask) != 0) ||
20568c2ecf20Sopenharmony_ci	    ((le32_to_cpu(iagp->wmap[extno]) & mask) != 0) ||
20578c2ecf20Sopenharmony_ci	    (addressPXD(&iagp->inoext[extno]) == 0)) {
20588c2ecf20Sopenharmony_ci		if (amp)
20598c2ecf20Sopenharmony_ci			release_metapage(amp);
20608c2ecf20Sopenharmony_ci		if (bmp)
20618c2ecf20Sopenharmony_ci			release_metapage(bmp);
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci		jfs_error(imap->im_ipimap->i_sb, "iag inconsistent\n");
20648c2ecf20Sopenharmony_ci		return -EIO;
20658c2ecf20Sopenharmony_ci	}
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci	/* mark the inode as allocated in the working map.
20688c2ecf20Sopenharmony_ci	 */
20698c2ecf20Sopenharmony_ci	iagp->wmap[extno] |= cpu_to_le32(mask);
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci	/* check if all inodes within the extent are now
20728c2ecf20Sopenharmony_ci	 * allocated.  if so, update the free inode summary
20738c2ecf20Sopenharmony_ci	 * map to reflect this.
20748c2ecf20Sopenharmony_ci	 */
20758c2ecf20Sopenharmony_ci	if (iagp->wmap[extno] == cpu_to_le32(ONES)) {
20768c2ecf20Sopenharmony_ci		sword = extno >> L2EXTSPERSUM;
20778c2ecf20Sopenharmony_ci		bitno = extno & (EXTSPERSUM - 1);
20788c2ecf20Sopenharmony_ci		iagp->inosmap[sword] |= cpu_to_le32(HIGHORDER >> bitno);
20798c2ecf20Sopenharmony_ci	}
20808c2ecf20Sopenharmony_ci
20818c2ecf20Sopenharmony_ci	/* if this was the last free inode in the iag, remove the
20828c2ecf20Sopenharmony_ci	 * iag from the ag free inode list.
20838c2ecf20Sopenharmony_ci	 */
20848c2ecf20Sopenharmony_ci	if (iagp->nfreeinos == cpu_to_le32(1)) {
20858c2ecf20Sopenharmony_ci		if (amp) {
20868c2ecf20Sopenharmony_ci			aiagp->inofreeback = iagp->inofreeback;
20878c2ecf20Sopenharmony_ci			write_metapage(amp);
20888c2ecf20Sopenharmony_ci		}
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci		if (bmp) {
20918c2ecf20Sopenharmony_ci			biagp->inofreefwd = iagp->inofreefwd;
20928c2ecf20Sopenharmony_ci			write_metapage(bmp);
20938c2ecf20Sopenharmony_ci		} else {
20948c2ecf20Sopenharmony_ci			imap->im_agctl[agno].inofree =
20958c2ecf20Sopenharmony_ci			    le32_to_cpu(iagp->inofreefwd);
20968c2ecf20Sopenharmony_ci		}
20978c2ecf20Sopenharmony_ci		iagp->inofreefwd = iagp->inofreeback = cpu_to_le32(-1);
20988c2ecf20Sopenharmony_ci	}
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci	/* update the free inode count at the iag, ag, inode
21018c2ecf20Sopenharmony_ci	 * map levels.
21028c2ecf20Sopenharmony_ci	 */
21038c2ecf20Sopenharmony_ci	le32_add_cpu(&iagp->nfreeinos, -1);
21048c2ecf20Sopenharmony_ci	imap->im_agctl[agno].numfree -= 1;
21058c2ecf20Sopenharmony_ci	atomic_dec(&imap->im_numfree);
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci	return (0);
21088c2ecf20Sopenharmony_ci}
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ci/*
21128c2ecf20Sopenharmony_ci * NAME:	diNewExt(imap,iagp,extno)
21138c2ecf20Sopenharmony_ci *
21148c2ecf20Sopenharmony_ci * FUNCTION:	initialize a new extent of inodes for an iag, allocating
21158c2ecf20Sopenharmony_ci *		the first inode of the extent for use for the current
21168c2ecf20Sopenharmony_ci *		allocation request.
21178c2ecf20Sopenharmony_ci *
21188c2ecf20Sopenharmony_ci *		disk resources are allocated for the new extent of inodes
21198c2ecf20Sopenharmony_ci *		and the inodes themselves are initialized to reflect their
21208c2ecf20Sopenharmony_ci *		existence within the extent (i.e. their inode numbers and
21218c2ecf20Sopenharmony_ci *		inode extent addresses are set) and their initial state
21228c2ecf20Sopenharmony_ci *		(mode and link count are set to zero).
21238c2ecf20Sopenharmony_ci *
21248c2ecf20Sopenharmony_ci *		if the iag is new, it is not yet on an ag extent free list
21258c2ecf20Sopenharmony_ci *		but will now be placed on this list.
21268c2ecf20Sopenharmony_ci *
21278c2ecf20Sopenharmony_ci *		if the allocation of the new extent causes the iag to
21288c2ecf20Sopenharmony_ci *		have no free extent, the iag will be removed from the
21298c2ecf20Sopenharmony_ci *		ag extent free list.
21308c2ecf20Sopenharmony_ci *
21318c2ecf20Sopenharmony_ci *		if the iag has no free backed inodes, it will be placed
21328c2ecf20Sopenharmony_ci *		on the ag free inode list, since the addition of the new
21338c2ecf20Sopenharmony_ci *		extent will now cause it to have free inodes.
21348c2ecf20Sopenharmony_ci *
21358c2ecf20Sopenharmony_ci *		a careful update approach is used to provide consistency
21368c2ecf20Sopenharmony_ci *		(i.e. list consistency) in the face of updates to multiple
21378c2ecf20Sopenharmony_ci *		buffers.  under this approach, all required buffers are
21388c2ecf20Sopenharmony_ci *		obtained before making any updates and are held until all
21398c2ecf20Sopenharmony_ci *		updates are complete.
21408c2ecf20Sopenharmony_ci *
21418c2ecf20Sopenharmony_ci * PRE CONDITION: Already have buffer lock on iagp.  Already have AG lock on
21428c2ecf20Sopenharmony_ci *	this AG.  Must have read lock on imap inode.
21438c2ecf20Sopenharmony_ci *
21448c2ecf20Sopenharmony_ci * PARAMETERS:
21458c2ecf20Sopenharmony_ci *	imap	- pointer to inode map control structure.
21468c2ecf20Sopenharmony_ci *	iagp	- pointer to iag.
21478c2ecf20Sopenharmony_ci *	extno	- extent number.
21488c2ecf20Sopenharmony_ci *
21498c2ecf20Sopenharmony_ci * RETURN VALUES:
21508c2ecf20Sopenharmony_ci *	0	- success.
21518c2ecf20Sopenharmony_ci *	-ENOSPC	- insufficient disk resources.
21528c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
21538c2ecf20Sopenharmony_ci */
21548c2ecf20Sopenharmony_cistatic int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
21558c2ecf20Sopenharmony_ci{
21568c2ecf20Sopenharmony_ci	int agno, iagno, fwd, back, freei = 0, sword, rc;
21578c2ecf20Sopenharmony_ci	struct iag *aiagp = NULL, *biagp = NULL, *ciagp = NULL;
21588c2ecf20Sopenharmony_ci	struct metapage *amp, *bmp, *cmp, *dmp;
21598c2ecf20Sopenharmony_ci	struct inode *ipimap;
21608c2ecf20Sopenharmony_ci	s64 blkno, hint;
21618c2ecf20Sopenharmony_ci	int i, j;
21628c2ecf20Sopenharmony_ci	u32 mask;
21638c2ecf20Sopenharmony_ci	ino_t ino;
21648c2ecf20Sopenharmony_ci	struct dinode *dp;
21658c2ecf20Sopenharmony_ci	struct jfs_sb_info *sbi;
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	/* better have free extents.
21688c2ecf20Sopenharmony_ci	 */
21698c2ecf20Sopenharmony_ci	if (!iagp->nfreeexts) {
21708c2ecf20Sopenharmony_ci		jfs_error(imap->im_ipimap->i_sb, "no free extents\n");
21718c2ecf20Sopenharmony_ci		return -EIO;
21728c2ecf20Sopenharmony_ci	}
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	/* get the inode map inode.
21758c2ecf20Sopenharmony_ci	 */
21768c2ecf20Sopenharmony_ci	ipimap = imap->im_ipimap;
21778c2ecf20Sopenharmony_ci	sbi = JFS_SBI(ipimap->i_sb);
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_ci	amp = bmp = cmp = NULL;
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci	/* get the ag and iag numbers for this iag.
21828c2ecf20Sopenharmony_ci	 */
21838c2ecf20Sopenharmony_ci	agno = BLKTOAG(le64_to_cpu(iagp->agstart), sbi);
21848c2ecf20Sopenharmony_ci	if (agno >= MAXAG || agno < 0)
21858c2ecf20Sopenharmony_ci		return -EIO;
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci	iagno = le32_to_cpu(iagp->iagnum);
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci	/* check if this is the last free extent within the
21908c2ecf20Sopenharmony_ci	 * iag.  if so, the iag must be removed from the ag
21918c2ecf20Sopenharmony_ci	 * free extent list, so get the iags preceding and
21928c2ecf20Sopenharmony_ci	 * following the iag on this list.
21938c2ecf20Sopenharmony_ci	 */
21948c2ecf20Sopenharmony_ci	if (iagp->nfreeexts == cpu_to_le32(1)) {
21958c2ecf20Sopenharmony_ci		if ((fwd = le32_to_cpu(iagp->extfreefwd)) >= 0) {
21968c2ecf20Sopenharmony_ci			if ((rc = diIAGRead(imap, fwd, &amp)))
21978c2ecf20Sopenharmony_ci				return (rc);
21988c2ecf20Sopenharmony_ci			aiagp = (struct iag *) amp->data;
21998c2ecf20Sopenharmony_ci		}
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci		if ((back = le32_to_cpu(iagp->extfreeback)) >= 0) {
22028c2ecf20Sopenharmony_ci			if ((rc = diIAGRead(imap, back, &bmp)))
22038c2ecf20Sopenharmony_ci				goto error_out;
22048c2ecf20Sopenharmony_ci			biagp = (struct iag *) bmp->data;
22058c2ecf20Sopenharmony_ci		}
22068c2ecf20Sopenharmony_ci	} else {
22078c2ecf20Sopenharmony_ci		/* the iag has free extents.  if all extents are free
22088c2ecf20Sopenharmony_ci		 * (as is the case for a newly allocated iag), the iag
22098c2ecf20Sopenharmony_ci		 * must be added to the ag free extent list, so get
22108c2ecf20Sopenharmony_ci		 * the iag at the head of the list in preparation for
22118c2ecf20Sopenharmony_ci		 * adding this iag to this list.
22128c2ecf20Sopenharmony_ci		 */
22138c2ecf20Sopenharmony_ci		fwd = back = -1;
22148c2ecf20Sopenharmony_ci		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
22158c2ecf20Sopenharmony_ci			if ((fwd = imap->im_agctl[agno].extfree) >= 0) {
22168c2ecf20Sopenharmony_ci				if ((rc = diIAGRead(imap, fwd, &amp)))
22178c2ecf20Sopenharmony_ci					goto error_out;
22188c2ecf20Sopenharmony_ci				aiagp = (struct iag *) amp->data;
22198c2ecf20Sopenharmony_ci			}
22208c2ecf20Sopenharmony_ci		}
22218c2ecf20Sopenharmony_ci	}
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	/* check if the iag has no free inodes.  if so, the iag
22248c2ecf20Sopenharmony_ci	 * will have to be added to the ag free inode list, so get
22258c2ecf20Sopenharmony_ci	 * the iag at the head of the list in preparation for
22268c2ecf20Sopenharmony_ci	 * adding this iag to this list.  in doing this, we must
22278c2ecf20Sopenharmony_ci	 * check if we already have the iag at the head of
22288c2ecf20Sopenharmony_ci	 * the list in hand.
22298c2ecf20Sopenharmony_ci	 */
22308c2ecf20Sopenharmony_ci	if (iagp->nfreeinos == 0) {
22318c2ecf20Sopenharmony_ci		freei = imap->im_agctl[agno].inofree;
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci		if (freei >= 0) {
22348c2ecf20Sopenharmony_ci			if (freei == fwd) {
22358c2ecf20Sopenharmony_ci				ciagp = aiagp;
22368c2ecf20Sopenharmony_ci			} else if (freei == back) {
22378c2ecf20Sopenharmony_ci				ciagp = biagp;
22388c2ecf20Sopenharmony_ci			} else {
22398c2ecf20Sopenharmony_ci				if ((rc = diIAGRead(imap, freei, &cmp)))
22408c2ecf20Sopenharmony_ci					goto error_out;
22418c2ecf20Sopenharmony_ci				ciagp = (struct iag *) cmp->data;
22428c2ecf20Sopenharmony_ci			}
22438c2ecf20Sopenharmony_ci			if (ciagp == NULL) {
22448c2ecf20Sopenharmony_ci				jfs_error(imap->im_ipimap->i_sb,
22458c2ecf20Sopenharmony_ci					  "ciagp == NULL\n");
22468c2ecf20Sopenharmony_ci				rc = -EIO;
22478c2ecf20Sopenharmony_ci				goto error_out;
22488c2ecf20Sopenharmony_ci			}
22498c2ecf20Sopenharmony_ci		}
22508c2ecf20Sopenharmony_ci	}
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_ci	/* allocate disk space for the inode extent.
22538c2ecf20Sopenharmony_ci	 */
22548c2ecf20Sopenharmony_ci	if ((extno == 0) || (addressPXD(&iagp->inoext[extno - 1]) == 0))
22558c2ecf20Sopenharmony_ci		hint = ((s64) agno << sbi->bmap->db_agl2size) - 1;
22568c2ecf20Sopenharmony_ci	else
22578c2ecf20Sopenharmony_ci		hint = addressPXD(&iagp->inoext[extno - 1]) +
22588c2ecf20Sopenharmony_ci		    lengthPXD(&iagp->inoext[extno - 1]) - 1;
22598c2ecf20Sopenharmony_ci
22608c2ecf20Sopenharmony_ci	if ((rc = dbAlloc(ipimap, hint, (s64) imap->im_nbperiext, &blkno)))
22618c2ecf20Sopenharmony_ci		goto error_out;
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci	/* compute the inode number of the first inode within the
22648c2ecf20Sopenharmony_ci	 * extent.
22658c2ecf20Sopenharmony_ci	 */
22668c2ecf20Sopenharmony_ci	ino = (iagno << L2INOSPERIAG) + (extno << L2INOSPEREXT);
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci	/* initialize the inodes within the newly allocated extent a
22698c2ecf20Sopenharmony_ci	 * page at a time.
22708c2ecf20Sopenharmony_ci	 */
22718c2ecf20Sopenharmony_ci	for (i = 0; i < imap->im_nbperiext; i += sbi->nbperpage) {
22728c2ecf20Sopenharmony_ci		/* get a buffer for this page of disk inodes.
22738c2ecf20Sopenharmony_ci		 */
22748c2ecf20Sopenharmony_ci		dmp = get_metapage(ipimap, blkno + i, PSIZE, 1);
22758c2ecf20Sopenharmony_ci		if (dmp == NULL) {
22768c2ecf20Sopenharmony_ci			rc = -EIO;
22778c2ecf20Sopenharmony_ci			goto error_out;
22788c2ecf20Sopenharmony_ci		}
22798c2ecf20Sopenharmony_ci		dp = (struct dinode *) dmp->data;
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci		/* initialize the inode number, mode, link count and
22828c2ecf20Sopenharmony_ci		 * inode extent address.
22838c2ecf20Sopenharmony_ci		 */
22848c2ecf20Sopenharmony_ci		for (j = 0; j < INOSPERPAGE; j++, dp++, ino++) {
22858c2ecf20Sopenharmony_ci			dp->di_inostamp = cpu_to_le32(sbi->inostamp);
22868c2ecf20Sopenharmony_ci			dp->di_number = cpu_to_le32(ino);
22878c2ecf20Sopenharmony_ci			dp->di_fileset = cpu_to_le32(FILESYSTEM_I);
22888c2ecf20Sopenharmony_ci			dp->di_mode = 0;
22898c2ecf20Sopenharmony_ci			dp->di_nlink = 0;
22908c2ecf20Sopenharmony_ci			PXDaddress(&(dp->di_ixpxd), blkno);
22918c2ecf20Sopenharmony_ci			PXDlength(&(dp->di_ixpxd), imap->im_nbperiext);
22928c2ecf20Sopenharmony_ci		}
22938c2ecf20Sopenharmony_ci		write_metapage(dmp);
22948c2ecf20Sopenharmony_ci	}
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci	/* if this is the last free extent within the iag, remove the
22978c2ecf20Sopenharmony_ci	 * iag from the ag free extent list.
22988c2ecf20Sopenharmony_ci	 */
22998c2ecf20Sopenharmony_ci	if (iagp->nfreeexts == cpu_to_le32(1)) {
23008c2ecf20Sopenharmony_ci		if (fwd >= 0)
23018c2ecf20Sopenharmony_ci			aiagp->extfreeback = iagp->extfreeback;
23028c2ecf20Sopenharmony_ci
23038c2ecf20Sopenharmony_ci		if (back >= 0)
23048c2ecf20Sopenharmony_ci			biagp->extfreefwd = iagp->extfreefwd;
23058c2ecf20Sopenharmony_ci		else
23068c2ecf20Sopenharmony_ci			imap->im_agctl[agno].extfree =
23078c2ecf20Sopenharmony_ci			    le32_to_cpu(iagp->extfreefwd);
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_ci		iagp->extfreefwd = iagp->extfreeback = cpu_to_le32(-1);
23108c2ecf20Sopenharmony_ci	} else {
23118c2ecf20Sopenharmony_ci		/* if the iag has all free extents (newly allocated iag),
23128c2ecf20Sopenharmony_ci		 * add the iag to the ag free extent list.
23138c2ecf20Sopenharmony_ci		 */
23148c2ecf20Sopenharmony_ci		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
23158c2ecf20Sopenharmony_ci			if (fwd >= 0)
23168c2ecf20Sopenharmony_ci				aiagp->extfreeback = cpu_to_le32(iagno);
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci			iagp->extfreefwd = cpu_to_le32(fwd);
23198c2ecf20Sopenharmony_ci			iagp->extfreeback = cpu_to_le32(-1);
23208c2ecf20Sopenharmony_ci			imap->im_agctl[agno].extfree = iagno;
23218c2ecf20Sopenharmony_ci		}
23228c2ecf20Sopenharmony_ci	}
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ci	/* if the iag has no free inodes, add the iag to the
23258c2ecf20Sopenharmony_ci	 * ag free inode list.
23268c2ecf20Sopenharmony_ci	 */
23278c2ecf20Sopenharmony_ci	if (iagp->nfreeinos == 0) {
23288c2ecf20Sopenharmony_ci		if (freei >= 0)
23298c2ecf20Sopenharmony_ci			ciagp->inofreeback = cpu_to_le32(iagno);
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_ci		iagp->inofreefwd =
23328c2ecf20Sopenharmony_ci		    cpu_to_le32(imap->im_agctl[agno].inofree);
23338c2ecf20Sopenharmony_ci		iagp->inofreeback = cpu_to_le32(-1);
23348c2ecf20Sopenharmony_ci		imap->im_agctl[agno].inofree = iagno;
23358c2ecf20Sopenharmony_ci	}
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci	/* initialize the extent descriptor of the extent. */
23388c2ecf20Sopenharmony_ci	PXDlength(&iagp->inoext[extno], imap->im_nbperiext);
23398c2ecf20Sopenharmony_ci	PXDaddress(&iagp->inoext[extno], blkno);
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci	/* initialize the working and persistent map of the extent.
23428c2ecf20Sopenharmony_ci	 * the working map will be initialized such that
23438c2ecf20Sopenharmony_ci	 * it indicates the first inode of the extent is allocated.
23448c2ecf20Sopenharmony_ci	 */
23458c2ecf20Sopenharmony_ci	iagp->wmap[extno] = cpu_to_le32(HIGHORDER);
23468c2ecf20Sopenharmony_ci	iagp->pmap[extno] = 0;
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci	/* update the free inode and free extent summary maps
23498c2ecf20Sopenharmony_ci	 * for the extent to indicate the extent has free inodes
23508c2ecf20Sopenharmony_ci	 * and no longer represents a free extent.
23518c2ecf20Sopenharmony_ci	 */
23528c2ecf20Sopenharmony_ci	sword = extno >> L2EXTSPERSUM;
23538c2ecf20Sopenharmony_ci	mask = HIGHORDER >> (extno & (EXTSPERSUM - 1));
23548c2ecf20Sopenharmony_ci	iagp->extsmap[sword] |= cpu_to_le32(mask);
23558c2ecf20Sopenharmony_ci	iagp->inosmap[sword] &= cpu_to_le32(~mask);
23568c2ecf20Sopenharmony_ci
23578c2ecf20Sopenharmony_ci	/* update the free inode and free extent counts for the
23588c2ecf20Sopenharmony_ci	 * iag.
23598c2ecf20Sopenharmony_ci	 */
23608c2ecf20Sopenharmony_ci	le32_add_cpu(&iagp->nfreeinos, (INOSPEREXT - 1));
23618c2ecf20Sopenharmony_ci	le32_add_cpu(&iagp->nfreeexts, -1);
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci	/* update the free and backed inode counts for the ag.
23648c2ecf20Sopenharmony_ci	 */
23658c2ecf20Sopenharmony_ci	imap->im_agctl[agno].numfree += (INOSPEREXT - 1);
23668c2ecf20Sopenharmony_ci	imap->im_agctl[agno].numinos += INOSPEREXT;
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci	/* update the free and backed inode counts for the inode map.
23698c2ecf20Sopenharmony_ci	 */
23708c2ecf20Sopenharmony_ci	atomic_add(INOSPEREXT - 1, &imap->im_numfree);
23718c2ecf20Sopenharmony_ci	atomic_add(INOSPEREXT, &imap->im_numinos);
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_ci	/* write the iags.
23748c2ecf20Sopenharmony_ci	 */
23758c2ecf20Sopenharmony_ci	if (amp)
23768c2ecf20Sopenharmony_ci		write_metapage(amp);
23778c2ecf20Sopenharmony_ci	if (bmp)
23788c2ecf20Sopenharmony_ci		write_metapage(bmp);
23798c2ecf20Sopenharmony_ci	if (cmp)
23808c2ecf20Sopenharmony_ci		write_metapage(cmp);
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_ci	return (0);
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_ci      error_out:
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	/* release the iags.
23878c2ecf20Sopenharmony_ci	 */
23888c2ecf20Sopenharmony_ci	if (amp)
23898c2ecf20Sopenharmony_ci		release_metapage(amp);
23908c2ecf20Sopenharmony_ci	if (bmp)
23918c2ecf20Sopenharmony_ci		release_metapage(bmp);
23928c2ecf20Sopenharmony_ci	if (cmp)
23938c2ecf20Sopenharmony_ci		release_metapage(cmp);
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci	return (rc);
23968c2ecf20Sopenharmony_ci}
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci/*
24008c2ecf20Sopenharmony_ci * NAME:	diNewIAG(imap,iagnop,agno)
24018c2ecf20Sopenharmony_ci *
24028c2ecf20Sopenharmony_ci * FUNCTION:	allocate a new iag for an allocation group.
24038c2ecf20Sopenharmony_ci *
24048c2ecf20Sopenharmony_ci *		first tries to allocate the iag from the inode map
24058c2ecf20Sopenharmony_ci *		iagfree list:
24068c2ecf20Sopenharmony_ci *		if the list has free iags, the head of the list is removed
24078c2ecf20Sopenharmony_ci *		and returned to satisfy the request.
24088c2ecf20Sopenharmony_ci *		if the inode map's iag free list is empty, the inode map
24098c2ecf20Sopenharmony_ci *		is extended to hold a new iag. this new iag is initialized
24108c2ecf20Sopenharmony_ci *		and returned to satisfy the request.
24118c2ecf20Sopenharmony_ci *
24128c2ecf20Sopenharmony_ci * PARAMETERS:
24138c2ecf20Sopenharmony_ci *	imap	- pointer to inode map control structure.
24148c2ecf20Sopenharmony_ci *	iagnop	- pointer to an iag number set with the number of the
24158c2ecf20Sopenharmony_ci *		  newly allocated iag upon successful return.
24168c2ecf20Sopenharmony_ci *	agno	- allocation group number.
24178c2ecf20Sopenharmony_ci *	bpp	- Buffer pointer to be filled in with new IAG's buffer
24188c2ecf20Sopenharmony_ci *
24198c2ecf20Sopenharmony_ci * RETURN VALUES:
24208c2ecf20Sopenharmony_ci *	0	- success.
24218c2ecf20Sopenharmony_ci *	-ENOSPC	- insufficient disk resources.
24228c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
24238c2ecf20Sopenharmony_ci *
24248c2ecf20Sopenharmony_ci * serialization:
24258c2ecf20Sopenharmony_ci *	AG lock held on entry/exit;
24268c2ecf20Sopenharmony_ci *	write lock on the map is held inside;
24278c2ecf20Sopenharmony_ci *	read lock on the map is held on successful completion;
24288c2ecf20Sopenharmony_ci *
24298c2ecf20Sopenharmony_ci * note: new iag transaction:
24308c2ecf20Sopenharmony_ci * . synchronously write iag;
24318c2ecf20Sopenharmony_ci * . write log of xtree and inode of imap;
24328c2ecf20Sopenharmony_ci * . commit;
24338c2ecf20Sopenharmony_ci * . synchronous write of xtree (right to left, bottom to top);
24348c2ecf20Sopenharmony_ci * . at start of logredo(): init in-memory imap with one additional iag page;
24358c2ecf20Sopenharmony_ci * . at end of logredo(): re-read imap inode to determine
24368c2ecf20Sopenharmony_ci *   new imap size;
24378c2ecf20Sopenharmony_ci */
24388c2ecf20Sopenharmony_cistatic int
24398c2ecf20Sopenharmony_cidiNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
24408c2ecf20Sopenharmony_ci{
24418c2ecf20Sopenharmony_ci	int rc;
24428c2ecf20Sopenharmony_ci	int iagno, i, xlen;
24438c2ecf20Sopenharmony_ci	struct inode *ipimap;
24448c2ecf20Sopenharmony_ci	struct super_block *sb;
24458c2ecf20Sopenharmony_ci	struct jfs_sb_info *sbi;
24468c2ecf20Sopenharmony_ci	struct metapage *mp;
24478c2ecf20Sopenharmony_ci	struct iag *iagp;
24488c2ecf20Sopenharmony_ci	s64 xaddr = 0;
24498c2ecf20Sopenharmony_ci	s64 blkno;
24508c2ecf20Sopenharmony_ci	tid_t tid;
24518c2ecf20Sopenharmony_ci	struct inode *iplist[1];
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ci	/* pick up pointers to the inode map and mount inodes */
24548c2ecf20Sopenharmony_ci	ipimap = imap->im_ipimap;
24558c2ecf20Sopenharmony_ci	sb = ipimap->i_sb;
24568c2ecf20Sopenharmony_ci	sbi = JFS_SBI(sb);
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci	/* acquire the free iag lock */
24598c2ecf20Sopenharmony_ci	IAGFREE_LOCK(imap);
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	/* if there are any iags on the inode map free iag list,
24628c2ecf20Sopenharmony_ci	 * allocate the iag from the head of the list.
24638c2ecf20Sopenharmony_ci	 */
24648c2ecf20Sopenharmony_ci	if (imap->im_freeiag >= 0) {
24658c2ecf20Sopenharmony_ci		/* pick up the iag number at the head of the list */
24668c2ecf20Sopenharmony_ci		iagno = imap->im_freeiag;
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci		/* determine the logical block number of the iag */
24698c2ecf20Sopenharmony_ci		blkno = IAGTOLBLK(iagno, sbi->l2nbperpage);
24708c2ecf20Sopenharmony_ci	} else {
24718c2ecf20Sopenharmony_ci		/* no free iags. the inode map will have to be extented
24728c2ecf20Sopenharmony_ci		 * to include a new iag.
24738c2ecf20Sopenharmony_ci		 */
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci		/* acquire inode map lock */
24768c2ecf20Sopenharmony_ci		IWRITE_LOCK(ipimap, RDWRLOCK_IMAP);
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci		if (ipimap->i_size >> L2PSIZE != imap->im_nextiag + 1) {
24798c2ecf20Sopenharmony_ci			IWRITE_UNLOCK(ipimap);
24808c2ecf20Sopenharmony_ci			IAGFREE_UNLOCK(imap);
24818c2ecf20Sopenharmony_ci			jfs_error(imap->im_ipimap->i_sb,
24828c2ecf20Sopenharmony_ci				  "ipimap->i_size is wrong\n");
24838c2ecf20Sopenharmony_ci			return -EIO;
24848c2ecf20Sopenharmony_ci		}
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci		/* get the next available iag number */
24888c2ecf20Sopenharmony_ci		iagno = imap->im_nextiag;
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_ci		/* make sure that we have not exceeded the maximum inode
24918c2ecf20Sopenharmony_ci		 * number limit.
24928c2ecf20Sopenharmony_ci		 */
24938c2ecf20Sopenharmony_ci		if (iagno > (MAXIAGS - 1)) {
24948c2ecf20Sopenharmony_ci			/* release the inode map lock */
24958c2ecf20Sopenharmony_ci			IWRITE_UNLOCK(ipimap);
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci			rc = -ENOSPC;
24988c2ecf20Sopenharmony_ci			goto out;
24998c2ecf20Sopenharmony_ci		}
25008c2ecf20Sopenharmony_ci
25018c2ecf20Sopenharmony_ci		/*
25028c2ecf20Sopenharmony_ci		 * synchronously append new iag page.
25038c2ecf20Sopenharmony_ci		 */
25048c2ecf20Sopenharmony_ci		/* determine the logical address of iag page to append */
25058c2ecf20Sopenharmony_ci		blkno = IAGTOLBLK(iagno, sbi->l2nbperpage);
25068c2ecf20Sopenharmony_ci
25078c2ecf20Sopenharmony_ci		/* Allocate extent for new iag page */
25088c2ecf20Sopenharmony_ci		xlen = sbi->nbperpage;
25098c2ecf20Sopenharmony_ci		if ((rc = dbAlloc(ipimap, 0, (s64) xlen, &xaddr))) {
25108c2ecf20Sopenharmony_ci			/* release the inode map lock */
25118c2ecf20Sopenharmony_ci			IWRITE_UNLOCK(ipimap);
25128c2ecf20Sopenharmony_ci
25138c2ecf20Sopenharmony_ci			goto out;
25148c2ecf20Sopenharmony_ci		}
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_ci		/*
25178c2ecf20Sopenharmony_ci		 * start transaction of update of the inode map
25188c2ecf20Sopenharmony_ci		 * addressing structure pointing to the new iag page;
25198c2ecf20Sopenharmony_ci		 */
25208c2ecf20Sopenharmony_ci		tid = txBegin(sb, COMMIT_FORCE);
25218c2ecf20Sopenharmony_ci		mutex_lock(&JFS_IP(ipimap)->commit_mutex);
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci		/* update the inode map addressing structure to point to it */
25248c2ecf20Sopenharmony_ci		if ((rc =
25258c2ecf20Sopenharmony_ci		     xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) {
25268c2ecf20Sopenharmony_ci			txEnd(tid);
25278c2ecf20Sopenharmony_ci			mutex_unlock(&JFS_IP(ipimap)->commit_mutex);
25288c2ecf20Sopenharmony_ci			/* Free the blocks allocated for the iag since it was
25298c2ecf20Sopenharmony_ci			 * not successfully added to the inode map
25308c2ecf20Sopenharmony_ci			 */
25318c2ecf20Sopenharmony_ci			dbFree(ipimap, xaddr, (s64) xlen);
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ci			/* release the inode map lock */
25348c2ecf20Sopenharmony_ci			IWRITE_UNLOCK(ipimap);
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_ci			goto out;
25378c2ecf20Sopenharmony_ci		}
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci		/* update the inode map's inode to reflect the extension */
25408c2ecf20Sopenharmony_ci		ipimap->i_size += PSIZE;
25418c2ecf20Sopenharmony_ci		inode_add_bytes(ipimap, PSIZE);
25428c2ecf20Sopenharmony_ci
25438c2ecf20Sopenharmony_ci		/* assign a buffer for the page */
25448c2ecf20Sopenharmony_ci		mp = get_metapage(ipimap, blkno, PSIZE, 0);
25458c2ecf20Sopenharmony_ci		if (!mp) {
25468c2ecf20Sopenharmony_ci			/*
25478c2ecf20Sopenharmony_ci			 * This is very unlikely since we just created the
25488c2ecf20Sopenharmony_ci			 * extent, but let's try to handle it correctly
25498c2ecf20Sopenharmony_ci			 */
25508c2ecf20Sopenharmony_ci			xtTruncate(tid, ipimap, ipimap->i_size - PSIZE,
25518c2ecf20Sopenharmony_ci				   COMMIT_PWMAP);
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci			txAbort(tid, 0);
25548c2ecf20Sopenharmony_ci			txEnd(tid);
25558c2ecf20Sopenharmony_ci			mutex_unlock(&JFS_IP(ipimap)->commit_mutex);
25568c2ecf20Sopenharmony_ci
25578c2ecf20Sopenharmony_ci			/* release the inode map lock */
25588c2ecf20Sopenharmony_ci			IWRITE_UNLOCK(ipimap);
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci			rc = -EIO;
25618c2ecf20Sopenharmony_ci			goto out;
25628c2ecf20Sopenharmony_ci		}
25638c2ecf20Sopenharmony_ci		iagp = (struct iag *) mp->data;
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci		/* init the iag */
25668c2ecf20Sopenharmony_ci		memset(iagp, 0, sizeof(struct iag));
25678c2ecf20Sopenharmony_ci		iagp->iagnum = cpu_to_le32(iagno);
25688c2ecf20Sopenharmony_ci		iagp->inofreefwd = iagp->inofreeback = cpu_to_le32(-1);
25698c2ecf20Sopenharmony_ci		iagp->extfreefwd = iagp->extfreeback = cpu_to_le32(-1);
25708c2ecf20Sopenharmony_ci		iagp->iagfree = cpu_to_le32(-1);
25718c2ecf20Sopenharmony_ci		iagp->nfreeinos = 0;
25728c2ecf20Sopenharmony_ci		iagp->nfreeexts = cpu_to_le32(EXTSPERIAG);
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci		/* initialize the free inode summary map (free extent
25758c2ecf20Sopenharmony_ci		 * summary map initialization handled by bzero).
25768c2ecf20Sopenharmony_ci		 */
25778c2ecf20Sopenharmony_ci		for (i = 0; i < SMAPSZ; i++)
25788c2ecf20Sopenharmony_ci			iagp->inosmap[i] = cpu_to_le32(ONES);
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci		/*
25818c2ecf20Sopenharmony_ci		 * Write and sync the metapage
25828c2ecf20Sopenharmony_ci		 */
25838c2ecf20Sopenharmony_ci		flush_metapage(mp);
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci		/*
25868c2ecf20Sopenharmony_ci		 * txCommit(COMMIT_FORCE) will synchronously write address
25878c2ecf20Sopenharmony_ci		 * index pages and inode after commit in careful update order
25888c2ecf20Sopenharmony_ci		 * of address index pages (right to left, bottom up);
25898c2ecf20Sopenharmony_ci		 */
25908c2ecf20Sopenharmony_ci		iplist[0] = ipimap;
25918c2ecf20Sopenharmony_ci		rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
25928c2ecf20Sopenharmony_ci
25938c2ecf20Sopenharmony_ci		txEnd(tid);
25948c2ecf20Sopenharmony_ci		mutex_unlock(&JFS_IP(ipimap)->commit_mutex);
25958c2ecf20Sopenharmony_ci
25968c2ecf20Sopenharmony_ci		duplicateIXtree(sb, blkno, xlen, &xaddr);
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci		/* update the next available iag number */
25998c2ecf20Sopenharmony_ci		imap->im_nextiag += 1;
26008c2ecf20Sopenharmony_ci
26018c2ecf20Sopenharmony_ci		/* Add the iag to the iag free list so we don't lose the iag
26028c2ecf20Sopenharmony_ci		 * if a failure happens now.
26038c2ecf20Sopenharmony_ci		 */
26048c2ecf20Sopenharmony_ci		imap->im_freeiag = iagno;
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci		/* Until we have logredo working, we want the imap inode &
26078c2ecf20Sopenharmony_ci		 * control page to be up to date.
26088c2ecf20Sopenharmony_ci		 */
26098c2ecf20Sopenharmony_ci		diSync(ipimap);
26108c2ecf20Sopenharmony_ci
26118c2ecf20Sopenharmony_ci		/* release the inode map lock */
26128c2ecf20Sopenharmony_ci		IWRITE_UNLOCK(ipimap);
26138c2ecf20Sopenharmony_ci	}
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_ci	/* obtain read lock on map */
26168c2ecf20Sopenharmony_ci	IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci	/* read the iag */
26198c2ecf20Sopenharmony_ci	if ((rc = diIAGRead(imap, iagno, &mp))) {
26208c2ecf20Sopenharmony_ci		IREAD_UNLOCK(ipimap);
26218c2ecf20Sopenharmony_ci		rc = -EIO;
26228c2ecf20Sopenharmony_ci		goto out;
26238c2ecf20Sopenharmony_ci	}
26248c2ecf20Sopenharmony_ci	iagp = (struct iag *) mp->data;
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_ci	/* remove the iag from the iag free list */
26278c2ecf20Sopenharmony_ci	imap->im_freeiag = le32_to_cpu(iagp->iagfree);
26288c2ecf20Sopenharmony_ci	iagp->iagfree = cpu_to_le32(-1);
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	/* set the return iag number and buffer pointer */
26318c2ecf20Sopenharmony_ci	*iagnop = iagno;
26328c2ecf20Sopenharmony_ci	*mpp = mp;
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ci      out:
26358c2ecf20Sopenharmony_ci	/* release the iag free lock */
26368c2ecf20Sopenharmony_ci	IAGFREE_UNLOCK(imap);
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci	return (rc);
26398c2ecf20Sopenharmony_ci}
26408c2ecf20Sopenharmony_ci
26418c2ecf20Sopenharmony_ci/*
26428c2ecf20Sopenharmony_ci * NAME:	diIAGRead()
26438c2ecf20Sopenharmony_ci *
26448c2ecf20Sopenharmony_ci * FUNCTION:	get the buffer for the specified iag within a fileset
26458c2ecf20Sopenharmony_ci *		or aggregate inode map.
26468c2ecf20Sopenharmony_ci *
26478c2ecf20Sopenharmony_ci * PARAMETERS:
26488c2ecf20Sopenharmony_ci *	imap	- pointer to inode map control structure.
26498c2ecf20Sopenharmony_ci *	iagno	- iag number.
26508c2ecf20Sopenharmony_ci *	bpp	- point to buffer pointer to be filled in on successful
26518c2ecf20Sopenharmony_ci *		  exit.
26528c2ecf20Sopenharmony_ci *
26538c2ecf20Sopenharmony_ci * SERIALIZATION:
26548c2ecf20Sopenharmony_ci *	must have read lock on imap inode
26558c2ecf20Sopenharmony_ci *	(When called by diExtendFS, the filesystem is quiesced, therefore
26568c2ecf20Sopenharmony_ci *	 the read lock is unnecessary.)
26578c2ecf20Sopenharmony_ci *
26588c2ecf20Sopenharmony_ci * RETURN VALUES:
26598c2ecf20Sopenharmony_ci *	0	- success.
26608c2ecf20Sopenharmony_ci *	-EIO	- i/o error.
26618c2ecf20Sopenharmony_ci */
26628c2ecf20Sopenharmony_cistatic int diIAGRead(struct inomap * imap, int iagno, struct metapage ** mpp)
26638c2ecf20Sopenharmony_ci{
26648c2ecf20Sopenharmony_ci	struct inode *ipimap = imap->im_ipimap;
26658c2ecf20Sopenharmony_ci	s64 blkno;
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci	/* compute the logical block number of the iag. */
26688c2ecf20Sopenharmony_ci	blkno = IAGTOLBLK(iagno, JFS_SBI(ipimap->i_sb)->l2nbperpage);
26698c2ecf20Sopenharmony_ci
26708c2ecf20Sopenharmony_ci	/* read the iag. */
26718c2ecf20Sopenharmony_ci	*mpp = read_metapage(ipimap, blkno, PSIZE, 0);
26728c2ecf20Sopenharmony_ci	if (*mpp == NULL) {
26738c2ecf20Sopenharmony_ci		return -EIO;
26748c2ecf20Sopenharmony_ci	}
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_ci	return (0);
26778c2ecf20Sopenharmony_ci}
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_ci/*
26808c2ecf20Sopenharmony_ci * NAME:	diFindFree()
26818c2ecf20Sopenharmony_ci *
26828c2ecf20Sopenharmony_ci * FUNCTION:	find the first free bit in a word starting at
26838c2ecf20Sopenharmony_ci *		the specified bit position.
26848c2ecf20Sopenharmony_ci *
26858c2ecf20Sopenharmony_ci * PARAMETERS:
26868c2ecf20Sopenharmony_ci *	word	- word to be examined.
26878c2ecf20Sopenharmony_ci *	start	- starting bit position.
26888c2ecf20Sopenharmony_ci *
26898c2ecf20Sopenharmony_ci * RETURN VALUES:
26908c2ecf20Sopenharmony_ci *	bit position of first free bit in the word or 32 if
26918c2ecf20Sopenharmony_ci *	no free bits were found.
26928c2ecf20Sopenharmony_ci */
26938c2ecf20Sopenharmony_cistatic int diFindFree(u32 word, int start)
26948c2ecf20Sopenharmony_ci{
26958c2ecf20Sopenharmony_ci	int bitno;
26968c2ecf20Sopenharmony_ci	assert(start < 32);
26978c2ecf20Sopenharmony_ci	/* scan the word for the first free bit. */
26988c2ecf20Sopenharmony_ci	for (word <<= start, bitno = start; bitno < 32;
26998c2ecf20Sopenharmony_ci	     bitno++, word <<= 1) {
27008c2ecf20Sopenharmony_ci		if ((word & HIGHORDER) == 0)
27018c2ecf20Sopenharmony_ci			break;
27028c2ecf20Sopenharmony_ci	}
27038c2ecf20Sopenharmony_ci	return (bitno);
27048c2ecf20Sopenharmony_ci}
27058c2ecf20Sopenharmony_ci
27068c2ecf20Sopenharmony_ci/*
27078c2ecf20Sopenharmony_ci * NAME:	diUpdatePMap()
27088c2ecf20Sopenharmony_ci *
27098c2ecf20Sopenharmony_ci * FUNCTION: Update the persistent map in an IAG for the allocation or
27108c2ecf20Sopenharmony_ci *	freeing of the specified inode.
27118c2ecf20Sopenharmony_ci *
27128c2ecf20Sopenharmony_ci * PRE CONDITIONS: Working map has already been updated for allocate.
27138c2ecf20Sopenharmony_ci *
27148c2ecf20Sopenharmony_ci * PARAMETERS:
27158c2ecf20Sopenharmony_ci *	ipimap	- Incore inode map inode
27168c2ecf20Sopenharmony_ci *	inum	- Number of inode to mark in permanent map
27178c2ecf20Sopenharmony_ci *	is_free	- If 'true' indicates inode should be marked freed, otherwise
27188c2ecf20Sopenharmony_ci *		  indicates inode should be marked allocated.
27198c2ecf20Sopenharmony_ci *
27208c2ecf20Sopenharmony_ci * RETURN VALUES:
27218c2ecf20Sopenharmony_ci *		0 for success
27228c2ecf20Sopenharmony_ci */
27238c2ecf20Sopenharmony_ciint
27248c2ecf20Sopenharmony_cidiUpdatePMap(struct inode *ipimap,
27258c2ecf20Sopenharmony_ci	     unsigned long inum, bool is_free, struct tblock * tblk)
27268c2ecf20Sopenharmony_ci{
27278c2ecf20Sopenharmony_ci	int rc;
27288c2ecf20Sopenharmony_ci	struct iag *iagp;
27298c2ecf20Sopenharmony_ci	struct metapage *mp;
27308c2ecf20Sopenharmony_ci	int iagno, ino, extno, bitno;
27318c2ecf20Sopenharmony_ci	struct inomap *imap;
27328c2ecf20Sopenharmony_ci	u32 mask;
27338c2ecf20Sopenharmony_ci	struct jfs_log *log;
27348c2ecf20Sopenharmony_ci	int lsn, difft, diffp;
27358c2ecf20Sopenharmony_ci	unsigned long flags;
27368c2ecf20Sopenharmony_ci
27378c2ecf20Sopenharmony_ci	imap = JFS_IP(ipimap)->i_imap;
27388c2ecf20Sopenharmony_ci	/* get the iag number containing the inode */
27398c2ecf20Sopenharmony_ci	iagno = INOTOIAG(inum);
27408c2ecf20Sopenharmony_ci	/* make sure that the iag is contained within the map */
27418c2ecf20Sopenharmony_ci	if (iagno >= imap->im_nextiag) {
27428c2ecf20Sopenharmony_ci		jfs_error(ipimap->i_sb, "the iag is outside the map\n");
27438c2ecf20Sopenharmony_ci		return -EIO;
27448c2ecf20Sopenharmony_ci	}
27458c2ecf20Sopenharmony_ci	/* read the iag */
27468c2ecf20Sopenharmony_ci	IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
27478c2ecf20Sopenharmony_ci	rc = diIAGRead(imap, iagno, &mp);
27488c2ecf20Sopenharmony_ci	IREAD_UNLOCK(ipimap);
27498c2ecf20Sopenharmony_ci	if (rc)
27508c2ecf20Sopenharmony_ci		return (rc);
27518c2ecf20Sopenharmony_ci	metapage_wait_for_io(mp);
27528c2ecf20Sopenharmony_ci	iagp = (struct iag *) mp->data;
27538c2ecf20Sopenharmony_ci	/* get the inode number and extent number of the inode within
27548c2ecf20Sopenharmony_ci	 * the iag and the inode number within the extent.
27558c2ecf20Sopenharmony_ci	 */
27568c2ecf20Sopenharmony_ci	ino = inum & (INOSPERIAG - 1);
27578c2ecf20Sopenharmony_ci	extno = ino >> L2INOSPEREXT;
27588c2ecf20Sopenharmony_ci	bitno = ino & (INOSPEREXT - 1);
27598c2ecf20Sopenharmony_ci	mask = HIGHORDER >> bitno;
27608c2ecf20Sopenharmony_ci	/*
27618c2ecf20Sopenharmony_ci	 * mark the inode free in persistent map:
27628c2ecf20Sopenharmony_ci	 */
27638c2ecf20Sopenharmony_ci	if (is_free) {
27648c2ecf20Sopenharmony_ci		/* The inode should have been allocated both in working
27658c2ecf20Sopenharmony_ci		 * map and in persistent map;
27668c2ecf20Sopenharmony_ci		 * the inode will be freed from working map at the release
27678c2ecf20Sopenharmony_ci		 * of last reference release;
27688c2ecf20Sopenharmony_ci		 */
27698c2ecf20Sopenharmony_ci		if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
27708c2ecf20Sopenharmony_ci			jfs_error(ipimap->i_sb,
27718c2ecf20Sopenharmony_ci				  "inode %ld not marked as allocated in wmap!\n",
27728c2ecf20Sopenharmony_ci				  inum);
27738c2ecf20Sopenharmony_ci		}
27748c2ecf20Sopenharmony_ci		if (!(le32_to_cpu(iagp->pmap[extno]) & mask)) {
27758c2ecf20Sopenharmony_ci			jfs_error(ipimap->i_sb,
27768c2ecf20Sopenharmony_ci				  "inode %ld not marked as allocated in pmap!\n",
27778c2ecf20Sopenharmony_ci				  inum);
27788c2ecf20Sopenharmony_ci		}
27798c2ecf20Sopenharmony_ci		/* update the bitmap for the extent of the freed inode */
27808c2ecf20Sopenharmony_ci		iagp->pmap[extno] &= cpu_to_le32(~mask);
27818c2ecf20Sopenharmony_ci	}
27828c2ecf20Sopenharmony_ci	/*
27838c2ecf20Sopenharmony_ci	 * mark the inode allocated in persistent map:
27848c2ecf20Sopenharmony_ci	 */
27858c2ecf20Sopenharmony_ci	else {
27868c2ecf20Sopenharmony_ci		/* The inode should be already allocated in the working map
27878c2ecf20Sopenharmony_ci		 * and should be free in persistent map;
27888c2ecf20Sopenharmony_ci		 */
27898c2ecf20Sopenharmony_ci		if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
27908c2ecf20Sopenharmony_ci			release_metapage(mp);
27918c2ecf20Sopenharmony_ci			jfs_error(ipimap->i_sb,
27928c2ecf20Sopenharmony_ci				  "the inode is not allocated in the working map\n");
27938c2ecf20Sopenharmony_ci			return -EIO;
27948c2ecf20Sopenharmony_ci		}
27958c2ecf20Sopenharmony_ci		if ((le32_to_cpu(iagp->pmap[extno]) & mask) != 0) {
27968c2ecf20Sopenharmony_ci			release_metapage(mp);
27978c2ecf20Sopenharmony_ci			jfs_error(ipimap->i_sb,
27988c2ecf20Sopenharmony_ci				  "the inode is not free in the persistent map\n");
27998c2ecf20Sopenharmony_ci			return -EIO;
28008c2ecf20Sopenharmony_ci		}
28018c2ecf20Sopenharmony_ci		/* update the bitmap for the extent of the allocated inode */
28028c2ecf20Sopenharmony_ci		iagp->pmap[extno] |= cpu_to_le32(mask);
28038c2ecf20Sopenharmony_ci	}
28048c2ecf20Sopenharmony_ci	/*
28058c2ecf20Sopenharmony_ci	 * update iag lsn
28068c2ecf20Sopenharmony_ci	 */
28078c2ecf20Sopenharmony_ci	lsn = tblk->lsn;
28088c2ecf20Sopenharmony_ci	log = JFS_SBI(tblk->sb)->log;
28098c2ecf20Sopenharmony_ci	LOGSYNC_LOCK(log, flags);
28108c2ecf20Sopenharmony_ci	if (mp->lsn != 0) {
28118c2ecf20Sopenharmony_ci		/* inherit older/smaller lsn */
28128c2ecf20Sopenharmony_ci		logdiff(difft, lsn, log);
28138c2ecf20Sopenharmony_ci		logdiff(diffp, mp->lsn, log);
28148c2ecf20Sopenharmony_ci		if (difft < diffp) {
28158c2ecf20Sopenharmony_ci			mp->lsn = lsn;
28168c2ecf20Sopenharmony_ci			/* move mp after tblock in logsync list */
28178c2ecf20Sopenharmony_ci			list_move(&mp->synclist, &tblk->synclist);
28188c2ecf20Sopenharmony_ci		}
28198c2ecf20Sopenharmony_ci		/* inherit younger/larger clsn */
28208c2ecf20Sopenharmony_ci		assert(mp->clsn);
28218c2ecf20Sopenharmony_ci		logdiff(difft, tblk->clsn, log);
28228c2ecf20Sopenharmony_ci		logdiff(diffp, mp->clsn, log);
28238c2ecf20Sopenharmony_ci		if (difft > diffp)
28248c2ecf20Sopenharmony_ci			mp->clsn = tblk->clsn;
28258c2ecf20Sopenharmony_ci	} else {
28268c2ecf20Sopenharmony_ci		mp->log = log;
28278c2ecf20Sopenharmony_ci		mp->lsn = lsn;
28288c2ecf20Sopenharmony_ci		/* insert mp after tblock in logsync list */
28298c2ecf20Sopenharmony_ci		log->count++;
28308c2ecf20Sopenharmony_ci		list_add(&mp->synclist, &tblk->synclist);
28318c2ecf20Sopenharmony_ci		mp->clsn = tblk->clsn;
28328c2ecf20Sopenharmony_ci	}
28338c2ecf20Sopenharmony_ci	LOGSYNC_UNLOCK(log, flags);
28348c2ecf20Sopenharmony_ci	write_metapage(mp);
28358c2ecf20Sopenharmony_ci	return (0);
28368c2ecf20Sopenharmony_ci}
28378c2ecf20Sopenharmony_ci
28388c2ecf20Sopenharmony_ci/*
28398c2ecf20Sopenharmony_ci *	diExtendFS()
28408c2ecf20Sopenharmony_ci *
28418c2ecf20Sopenharmony_ci * function: update imap for extendfs();
28428c2ecf20Sopenharmony_ci *
28438c2ecf20Sopenharmony_ci * note: AG size has been increased s.t. each k old contiguous AGs are
28448c2ecf20Sopenharmony_ci * coalesced into a new AG;
28458c2ecf20Sopenharmony_ci */
28468c2ecf20Sopenharmony_ciint diExtendFS(struct inode *ipimap, struct inode *ipbmap)
28478c2ecf20Sopenharmony_ci{
28488c2ecf20Sopenharmony_ci	int rc, rcx = 0;
28498c2ecf20Sopenharmony_ci	struct inomap *imap = JFS_IP(ipimap)->i_imap;
28508c2ecf20Sopenharmony_ci	struct iag *iagp = NULL, *hiagp = NULL;
28518c2ecf20Sopenharmony_ci	struct bmap *mp = JFS_SBI(ipbmap->i_sb)->bmap;
28528c2ecf20Sopenharmony_ci	struct metapage *bp, *hbp;
28538c2ecf20Sopenharmony_ci	int i, n, head;
28548c2ecf20Sopenharmony_ci	int numinos, xnuminos = 0, xnumfree = 0;
28558c2ecf20Sopenharmony_ci	s64 agstart;
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ci	jfs_info("diExtendFS: nextiag:%d numinos:%d numfree:%d",
28588c2ecf20Sopenharmony_ci		   imap->im_nextiag, atomic_read(&imap->im_numinos),
28598c2ecf20Sopenharmony_ci		   atomic_read(&imap->im_numfree));
28608c2ecf20Sopenharmony_ci
28618c2ecf20Sopenharmony_ci	/*
28628c2ecf20Sopenharmony_ci	 *	reconstruct imap
28638c2ecf20Sopenharmony_ci	 *
28648c2ecf20Sopenharmony_ci	 * coalesce contiguous k (newAGSize/oldAGSize) AGs;
28658c2ecf20Sopenharmony_ci	 * i.e., (AGi, ..., AGj) where i = k*n and j = k*(n+1) - 1 to AGn;
28668c2ecf20Sopenharmony_ci	 * note: new AG size = old AG size * (2**x).
28678c2ecf20Sopenharmony_ci	 */
28688c2ecf20Sopenharmony_ci
28698c2ecf20Sopenharmony_ci	/* init per AG control information im_agctl[] */
28708c2ecf20Sopenharmony_ci	for (i = 0; i < MAXAG; i++) {
28718c2ecf20Sopenharmony_ci		imap->im_agctl[i].inofree = -1;
28728c2ecf20Sopenharmony_ci		imap->im_agctl[i].extfree = -1;
28738c2ecf20Sopenharmony_ci		imap->im_agctl[i].numinos = 0;	/* number of backed inodes */
28748c2ecf20Sopenharmony_ci		imap->im_agctl[i].numfree = 0;	/* number of free backed inodes */
28758c2ecf20Sopenharmony_ci	}
28768c2ecf20Sopenharmony_ci
28778c2ecf20Sopenharmony_ci	/*
28788c2ecf20Sopenharmony_ci	 *	process each iag page of the map.
28798c2ecf20Sopenharmony_ci	 *
28808c2ecf20Sopenharmony_ci	 * rebuild AG Free Inode List, AG Free Inode Extent List;
28818c2ecf20Sopenharmony_ci	 */
28828c2ecf20Sopenharmony_ci	for (i = 0; i < imap->im_nextiag; i++) {
28838c2ecf20Sopenharmony_ci		if ((rc = diIAGRead(imap, i, &bp))) {
28848c2ecf20Sopenharmony_ci			rcx = rc;
28858c2ecf20Sopenharmony_ci			continue;
28868c2ecf20Sopenharmony_ci		}
28878c2ecf20Sopenharmony_ci		iagp = (struct iag *) bp->data;
28888c2ecf20Sopenharmony_ci		if (le32_to_cpu(iagp->iagnum) != i) {
28898c2ecf20Sopenharmony_ci			release_metapage(bp);
28908c2ecf20Sopenharmony_ci			jfs_error(ipimap->i_sb, "unexpected value of iagnum\n");
28918c2ecf20Sopenharmony_ci			return -EIO;
28928c2ecf20Sopenharmony_ci		}
28938c2ecf20Sopenharmony_ci
28948c2ecf20Sopenharmony_ci		/* leave free iag in the free iag list */
28958c2ecf20Sopenharmony_ci		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
28968c2ecf20Sopenharmony_ci			release_metapage(bp);
28978c2ecf20Sopenharmony_ci			continue;
28988c2ecf20Sopenharmony_ci		}
28998c2ecf20Sopenharmony_ci
29008c2ecf20Sopenharmony_ci		agstart = le64_to_cpu(iagp->agstart);
29018c2ecf20Sopenharmony_ci		n = agstart >> mp->db_agl2size;
29028c2ecf20Sopenharmony_ci		iagp->agstart = cpu_to_le64((s64)n << mp->db_agl2size);
29038c2ecf20Sopenharmony_ci
29048c2ecf20Sopenharmony_ci		/* compute backed inodes */
29058c2ecf20Sopenharmony_ci		numinos = (EXTSPERIAG - le32_to_cpu(iagp->nfreeexts))
29068c2ecf20Sopenharmony_ci		    << L2INOSPEREXT;
29078c2ecf20Sopenharmony_ci		if (numinos > 0) {
29088c2ecf20Sopenharmony_ci			/* merge AG backed inodes */
29098c2ecf20Sopenharmony_ci			imap->im_agctl[n].numinos += numinos;
29108c2ecf20Sopenharmony_ci			xnuminos += numinos;
29118c2ecf20Sopenharmony_ci		}
29128c2ecf20Sopenharmony_ci
29138c2ecf20Sopenharmony_ci		/* if any backed free inodes, insert at AG free inode list */
29148c2ecf20Sopenharmony_ci		if ((int) le32_to_cpu(iagp->nfreeinos) > 0) {
29158c2ecf20Sopenharmony_ci			if ((head = imap->im_agctl[n].inofree) == -1) {
29168c2ecf20Sopenharmony_ci				iagp->inofreefwd = cpu_to_le32(-1);
29178c2ecf20Sopenharmony_ci				iagp->inofreeback = cpu_to_le32(-1);
29188c2ecf20Sopenharmony_ci			} else {
29198c2ecf20Sopenharmony_ci				if ((rc = diIAGRead(imap, head, &hbp))) {
29208c2ecf20Sopenharmony_ci					rcx = rc;
29218c2ecf20Sopenharmony_ci					goto nextiag;
29228c2ecf20Sopenharmony_ci				}
29238c2ecf20Sopenharmony_ci				hiagp = (struct iag *) hbp->data;
29248c2ecf20Sopenharmony_ci				hiagp->inofreeback = iagp->iagnum;
29258c2ecf20Sopenharmony_ci				iagp->inofreefwd = cpu_to_le32(head);
29268c2ecf20Sopenharmony_ci				iagp->inofreeback = cpu_to_le32(-1);
29278c2ecf20Sopenharmony_ci				write_metapage(hbp);
29288c2ecf20Sopenharmony_ci			}
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_ci			imap->im_agctl[n].inofree =
29318c2ecf20Sopenharmony_ci			    le32_to_cpu(iagp->iagnum);
29328c2ecf20Sopenharmony_ci
29338c2ecf20Sopenharmony_ci			/* merge AG backed free inodes */
29348c2ecf20Sopenharmony_ci			imap->im_agctl[n].numfree +=
29358c2ecf20Sopenharmony_ci			    le32_to_cpu(iagp->nfreeinos);
29368c2ecf20Sopenharmony_ci			xnumfree += le32_to_cpu(iagp->nfreeinos);
29378c2ecf20Sopenharmony_ci		}
29388c2ecf20Sopenharmony_ci
29398c2ecf20Sopenharmony_ci		/* if any free extents, insert at AG free extent list */
29408c2ecf20Sopenharmony_ci		if (le32_to_cpu(iagp->nfreeexts) > 0) {
29418c2ecf20Sopenharmony_ci			if ((head = imap->im_agctl[n].extfree) == -1) {
29428c2ecf20Sopenharmony_ci				iagp->extfreefwd = cpu_to_le32(-1);
29438c2ecf20Sopenharmony_ci				iagp->extfreeback = cpu_to_le32(-1);
29448c2ecf20Sopenharmony_ci			} else {
29458c2ecf20Sopenharmony_ci				if ((rc = diIAGRead(imap, head, &hbp))) {
29468c2ecf20Sopenharmony_ci					rcx = rc;
29478c2ecf20Sopenharmony_ci					goto nextiag;
29488c2ecf20Sopenharmony_ci				}
29498c2ecf20Sopenharmony_ci				hiagp = (struct iag *) hbp->data;
29508c2ecf20Sopenharmony_ci				hiagp->extfreeback = iagp->iagnum;
29518c2ecf20Sopenharmony_ci				iagp->extfreefwd = cpu_to_le32(head);
29528c2ecf20Sopenharmony_ci				iagp->extfreeback = cpu_to_le32(-1);
29538c2ecf20Sopenharmony_ci				write_metapage(hbp);
29548c2ecf20Sopenharmony_ci			}
29558c2ecf20Sopenharmony_ci
29568c2ecf20Sopenharmony_ci			imap->im_agctl[n].extfree =
29578c2ecf20Sopenharmony_ci			    le32_to_cpu(iagp->iagnum);
29588c2ecf20Sopenharmony_ci		}
29598c2ecf20Sopenharmony_ci
29608c2ecf20Sopenharmony_ci	      nextiag:
29618c2ecf20Sopenharmony_ci		write_metapage(bp);
29628c2ecf20Sopenharmony_ci	}
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci	if (xnuminos != atomic_read(&imap->im_numinos) ||
29658c2ecf20Sopenharmony_ci	    xnumfree != atomic_read(&imap->im_numfree)) {
29668c2ecf20Sopenharmony_ci		jfs_error(ipimap->i_sb, "numinos or numfree incorrect\n");
29678c2ecf20Sopenharmony_ci		return -EIO;
29688c2ecf20Sopenharmony_ci	}
29698c2ecf20Sopenharmony_ci
29708c2ecf20Sopenharmony_ci	return rcx;
29718c2ecf20Sopenharmony_ci}
29728c2ecf20Sopenharmony_ci
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_ci/*
29758c2ecf20Sopenharmony_ci *	duplicateIXtree()
29768c2ecf20Sopenharmony_ci *
29778c2ecf20Sopenharmony_ci * serialization: IWRITE_LOCK held on entry/exit
29788c2ecf20Sopenharmony_ci *
29798c2ecf20Sopenharmony_ci * note: shadow page with regular inode (rel.2);
29808c2ecf20Sopenharmony_ci */
29818c2ecf20Sopenharmony_cistatic void duplicateIXtree(struct super_block *sb, s64 blkno,
29828c2ecf20Sopenharmony_ci			    int xlen, s64 *xaddr)
29838c2ecf20Sopenharmony_ci{
29848c2ecf20Sopenharmony_ci	struct jfs_superblock *j_sb;
29858c2ecf20Sopenharmony_ci	struct buffer_head *bh;
29868c2ecf20Sopenharmony_ci	struct inode *ip;
29878c2ecf20Sopenharmony_ci	tid_t tid;
29888c2ecf20Sopenharmony_ci
29898c2ecf20Sopenharmony_ci	/* if AIT2 ipmap2 is bad, do not try to update it */
29908c2ecf20Sopenharmony_ci	if (JFS_SBI(sb)->mntflag & JFS_BAD_SAIT)	/* s_flag */
29918c2ecf20Sopenharmony_ci		return;
29928c2ecf20Sopenharmony_ci	ip = diReadSpecial(sb, FILESYSTEM_I, 1);
29938c2ecf20Sopenharmony_ci	if (ip == NULL) {
29948c2ecf20Sopenharmony_ci		JFS_SBI(sb)->mntflag |= JFS_BAD_SAIT;
29958c2ecf20Sopenharmony_ci		if (readSuper(sb, &bh))
29968c2ecf20Sopenharmony_ci			return;
29978c2ecf20Sopenharmony_ci		j_sb = (struct jfs_superblock *)bh->b_data;
29988c2ecf20Sopenharmony_ci		j_sb->s_flag |= cpu_to_le32(JFS_BAD_SAIT);
29998c2ecf20Sopenharmony_ci
30008c2ecf20Sopenharmony_ci		mark_buffer_dirty(bh);
30018c2ecf20Sopenharmony_ci		sync_dirty_buffer(bh);
30028c2ecf20Sopenharmony_ci		brelse(bh);
30038c2ecf20Sopenharmony_ci		return;
30048c2ecf20Sopenharmony_ci	}
30058c2ecf20Sopenharmony_ci
30068c2ecf20Sopenharmony_ci	/* start transaction */
30078c2ecf20Sopenharmony_ci	tid = txBegin(sb, COMMIT_FORCE);
30088c2ecf20Sopenharmony_ci	/* update the inode map addressing structure to point to it */
30098c2ecf20Sopenharmony_ci	if (xtInsert(tid, ip, 0, blkno, xlen, xaddr, 0)) {
30108c2ecf20Sopenharmony_ci		JFS_SBI(sb)->mntflag |= JFS_BAD_SAIT;
30118c2ecf20Sopenharmony_ci		txAbort(tid, 1);
30128c2ecf20Sopenharmony_ci		goto cleanup;
30138c2ecf20Sopenharmony_ci
30148c2ecf20Sopenharmony_ci	}
30158c2ecf20Sopenharmony_ci	/* update the inode map's inode to reflect the extension */
30168c2ecf20Sopenharmony_ci	ip->i_size += PSIZE;
30178c2ecf20Sopenharmony_ci	inode_add_bytes(ip, PSIZE);
30188c2ecf20Sopenharmony_ci	txCommit(tid, 1, &ip, COMMIT_FORCE);
30198c2ecf20Sopenharmony_ci      cleanup:
30208c2ecf20Sopenharmony_ci	txEnd(tid);
30218c2ecf20Sopenharmony_ci	diFreeSpecial(ip);
30228c2ecf20Sopenharmony_ci}
30238c2ecf20Sopenharmony_ci
30248c2ecf20Sopenharmony_ci/*
30258c2ecf20Sopenharmony_ci * NAME:	copy_from_dinode()
30268c2ecf20Sopenharmony_ci *
30278c2ecf20Sopenharmony_ci * FUNCTION:	Copies inode info from disk inode to in-memory inode
30288c2ecf20Sopenharmony_ci *
30298c2ecf20Sopenharmony_ci * RETURN VALUES:
30308c2ecf20Sopenharmony_ci *	0	- success
30318c2ecf20Sopenharmony_ci *	-ENOMEM	- insufficient memory
30328c2ecf20Sopenharmony_ci */
30338c2ecf20Sopenharmony_cistatic int copy_from_dinode(struct dinode * dip, struct inode *ip)
30348c2ecf20Sopenharmony_ci{
30358c2ecf20Sopenharmony_ci	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
30368c2ecf20Sopenharmony_ci	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
30378c2ecf20Sopenharmony_ci
30388c2ecf20Sopenharmony_ci	jfs_ip->fileset = le32_to_cpu(dip->di_fileset);
30398c2ecf20Sopenharmony_ci	jfs_ip->mode2 = le32_to_cpu(dip->di_mode);
30408c2ecf20Sopenharmony_ci	jfs_set_inode_flags(ip);
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci	ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff;
30438c2ecf20Sopenharmony_ci	if (sbi->umask != -1) {
30448c2ecf20Sopenharmony_ci		ip->i_mode = (ip->i_mode & ~0777) | (0777 & ~sbi->umask);
30458c2ecf20Sopenharmony_ci		/* For directories, add x permission if r is allowed by umask */
30468c2ecf20Sopenharmony_ci		if (S_ISDIR(ip->i_mode)) {
30478c2ecf20Sopenharmony_ci			if (ip->i_mode & 0400)
30488c2ecf20Sopenharmony_ci				ip->i_mode |= 0100;
30498c2ecf20Sopenharmony_ci			if (ip->i_mode & 0040)
30508c2ecf20Sopenharmony_ci				ip->i_mode |= 0010;
30518c2ecf20Sopenharmony_ci			if (ip->i_mode & 0004)
30528c2ecf20Sopenharmony_ci				ip->i_mode |= 0001;
30538c2ecf20Sopenharmony_ci		}
30548c2ecf20Sopenharmony_ci	}
30558c2ecf20Sopenharmony_ci	set_nlink(ip, le32_to_cpu(dip->di_nlink));
30568c2ecf20Sopenharmony_ci
30578c2ecf20Sopenharmony_ci	jfs_ip->saved_uid = make_kuid(&init_user_ns, le32_to_cpu(dip->di_uid));
30588c2ecf20Sopenharmony_ci	if (!uid_valid(sbi->uid))
30598c2ecf20Sopenharmony_ci		ip->i_uid = jfs_ip->saved_uid;
30608c2ecf20Sopenharmony_ci	else {
30618c2ecf20Sopenharmony_ci		ip->i_uid = sbi->uid;
30628c2ecf20Sopenharmony_ci	}
30638c2ecf20Sopenharmony_ci
30648c2ecf20Sopenharmony_ci	jfs_ip->saved_gid = make_kgid(&init_user_ns, le32_to_cpu(dip->di_gid));
30658c2ecf20Sopenharmony_ci	if (!gid_valid(sbi->gid))
30668c2ecf20Sopenharmony_ci		ip->i_gid = jfs_ip->saved_gid;
30678c2ecf20Sopenharmony_ci	else {
30688c2ecf20Sopenharmony_ci		ip->i_gid = sbi->gid;
30698c2ecf20Sopenharmony_ci	}
30708c2ecf20Sopenharmony_ci
30718c2ecf20Sopenharmony_ci	ip->i_size = le64_to_cpu(dip->di_size);
30728c2ecf20Sopenharmony_ci	ip->i_atime.tv_sec = le32_to_cpu(dip->di_atime.tv_sec);
30738c2ecf20Sopenharmony_ci	ip->i_atime.tv_nsec = le32_to_cpu(dip->di_atime.tv_nsec);
30748c2ecf20Sopenharmony_ci	ip->i_mtime.tv_sec = le32_to_cpu(dip->di_mtime.tv_sec);
30758c2ecf20Sopenharmony_ci	ip->i_mtime.tv_nsec = le32_to_cpu(dip->di_mtime.tv_nsec);
30768c2ecf20Sopenharmony_ci	ip->i_ctime.tv_sec = le32_to_cpu(dip->di_ctime.tv_sec);
30778c2ecf20Sopenharmony_ci	ip->i_ctime.tv_nsec = le32_to_cpu(dip->di_ctime.tv_nsec);
30788c2ecf20Sopenharmony_ci	ip->i_blocks = LBLK2PBLK(ip->i_sb, le64_to_cpu(dip->di_nblocks));
30798c2ecf20Sopenharmony_ci	ip->i_generation = le32_to_cpu(dip->di_gen);
30808c2ecf20Sopenharmony_ci
30818c2ecf20Sopenharmony_ci	jfs_ip->ixpxd = dip->di_ixpxd;	/* in-memory pxd's are little-endian */
30828c2ecf20Sopenharmony_ci	jfs_ip->acl = dip->di_acl;	/* as are dxd's */
30838c2ecf20Sopenharmony_ci	jfs_ip->ea = dip->di_ea;
30848c2ecf20Sopenharmony_ci	jfs_ip->next_index = le32_to_cpu(dip->di_next_index);
30858c2ecf20Sopenharmony_ci	jfs_ip->otime = le32_to_cpu(dip->di_otime.tv_sec);
30868c2ecf20Sopenharmony_ci	jfs_ip->acltype = le32_to_cpu(dip->di_acltype);
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_ci	if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode)) {
30898c2ecf20Sopenharmony_ci		jfs_ip->dev = le32_to_cpu(dip->di_rdev);
30908c2ecf20Sopenharmony_ci		ip->i_rdev = new_decode_dev(jfs_ip->dev);
30918c2ecf20Sopenharmony_ci	}
30928c2ecf20Sopenharmony_ci
30938c2ecf20Sopenharmony_ci	if (S_ISDIR(ip->i_mode)) {
30948c2ecf20Sopenharmony_ci		memcpy(&jfs_ip->i_dirtable, &dip->di_dirtable, 384);
30958c2ecf20Sopenharmony_ci	} else if (S_ISREG(ip->i_mode) || S_ISLNK(ip->i_mode)) {
30968c2ecf20Sopenharmony_ci		memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288);
30978c2ecf20Sopenharmony_ci	} else
30988c2ecf20Sopenharmony_ci		memcpy(&jfs_ip->i_inline_ea, &dip->di_inlineea, 128);
30998c2ecf20Sopenharmony_ci
31008c2ecf20Sopenharmony_ci	/* Zero the in-memory-only stuff */
31018c2ecf20Sopenharmony_ci	jfs_ip->cflag = 0;
31028c2ecf20Sopenharmony_ci	jfs_ip->btindex = 0;
31038c2ecf20Sopenharmony_ci	jfs_ip->btorder = 0;
31048c2ecf20Sopenharmony_ci	jfs_ip->bxflag = 0;
31058c2ecf20Sopenharmony_ci	jfs_ip->blid = 0;
31068c2ecf20Sopenharmony_ci	jfs_ip->atlhead = 0;
31078c2ecf20Sopenharmony_ci	jfs_ip->atltail = 0;
31088c2ecf20Sopenharmony_ci	jfs_ip->xtlid = 0;
31098c2ecf20Sopenharmony_ci	return (0);
31108c2ecf20Sopenharmony_ci}
31118c2ecf20Sopenharmony_ci
31128c2ecf20Sopenharmony_ci/*
31138c2ecf20Sopenharmony_ci * NAME:	copy_to_dinode()
31148c2ecf20Sopenharmony_ci *
31158c2ecf20Sopenharmony_ci * FUNCTION:	Copies inode info from in-memory inode to disk inode
31168c2ecf20Sopenharmony_ci */
31178c2ecf20Sopenharmony_cistatic void copy_to_dinode(struct dinode * dip, struct inode *ip)
31188c2ecf20Sopenharmony_ci{
31198c2ecf20Sopenharmony_ci	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
31208c2ecf20Sopenharmony_ci	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
31218c2ecf20Sopenharmony_ci
31228c2ecf20Sopenharmony_ci	dip->di_fileset = cpu_to_le32(jfs_ip->fileset);
31238c2ecf20Sopenharmony_ci	dip->di_inostamp = cpu_to_le32(sbi->inostamp);
31248c2ecf20Sopenharmony_ci	dip->di_number = cpu_to_le32(ip->i_ino);
31258c2ecf20Sopenharmony_ci	dip->di_gen = cpu_to_le32(ip->i_generation);
31268c2ecf20Sopenharmony_ci	dip->di_size = cpu_to_le64(ip->i_size);
31278c2ecf20Sopenharmony_ci	dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks));
31288c2ecf20Sopenharmony_ci	dip->di_nlink = cpu_to_le32(ip->i_nlink);
31298c2ecf20Sopenharmony_ci	if (!uid_valid(sbi->uid))
31308c2ecf20Sopenharmony_ci		dip->di_uid = cpu_to_le32(i_uid_read(ip));
31318c2ecf20Sopenharmony_ci	else
31328c2ecf20Sopenharmony_ci		dip->di_uid =cpu_to_le32(from_kuid(&init_user_ns,
31338c2ecf20Sopenharmony_ci						   jfs_ip->saved_uid));
31348c2ecf20Sopenharmony_ci	if (!gid_valid(sbi->gid))
31358c2ecf20Sopenharmony_ci		dip->di_gid = cpu_to_le32(i_gid_read(ip));
31368c2ecf20Sopenharmony_ci	else
31378c2ecf20Sopenharmony_ci		dip->di_gid = cpu_to_le32(from_kgid(&init_user_ns,
31388c2ecf20Sopenharmony_ci						    jfs_ip->saved_gid));
31398c2ecf20Sopenharmony_ci	/*
31408c2ecf20Sopenharmony_ci	 * mode2 is only needed for storing the higher order bits.
31418c2ecf20Sopenharmony_ci	 * Trust i_mode for the lower order ones
31428c2ecf20Sopenharmony_ci	 */
31438c2ecf20Sopenharmony_ci	if (sbi->umask == -1)
31448c2ecf20Sopenharmony_ci		dip->di_mode = cpu_to_le32((jfs_ip->mode2 & 0xffff0000) |
31458c2ecf20Sopenharmony_ci					   ip->i_mode);
31468c2ecf20Sopenharmony_ci	else /* Leave the original permissions alone */
31478c2ecf20Sopenharmony_ci		dip->di_mode = cpu_to_le32(jfs_ip->mode2);
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_ci	dip->di_atime.tv_sec = cpu_to_le32(ip->i_atime.tv_sec);
31508c2ecf20Sopenharmony_ci	dip->di_atime.tv_nsec = cpu_to_le32(ip->i_atime.tv_nsec);
31518c2ecf20Sopenharmony_ci	dip->di_ctime.tv_sec = cpu_to_le32(ip->i_ctime.tv_sec);
31528c2ecf20Sopenharmony_ci	dip->di_ctime.tv_nsec = cpu_to_le32(ip->i_ctime.tv_nsec);
31538c2ecf20Sopenharmony_ci	dip->di_mtime.tv_sec = cpu_to_le32(ip->i_mtime.tv_sec);
31548c2ecf20Sopenharmony_ci	dip->di_mtime.tv_nsec = cpu_to_le32(ip->i_mtime.tv_nsec);
31558c2ecf20Sopenharmony_ci	dip->di_ixpxd = jfs_ip->ixpxd;	/* in-memory pxd's are little-endian */
31568c2ecf20Sopenharmony_ci	dip->di_acl = jfs_ip->acl;	/* as are dxd's */
31578c2ecf20Sopenharmony_ci	dip->di_ea = jfs_ip->ea;
31588c2ecf20Sopenharmony_ci	dip->di_next_index = cpu_to_le32(jfs_ip->next_index);
31598c2ecf20Sopenharmony_ci	dip->di_otime.tv_sec = cpu_to_le32(jfs_ip->otime);
31608c2ecf20Sopenharmony_ci	dip->di_otime.tv_nsec = 0;
31618c2ecf20Sopenharmony_ci	dip->di_acltype = cpu_to_le32(jfs_ip->acltype);
31628c2ecf20Sopenharmony_ci	if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode))
31638c2ecf20Sopenharmony_ci		dip->di_rdev = cpu_to_le32(jfs_ip->dev);
31648c2ecf20Sopenharmony_ci}
3165