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

📄 dir.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		if (gfs2_check_dirent(dent, offset, size, len, 0))			goto consist_inode;	} while(1);	switch(ret) {	case 0:		return NULL;	case 1:		return dent;	case 2:		return prev ? prev : dent;	default:		BUG_ON(ret > 0);		return ERR_PTR(ret);	}consist_inode:	gfs2_consist_inode(GFS2_I(inode));	return ERR_PTR(-EIO);}/** * dirent_first - Return the first dirent * @dip: the directory * @bh: The buffer * @dent: Pointer to list of dirents * * return first dirent whether bh points to leaf or stuffed dinode * * Returns: IS_LEAF, IS_DINODE, or -errno */static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh,			struct gfs2_dirent **dent){	struct gfs2_meta_header *h = (struct gfs2_meta_header *)bh->b_data;	if (be32_to_cpu(h->mh_type) == GFS2_METATYPE_LF) {		if (gfs2_meta_check(GFS2_SB(&dip->i_inode), bh))			return -EIO;		*dent = (struct gfs2_dirent *)(bh->b_data +					       sizeof(struct gfs2_leaf));		return IS_LEAF;	} else {		if (gfs2_metatype_check(GFS2_SB(&dip->i_inode), bh, GFS2_METATYPE_DI))			return -EIO;		*dent = (struct gfs2_dirent *)(bh->b_data +					       sizeof(struct gfs2_dinode));		return IS_DINODE;	}}static int dirent_check_reclen(struct gfs2_inode *dip,			       const struct gfs2_dirent *d, const void *end_p){	const void *ptr = d;	u16 rec_len = be16_to_cpu(d->de_rec_len);	if (unlikely(rec_len < sizeof(struct gfs2_dirent)))		goto broken;	ptr += rec_len;	if (ptr < end_p)		return rec_len;	if (ptr == end_p)		return -ENOENT;broken:	gfs2_consist_inode(dip);	return -EIO;}/** * dirent_next - Next dirent * @dip: the directory * @bh: The buffer * @dent: Pointer to list of dirents * * Returns: 0 on success, error code otherwise */static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh,		       struct gfs2_dirent **dent){	struct gfs2_dirent *cur = *dent, *tmp;	char *bh_end = bh->b_data + bh->b_size;	int ret;	ret = dirent_check_reclen(dip, cur, bh_end);	if (ret < 0)		return ret;	tmp = (void *)cur + ret;	ret = dirent_check_reclen(dip, tmp, bh_end);	if (ret == -EIO)		return ret;        /* Only the first dent could ever have de_inum.no_addr == 0 */	if (gfs2_dirent_sentinel(tmp)) {		gfs2_consist_inode(dip);		return -EIO;	}	*dent = tmp;	return 0;}/** * dirent_del - Delete a dirent * @dip: The GFS2 inode * @bh: The buffer * @prev: The previous dirent * @cur: The current dirent * */static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh,		       struct gfs2_dirent *prev, struct gfs2_dirent *cur){	u16 cur_rec_len, prev_rec_len;	if (gfs2_dirent_sentinel(cur)) {		gfs2_consist_inode(dip);		return;	}	gfs2_trans_add_bh(dip->i_gl, bh, 1);	/* If there is no prev entry, this is the first entry in the block.	   The de_rec_len is already as big as it needs to be.  Just zero	   out the inode number and return.  */	if (!prev) {		cur->de_inum.no_addr = 0;		cur->de_inum.no_formal_ino = 0;		return;	}	/*  Combine this dentry with the previous one.  */	prev_rec_len = be16_to_cpu(prev->de_rec_len);	cur_rec_len = be16_to_cpu(cur->de_rec_len);	if ((char *)prev + prev_rec_len != (char *)cur)		gfs2_consist_inode(dip);	if ((char *)cur + cur_rec_len > bh->b_data + bh->b_size)		gfs2_consist_inode(dip);	prev_rec_len += cur_rec_len;	prev->de_rec_len = cpu_to_be16(prev_rec_len);}/* * Takes a dent from which to grab space as an argument. Returns the * newly created dent. */static struct gfs2_dirent *gfs2_init_dirent(struct inode *inode,					    struct gfs2_dirent *dent,					    const struct qstr *name,					    struct buffer_head *bh){	struct gfs2_inode *ip = GFS2_I(inode);	struct gfs2_dirent *ndent;	unsigned offset = 0, totlen;	if (!gfs2_dirent_sentinel(dent))		offset = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len));	totlen = be16_to_cpu(dent->de_rec_len);	BUG_ON(offset + name->len > totlen);	gfs2_trans_add_bh(ip->i_gl, bh, 1);	ndent = (struct gfs2_dirent *)((char *)dent + offset);	dent->de_rec_len = cpu_to_be16(offset);	gfs2_qstr2dirent(name, totlen - offset, ndent);	return ndent;}static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode,					     struct buffer_head *bh,					     const struct qstr *name){	struct gfs2_dirent *dent;	dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,				gfs2_dirent_find_space, name, NULL);	if (!dent || IS_ERR(dent))		return dent;	return gfs2_init_dirent(inode, dent, name, bh);}static int get_leaf(struct gfs2_inode *dip, u64 leaf_no,		    struct buffer_head **bhp){	int error;	error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, bhp);	if (!error && gfs2_metatype_check(GFS2_SB(&dip->i_inode), *bhp, GFS2_METATYPE_LF)) {		/* printk(KERN_INFO "block num=%llu\n", leaf_no); */		error = -EIO;	}	return error;}/** * get_leaf_nr - Get a leaf number associated with the index * @dip: The GFS2 inode * @index: * @leaf_out: * * Returns: 0 on success, error code otherwise */static int get_leaf_nr(struct gfs2_inode *dip, u32 index,		       u64 *leaf_out){	__be64 leaf_no;	int error;	error = gfs2_dir_read_data(dip, (char *)&leaf_no,				    index * sizeof(__be64),				    sizeof(__be64), 0);	if (error != sizeof(u64))		return (error < 0) ? error : -EIO;	*leaf_out = be64_to_cpu(leaf_no);	return 0;}static int get_first_leaf(struct gfs2_inode *dip, u32 index,			  struct buffer_head **bh_out){	u64 leaf_no;	int error;	error = get_leaf_nr(dip, index, &leaf_no);	if (!error)		error = get_leaf(dip, leaf_no, bh_out);	return error;}static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode,					      const struct qstr *name,					      gfs2_dscan_t scan,					      struct buffer_head **pbh){	struct buffer_head *bh;	struct gfs2_dirent *dent;	struct gfs2_inode *ip = GFS2_I(inode);	int error;	if (ip->i_di.di_flags & GFS2_DIF_EXHASH) {		struct gfs2_leaf *leaf;		unsigned hsize = 1 << ip->i_di.di_depth;		unsigned index;		u64 ln;		if (hsize * sizeof(u64) != ip->i_di.di_size) {			gfs2_consist_inode(ip);			return ERR_PTR(-EIO);		}		index = name->hash >> (32 - ip->i_di.di_depth);		error = get_first_leaf(ip, index, &bh);		if (error)			return ERR_PTR(error);		do {			dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,						scan, name, NULL);			if (dent)				goto got_dent;			leaf = (struct gfs2_leaf *)bh->b_data;			ln = be64_to_cpu(leaf->lf_next);			brelse(bh);			if (!ln)				break;			error = get_leaf(ip, ln, &bh);		} while(!error);		return error ? ERR_PTR(error) : NULL;	}	error = gfs2_meta_inode_buffer(ip, &bh);	if (error)		return ERR_PTR(error);	dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name, NULL);got_dent:	if (unlikely(dent == NULL || IS_ERR(dent))) {		brelse(bh);		bh = NULL;	}	*pbh = bh;	return dent;}static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth){	struct gfs2_inode *ip = GFS2_I(inode);	u64 bn = gfs2_alloc_meta(ip);	struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn);	struct gfs2_leaf *leaf;	struct gfs2_dirent *dent;	struct qstr name = { .name = "", .len = 0, .hash = 0 };	if (!bh)		return NULL;	gfs2_trans_add_bh(ip->i_gl, bh, 1);	gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF);	leaf = (struct gfs2_leaf *)bh->b_data;	leaf->lf_depth = cpu_to_be16(depth);	leaf->lf_entries = 0;	leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);	leaf->lf_next = 0;	memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved));	dent = (struct gfs2_dirent *)(leaf+1);	gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent);	*pbh = bh;	return leaf;}/** * dir_make_exhash - Convert a stuffed directory into an ExHash directory * @dip: The GFS2 inode * * Returns: 0 on success, error code otherwise */static int dir_make_exhash(struct inode *inode){	struct gfs2_inode *dip = GFS2_I(inode);	struct gfs2_sbd *sdp = GFS2_SB(inode);	struct gfs2_dirent *dent;	struct qstr args;	struct buffer_head *bh, *dibh;	struct gfs2_leaf *leaf;	int y;	u32 x;	__be64 *lp;	u64 bn;	int error;	error = gfs2_meta_inode_buffer(dip, &dibh);	if (error)		return error;	/*  Turn over a new leaf  */	leaf = new_leaf(inode, &bh, 0);	if (!leaf)		return -ENOSPC;	bn = bh->b_blocknr;	gfs2_assert(sdp, dip->i_di.di_entries < (1 << 16));	leaf->lf_entries = cpu_to_be16(dip->i_di.di_entries);	/*  Copy dirents  */	gfs2_buffer_copy_tail(bh, sizeof(struct gfs2_leaf), dibh,			     sizeof(struct gfs2_dinode));	/*  Find last entry  */	x = 0;	args.len = bh->b_size - sizeof(struct gfs2_dinode) +		   sizeof(struct gfs2_leaf);	args.name = bh->b_data;	dent = gfs2_dirent_scan(&dip->i_inode, bh->b_data, bh->b_size,				gfs2_dirent_last, &args, NULL);	if (!dent) {		brelse(bh);		brelse(dibh);		return -EIO;	}	if (IS_ERR(dent)) {		brelse(bh);		brelse(dibh);		return PTR_ERR(dent);	}	/*  Adjust the last dirent's record length	   (Remember that dent still points to the last entry.)  */	dent->de_rec_len = cpu_to_be16(be16_to_cpu(dent->de_rec_len) +		sizeof(struct gfs2_dinode) -		sizeof(struct gfs2_leaf));	brelse(bh);	/*  We're done with the new leaf block, now setup the new	    hash table.  */	gfs2_trans_add_bh(dip->i_gl, dibh, 1);	gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));	lp = (__be64 *)(dibh->b_data + sizeof(struct gfs2_dinode));	for (x = sdp->sd_hash_ptrs; x--; lp++)		*lp = cpu_to_be64(bn);	dip->i_di.di_size = sdp->sd_sb.sb_bsize / 2;	dip->i_di.di_blocks++;	gfs2_set_inode_blocks(&dip->i_inode);	dip->i_di.di_flags |= GFS2_DIF_EXHASH;	for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ;	dip->i_di.di_depth = y;	gfs2_dinode_out(dip, dibh->b_data);	brelse(dibh);	return 0;}/** * dir_split_leaf - Split a leaf block into two * @dip: The GFS2 inode * @index: * @leaf_no: * * Returns: 0 on success, error code on failure */static int dir_split_leaf(struct inode *inode, const struct qstr *name){	struct gfs2_inode *dip = GFS2_I(inode);	struct buffer_head *nbh, *obh, *dibh;	struct gfs2_leaf *nleaf, *oleaf;	struct gfs2_dirent *dent = NULL, *prev = NULL, *next = NULL, *new;	u32 start, len, half_len, divider;	u64 bn, leaf_no;	__be64 *lp;	u32 index;	int x, moved = 0;	int error;	index = name->hash >> (32 - dip->i_di.di_depth);	error = get_leaf_nr(dip, index, &leaf_no);	if (error)		return error;	/*  Get the old leaf block  */	error = get_leaf(dip, leaf_no, &obh);	if (error)		return error;	oleaf = (struct gfs2_leaf *)obh->b_data;	if (dip->i_di.di_depth == be16_to_cpu(oleaf->lf_depth)) {		brelse(obh);		return 1; /* can't split */	}	gfs2_trans_add_bh(dip->i_gl, obh, 1);	nleaf = new_leaf(inode, &nbh, be16_to_cpu(oleaf->lf_depth) + 1);	if (!nleaf) {		brelse(obh);		return -ENOSPC;	}	bn = nbh->b_blocknr;	/*  Compute the start and len of leaf pointers in the hash table.  */	len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth));	half_len = len >> 1;	if (!half_len) {		printk(KERN_WARNING "di_depth %u lf_depth %u index %u\n", dip->i_di.di_depth, be16_to_cpu(oleaf->lf_depth), index);		gfs2_consist_inode(dip);		error = -EIO;		goto fail_brelse;	}	start = (index & ~(len - 1));	/* Change the pointers.	   Don't bother distinguishing stuffed from non-stuffed.	   This code is complicated enough already. */	lp = kmalloc(half_len * sizeof(__be64), GFP_NOFS | __GFP_NOFAIL);	/*  Change the pointers  */	for (x = 0; x < half_len; x++)		lp[x] = cpu_to_be64(bn);	error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(u64),				    half_len * sizeof(u64));	if (error != half_len * sizeof(u64)) {		if (error >= 0)			error = -EIO;		goto fail_lpfree;	}	kfree(lp);	/*  Compute the divider  */	divider = (start + half_len) << (32 - dip->i_di.di_depth);	/*  Copy the entries  */	dirent_first(dip, obh, &dent);	do {		next = dent;		if (dirent_next(dip, obh, &next))			next = NULL;		if (!gfs2_dirent_sentinel(dent) &&		    be32_to_cpu(dent->de_hash) < divider) {			struct qstr str;			str.name = (char*)(dent+1);			str.len = be16_to_cpu(dent->de_name_len);

⌨️ 快捷键说明

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