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

📄 namei.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	return add_dirent_to_buf(handle, dentry, inode, de, bh);}/* *	ext4_add_entry() * * adds a file entry to the specified directory, using the same * semantics as ext4_find_entry(). It returns NULL if it failed. * * NOTE!! The inode part of 'de' is left at 0 - which means you * may not sleep between calling this and putting something into * the entry, as someone else might have used it while you slept. */static int ext4_add_entry (handle_t *handle, struct dentry *dentry,	struct inode *inode){	struct inode *dir = dentry->d_parent->d_inode;	unsigned long offset;	struct buffer_head * bh;	struct ext4_dir_entry_2 *de;	struct super_block * sb;	int	retval;	int	dx_fallback=0;	unsigned blocksize;	u32 block, blocks;	sb = dir->i_sb;	blocksize = sb->s_blocksize;	if (!dentry->d_name.len)		return -EINVAL;	if (is_dx(dir)) {		retval = ext4_dx_add_entry(handle, dentry, inode);		if (!retval || (retval != ERR_BAD_DX_DIR))			return retval;		EXT4_I(dir)->i_flags &= ~EXT4_INDEX_FL;		dx_fallback++;		ext4_mark_inode_dirty(handle, dir);	}	blocks = dir->i_size >> sb->s_blocksize_bits;	for (block = 0, offset = 0; block < blocks; block++) {		bh = ext4_bread(handle, dir, block, 0, &retval);		if(!bh)			return retval;		retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh);		if (retval != -ENOSPC)			return retval;		if (blocks == 1 && !dx_fallback &&		    EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX))			return make_indexed_dir(handle, dentry, inode, bh);		brelse(bh);	}	bh = ext4_append(handle, dir, &block, &retval);	if (!bh)		return retval;	de = (struct ext4_dir_entry_2 *) bh->b_data;	de->inode = 0;	de->rec_len = cpu_to_le16(blocksize);	return add_dirent_to_buf(handle, dentry, inode, de, bh);}/* * Returns 0 for success, or a negative error value */static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,			     struct inode *inode){	struct dx_frame frames[2], *frame;	struct dx_entry *entries, *at;	struct dx_hash_info hinfo;	struct buffer_head * bh;	struct inode *dir = dentry->d_parent->d_inode;	struct super_block * sb = dir->i_sb;	struct ext4_dir_entry_2 *de;	int err;	frame = dx_probe(dentry, NULL, &hinfo, frames, &err);	if (!frame)		return err;	entries = frame->entries;	at = frame->at;	if (!(bh = ext4_bread(handle,dir, dx_get_block(frame->at), 0, &err)))		goto cleanup;	BUFFER_TRACE(bh, "get_write_access");	err = ext4_journal_get_write_access(handle, bh);	if (err)		goto journal_error;	err = add_dirent_to_buf(handle, dentry, inode, NULL, bh);	if (err != -ENOSPC) {		bh = NULL;		goto cleanup;	}	/* Block full, should compress but for now just split */	dxtrace(printk("using %u of %u node entries\n",		       dx_get_count(entries), dx_get_limit(entries)));	/* Need to split index? */	if (dx_get_count(entries) == dx_get_limit(entries)) {		u32 newblock;		unsigned icount = dx_get_count(entries);		int levels = frame - frames;		struct dx_entry *entries2;		struct dx_node *node2;		struct buffer_head *bh2;		if (levels && (dx_get_count(frames->entries) ==			       dx_get_limit(frames->entries))) {			ext4_warning(sb, __FUNCTION__,				     "Directory index full!");			err = -ENOSPC;			goto cleanup;		}		bh2 = ext4_append (handle, dir, &newblock, &err);		if (!(bh2))			goto cleanup;		node2 = (struct dx_node *)(bh2->b_data);		entries2 = node2->entries;		node2->fake.rec_len = cpu_to_le16(sb->s_blocksize);		node2->fake.inode = 0;		BUFFER_TRACE(frame->bh, "get_write_access");		err = ext4_journal_get_write_access(handle, frame->bh);		if (err)			goto journal_error;		if (levels) {			unsigned icount1 = icount/2, icount2 = icount - icount1;			unsigned hash2 = dx_get_hash(entries + icount1);			dxtrace(printk("Split index %i/%i\n", icount1, icount2));			BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */			err = ext4_journal_get_write_access(handle,							     frames[0].bh);			if (err)				goto journal_error;			memcpy ((char *) entries2, (char *) (entries + icount1),				icount2 * sizeof(struct dx_entry));			dx_set_count (entries, icount1);			dx_set_count (entries2, icount2);			dx_set_limit (entries2, dx_node_limit(dir));			/* Which index block gets the new entry? */			if (at - entries >= icount1) {				frame->at = at = at - entries - icount1 + entries2;				frame->entries = entries = entries2;				swap(frame->bh, bh2);			}			dx_insert_block (frames + 0, hash2, newblock);			dxtrace(dx_show_index ("node", frames[1].entries));			dxtrace(dx_show_index ("node",			       ((struct dx_node *) bh2->b_data)->entries));			err = ext4_journal_dirty_metadata(handle, bh2);			if (err)				goto journal_error;			brelse (bh2);		} else {			dxtrace(printk("Creating second level index...\n"));			memcpy((char *) entries2, (char *) entries,			       icount * sizeof(struct dx_entry));			dx_set_limit(entries2, dx_node_limit(dir));			/* Set up root */			dx_set_count(entries, 1);			dx_set_block(entries + 0, newblock);			((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1;			/* Add new access path frame */			frame = frames + 1;			frame->at = at = at - entries + entries2;			frame->entries = entries = entries2;			frame->bh = bh2;			err = ext4_journal_get_write_access(handle,							     frame->bh);			if (err)				goto journal_error;		}		ext4_journal_dirty_metadata(handle, frames[0].bh);	}	de = do_split(handle, dir, &bh, frame, &hinfo, &err);	if (!de)		goto cleanup;	err = add_dirent_to_buf(handle, dentry, inode, de, bh);	bh = NULL;	goto cleanup;journal_error:	ext4_std_error(dir->i_sb, err);cleanup:	if (bh)		brelse(bh);	dx_release(frames);	return err;}/* * ext4_delete_entry deletes a directory entry by merging it with the * previous entry */static int ext4_delete_entry (handle_t *handle,			      struct inode * dir,			      struct ext4_dir_entry_2 * de_del,			      struct buffer_head * bh){	struct ext4_dir_entry_2 * de, * pde;	int i;	i = 0;	pde = NULL;	de = (struct ext4_dir_entry_2 *) bh->b_data;	while (i < bh->b_size) {		if (!ext4_check_dir_entry("ext4_delete_entry", dir, de, bh, i))			return -EIO;		if (de == de_del)  {			BUFFER_TRACE(bh, "get_write_access");			ext4_journal_get_write_access(handle, bh);			if (pde)				pde->rec_len =					cpu_to_le16(le16_to_cpu(pde->rec_len) +						    le16_to_cpu(de->rec_len));			else				de->inode = 0;			dir->i_version++;			BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata");			ext4_journal_dirty_metadata(handle, bh);			return 0;		}		i += le16_to_cpu(de->rec_len);		pde = de;		de = (struct ext4_dir_entry_2 *)			((char *) de + le16_to_cpu(de->rec_len));	}	return -ENOENT;}/* * DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2, * since this indicates that nlinks count was previously 1. */static void ext4_inc_count(handle_t *handle, struct inode *inode){	inc_nlink(inode);	if (is_dx(inode) && inode->i_nlink > 1) {		/* limit is 16-bit i_links_count */		if (inode->i_nlink >= EXT4_LINK_MAX || inode->i_nlink == 2) {			inode->i_nlink = 1;			EXT4_SET_RO_COMPAT_FEATURE(inode->i_sb,					      EXT4_FEATURE_RO_COMPAT_DIR_NLINK);		}	}}/* * If a directory had nlink == 1, then we should let it be 1. This indicates * directory has >EXT4_LINK_MAX subdirs. */static void ext4_dec_count(handle_t *handle, struct inode *inode){	drop_nlink(inode);	if (S_ISDIR(inode->i_mode) && inode->i_nlink == 0)		inc_nlink(inode);}static int ext4_add_nondir(handle_t *handle,		struct dentry *dentry, struct inode *inode){	int err = ext4_add_entry(handle, dentry, inode);	if (!err) {		ext4_mark_inode_dirty(handle, inode);		d_instantiate(dentry, inode);		return 0;	}	drop_nlink(inode);	iput(inode);	return err;}/* * By the time this is called, we already have created * the directory cache entry for the new file, but it * is so far negative - it has no inode. * * If the create succeeds, we fill in the inode information * with d_instantiate(). */static int ext4_create (struct inode * dir, struct dentry * dentry, int mode,		struct nameidata *nd){	handle_t *handle;	struct inode * inode;	int err, retries = 0;retry:	handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +					EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +					2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));	if (IS_ERR(handle))		return PTR_ERR(handle);	if (IS_DIRSYNC(dir))		handle->h_sync = 1;	inode = ext4_new_inode (handle, dir, mode);	err = PTR_ERR(inode);	if (!IS_ERR(inode)) {		inode->i_op = &ext4_file_inode_operations;		inode->i_fop = &ext4_file_operations;		ext4_set_aops(inode);		err = ext4_add_nondir(handle, dentry, inode);	}	ext4_journal_stop(handle);	if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))		goto retry;	return err;}static int ext4_mknod (struct inode * dir, struct dentry *dentry,			int mode, dev_t rdev){	handle_t *handle;	struct inode *inode;	int err, retries = 0;	if (!new_valid_dev(rdev))		return -EINVAL;retry:	handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +					EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +					2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));	if (IS_ERR(handle))		return PTR_ERR(handle);	if (IS_DIRSYNC(dir))		handle->h_sync = 1;	inode = ext4_new_inode (handle, dir, mode);	err = PTR_ERR(inode);	if (!IS_ERR(inode)) {		init_special_inode(inode, inode->i_mode, rdev);#ifdef CONFIG_EXT4DEV_FS_XATTR		inode->i_op = &ext4_special_inode_operations;#endif		err = ext4_add_nondir(handle, dentry, inode);	}	ext4_journal_stop(handle);	if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))		goto retry;	return err;}static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode){	handle_t *handle;	struct inode * inode;	struct buffer_head * dir_block;	struct ext4_dir_entry_2 * de;	int err, retries = 0;	if (EXT4_DIR_LINK_MAX(dir))		return -EMLINK;retry:	handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +					EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +					2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));	if (IS_ERR(handle))		return PTR_ERR(handle);	if (IS_DIRSYNC(dir))		handle->h_sync = 1;	inode = ext4_new_inode (handle, dir, S_IFDIR | mode);	err = PTR_ERR(inode);	if (IS_ERR(inode))		goto out_stop;	inode->i_op = &ext4_dir_inode_operations;	inode->i_fop = &ext4_dir_operations;	inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;	dir_block = ext4_bread (handle, inode, 0, 1, &err);	if (!dir_block) {		ext4_dec_count(handle, inode); /* is this nlink == 0? */		ext4_mark_inode_dirty(handle, inode);		iput (inode);		goto out_stop;	}	BUFFER_TRACE(dir_block, "get_write_access");	ext4_journal_get_write_access(handle, dir_block);	de = (struct ext4_dir_entry_2 *) dir_block->b_data;	de->inode = cpu_to_le32(inode->i_ino);	de->name_len = 1;	de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(de->name_len));	strcpy (de->name, ".");	ext4_set_de_type(dir->i_sb, de, S_IFDIR);	de = (struct ext4_dir_entry_2 *)			((char *) de + le16_to_cpu(de->rec_len));	de->inode = cpu_to_le32(dir->i_ino);	de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize-EXT4_DIR_REC_LEN(1));	de->name_len = 2;	strcpy (de->name, "..");	ext4_set_de_type(dir->i_sb, de, S_IFDIR);	inode->i_nlink = 2;	BUFFER_TRACE(dir_block, "call ext4_journal_dirty_metadata");	ext4_journal_dirty_metadata(handle, dir_block);	brelse (dir_block);	ext4_mark_inode_dirty(handle, inode);	err = ext4_add_entry (handle, dentry, inode);	if (err) {		inode->i_nlink = 0;		ext4_mark_inode_dirty(handle, inode);		iput (inode);		goto out_stop;	}	ext4_inc_count(handle, dir);	ext4_update_dx_flag(dir);	ext4_mark_inode_dirty(handle, dir);	d_instantiate(dentry, inode);out_stop:	ext4_journal_stop(handle);	if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))		goto retry;	return err;}/* * routine to check that the specified directory is empty (for rmdir) */static int empty_dir (struct inode * inode){	unsigned long offset;	struct buffer_head * bh;	struct ext4_dir_entry_2 * de, * de1;	struct super_block * sb;	int err = 0;	sb = inode->i_sb;	if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) ||	    !(bh = ext4_bread (NULL, inode, 0, 0, &err))) {		if (err)			ext4_error(inode->i_sb, __FUNCTION__,				   "error %d reading directory #%lu offset 0",				   err, inode->i_ino);		else			ext4_warning(inode->i_sb, __FUNCTION__,				     "bad directory (dir #%lu) - no data block",				     inode->i_ino);		return 1;	}	de = (struct ext4_dir_entry_2 *) bh->b_data;	de1 = (struct ext4_dir_entry_2 *)			((char *) de + le16_to_cpu(de->rec_len));	if (le32_to_cpu(de->inode) != inode->i_ino ||			!le32_to_cpu(de1->inode) ||			strcmp (".", de->name) ||			strcmp ("..", de1->name)) {		ext4_warning (inode->i_sb, "empty_dir",			      "bad directory (dir #%lu) - no `.' or `..'",			      inode->i_ino);		brelse (bh);		return 1;	}	offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);	de = (struct ext4_dir_entry_2 *)			((char *) de1 + le16_to_cpu(de1->rec_len));	while (offset < inode->i_size ) {		if (!bh ||			(void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {			err = 0;			brelse (bh);			bh = ext4_bread (NULL, inode,				offset >> EXT4_BLOCK_SIZE_BITS(sb), 0, &err);			if (!bh) {				if (err)

⌨️ 快捷键说明

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