⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xfs_ialloc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Allocate an inode on disk. * Mode is used to tell whether the new inode will need space, and whether * it is a directory. * * The arguments IO_agbp and alloc_done are defined to work within * the constraint of one allocation per transaction. * xfs_dialloc() is designed to be called twice if it has to do an * allocation to make more free inodes.  On the first call, * IO_agbp should be set to NULL. If an inode is available, * i.e., xfs_dialloc() did not need to do an allocation, an inode * number is returned.  In this case, IO_agbp would be set to the * current ag_buf and alloc_done set to false. * If an allocation needed to be done, xfs_dialloc would return * the current ag_buf in IO_agbp and set alloc_done to true. * The caller should then commit the current transaction, allocate a new * transaction, and call xfs_dialloc() again, passing in the previous * value of IO_agbp.  IO_agbp should be held across the transactions. * Since the agbp is locked across the two calls, the second call is * guaranteed to have a free inode available. * * Once we successfully pick an inode its number is returned and the * on-disk data structures are updated.  The inode itself is not read * in, since doing so would break ordering constraints with xfs_reclaim. */intxfs_dialloc(	xfs_trans_t	*tp,		/* transaction pointer */	xfs_ino_t	parent,		/* parent inode (directory) */	mode_t		mode,		/* mode bits for new inode */	int		okalloc,	/* ok to allocate more space */	xfs_buf_t	**IO_agbp,	/* in/out ag header's buffer */	boolean_t	*alloc_done,	/* true if we needed to replenish					   inode freelist */	xfs_ino_t	*inop)		/* inode number allocated */{	xfs_agnumber_t	agcount;	/* number of allocation groups */	xfs_buf_t	*agbp;		/* allocation group header's buffer */	xfs_agnumber_t	agno;		/* allocation group number */	xfs_agi_t	*agi;		/* allocation group header structure */	xfs_btree_cur_t	*cur;		/* inode allocation btree cursor */	int		error;		/* error return value */	int		i;		/* result code */	int		ialloced;	/* inode allocation status */	int		noroom = 0;	/* no space for inode blk allocation */	xfs_ino_t	ino;		/* fs-relative inode to be returned */	/* REFERENCED */	int		j;		/* result code */	xfs_mount_t	*mp;		/* file system mount structure */	int		offset;		/* index of inode in chunk */	xfs_agino_t	pagino;		/* parent's a.g. relative inode # */	xfs_agnumber_t	pagno;		/* parent's allocation group number */	xfs_inobt_rec_incore_t rec;	/* inode allocation record */	xfs_agnumber_t	tagno;		/* testing allocation group number */	xfs_btree_cur_t	*tcur;		/* temp cursor */	xfs_inobt_rec_incore_t trec;	/* temp inode allocation record */	if (*IO_agbp == NULL) {		/*		 * We do not have an agbp, so select an initial allocation		 * group for inode allocation.		 */		agbp = xfs_ialloc_ag_select(tp, parent, mode, okalloc);		/*		 * Couldn't find an allocation group satisfying the		 * criteria, give up.		 */		if (!agbp) {			*inop = NULLFSINO;			return 0;		}		agi = XFS_BUF_TO_AGI(agbp);		ASSERT(be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC);	} else {		/*		 * Continue where we left off before.  In this case, we		 * know that the allocation group has free inodes.		 */		agbp = *IO_agbp;		agi = XFS_BUF_TO_AGI(agbp);		ASSERT(be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC);		ASSERT(be32_to_cpu(agi->agi_freecount) > 0);	}	mp = tp->t_mountp;	agcount = mp->m_sb.sb_agcount;	agno = be32_to_cpu(agi->agi_seqno);	tagno = agno;	pagno = XFS_INO_TO_AGNO(mp, parent);	pagino = XFS_INO_TO_AGINO(mp, parent);	/*	 * If we have already hit the ceiling of inode blocks then clear	 * okalloc so we scan all available agi structures for a free	 * inode.	 */	if (mp->m_maxicount &&	    mp->m_sb.sb_icount + XFS_IALLOC_INODES(mp) > mp->m_maxicount) {		noroom = 1;		okalloc = 0;	}	/*	 * Loop until we find an allocation group that either has free inodes	 * or in which we can allocate some inodes.  Iterate through the	 * allocation groups upward, wrapping at the end.	 */	*alloc_done = B_FALSE;	while (!agi->agi_freecount) {		/*		 * Don't do anything if we're not supposed to allocate		 * any blocks, just go on to the next ag.		 */		if (okalloc) {			/*			 * Try to allocate some new inodes in the allocation			 * group.			 */			if ((error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced))) {				xfs_trans_brelse(tp, agbp);				if (error == ENOSPC) {					*inop = NULLFSINO;					return 0;				} else					return error;			}			if (ialloced) {				/*				 * We successfully allocated some inodes, return				 * the current context to the caller so that it				 * can commit the current transaction and call				 * us again where we left off.				 */				ASSERT(be32_to_cpu(agi->agi_freecount) > 0);				*alloc_done = B_TRUE;				*IO_agbp = agbp;				*inop = NULLFSINO;				return 0;			}		}		/*		 * If it failed, give up on this ag.		 */		xfs_trans_brelse(tp, agbp);		/*		 * Go on to the next ag: get its ag header.		 */nextag:		if (++tagno == agcount)			tagno = 0;		if (tagno == agno) {			*inop = NULLFSINO;			return noroom ? ENOSPC : 0;		}		down_read(&mp->m_peraglock);		if (mp->m_perag[tagno].pagi_inodeok == 0) {			up_read(&mp->m_peraglock);			goto nextag;		}		error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp);		up_read(&mp->m_peraglock);		if (error)			goto nextag;		agi = XFS_BUF_TO_AGI(agbp);		ASSERT(be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC);	}	/*	 * Here with an allocation group that has a free inode.	 * Reset agno since we may have chosen a new ag in the	 * loop above.	 */	agno = tagno;	*IO_agbp = NULL;	cur = xfs_btree_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno),				    XFS_BTNUM_INO, (xfs_inode_t *)0, 0);	/*	 * If pagino is 0 (this is the root inode allocation) use newino.	 * This must work because we've just allocated some.	 */	if (!pagino)		pagino = be32_to_cpu(agi->agi_newino);#ifdef DEBUG	if (cur->bc_nlevels == 1) {		int	freecount = 0;		if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i)))			goto error0;		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);		do {			if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino,					&rec.ir_freecount, &rec.ir_free, &i)))				goto error0;			XFS_WANT_CORRUPTED_GOTO(i == 1, error0);			freecount += rec.ir_freecount;			if ((error = xfs_inobt_increment(cur, 0, &i)))				goto error0;		} while (i == 1);		ASSERT(freecount == be32_to_cpu(agi->agi_freecount) ||		       XFS_FORCED_SHUTDOWN(mp));	}#endif	/*	 * If in the same a.g. as the parent, try to get near the parent.	 */	if (pagno == agno) {		if ((error = xfs_inobt_lookup_le(cur, pagino, 0, 0, &i)))			goto error0;		if (i != 0 &&		    (error = xfs_inobt_get_rec(cur, &rec.ir_startino,			    &rec.ir_freecount, &rec.ir_free, &j)) == 0 &&		    j == 1 &&		    rec.ir_freecount > 0) {			/*			 * Found a free inode in the same chunk			 * as parent, done.			 */		}		/*		 * In the same a.g. as parent, but parent's chunk is full.		 */		else {			int	doneleft;	/* done, to the left */			int	doneright;	/* done, to the right */			if (error)				goto error0;			ASSERT(i == 1);			ASSERT(j == 1);			/*			 * Duplicate the cursor, search left & right			 * simultaneously.			 */			if ((error = xfs_btree_dup_cursor(cur, &tcur)))				goto error0;			/*			 * Search left with tcur, back up 1 record.			 */			if ((error = xfs_inobt_decrement(tcur, 0, &i)))				goto error1;			doneleft = !i;			if (!doneleft) {				if ((error = xfs_inobt_get_rec(tcur,						&trec.ir_startino,						&trec.ir_freecount,						&trec.ir_free, &i)))					goto error1;				XFS_WANT_CORRUPTED_GOTO(i == 1, error1);			}			/*			 * Search right with cur, go forward 1 record.			 */			if ((error = xfs_inobt_increment(cur, 0, &i)))				goto error1;			doneright = !i;			if (!doneright) {				if ((error = xfs_inobt_get_rec(cur,						&rec.ir_startino,						&rec.ir_freecount,						&rec.ir_free, &i)))					goto error1;				XFS_WANT_CORRUPTED_GOTO(i == 1, error1);			}			/*			 * Loop until we find the closest inode chunk			 * with a free one.			 */			while (!doneleft || !doneright) {				int	useleft;  /* using left inode						     chunk this time */				/*				 * Figure out which block is closer,				 * if both are valid.				 */				if (!doneleft && !doneright)					useleft =						pagino -						(trec.ir_startino +						 XFS_INODES_PER_CHUNK - 1) <						 rec.ir_startino - pagino;				else					useleft = !doneleft;				/*				 * If checking the left, does it have				 * free inodes?				 */				if (useleft && trec.ir_freecount) {					/*					 * Yes, set it up as the chunk to use.					 */					rec = trec;					xfs_btree_del_cursor(cur,						XFS_BTREE_NOERROR);					cur = tcur;					break;				}				/*				 * If checking the right, does it have				 * free inodes?				 */				if (!useleft && rec.ir_freecount) {					/*					 * Yes, it's already set up.					 */					xfs_btree_del_cursor(tcur,						XFS_BTREE_NOERROR);					break;				}				/*				 * If used the left, get another one				 * further left.				 */				if (useleft) {					if ((error = xfs_inobt_decrement(tcur, 0,							&i)))						goto error1;					doneleft = !i;					if (!doneleft) {						if ((error = xfs_inobt_get_rec(							    tcur,							    &trec.ir_startino,							    &trec.ir_freecount,							    &trec.ir_free, &i)))							goto error1;						XFS_WANT_CORRUPTED_GOTO(i == 1,							error1);					}				}				/*				 * If used the right, get another one				 * further right.				 */				else {					if ((error = xfs_inobt_increment(cur, 0,							&i)))						goto error1;					doneright = !i;					if (!doneright) {						if ((error = xfs_inobt_get_rec(							    cur,							    &rec.ir_startino,							    &rec.ir_freecount,							    &rec.ir_free, &i)))							goto error1;						XFS_WANT_CORRUPTED_GOTO(i == 1,							error1);					}				}			}			ASSERT(!doneleft || !doneright);		}	}	/*	 * In a different a.g. from the parent.	 * See if the most recently allocated block has any free.	 */	else if (be32_to_cpu(agi->agi_newino) != NULLAGINO) {		if ((error = xfs_inobt_lookup_eq(cur,				be32_to_cpu(agi->agi_newino), 0, 0, &i)))			goto error0;		if (i == 1 &&		    (error = xfs_inobt_get_rec(cur, &rec.ir_startino,			    &rec.ir_freecount, &rec.ir_free, &j)) == 0 &&		    j == 1 &&		    rec.ir_freecount > 0) {			/*			 * The last chunk allocated in the group still has			 * a free inode.			 */		}		/*		 * None left in the last group, search the whole a.g.		 */		else {			if (error)				goto error0;			if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i)))				goto error0;			ASSERT(i == 1);			for (;;) {				if ((error = xfs_inobt_get_rec(cur,						&rec.ir_startino,						&rec.ir_freecount, &rec.ir_free,						&i)))					goto error0;				XFS_WANT_CORRUPTED_GOTO(i == 1, error0);				if (rec.ir_freecount > 0)					break;				if ((error = xfs_inobt_increment(cur, 0, &i)))					goto error0;				XFS_WANT_CORRUPTED_GOTO(i == 1, error0);			}		}	}	offset = XFS_IALLOC_FIND_FREE(&rec.ir_free);	ASSERT(offset >= 0);	ASSERT(offset < XFS_INODES_PER_CHUNK);	ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %				   XFS_INODES_PER_CHUNK) == 0);	ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset);	XFS_INOBT_CLR_FREE(&rec, offset);	rec.ir_freecount--;	if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount,			rec.ir_free)))		goto error0;	be32_add(&agi->agi_freecount, -1);	xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);	down_read(&mp->m_peraglock);	mp->m_perag[tagno].pagi_freecount--;	up_read(&mp->m_peraglock);#ifdef DEBUG	if (cur->bc_nlevels == 1) {		int	freecount = 0;		if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i)))			goto error0;		do {			if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino,					&rec.ir_freecount, &rec.ir_free, &i)))				goto error0;			XFS_WANT_CORRUPTED_GOTO(i == 1, error0);			freecount += rec.ir_freecount;			if ((error = xfs_inobt_increment(cur, 0, &i)))				goto error0;		} while (i == 1);		ASSERT(freecount == be32_to_cpu(agi->agi_freecount) ||		       XFS_FORCED_SHUTDOWN(mp));	}#endif	xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);	xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1);	*inop = ino;	return 0;error1:	xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);error0:	xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);	return error;}/* * Free disk inode.  Carefully avoids touching the incore inode, all * manipulations incore are the caller's responsibility. * The on-disk inode is not changed by this operation, only the * btree (free inode mask) is changed. */intxfs_difree(	xfs_trans_t	*tp,		/* transaction pointer */	xfs_ino_t	inode,		/* inode to be freed */	xfs_bmap_free_t	*flist,		/* extents to free */	int		*delete,	/* set if inode cluster was deleted */	xfs_ino_t	*first_ino)	/* first inode in deleted cluster */{	/* REFERENCED */	xfs_agblock_t	agbno;	/* block number containing inode */	xfs_buf_t	*agbp;	/* buffer containing allocation group header */	xfs_agino_t	agino;	/* inode number relative to allocation group */	xfs_agnumber_t	agno;	/* allocation group number */	xfs_agi_t	*agi;	/* allocation group header */	xfs_btree_cur_t	*cur;	/* inode btree cursor */	int		error;	/* error return value */	int		i;	/* result code */	int		ilen;	/* inodes in an inode cluster */	xfs_mount_t	*mp;	/* mount structure for filesystem */	int		off;	/* offset of inode in inode chunk */	xfs_inobt_rec_incore_t rec;	/* btree record */	mp = tp->t_mountp;	/*	 * Break up inode number into its components.	 */	agno = XFS_INO_TO_AGNO(mp, inode);	if (agno >= mp->m_sb.sb_agcount)  {		cmn_err(CE_WARN,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -