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

📄 namei.c

📁 ocfs1.4.1 oracle分布式文件系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * namei.c * * Create and rename file, directory, symlinks * * Copyright (C) 2002, 2004 Oracle.  All rights reserved. * *  Portions of this code from linux/fs/ext3/dir.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/dir.c * *   Copyright (C) 1991, 1992 Linux Torvalds * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */#include <linux/fs.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/highmem.h>#define MLOG_MASK_PREFIX ML_NAMEI#include <cluster/masklog.h>#include "ocfs2.h"#include "alloc.h"#include "dcache.h"#include "dir.h"#include "dlmglue.h"#include "extent_map.h"#include "file.h"#include "inode.h"#include "journal.h"#include "namei.h"#include "suballoc.h"#include "super.h"#include "symlink.h"#include "sysfile.h"#include "uptodate.h"#include "buffer_head_io.h"static int ocfs2_mknod_locked(struct ocfs2_super *osb,			      struct inode *dir,			      struct dentry *dentry, int mode,			      dev_t dev,			      struct buffer_head **new_fe_bh,			      struct buffer_head *parent_fe_bh,			      handle_t *handle,			      struct inode **ret_inode,			      struct ocfs2_alloc_context *inode_ac);static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,				    struct inode **ret_orphan_dir,				    struct inode *inode,				    char *name,				    struct buffer_head **de_bh);static int ocfs2_orphan_add(struct ocfs2_super *osb,			    handle_t *handle,			    struct inode *inode,			    struct ocfs2_dinode *fe,			    char *name,			    struct buffer_head *de_bh,			    struct inode *orphan_dir_inode);static int ocfs2_create_symlink_data(struct ocfs2_super *osb,				     handle_t *handle,				     struct inode *inode,				     const char *symname);/* An orphan dir name is an 8 byte value, printed as a hex string */#define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64)))static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,				   struct nameidata *nd){	int status;	u64 blkno;	struct inode *inode = NULL;	struct dentry *ret;	struct ocfs2_inode_info *oi;	mlog_entry("(0x%p, 0x%p, '%.*s')\n", dir, dentry,		   dentry->d_name.len, dentry->d_name.name);	if (dentry->d_name.len > OCFS2_MAX_FILENAME_LEN) {		ret = ERR_PTR(-ENAMETOOLONG);		goto bail;	}	mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len,	     dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno);	status = ocfs2_inode_lock(dir, NULL, 0);	if (status < 0) {		if (status != -ENOENT)			mlog_errno(status);		ret = ERR_PTR(status);		goto bail;	}	status = ocfs2_lookup_ino_from_name(dir, dentry->d_name.name,					    dentry->d_name.len, &blkno);	if (status < 0)		goto bail_add;	inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0);	if (IS_ERR(inode)) {		ret = ERR_PTR(-EACCES);		goto bail_unlock;	}	oi = OCFS2_I(inode);	/* Clear any orphaned state... If we were able to look up the	 * inode from a directory, it certainly can't be orphaned. We	 * might have the bad state from a node which intended to	 * orphan this inode but crashed before it could commit the	 * unlink. */	spin_lock(&oi->ip_lock);	oi->ip_flags &= ~OCFS2_INODE_MAYBE_ORPHANED;	spin_unlock(&oi->ip_lock);bail_add:	dentry->d_op = &ocfs2_dentry_ops;	ret = d_splice_alias(inode, dentry);	if (inode) {		/*		 * If d_splice_alias() finds a DCACHE_DISCONNECTED		 * dentry, it will d_move() it on top of ourse. The		 * return value will indicate this however, so in		 * those cases, we switch them around for the locking		 * code.		 *		 * NOTE: This dentry already has ->d_op set from		 * ocfs2_get_parent() and ocfs2_get_dentry()		 */		if (ret)			dentry = ret;		status = ocfs2_dentry_attach_lock(dentry, inode,						  OCFS2_I(dir)->ip_blkno);		if (status) {			mlog_errno(status);			ret = ERR_PTR(status);			goto bail_unlock;		}	}bail_unlock:	/* Don't drop the cluster lock until *after* the d_add --	 * unlink on another node will message us to remove that	 * dentry under this lock so otherwise we can race this with	 * the downconvert thread and have a stale dentry. */	ocfs2_inode_unlock(dir, 0);bail:	mlog_exit_ptr(ret);	return ret;}static int ocfs2_mknod(struct inode *dir,		       struct dentry *dentry,		       int mode,		       dev_t dev){	int status = 0;	struct buffer_head *parent_fe_bh = NULL;	handle_t *handle = NULL;	struct ocfs2_super *osb;	struct ocfs2_dinode *dirfe;	struct buffer_head *new_fe_bh = NULL;	struct buffer_head *de_bh = NULL;	struct inode *inode = NULL;	struct ocfs2_alloc_context *inode_ac = NULL;	struct ocfs2_alloc_context *data_ac = NULL;	mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry, mode,		   (unsigned long)dev, dentry->d_name.len,		   dentry->d_name.name);	/* get our super block */	osb = OCFS2_SB(dir->i_sb);	status = ocfs2_inode_lock(dir, &parent_fe_bh, 1);	if (status < 0) {		if (status != -ENOENT)			mlog_errno(status);		return status;	}	if (S_ISDIR(mode) && (dir->i_nlink >= OCFS2_LINK_MAX)) {		status = -EMLINK;		goto leave;	}	dirfe = (struct ocfs2_dinode *) parent_fe_bh->b_data;	if (!dirfe->i_links_count) {		/* can't make a file in a deleted directory. */		status = -ENOENT;		goto leave;	}	status = ocfs2_check_dir_for_entry(dir, dentry->d_name.name,					   dentry->d_name.len);	if (status)		goto leave;	/* get a spot inside the dir. */	status = ocfs2_prepare_dir_for_insert(osb, dir, parent_fe_bh,					      dentry->d_name.name,					      dentry->d_name.len, &de_bh);	if (status < 0) {		mlog_errno(status);		goto leave;	}	/* reserve an inode spot */	status = ocfs2_reserve_new_inode(osb, &inode_ac);	if (status < 0) {		if (status != -ENOSPC)			mlog_errno(status);		goto leave;	}	/* Reserve a cluster if creating an extent based directory. */	if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) {		status = ocfs2_reserve_clusters(osb, 1, &data_ac);		if (status < 0) {			if (status != -ENOSPC)				mlog_errno(status);			goto leave;		}	}	handle = ocfs2_start_trans(osb, OCFS2_MKNOD_CREDITS);	if (IS_ERR(handle)) {		status = PTR_ERR(handle);		handle = NULL;		mlog_errno(status);		goto leave;	}	/* do the real work now. */	status = ocfs2_mknod_locked(osb, dir, dentry, mode, dev,				    &new_fe_bh, parent_fe_bh, handle,				    &inode, inode_ac);	if (status < 0) {		mlog_errno(status);		goto leave;	}	if (S_ISDIR(mode)) {		status = ocfs2_fill_new_dir(osb, handle, dir, inode,					    new_fe_bh, data_ac);		if (status < 0) {			mlog_errno(status);			goto leave;		}		status = ocfs2_journal_access(handle, dir, parent_fe_bh,					      OCFS2_JOURNAL_ACCESS_WRITE);		if (status < 0) {			mlog_errno(status);			goto leave;		}		le16_add_cpu(&dirfe->i_links_count, 1);		status = ocfs2_journal_dirty(handle, parent_fe_bh);		if (status < 0) {			mlog_errno(status);			goto leave;		}		inc_nlink(dir);	}	status = ocfs2_add_entry(handle, dentry, inode,				 OCFS2_I(inode)->ip_blkno, parent_fe_bh,				 de_bh);	if (status < 0) {		mlog_errno(status);		goto leave;	}	status = ocfs2_dentry_attach_lock(dentry, inode,					  OCFS2_I(dir)->ip_blkno);	if (status) {		mlog_errno(status);		goto leave;	}	insert_inode_hash(inode);	dentry->d_op = &ocfs2_dentry_ops;	d_instantiate(dentry, inode);	status = 0;leave:	if (handle)		ocfs2_commit_trans(osb, handle);	ocfs2_inode_unlock(dir, 1);	if (status == -ENOSPC)		mlog(0, "Disk is full\n");	if (new_fe_bh)		brelse(new_fe_bh);	if (de_bh)		brelse(de_bh);	if (parent_fe_bh)		brelse(parent_fe_bh);	if ((status < 0) && inode)		iput(inode);	if (inode_ac)		ocfs2_free_alloc_context(inode_ac);	if (data_ac)		ocfs2_free_alloc_context(data_ac);	mlog_exit(status);	return status;}static int ocfs2_mknod_locked(struct ocfs2_super *osb,			      struct inode *dir,			      struct dentry *dentry, int mode,			      dev_t dev,			      struct buffer_head **new_fe_bh,			      struct buffer_head *parent_fe_bh,			      handle_t *handle,			      struct inode **ret_inode,			      struct ocfs2_alloc_context *inode_ac){	int status = 0;	struct ocfs2_dinode *fe = NULL;	struct ocfs2_extent_list *fel;	u64 fe_blkno = 0;	u16 suballoc_bit;	struct inode *inode = NULL;	mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry, mode,		   (unsigned long)dev, dentry->d_name.len,		   dentry->d_name.name);	*new_fe_bh = NULL;	*ret_inode = NULL;	status = ocfs2_claim_new_inode(osb, handle, inode_ac, &suballoc_bit,				       &fe_blkno);	if (status < 0) {		mlog_errno(status);		goto leave;	}	inode = new_inode(dir->i_sb);	if (IS_ERR(inode)) {		status = PTR_ERR(inode);		mlog(ML_ERROR, "new_inode failed!\n");		goto leave;	}	/* populate as many fields early on as possible - many of	 * these are used by the support functions here and in	 * callers. */	inode->i_ino = ino_from_blkno(osb->sb, fe_blkno);	OCFS2_I(inode)->ip_blkno = fe_blkno;	if (S_ISDIR(mode))		inode->i_nlink = 2;	else		inode->i_nlink = 1;	inode->i_mode = mode;	spin_lock(&osb->osb_lock);	inode->i_generation = osb->s_next_generation++;	spin_unlock(&osb->osb_lock);	*new_fe_bh = sb_getblk(osb->sb, fe_blkno);	if (!*new_fe_bh) {		status = -EIO;		mlog_errno(status);		goto leave;	}	ocfs2_set_new_buffer_uptodate(inode, *new_fe_bh);	status = ocfs2_journal_access(handle, inode, *new_fe_bh,				      OCFS2_JOURNAL_ACCESS_CREATE);	if (status < 0) {		mlog_errno(status);		goto leave;	}	fe = (struct ocfs2_dinode *) (*new_fe_bh)->b_data;	memset(fe, 0, osb->sb->s_blocksize);	fe->i_generation = cpu_to_le32(inode->i_generation);	fe->i_fs_generation = cpu_to_le32(osb->fs_generation);	fe->i_blkno = cpu_to_le64(fe_blkno);	fe->i_suballoc_bit = cpu_to_le16(suballoc_bit);	fe->i_suballoc_slot = cpu_to_le16(inode_ac->ac_alloc_slot);	fe->i_uid = cpu_to_le32(current->fsuid);	if (dir->i_mode & S_ISGID) {		fe->i_gid = cpu_to_le32(dir->i_gid);		if (S_ISDIR(mode))			mode |= S_ISGID;	} else		fe->i_gid = cpu_to_le32(current->fsgid);	fe->i_mode = cpu_to_le16(mode);	if (S_ISCHR(mode) || S_ISBLK(mode))		fe->id1.dev1.i_rdev = cpu_to_le64(huge_encode_dev(dev));	fe->i_links_count = cpu_to_le16(inode->i_nlink);	fe->i_last_eb_blk = 0;	strcpy(fe->i_signature, OCFS2_INODE_SIGNATURE);	le32_add_cpu(&fe->i_flags, OCFS2_VALID_FL);	fe->i_atime = fe->i_ctime = fe->i_mtime =		cpu_to_le64(CURRENT_TIME.tv_sec);	fe->i_mtime_nsec = fe->i_ctime_nsec = fe->i_atime_nsec =		cpu_to_le32(CURRENT_TIME.tv_nsec);	fe->i_dtime = 0;	/*	 * If supported, directories start with inline data.	 */	if (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) {		u16 feat = le16_to_cpu(fe->i_dyn_features);		fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL);		fe->id2.i_data.id_count = cpu_to_le16(ocfs2_max_inline_data(osb->sb));	} else {		fel = &fe->id2.i_list;		fel->l_tree_depth = 0;		fel->l_next_free_rec = 0;		fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb));	}	status = ocfs2_journal_dirty(handle, *new_fe_bh);	if (status < 0) {		mlog_errno(status);		goto leave;	}	if (ocfs2_populate_inode(inode, fe, 1) < 0) {		mlog(ML_ERROR, "populate inode failed! bh->b_blocknr=%llu, "		     "i_blkno=%llu, i_ino=%lu\n",		     (unsigned long long)(*new_fe_bh)->b_blocknr,		     (unsigned long long)le64_to_cpu(fe->i_blkno),		     inode->i_ino);		BUG();	}	ocfs2_inode_set_new(osb, inode);	if (!ocfs2_mount_local(osb)) {

⌨️ 快捷键说明

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