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

📄 namei.c

📁 ocfs1.2.7 源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	const int rlen = le16_to_cpu(de->rec_len);	if (rlen < OCFS2_DIR_REC_LEN(1))		error_msg = "rec_len is smaller than minimal";	else if (rlen % 4 != 0)		error_msg = "rec_len % 4 != 0";	else if (rlen < OCFS2_DIR_REC_LEN(de->name_len))		error_msg = "rec_len is too small for name_len";	else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)		error_msg = "directory entry across blocks";	if (error_msg != NULL)		mlog(ML_ERROR, "bad entry in directory #%"MLFu64": %s - "		     "offset=%lu, inode=%"MLFu64", rec_len=%d, name_len=%d\n",		     OCFS2_I(dir)->ip_blkno, error_msg, offset,		     le64_to_cpu(de->inode), rlen, de->name_len);	return error_msg == NULL ? 1 : 0;}/* we don't always have a dentry for what we want to add, so people * like orphan dir can call this instead. * * If you pass me insert_bh, I'll skip the search of the other dir * blocks and put the record in there. */static int __ocfs2_add_entry(struct ocfs2_journal_handle *handle,			     struct inode *dir,			     const char *name, int namelen,			     struct inode *inode, u64 blkno,			     struct buffer_head *parent_fe_bh,			     struct buffer_head *insert_bh){	unsigned long offset;	unsigned short rec_len;	struct ocfs2_dir_entry *de, *de1;	struct super_block *sb;	int retval, status;	mlog_entry_void();	sb = dir->i_sb;	if (!namelen)		return -EINVAL;	rec_len = OCFS2_DIR_REC_LEN(namelen);	offset = 0;	de = (struct ocfs2_dir_entry *) insert_bh->b_data;	while (1) {		BUG_ON((char *)de >= sb->s_blocksize + insert_bh->b_data);		/* These checks should've already been passed by the		 * prepare function, but I guess we can leave them		 * here anyway. */		if (!ocfs2_check_dir_entry(dir, de, insert_bh, offset)) {			retval = -ENOENT;			goto bail;		}		if (ocfs2_match(namelen, name, de)) {			retval = -EEXIST;			goto bail;		}		if (((le64_to_cpu(de->inode) == 0) &&		     (le16_to_cpu(de->rec_len) >= rec_len)) ||		    (le16_to_cpu(de->rec_len) >=		     (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) {			dir->i_mtime = dir->i_ctime = CURRENT_TIME;			retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh);			if (retval < 0) {				mlog_errno(retval);				goto bail;			}			status = ocfs2_journal_access(handle, dir, insert_bh,						      OCFS2_JOURNAL_ACCESS_WRITE);			/* By now the buffer is marked for journaling */			offset += le16_to_cpu(de->rec_len);			if (le64_to_cpu(de->inode)) {				de1 = (struct ocfs2_dir_entry *)((char *) de +					OCFS2_DIR_REC_LEN(de->name_len));				de1->rec_len =					cpu_to_le16(le16_to_cpu(de->rec_len) -					OCFS2_DIR_REC_LEN(de->name_len));				de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));				de = de1;			}			de->file_type = OCFS2_FT_UNKNOWN;			if (blkno) {				de->inode = cpu_to_le64(blkno);				ocfs2_set_de_type(de, inode->i_mode);			} else				de->inode = 0;			de->name_len = namelen;			memcpy(de->name, name, namelen);			dir->i_version++;			status = ocfs2_journal_dirty(handle, insert_bh);			retval = 0;			goto bail;		}		offset += le16_to_cpu(de->rec_len);		de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));	}	/* when you think about it, the assert above should prevent us	 * from ever getting here. */	retval = -ENOSPC;bail:	mlog_exit(retval);	return retval;}/* * ocfs2_delete_entry deletes a directory entry by merging it with the * previous entry */static int ocfs2_delete_entry(struct ocfs2_journal_handle *handle,			      struct inode *dir,			      struct ocfs2_dir_entry *de_del,			      struct buffer_head *bh){	struct ocfs2_dir_entry *de, *pde;	int i, status = -ENOENT;	mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh);	i = 0;	pde = NULL;	de = (struct ocfs2_dir_entry *) bh->b_data;	while (i < bh->b_size) {		if (!ocfs2_check_dir_entry(dir, de, bh, i)) {			status = -EIO;			mlog_errno(status);			goto bail;		}		if (de == de_del)  {			status = ocfs2_journal_access(handle, dir, bh,						      OCFS2_JOURNAL_ACCESS_WRITE);			if (status < 0) {				status = -EIO;				mlog_errno(status);				goto bail;			}			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++;			status = ocfs2_journal_dirty(handle, bh);			goto bail;		}		i += le16_to_cpu(de->rec_len);		pde = de;		de = (struct ocfs2_dir_entry *)((char *)de + le16_to_cpu(de->rec_len));	}bail:	mlog_exit(status);	return status;}/* * Returns 0 if not found, -1 on failure, and 1 on success */static int inline ocfs2_search_dirblock(struct buffer_head *bh,					struct inode *dir,					const char *name, int namelen,					unsigned long offset,					struct ocfs2_dir_entry **res_dir){	struct ocfs2_dir_entry *de;	char *dlimit, *de_buf;	int de_len;	int ret = 0;	mlog_entry_void();	de_buf = bh->b_data;	dlimit = de_buf + dir->i_sb->s_blocksize;	while (de_buf < dlimit) {		/* this code is executed quadratically often */		/* do minimal checking `by hand' */		de = (struct ocfs2_dir_entry *) de_buf;		if (de_buf + namelen <= dlimit &&		    ocfs2_match(namelen, name, de)) {			/* found a match - just to be sure, do a full check */			if (!ocfs2_check_dir_entry(dir, de, bh, offset)) {				ret = -1;				goto bail;			}			*res_dir = de;			ret = 1;			goto bail;		}		/* prevent looping on a bad block */		de_len = le16_to_cpu(de->rec_len);		if (de_len <= 0) {			ret = -1;			goto bail;		}		de_buf += de_len;		offset += de_len;	}bail:	mlog_exit(ret);	return ret;}struct buffer_head *ocfs2_find_entry(const char *name, int namelen,				     struct inode *dir,				     struct ocfs2_dir_entry **res_dir){	struct super_block *sb;	struct buffer_head *bh_use[NAMEI_RA_SIZE];	struct buffer_head *bh, *ret = NULL;	unsigned long start, block, b;	int ra_max = 0;		/* Number of bh's in the readahead				   buffer, bh_use[] */	int ra_ptr = 0;		/* Current index into readahead				   buffer */	int num = 0;	int nblocks, i, err;	mlog_entry_void();	*res_dir = NULL;	sb = dir->i_sb;	nblocks = i_size_read(dir) >> sb->s_blocksize_bits;	start = OCFS2_I(dir)->ip_dir_start_lookup;	if (start >= nblocks)		start = 0;	block = start;restart:	do {		/*		 * We deal with the read-ahead logic here.		 */		if (ra_ptr >= ra_max) {			/* Refill the readahead buffer */			ra_ptr = 0;			b = block;			for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) {				/*				 * Terminate if we reach the end of the				 * directory and must wrap, or if our				 * search has finished at this block.				 */				if (b >= nblocks || (num && block == start)) {					bh_use[ra_max] = NULL;					break;				}				num++;				/* XXX: questionable readahead stuff here */				bh = ocfs2_bread(dir, b++, &err, 1);				bh_use[ra_max] = bh;#if 0		// ???				if (bh)					ll_rw_block(READ, 1, &bh);#endif			}		}		if ((bh = bh_use[ra_ptr++]) == NULL)			goto next;		wait_on_buffer(bh);		if (!buffer_uptodate(bh)) {			/* read error, skip block & hope for the best */			brelse(bh);			goto next;		}		i = ocfs2_search_dirblock(bh, dir, name, namelen,					  block << sb->s_blocksize_bits,					  res_dir);		if (i == 1) {			OCFS2_I(dir)->ip_dir_start_lookup = block;			ret = bh;			goto cleanup_and_exit;		} else {			brelse(bh);			if (i < 0)				goto cleanup_and_exit;		}	next:		if (++block >= nblocks)			block = 0;	} while (block != start);	/*	 * If the directory has grown while we were searching, then	 * search the last part of the directory before giving up.	 */	block = nblocks;	nblocks = i_size_read(dir) >> sb->s_blocksize_bits;	if (block < nblocks) {		start = 0;		goto restart;	}cleanup_and_exit:	/* Clean up the read-ahead blocks */	for (; ra_ptr < ra_max; ra_ptr++)		brelse(bh_use[ra_ptr]);	mlog_exit_ptr(ret);	return ret;}static int ocfs2_blkno_stringify(u64 blkno, char *name){	int status, namelen;	mlog_entry_void();	namelen = snprintf(name, OCFS2_ORPHAN_NAMELEN + 1, "%016"MLFx64,			   blkno);	if (namelen <= 0) {		if (namelen)			status = namelen;		else			status = -EINVAL;		mlog_errno(status);		goto bail;	}	if (namelen != OCFS2_ORPHAN_NAMELEN) {		status = -EINVAL;		mlog_errno(status);		goto bail;	}	mlog(0, "built filename '%s' for orphan dir (len=%d)\n", name,	     namelen);	status = 0;bail:	mlog_exit(status);	return status;}static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,				    struct ocfs2_journal_handle *handle,				    struct inode *inode,				    char *name,				    struct buffer_head **de_bh){	struct inode *orphan_dir_inode = NULL;	struct buffer_head *orphan_dir_bh = NULL;	int status = 0;	status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, name);	if (status < 0) {		mlog_errno(status);		goto leave;	}	orphan_dir_inode = ocfs2_get_system_file_inode(osb,						       ORPHAN_DIR_SYSTEM_INODE,						       osb->slot_num);	if (!orphan_dir_inode) {		status = -ENOENT;		mlog_errno(status);		goto leave;	}	ocfs2_handle_add_inode(handle, orphan_dir_inode);	status = ocfs2_meta_lock(orphan_dir_inode, handle, &orphan_dir_bh, 1);	if (status < 0) {		mlog_errno(status);		goto leave;	}	status = ocfs2_prepare_dir_for_insert(osb, orphan_dir_inode,					      orphan_dir_bh, name,					      OCFS2_ORPHAN_NAMELEN, de_bh);	if (status < 0) {		mlog_errno(status);		goto leave;	}leave:	if (orphan_dir_inode)		iput(orphan_dir_inode);	if (orphan_dir_bh)		brelse(orphan_dir_bh);	mlog_exit(status);	return status;}static int ocfs2_orphan_add(struct ocfs2_super *osb,			    struct ocfs2_journal_handle *handle,			    struct inode *inode,			    struct ocfs2_dinode *fe,			    char *name,			    struct buffer_head *de_bh){	struct inode *orphan_dir_inode = NULL;	struct buffer_head *orphan_dir_bh = NULL;	int status = 0;	struct ocfs2_dinode *orphan_fe;	mlog_entry("(inode->i_ino = %lu)\n", inode->i_ino);	orphan_dir_inode = ocfs2_get_system_file_inode(osb,						       ORPHAN_DIR_SYSTEM_INODE,						       osb->slot_num);	if (!orphan_dir_inode) {		status = -ENOENT;		mlog_errno(status);		goto leave;	}	status = ocfs2_read_block(osb,				  OCFS2_I(orphan_dir_inode)->ip_blkno,				  &orphan_dir_bh, OCFS2_BH_CACHED,				  orphan_dir_inode);	if (status < 0) {		mlog_errno(status);		goto leave;	}	status = ocfs2_journal_access(handle, orphan_dir_inode, orphan_dir_bh,				      OCFS2_JOURNAL_ACCESS_WRITE);	if (status < 0) {		mlog_errno(status);		goto leave;	}	/* we're a cluster, and nlink can change on disk from	 * underneath us... */	orphan_fe = (struct ocfs2_dinode *) orphan_dir_bh->b_data;	if (S_ISDIR(inode->i_mode))		le16_add_cpu(&orphan_fe->i_links_count, 1);	orphan_dir_inode->i_nlink = le16_to_cpu(orphan_fe->i_links_count);	status = ocfs2_journal_dirty(handle, orphan_dir_bh);	if (status < 0) {		mlog_errno(status);		goto leave;	}	status = __ocfs2_add_entry(handle, orphan_dir_inode, name,				   OCFS2_ORPHAN_NAMELEN, inode,				   OCFS2_I(inode)->ip_blkno,				   orphan_dir_bh, de_bh);	if (status < 0) {		mlog_errno(status);		goto leave;	}	le32_add_cpu(&fe->i_flags, OCFS2_ORPHANED_FL);	/* Record which orphan dir our inode now resides	 * in. delete_inode will use this to determine which orphan	 * dir to lock. */	spin_lock(&OCFS2_I(inode)->ip_lock);	OCFS2_I(inode)->ip_orphaned_slot = osb->slot_num;	spin_unlock(&OCFS2_I(inode)->ip_lock);	mlog(0, "Inode %"MLFu64" orphaned in slot %d\n",	     OCFS2_I(inode)->ip_blkno, osb->slot_num);leave:	if (orphan_dir_inode)		iput(orphan_dir_inode);	if (orphan_dir_bh)		brelse(orphan_dir_bh);	mlog_exit(status);	return status;}/* unlike orphan_add, we expect the orphan dir to already be locked here. */int ocfs2_orphan_del(struct ocfs2_super *osb,		     struct ocfs2_journal_handle *handle,		     struct inode *orphan_dir_inode,		     struct inode *inode,		     struct buffer_head *orphan_dir_bh){	char name[OCFS2_ORPHAN_NAMELEN + 1];	struct ocfs2_dinode *orphan_fe;	int status = 0;	struct buffer_head *target_de_bh = NULL;	struct ocfs2_dir_entry *target_de = NULL;	mlog_entry_void();	status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, name);	if (status < 0) {		mlog_errno(status);		goto leave;	}	mlog(0, "removing '%s' from orphan dir %"MLFu64" (namelen=%d)\n",	     name, OCFS2_I(orphan_dir_inode)->ip_blkno, OCFS2_ORPHAN_NAMELEN);	/* find it's spot in the orphan directory */	target_de_bh = ocfs2_find_entry(name, OCFS2_ORPHAN_NAMELEN,					orphan_dir_inode, &target_de);	if (!target_de_bh) {		status = -ENOENT;		mlog_errno(status);		goto leave;	}	/* remove it from the orphan directory */	status = ocfs2_delete_entry(handle, orphan_dir_inode, target_de,				    target_de_bh);	if (status < 0) {		mlog_errno(status);		goto leave;	}	status = ocfs2_journal_access(handle,orphan_dir_inode,  orphan_dir_bh,				      OCFS2_JOURNAL_ACCESS_WRITE);	if (status < 0) {		mlog_errno(status);		goto leave;	}	/* do the i_nlink dance! :) */	orphan_fe = (struct ocfs2_dinode *) orphan_dir_bh->b_data;	if (S_ISDIR(inode->i_mode))		le16_add_cpu(&orphan_fe->i_links_count, -1);	orphan_dir_inode->i_nlink = le16_to_cpu(orphan_fe->i_links_count);	status = ocfs2_journal_dirty(handle, orphan_dir_bh);	if (status < 0) {		mlog_errno(status);		goto leave;	}leave:	if (target_de_bh)		brelse(target_de_bh);	mlog_exit(status);	return status;}struct inode_operations ocfs2_dir_iops = {	.create		= ocfs2_create,	.lookup		= ocfs2_lookup,	.link		= ocfs2_link,	.unlink		= ocfs2_unlink,	.rmdir		= ocfs2_unlink,	.symlink	= ocfs2_symlink,	.mkdir		= ocfs2_mkdir,	.mknod		= ocfs2_mknod,	.rename		= ocfs2_rename,	.setattr	= ocfs2_setattr,	.getattr	= ocfs2_getattr,};

⌨️ 快捷键说明

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