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, &))) { 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, &))) 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, &))) 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 &))) 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, &))) 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, &))) 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