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

📄 dir.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
			return PTR_ERR(dent);		if (ip) {			if (be64_to_cpu(dent->de_inum.no_addr) != ip->i_no_addr)				goto out;			if (be64_to_cpu(dent->de_inum.no_formal_ino) !=			    ip->i_no_formal_ino)				goto out;			if (unlikely(IF2DT(ip->i_inode.i_mode) !=			    be16_to_cpu(dent->de_type))) {				gfs2_consist_inode(GFS2_I(dir));				ret = -EIO;				goto out;			}		}		ret = 0;out:		brelse(bh);	}	return ret;}static int dir_new_leaf(struct inode *inode, const struct qstr *name){	struct buffer_head *bh, *obh;	struct gfs2_inode *ip = GFS2_I(inode);	struct gfs2_leaf *leaf, *oleaf;	int error;	u32 index;	u64 bn;	index = name->hash >> (32 - ip->i_di.di_depth);	error = get_first_leaf(ip, index, &obh);	if (error)		return error;	do {		oleaf = (struct gfs2_leaf *)obh->b_data;		bn = be64_to_cpu(oleaf->lf_next);		if (!bn)			break;		brelse(obh);		error = get_leaf(ip, bn, &obh);		if (error)			return error;	} while(1);	gfs2_trans_add_bh(ip->i_gl, obh, 1);	leaf = new_leaf(inode, &bh, be16_to_cpu(oleaf->lf_depth));	if (!leaf) {		brelse(obh);		return -ENOSPC;	}	oleaf->lf_next = cpu_to_be64(bh->b_blocknr);	brelse(bh);	brelse(obh);	error = gfs2_meta_inode_buffer(ip, &bh);	if (error)		return error;	gfs2_trans_add_bh(ip->i_gl, bh, 1);	ip->i_di.di_blocks++;	gfs2_set_inode_blocks(&ip->i_inode);	gfs2_dinode_out(ip, bh->b_data);	brelse(bh);	return 0;}/** * gfs2_dir_add - Add new filename into directory * @dip: The GFS2 inode * @filename: The new name * @inode: The inode number of the entry * @type: The type of the entry * * Returns: 0 on success, error code on failure */int gfs2_dir_add(struct inode *inode, const struct qstr *name,		 const struct gfs2_inode *nip, unsigned type){	struct gfs2_inode *ip = GFS2_I(inode);	struct buffer_head *bh;	struct gfs2_dirent *dent;	struct gfs2_leaf *leaf;	int error;	while(1) {		dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space,					  &bh);		if (dent) {			if (IS_ERR(dent))				return PTR_ERR(dent);			dent = gfs2_init_dirent(inode, dent, name, bh);			gfs2_inum_out(nip, dent);			dent->de_type = cpu_to_be16(type);			if (ip->i_di.di_flags & GFS2_DIF_EXHASH) {				leaf = (struct gfs2_leaf *)bh->b_data;				leaf->lf_entries = cpu_to_be16(be16_to_cpu(leaf->lf_entries) + 1);			}			brelse(bh);			error = gfs2_meta_inode_buffer(ip, &bh);			if (error)				break;			gfs2_trans_add_bh(ip->i_gl, bh, 1);			ip->i_di.di_entries++;			ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;			gfs2_dinode_out(ip, bh->b_data);			brelse(bh);			error = 0;			break;		}		if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH)) {			error = dir_make_exhash(inode);			if (error)				break;			continue;		}		error = dir_split_leaf(inode, name);		if (error == 0)			continue;		if (error < 0)			break;		if (ip->i_di.di_depth < GFS2_DIR_MAX_DEPTH) {			error = dir_double_exhash(ip);			if (error)				break;			error = dir_split_leaf(inode, name);			if (error < 0)				break;			if (error == 0)				continue;		}		error = dir_new_leaf(inode, name);		if (!error)			continue;		error = -ENOSPC;		break;	}	return error;}/** * gfs2_dir_del - Delete a directory entry * @dip: The GFS2 inode * @filename: The filename * * Returns: 0 on success, error code on failure */int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name){	struct gfs2_dirent *dent, *prev = NULL;	struct buffer_head *bh;	int error;	/* Returns _either_ the entry (if its first in block) or the	   previous entry otherwise */	dent = gfs2_dirent_search(&dip->i_inode, name, gfs2_dirent_prev, &bh);	if (!dent) {		gfs2_consist_inode(dip);		return -EIO;	}	if (IS_ERR(dent)) {		gfs2_consist_inode(dip);		return PTR_ERR(dent);	}	/* If not first in block, adjust pointers accordingly */	if (gfs2_dirent_find(dent, name, NULL) == 0) {		prev = dent;		dent = (struct gfs2_dirent *)((char *)dent + be16_to_cpu(prev->de_rec_len));	}	dirent_del(dip, bh, prev, dent);	if (dip->i_di.di_flags & GFS2_DIF_EXHASH) {		struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data;		u16 entries = be16_to_cpu(leaf->lf_entries);		if (!entries)			gfs2_consist_inode(dip);		leaf->lf_entries = cpu_to_be16(--entries);	}	brelse(bh);	error = gfs2_meta_inode_buffer(dip, &bh);	if (error)		return error;	if (!dip->i_di.di_entries)		gfs2_consist_inode(dip);	gfs2_trans_add_bh(dip->i_gl, bh, 1);	dip->i_di.di_entries--;	dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME;	gfs2_dinode_out(dip, bh->b_data);	brelse(bh);	mark_inode_dirty(&dip->i_inode);	return error;}/** * gfs2_dir_mvino - Change inode number of directory entry * @dip: The GFS2 inode * @filename: * @new_inode: * * This routine changes the inode number of a directory entry.  It's used * by rename to change ".." when a directory is moved. * Assumes a glock is held on dvp. * * Returns: errno */int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,		   const struct gfs2_inode *nip, unsigned int new_type){	struct buffer_head *bh;	struct gfs2_dirent *dent;	int error;	dent = gfs2_dirent_search(&dip->i_inode, filename, gfs2_dirent_find, &bh);	if (!dent) {		gfs2_consist_inode(dip);		return -EIO;	}	if (IS_ERR(dent))		return PTR_ERR(dent);	gfs2_trans_add_bh(dip->i_gl, bh, 1);	gfs2_inum_out(nip, dent);	dent->de_type = cpu_to_be16(new_type);	if (dip->i_di.di_flags & GFS2_DIF_EXHASH) {		brelse(bh);		error = gfs2_meta_inode_buffer(dip, &bh);		if (error)			return error;		gfs2_trans_add_bh(dip->i_gl, bh, 1);	}	dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME;	gfs2_dinode_out(dip, bh->b_data);	brelse(bh);	return 0;}/** * foreach_leaf - call a function for each leaf in a directory * @dip: the directory * @lc: the function to call for each each * @data: private data to pass to it * * Returns: errno */static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data){	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);	struct buffer_head *bh;	struct gfs2_leaf *leaf;	u32 hsize, len;	u32 ht_offset, lp_offset, ht_offset_cur = -1;	u32 index = 0;	__be64 *lp;	u64 leaf_no;	int error = 0;	hsize = 1 << dip->i_di.di_depth;	if (hsize * sizeof(u64) != dip->i_di.di_size) {		gfs2_consist_inode(dip);		return -EIO;	}	lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL);	if (!lp)		return -ENOMEM;	while (index < hsize) {		lp_offset = index & (sdp->sd_hash_ptrs - 1);		ht_offset = index - lp_offset;		if (ht_offset_cur != ht_offset) {			error = gfs2_dir_read_data(dip, (char *)lp,						ht_offset * sizeof(__be64),						sdp->sd_hash_bsize, 1);			if (error != sdp->sd_hash_bsize) {				if (error >= 0)					error = -EIO;				goto out;			}			ht_offset_cur = ht_offset;		}		leaf_no = be64_to_cpu(lp[lp_offset]);		if (leaf_no) {			error = get_leaf(dip, leaf_no, &bh);			if (error)				goto out;			leaf = (struct gfs2_leaf *)bh->b_data;			len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth));			brelse(bh);			error = lc(dip, index, len, leaf_no, data);			if (error)				goto out;			index = (index & ~(len - 1)) + len;		} else			index++;	}	if (index != hsize) {		gfs2_consist_inode(dip);		error = -EIO;	}out:	kfree(lp);	return error;}/** * leaf_dealloc - Deallocate a directory leaf * @dip: the directory * @index: the hash table offset in the directory * @len: the number of pointers to this leaf * @leaf_no: the leaf number * @data: not used * * Returns: errno */static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,			u64 leaf_no, void *data){	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);	struct gfs2_leaf *tmp_leaf;	struct gfs2_rgrp_list rlist;	struct buffer_head *bh, *dibh;	u64 blk, nblk;	unsigned int rg_blocks = 0, l_blocks = 0;	char *ht;	unsigned int x, size = len * sizeof(u64);	int error;	memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));	ht = kzalloc(size, GFP_KERNEL);	if (!ht)		return -ENOMEM;	gfs2_alloc_get(dip);	error = gfs2_quota_hold(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);	if (error)		goto out;	error = gfs2_rindex_hold(sdp, &dip->i_alloc.al_ri_gh);	if (error)		goto out_qs;	/*  Count the number of leaves  */	for (blk = leaf_no; blk; blk = nblk) {		error = get_leaf(dip, blk, &bh);		if (error)			goto out_rlist;		tmp_leaf = (struct gfs2_leaf *)bh->b_data;		nblk = be64_to_cpu(tmp_leaf->lf_next);		brelse(bh);		gfs2_rlist_add(sdp, &rlist, blk);		l_blocks++;	}	gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0);	for (x = 0; x < rlist.rl_rgrps; x++) {		struct gfs2_rgrpd *rgd;		rgd = rlist.rl_ghs[x].gh_gl->gl_object;		rg_blocks += rgd->rd_length;	}	error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs);	if (error)		goto out_rlist;	error = gfs2_trans_begin(sdp,			rg_blocks + (DIV_ROUND_UP(size, sdp->sd_jbsize) + 1) +			RES_DINODE + RES_STATFS + RES_QUOTA, l_blocks);	if (error)		goto out_rg_gunlock;	for (blk = leaf_no; blk; blk = nblk) {		error = get_leaf(dip, blk, &bh);		if (error)			goto out_end_trans;		tmp_leaf = (struct gfs2_leaf *)bh->b_data;		nblk = be64_to_cpu(tmp_leaf->lf_next);		brelse(bh);		gfs2_free_meta(dip, blk, 1);		if (!dip->i_di.di_blocks)			gfs2_consist_inode(dip);		dip->i_di.di_blocks--;		gfs2_set_inode_blocks(&dip->i_inode);	}	error = gfs2_dir_write_data(dip, ht, index * sizeof(u64), size);	if (error != size) {		if (error >= 0)			error = -EIO;		goto out_end_trans;	}	error = gfs2_meta_inode_buffer(dip, &dibh);	if (error)		goto out_end_trans;	gfs2_trans_add_bh(dip->i_gl, dibh, 1);	gfs2_dinode_out(dip, dibh->b_data);	brelse(dibh);out_end_trans:	gfs2_trans_end(sdp);out_rg_gunlock:	gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);out_rlist:	gfs2_rlist_free(&rlist);	gfs2_glock_dq_uninit(&dip->i_alloc.al_ri_gh);out_qs:	gfs2_quota_unhold(dip);out:	gfs2_alloc_put(dip);	kfree(ht);	return error;}/** * gfs2_dir_exhash_dealloc - free all the leaf blocks in a directory * @dip: the directory * * Dealloc all on-disk directory leaves to FREEMETA state * Change on-disk inode type to "regular file" * * Returns: errno */int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip){	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);	struct buffer_head *bh;	int error;	/* Dealloc on-disk leaves to FREEMETA state */	error = foreach_leaf(dip, leaf_dealloc, NULL);	if (error)		return error;	/* Make this a regular file in case we crash.	   (We don't want to free these blocks a second time.)  */	error = gfs2_trans_begin(sdp, RES_DINODE, 0);	if (error)		return error;	error = gfs2_meta_inode_buffer(dip, &bh);	if (!error) {		gfs2_trans_add_bh(dip->i_gl, bh, 1);		((struct gfs2_dinode *)bh->b_data)->di_mode =						cpu_to_be32(S_IFREG);		brelse(bh);	}	gfs2_trans_end(sdp);	return error;}/** * gfs2_diradd_alloc_required - find if adding entry will require an allocation * @ip: the file being written to * @filname: the filename that's going to be added * * Returns: 1 if alloc required, 0 if not, -ve on error */int gfs2_diradd_alloc_required(struct inode *inode, const struct qstr *name){	struct gfs2_dirent *dent;	struct buffer_head *bh;	dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, &bh);	if (!dent) {		return 1;	}	if (IS_ERR(dent))		return PTR_ERR(dent);	brelse(bh);	return 0;}

⌨️ 快捷键说明

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