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

📄 dir.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
			str.hash = be32_to_cpu(dent->de_hash);			new = gfs2_dirent_alloc(inode, nbh, &str);			if (IS_ERR(new)) {				error = PTR_ERR(new);				break;			}			new->de_inum = dent->de_inum; /* No endian worries */			new->de_type = dent->de_type; /* No endian worries */			nleaf->lf_entries = cpu_to_be16(be16_to_cpu(nleaf->lf_entries)+1);			dirent_del(dip, obh, prev, dent);			if (!oleaf->lf_entries)				gfs2_consist_inode(dip);			oleaf->lf_entries = cpu_to_be16(be16_to_cpu(oleaf->lf_entries)-1);			if (!prev)				prev = dent;			moved = 1;		} else {			prev = dent;		}		dent = next;	} while (dent);	oleaf->lf_depth = nleaf->lf_depth;	error = gfs2_meta_inode_buffer(dip, &dibh);	if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) {		gfs2_trans_add_bh(dip->i_gl, dibh, 1);		dip->i_di.di_blocks++;		gfs2_set_inode_blocks(&dip->i_inode);		gfs2_dinode_out(dip, dibh->b_data);		brelse(dibh);	}	brelse(obh);	brelse(nbh);	return error;fail_lpfree:	kfree(lp);fail_brelse:	brelse(obh);	brelse(nbh);	return error;}/** * dir_double_exhash - Double size of ExHash table * @dip: The GFS2 dinode * * Returns: 0 on success, error code on failure */static int dir_double_exhash(struct gfs2_inode *dip){	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);	struct buffer_head *dibh;	u32 hsize;	u64 *buf;	u64 *from, *to;	u64 block;	int x;	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;	}	/*  Allocate both the "from" and "to" buffers in one big chunk  */	buf = kcalloc(3, sdp->sd_hash_bsize, GFP_KERNEL | __GFP_NOFAIL);	for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) {		error = gfs2_dir_read_data(dip, (char *)buf,					    block * sdp->sd_hash_bsize,					    sdp->sd_hash_bsize, 1);		if (error != sdp->sd_hash_bsize) {			if (error >= 0)				error = -EIO;			goto fail;		}		from = buf;		to = (u64 *)((char *)buf + sdp->sd_hash_bsize);		for (x = sdp->sd_hash_ptrs; x--; from++) {			*to++ = *from;	/*  No endianess worries  */			*to++ = *from;		}		error = gfs2_dir_write_data(dip,					     (char *)buf + sdp->sd_hash_bsize,					     block * sdp->sd_sb.sb_bsize,					     sdp->sd_sb.sb_bsize);		if (error != sdp->sd_sb.sb_bsize) {			if (error >= 0)				error = -EIO;			goto fail;		}	}	kfree(buf);	error = gfs2_meta_inode_buffer(dip, &dibh);	if (!gfs2_assert_withdraw(sdp, !error)) {		dip->i_di.di_depth++;		gfs2_dinode_out(dip, dibh->b_data);		brelse(dibh);	}	return error;fail:	kfree(buf);	return error;}/** * compare_dents - compare directory entries by hash value * @a: first dent * @b: second dent * * When comparing the hash entries of @a to @b: *   gt: returns 1 *   lt: returns -1 *   eq: returns 0 */static int compare_dents(const void *a, const void *b){	const struct gfs2_dirent *dent_a, *dent_b;	u32 hash_a, hash_b;	int ret = 0;	dent_a = *(const struct gfs2_dirent **)a;	hash_a = be32_to_cpu(dent_a->de_hash);	dent_b = *(const struct gfs2_dirent **)b;	hash_b = be32_to_cpu(dent_b->de_hash);	if (hash_a > hash_b)		ret = 1;	else if (hash_a < hash_b)		ret = -1;	else {		unsigned int len_a = be16_to_cpu(dent_a->de_name_len);		unsigned int len_b = be16_to_cpu(dent_b->de_name_len);		if (len_a > len_b)			ret = 1;		else if (len_a < len_b)			ret = -1;		else			ret = memcmp(dent_a + 1, dent_b + 1, len_a);	}	return ret;}/** * do_filldir_main - read out directory entries * @dip: The GFS2 inode * @offset: The offset in the file to read from * @opaque: opaque data to pass to filldir * @filldir: The function to pass entries to * @darr: an array of struct gfs2_dirent pointers to read * @entries: the number of entries in darr * @copied: pointer to int that's non-zero if a entry has been copied out * * Jump through some hoops to make sure that if there are hash collsions, * they are read out at the beginning of a buffer.  We want to minimize * the possibility that they will fall into different readdir buffers or * that someone will want to seek to that location. * * Returns: errno, >0 on exception from filldir */static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,			   void *opaque, filldir_t filldir,			   const struct gfs2_dirent **darr, u32 entries,			   int *copied){	const struct gfs2_dirent *dent, *dent_next;	u64 off, off_next;	unsigned int x, y;	int run = 0;	int error = 0;	sort(darr, entries, sizeof(struct gfs2_dirent *), compare_dents, NULL);	dent_next = darr[0];	off_next = be32_to_cpu(dent_next->de_hash);	off_next = gfs2_disk_hash2offset(off_next);	for (x = 0, y = 1; x < entries; x++, y++) {		dent = dent_next;		off = off_next;		if (y < entries) {			dent_next = darr[y];			off_next = be32_to_cpu(dent_next->de_hash);			off_next = gfs2_disk_hash2offset(off_next);			if (off < *offset)				continue;			*offset = off;			if (off_next == off) {				if (*copied && !run)					return 1;				run = 1;			} else				run = 0;		} else {			if (off < *offset)				continue;			*offset = off;		}		error = filldir(opaque, (const char *)(dent + 1),				be16_to_cpu(dent->de_name_len),				off, be64_to_cpu(dent->de_inum.no_addr),				be16_to_cpu(dent->de_type));		if (error)			return 1;		*copied = 1;	}	/* Increment the *offset by one, so the next time we come into the	   do_filldir fxn, we get the next entry instead of the last one in the	   current leaf */	(*offset)++;	return 0;}static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,			      filldir_t filldir, int *copied, unsigned *depth,			      u64 leaf_no){	struct gfs2_inode *ip = GFS2_I(inode);	struct gfs2_sbd *sdp = GFS2_SB(inode);	struct buffer_head *bh;	struct gfs2_leaf *lf;	unsigned entries = 0, entries2 = 0;	unsigned leaves = 0;	const struct gfs2_dirent **darr, *dent;	struct dirent_gather g;	struct buffer_head **larr;	int leaf = 0;	int error, i;	u64 lfn = leaf_no;	do {		error = get_leaf(ip, lfn, &bh);		if (error)			goto out;		lf = (struct gfs2_leaf *)bh->b_data;		if (leaves == 0)			*depth = be16_to_cpu(lf->lf_depth);		entries += be16_to_cpu(lf->lf_entries);		leaves++;		lfn = be64_to_cpu(lf->lf_next);		brelse(bh);	} while(lfn);	if (!entries)		return 0;	error = -ENOMEM;	/*	 * The extra 99 entries are not normally used, but are a buffer	 * zone in case the number of entries in the leaf is corrupt.	 * 99 is the maximum number of entries that can fit in a single	 * leaf block.	 */	larr = vmalloc((leaves + entries + 99) * sizeof(void *));	if (!larr)		goto out;	darr = (const struct gfs2_dirent **)(larr + leaves);	g.pdent = darr;	g.offset = 0;	lfn = leaf_no;	do {		error = get_leaf(ip, lfn, &bh);		if (error)			goto out_kfree;		lf = (struct gfs2_leaf *)bh->b_data;		lfn = be64_to_cpu(lf->lf_next);		if (lf->lf_entries) {			entries2 += be16_to_cpu(lf->lf_entries);			dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,						gfs2_dirent_gather, NULL, &g);			error = PTR_ERR(dent);			if (IS_ERR(dent))				goto out_kfree;			if (entries2 != g.offset) {				fs_warn(sdp, "Number of entries corrupt in dir "						"leaf %llu, entries2 (%u) != "						"g.offset (%u)\n",					(unsigned long long)bh->b_blocknr,					entries2, g.offset);									error = -EIO;				goto out_kfree;			}			error = 0;			larr[leaf++] = bh;		} else {			brelse(bh);		}	} while(lfn);	BUG_ON(entries2 != entries);	error = do_filldir_main(ip, offset, opaque, filldir, darr,				entries, copied);out_kfree:	for(i = 0; i < leaf; i++)		brelse(larr[i]);	vfree(larr);out:	return error;}/** * dir_e_read - Reads the entries from a directory into a filldir buffer * @dip: dinode pointer * @offset: the hash of the last entry read shifted to the right once * @opaque: buffer for the filldir function to fill * @filldir: points to the filldir function to use * * Returns: errno */static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,		      filldir_t filldir){	struct gfs2_inode *dip = GFS2_I(inode);	struct gfs2_sbd *sdp = GFS2_SB(inode);	u32 hsize, len = 0;	u32 ht_offset, lp_offset, ht_offset_cur = -1;	u32 hash, index;	__be64 *lp;	int copied = 0;	int error = 0;	unsigned depth = 0;	hsize = 1 << dip->i_di.di_depth;	if (hsize * sizeof(u64) != dip->i_di.di_size) {		gfs2_consist_inode(dip);		return -EIO;	}	hash = gfs2_dir_offset2hash(*offset);	index = hash >> (32 - dip->i_di.di_depth);	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;		}		error = gfs2_dir_read_leaf(inode, offset, opaque, filldir,					   &copied, &depth,					   be64_to_cpu(lp[lp_offset]));		if (error)			break;		len = 1 << (dip->i_di.di_depth - depth);		index = (index & ~(len - 1)) + len;	}out:	kfree(lp);	if (error > 0)		error = 0;	return error;}int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,		  filldir_t filldir){	struct gfs2_inode *dip = GFS2_I(inode);	struct gfs2_sbd *sdp = GFS2_SB(inode);	struct dirent_gather g;	const struct gfs2_dirent **darr, *dent;	struct buffer_head *dibh;	int copied = 0;	int error;	if (!dip->i_di.di_entries)		return 0;	if (dip->i_di.di_flags & GFS2_DIF_EXHASH)		return dir_e_read(inode, offset, opaque, filldir);	if (!gfs2_is_stuffed(dip)) {		gfs2_consist_inode(dip);		return -EIO;	}	error = gfs2_meta_inode_buffer(dip, &dibh);	if (error)		return error;	error = -ENOMEM;	/* 96 is max number of dirents which can be stuffed into an inode */	darr = kmalloc(96 * sizeof(struct gfs2_dirent *), GFP_KERNEL);	if (darr) {		g.pdent = darr;		g.offset = 0;		dent = gfs2_dirent_scan(inode, dibh->b_data, dibh->b_size,					gfs2_dirent_gather, NULL, &g);		if (IS_ERR(dent)) {			error = PTR_ERR(dent);			goto out;		}		if (dip->i_di.di_entries != g.offset) {			fs_warn(sdp, "Number of entries corrupt in dir %llu, "				"ip->i_di.di_entries (%u) != g.offset (%u)\n",				(unsigned long long)dip->i_no_addr,				dip->i_di.di_entries,				g.offset);			error = -EIO;			goto out;		}		error = do_filldir_main(dip, offset, opaque, filldir, darr,					dip->i_di.di_entries, &copied);out:		kfree(darr);	}	if (error > 0)		error = 0;	brelse(dibh);	return error;}/** * gfs2_dir_search - Search a directory * @dip: The GFS2 inode * @filename: * @inode: * * This routine searches a directory for a file or another directory. * Assumes a glock is held on dip. * * Returns: errno */struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name){	struct buffer_head *bh;	struct gfs2_dirent *dent;	struct inode *inode;	dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh);	if (dent) {		if (IS_ERR(dent))			return ERR_PTR(PTR_ERR(dent));		inode = gfs2_inode_lookup(dir->i_sb, 				be16_to_cpu(dent->de_type),				be64_to_cpu(dent->de_inum.no_addr),				be64_to_cpu(dent->de_inum.no_formal_ino), 0);		brelse(bh);		return inode;	}	return ERR_PTR(-ENOENT);}int gfs2_dir_check(struct inode *dir, const struct qstr *name,		   const struct gfs2_inode *ip){	struct buffer_head *bh;	struct gfs2_dirent *dent;	int ret = -ENOENT;	dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh);	if (dent) {		if (IS_ERR(dent))

⌨️ 快捷键说明

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