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

📄 namei.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  linux/fs/ext4/namei.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) * Laboratoire MASI - Institut Blaise Pascal * Universite Pierre et Marie Curie (Paris VI) * *  from * *  linux/fs/minix/namei.c * *  Copyright (C) 1991, 1992  Linus Torvalds * *  Big-endian to little-endian byte-swapping/bitmaps by *        David S. Miller (davem@caip.rutgers.edu), 1995 *  Directory entry file type support and forward compatibility hooks *	for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998 *  Hash Tree Directory indexing (c) *	Daniel Phillips, 2001 *  Hash Tree Directory indexing porting *	Christopher Li, 2002 *  Hash Tree Directory indexing cleanup *	Theodore Ts'o, 2002 */#include <linux/fs.h>#include <linux/pagemap.h>#include <linux/jbd2.h>#include <linux/time.h>#include <linux/ext4_fs.h>#include <linux/ext4_jbd2.h>#include <linux/fcntl.h>#include <linux/stat.h>#include <linux/string.h>#include <linux/quotaops.h>#include <linux/buffer_head.h>#include <linux/bio.h>#include "namei.h"#include "xattr.h"#include "acl.h"/* * define how far ahead to read directories while searching them. */#define NAMEI_RA_CHUNKS  2#define NAMEI_RA_BLOCKS  4#define NAMEI_RA_SIZE	     (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))static struct buffer_head *ext4_append(handle_t *handle,					struct inode *inode,					u32 *block, int *err){	struct buffer_head *bh;	*block = inode->i_size >> inode->i_sb->s_blocksize_bits;	if ((bh = ext4_bread(handle, inode, *block, 1, err))) {		inode->i_size += inode->i_sb->s_blocksize;		EXT4_I(inode)->i_disksize = inode->i_size;		ext4_journal_get_write_access(handle,bh);	}	return bh;}#ifndef assert#define assert(test) J_ASSERT(test)#endif#ifndef swap#define swap(x, y) do { typeof(x) z = x; x = y; y = z; } while (0)#endif#ifdef DX_DEBUG#define dxtrace(command) command#else#define dxtrace(command)#endifstruct fake_dirent{	__le32 inode;	__le16 rec_len;	u8 name_len;	u8 file_type;};struct dx_countlimit{	__le16 limit;	__le16 count;};struct dx_entry{	__le32 hash;	__le32 block;};/* * dx_root_info is laid out so that if it should somehow get overlaid by a * dirent the two low bits of the hash version will be zero.  Therefore, the * hash version mod 4 should never be 0.  Sincerely, the paranoia department. */struct dx_root{	struct fake_dirent dot;	char dot_name[4];	struct fake_dirent dotdot;	char dotdot_name[4];	struct dx_root_info	{		__le32 reserved_zero;		u8 hash_version;		u8 info_length; /* 8 */		u8 indirect_levels;		u8 unused_flags;	}	info;	struct dx_entry	entries[0];};struct dx_node{	struct fake_dirent fake;	struct dx_entry	entries[0];};struct dx_frame{	struct buffer_head *bh;	struct dx_entry *entries;	struct dx_entry *at;};struct dx_map_entry{	u32 hash;	u16 offs;	u16 size;};static inline unsigned dx_get_block (struct dx_entry *entry);static void dx_set_block (struct dx_entry *entry, unsigned value);static inline unsigned dx_get_hash (struct dx_entry *entry);static void dx_set_hash (struct dx_entry *entry, unsigned value);static unsigned dx_get_count (struct dx_entry *entries);static unsigned dx_get_limit (struct dx_entry *entries);static void dx_set_count (struct dx_entry *entries, unsigned value);static void dx_set_limit (struct dx_entry *entries, unsigned value);static unsigned dx_root_limit (struct inode *dir, unsigned infosize);static unsigned dx_node_limit (struct inode *dir);static struct dx_frame *dx_probe(struct dentry *dentry,				 struct inode *dir,				 struct dx_hash_info *hinfo,				 struct dx_frame *frame,				 int *err);static void dx_release (struct dx_frame *frames);static int dx_make_map (struct ext4_dir_entry_2 *de, int size,			struct dx_hash_info *hinfo, struct dx_map_entry map[]);static void dx_sort_map(struct dx_map_entry *map, unsigned count);static struct ext4_dir_entry_2 *dx_move_dirents (char *from, char *to,		struct dx_map_entry *offsets, int count);static struct ext4_dir_entry_2* dx_pack_dirents (char *base, int size);static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);static int ext4_htree_next_block(struct inode *dir, __u32 hash,				 struct dx_frame *frame,				 struct dx_frame *frames,				 __u32 *start_hash);static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,		       struct ext4_dir_entry_2 **res_dir, int *err);static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,			     struct inode *inode);/* * Future: use high four bits of block for coalesce-on-delete flags * Mask them off for now. */static inline unsigned dx_get_block (struct dx_entry *entry){	return le32_to_cpu(entry->block) & 0x00ffffff;}static inline void dx_set_block (struct dx_entry *entry, unsigned value){	entry->block = cpu_to_le32(value);}static inline unsigned dx_get_hash (struct dx_entry *entry){	return le32_to_cpu(entry->hash);}static inline void dx_set_hash (struct dx_entry *entry, unsigned value){	entry->hash = cpu_to_le32(value);}static inline unsigned dx_get_count (struct dx_entry *entries){	return le16_to_cpu(((struct dx_countlimit *) entries)->count);}static inline unsigned dx_get_limit (struct dx_entry *entries){	return le16_to_cpu(((struct dx_countlimit *) entries)->limit);}static inline void dx_set_count (struct dx_entry *entries, unsigned value){	((struct dx_countlimit *) entries)->count = cpu_to_le16(value);}static inline void dx_set_limit (struct dx_entry *entries, unsigned value){	((struct dx_countlimit *) entries)->limit = cpu_to_le16(value);}static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize){	unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) -		EXT4_DIR_REC_LEN(2) - infosize;	return 0? 20: entry_space / sizeof(struct dx_entry);}static inline unsigned dx_node_limit (struct inode *dir){	unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0);	return 0? 22: entry_space / sizeof(struct dx_entry);}/* * Debug */#ifdef DX_DEBUGstatic void dx_show_index (char * label, struct dx_entry *entries){	int i, n = dx_get_count (entries);	printk("%s index ", label);	for (i = 0; i < n; i++) {		printk("%x->%u ", i? dx_get_hash(entries + i) :				0, dx_get_block(entries + i));	}	printk("\n");}struct stats{	unsigned names;	unsigned space;	unsigned bcount;};static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext4_dir_entry_2 *de,				 int size, int show_names){	unsigned names = 0, space = 0;	char *base = (char *) de;	struct dx_hash_info h = *hinfo;	printk("names: ");	while ((char *) de < base + size)	{		if (de->inode)		{			if (show_names)			{				int len = de->name_len;				char *name = de->name;				while (len--) printk("%c", *name++);				ext4fs_dirhash(de->name, de->name_len, &h);				printk(":%x.%u ", h.hash,				       ((char *) de - base));			}			space += EXT4_DIR_REC_LEN(de->name_len);			names++;		}		de = (struct ext4_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));	}	printk("(%i)\n", names);	return (struct stats) { names, space, 1 };}struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,			     struct dx_entry *entries, int levels){	unsigned blocksize = dir->i_sb->s_blocksize;	unsigned count = dx_get_count (entries), names = 0, space = 0, i;	unsigned bcount = 0;	struct buffer_head *bh;	int err;	printk("%i indexed blocks...\n", count);	for (i = 0; i < count; i++, entries++)	{		u32 block = dx_get_block(entries), hash = i? dx_get_hash(entries): 0;		u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash;		struct stats stats;		printk("%s%3u:%03u hash %8x/%8x ",levels?"":"   ", i, block, hash, range);		if (!(bh = ext4_bread (NULL,dir, block, 0,&err))) continue;		stats = levels?		   dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1):		   dx_show_leaf(hinfo, (struct ext4_dir_entry_2 *) bh->b_data, blocksize, 0);		names += stats.names;		space += stats.space;		bcount += stats.bcount;		brelse (bh);	}	if (bcount)		printk("%snames %u, fullness %u (%u%%)\n", levels?"":"   ",			names, space/bcount,(space/bcount)*100/blocksize);	return (struct stats) { names, space, bcount};}#endif /* DX_DEBUG *//* * Probe for a directory leaf block to search. * * dx_probe can return ERR_BAD_DX_DIR, which means there was a format * error in the directory index, and the caller should fall back to * searching the directory normally.  The callers of dx_probe **MUST** * check for this error code, and make sure it never gets reflected * back to userspace. */static struct dx_frame *dx_probe(struct dentry *dentry, struct inode *dir,	 struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err){	unsigned count, indirect;	struct dx_entry *at, *entries, *p, *q, *m;	struct dx_root *root;	struct buffer_head *bh;	struct dx_frame *frame = frame_in;	u32 hash;	frame->bh = NULL;	if (dentry)		dir = dentry->d_parent->d_inode;	if (!(bh = ext4_bread (NULL,dir, 0, 0, err)))		goto fail;	root = (struct dx_root *) bh->b_data;	if (root->info.hash_version != DX_HASH_TEA &&	    root->info.hash_version != DX_HASH_HALF_MD4 &&	    root->info.hash_version != DX_HASH_LEGACY) {		ext4_warning(dir->i_sb, __FUNCTION__,			     "Unrecognised inode hash code %d",			     root->info.hash_version);		brelse(bh);		*err = ERR_BAD_DX_DIR;		goto fail;	}	hinfo->hash_version = root->info.hash_version;	hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed;	if (dentry)		ext4fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);	hash = hinfo->hash;	if (root->info.unused_flags & 1) {		ext4_warning(dir->i_sb, __FUNCTION__,			     "Unimplemented inode hash flags: %#06x",			     root->info.unused_flags);		brelse(bh);		*err = ERR_BAD_DX_DIR;		goto fail;	}	if ((indirect = root->info.indirect_levels) > 1) {		ext4_warning(dir->i_sb, __FUNCTION__,			     "Unimplemented inode hash depth: %#06x",			     root->info.indirect_levels);		brelse(bh);		*err = ERR_BAD_DX_DIR;		goto fail;	}	entries = (struct dx_entry *) (((char *)&root->info) +				       root->info.info_length);	if (dx_get_limit(entries) != dx_root_limit(dir,						   root->info.info_length)) {		ext4_warning(dir->i_sb, __FUNCTION__,			     "dx entry: limit != root limit");		brelse(bh);		*err = ERR_BAD_DX_DIR;		goto fail;	}	dxtrace (printk("Look up %x", hash));	while (1)	{		count = dx_get_count(entries);		if (!count || count > dx_get_limit(entries)) {			ext4_warning(dir->i_sb, __FUNCTION__,				     "dx entry: no count or count > limit");			brelse(bh);			*err = ERR_BAD_DX_DIR;			goto fail2;		}		p = entries + 1;		q = entries + count - 1;		while (p <= q)		{			m = p + (q - p)/2;			dxtrace(printk("."));			if (dx_get_hash(m) > hash)				q = m - 1;			else				p = m + 1;		}		if (0) // linear search cross check		{			unsigned n = count - 1;			at = entries;			while (n--)			{				dxtrace(printk(","));				if (dx_get_hash(++at) > hash)				{					at--;					break;				}			}			assert (at == p - 1);		}		at = p - 1;		dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at)));		frame->bh = bh;		frame->entries = entries;		frame->at = at;		if (!indirect--) return frame;		if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err)))			goto fail2;		at = entries = ((struct dx_node *) bh->b_data)->entries;		if (dx_get_limit(entries) != dx_node_limit (dir)) {			ext4_warning(dir->i_sb, __FUNCTION__,				     "dx entry: limit != node limit");			brelse(bh);			*err = ERR_BAD_DX_DIR;			goto fail2;		}		frame++;		frame->bh = NULL;	}fail2:	while (frame >= frame_in) {		brelse(frame->bh);		frame--;	}fail:	if (*err == ERR_BAD_DX_DIR)		ext4_warning(dir->i_sb, __FUNCTION__,			     "Corrupt dir inode %ld, running e2fsck is "			     "recommended.", dir->i_ino);	return NULL;}static void dx_release (struct dx_frame *frames){	if (frames[0].bh == NULL)		return;	if (((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels)		brelse(frames[1].bh);	brelse(frames[0].bh);}/* * This function increments the frame pointer to search the next leaf * block, and reads in the necessary intervening nodes if the search * should be necessary.  Whether or not the search is necessary is

⌨️ 快捷键说明

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