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

📄 ops_inode.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		if (ip == nip)			return 0;	}	/* Make sure we aren't trying to move a dirctory into it's subdir */	if (S_ISDIR(ip->i_inode.i_mode) && odip != ndip) {		dir_rename = 1;		error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, 0,					   &r_gh);		if (error)			goto out;		error = gfs2_ok_to_move(ip, ndip);		if (error)			goto out_gunlock_r;	}	num_gh = 1;	gfs2_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);	if (odip != ndip) {		gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);		num_gh++;	}	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);	num_gh++;	if (nip) {		gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);		num_gh++;		/* grab the resource lock for unlink flag twiddling 		 * this is the case of the target file already existing		 * so we unlink before doing the rename		 */		nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr);		if (nrgd)			gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++);	}	error = gfs2_glock_nq_m(num_gh, ghs);	if (error)		goto out_uninit;	/* Check out the old directory */	error = gfs2_unlink_ok(odip, &odentry->d_name, ip);	if (error)		goto out_gunlock;	/* Check out the new directory */	if (nip) {		error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip);		if (error)			goto out_gunlock;		if (S_ISDIR(nip->i_inode.i_mode)) {			if (nip->i_di.di_entries < 2) {				if (gfs2_consist_inode(nip))					gfs2_dinode_print(nip);				error = -EIO;				goto out_gunlock;			}			if (nip->i_di.di_entries > 2) {				error = -ENOTEMPTY;				goto out_gunlock;			}		}	} else {		error = permission(ndir, MAY_WRITE | MAY_EXEC, NULL);		if (error)			goto out_gunlock;		error = gfs2_dir_check(ndir, &ndentry->d_name, NULL);		switch (error) {		case -ENOENT:			error = 0;			break;		case 0:			error = -EEXIST;		default:			goto out_gunlock;		};		if (odip != ndip) {			if (!ndip->i_inode.i_nlink) {				error = -EINVAL;				goto out_gunlock;			}			if (ndip->i_di.di_entries == (u32)-1) {				error = -EFBIG;				goto out_gunlock;			}			if (S_ISDIR(ip->i_inode.i_mode) &&			    ndip->i_inode.i_nlink == (u32)-1) {				error = -EMLINK;				goto out_gunlock;			}		}	}	/* Check out the dir to be renamed */	if (dir_rename) {		error = permission(odentry->d_inode, MAY_WRITE, NULL);		if (error)			goto out_gunlock;	}	alloc_required = error = gfs2_diradd_alloc_required(ndir, &ndentry->d_name);	if (error < 0)		goto out_gunlock;	error = 0;	if (alloc_required) {		struct gfs2_alloc *al = gfs2_alloc_get(ndip);		error = gfs2_quota_lock(ndip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);		if (error)			goto out_alloc;		error = gfs2_quota_check(ndip, ndip->i_inode.i_uid, ndip->i_inode.i_gid);		if (error)			goto out_gunlock_q;		al->al_requested = sdp->sd_max_dirres;		error = gfs2_inplace_reserve(ndip);		if (error)			goto out_gunlock_q;		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +					 al->al_rgd->rd_length +					 4 * RES_DINODE + 4 * RES_LEAF +					 RES_STATFS + RES_QUOTA + 4, 0);		if (error)			goto out_ipreserv;	} else {		error = gfs2_trans_begin(sdp, 4 * RES_DINODE +					 5 * RES_LEAF + 4, 0);		if (error)			goto out_gunlock;	}	/* Remove the target file, if it exists */	if (nip) {		if (S_ISDIR(nip->i_inode.i_mode))			error = gfs2_rmdiri(ndip, &ndentry->d_name, nip);		else {			error = gfs2_dir_del(ndip, &ndentry->d_name);			if (error)				goto out_end_trans;			error = gfs2_change_nlink(nip, -1);		}		if (error)			goto out_end_trans;	}	if (dir_rename) {		struct qstr name;		gfs2_str2qstr(&name, "..");		error = gfs2_change_nlink(ndip, +1);		if (error)			goto out_end_trans;		error = gfs2_change_nlink(odip, -1);		if (error)			goto out_end_trans;		error = gfs2_dir_mvino(ip, &name, ndip, DT_DIR);		if (error)			goto out_end_trans;	} else {		struct buffer_head *dibh;		error = gfs2_meta_inode_buffer(ip, &dibh);		if (error)			goto out_end_trans;		ip->i_inode.i_ctime = CURRENT_TIME;		gfs2_trans_add_bh(ip->i_gl, dibh, 1);		gfs2_dinode_out(ip, dibh->b_data);		brelse(dibh);	}	error = gfs2_dir_del(odip, &odentry->d_name);	if (error)		goto out_end_trans;	error = gfs2_dir_add(ndir, &ndentry->d_name, ip, IF2DT(ip->i_inode.i_mode));	if (error)		goto out_end_trans;out_end_trans:	gfs2_trans_end(sdp);out_ipreserv:	if (alloc_required)		gfs2_inplace_release(ndip);out_gunlock_q:	if (alloc_required)		gfs2_quota_unlock(ndip);out_alloc:	if (alloc_required)		gfs2_alloc_put(ndip);out_gunlock:	gfs2_glock_dq_m(num_gh, ghs);out_uninit:	for (x = 0; x < num_gh; x++)		gfs2_holder_uninit(ghs + x);out_gunlock_r:	if (dir_rename)		gfs2_glock_dq_uninit(&r_gh);out:	return error;}/** * gfs2_readlink - Read the value of a symlink * @dentry: the symlink * @buf: the buffer to read the symlink data into * @size: the size of the buffer * * Returns: errno */static int gfs2_readlink(struct dentry *dentry, char __user *user_buf,			 int user_size){	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);	char array[GFS2_FAST_NAME_SIZE], *buf = array;	unsigned int len = GFS2_FAST_NAME_SIZE;	int error;	error = gfs2_readlinki(ip, &buf, &len);	if (error)		return error;	if (user_size > len - 1)		user_size = len - 1;	if (copy_to_user(user_buf, buf, user_size))		error = -EFAULT;	else		error = user_size;	if (buf != array)		kfree(buf);	return error;}/** * gfs2_follow_link - Follow a symbolic link * @dentry: The dentry of the link * @nd: Data that we pass to vfs_follow_link() * * This can handle symlinks of any size. It is optimised for symlinks * under GFS2_FAST_NAME_SIZE. * * Returns: 0 on success or error code */static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd){	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);	char array[GFS2_FAST_NAME_SIZE], *buf = array;	unsigned int len = GFS2_FAST_NAME_SIZE;	int error;	error = gfs2_readlinki(ip, &buf, &len);	if (!error) {		error = vfs_follow_link(nd, buf);		if (buf != array)			kfree(buf);	}	return ERR_PTR(error);}/** * gfs2_permission - * @inode: * @mask: * @nd: passed from Linux VFS, ignored by us * * This may be called from the VFS directly, or from within GFS2 with the * inode locked, so we look to see if the glock is already locked and only * lock the glock if its not already been done. * * Returns: errno */static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd){	struct gfs2_inode *ip = GFS2_I(inode);	struct gfs2_holder i_gh;	int error;	int unlock = 0;	if (gfs2_glock_is_locked_by_me(ip->i_gl) == 0) {		error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);		if (error)			return error;		unlock = 1;	}	error = generic_permission(inode, mask, gfs2_check_acl);	if (unlock)		gfs2_glock_dq_uninit(&i_gh);	return error;}static int setattr_size(struct inode *inode, struct iattr *attr){	struct gfs2_inode *ip = GFS2_I(inode);	struct gfs2_sbd *sdp = GFS2_SB(inode);	int error;	if (attr->ia_size != ip->i_di.di_size) {		error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);		if (error)			return error;		error = vmtruncate(inode, attr->ia_size);		gfs2_trans_end(sdp);		if (error) 			return error;	}	error = gfs2_truncatei(ip, attr->ia_size);	if (error && (inode->i_size != ip->i_di.di_size))		i_size_write(inode, ip->i_di.di_size);	return error;}static int setattr_chown(struct inode *inode, struct iattr *attr){	struct gfs2_inode *ip = GFS2_I(inode);	struct gfs2_sbd *sdp = GFS2_SB(inode);	struct buffer_head *dibh;	u32 ouid, ogid, nuid, ngid;	int error;	ouid = inode->i_uid;	ogid = inode->i_gid;	nuid = attr->ia_uid;	ngid = attr->ia_gid;	if (!(attr->ia_valid & ATTR_UID) || ouid == nuid)		ouid = nuid = NO_QUOTA_CHANGE;	if (!(attr->ia_valid & ATTR_GID) || ogid == ngid)		ogid = ngid = NO_QUOTA_CHANGE;	gfs2_alloc_get(ip);	error = gfs2_quota_lock(ip, nuid, ngid);	if (error)		goto out_alloc;	if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) {		error = gfs2_quota_check(ip, nuid, ngid);		if (error)			goto out_gunlock_q;	}	error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_QUOTA, 0);	if (error)		goto out_gunlock_q;	error = gfs2_meta_inode_buffer(ip, &dibh);	if (error)		goto out_end_trans;	error = inode_setattr(inode, attr);	gfs2_assert_warn(sdp, !error);	gfs2_trans_add_bh(ip->i_gl, dibh, 1);	gfs2_dinode_out(ip, dibh->b_data);	brelse(dibh);	if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) {		gfs2_quota_change(ip, -ip->i_di.di_blocks, ouid, ogid);		gfs2_quota_change(ip, ip->i_di.di_blocks, nuid, ngid);	}out_end_trans:	gfs2_trans_end(sdp);out_gunlock_q:	gfs2_quota_unlock(ip);out_alloc:	gfs2_alloc_put(ip);	return error;}/** * gfs2_setattr - Change attributes on an inode * @dentry: The dentry which is changing * @attr: The structure describing the change * * The VFS layer wants to change one or more of an inodes attributes.  Write * that change out to disk. * * Returns: errno */static int gfs2_setattr(struct dentry *dentry, struct iattr *attr){	struct inode *inode = dentry->d_inode;	struct gfs2_inode *ip = GFS2_I(inode);	struct gfs2_holder i_gh;	int error;	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);	if (error)		return error;	error = -EPERM;	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))		goto out;	error = inode_change_ok(inode, attr);	if (error)		goto out;	if (attr->ia_valid & ATTR_SIZE)		error = setattr_size(inode, attr);	else if (attr->ia_valid & (ATTR_UID | ATTR_GID))		error = setattr_chown(inode, attr);	else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))		error = gfs2_acl_chmod(ip, attr);	else		error = gfs2_setattr_simple(ip, attr);out:	gfs2_glock_dq_uninit(&i_gh);	if (!error)		mark_inode_dirty(inode);	return error;}/** * gfs2_getattr - Read out an inode's attributes * @mnt: The vfsmount the inode is being accessed from * @dentry: The dentry to stat * @stat: The inode's stats * * This may be called from the VFS directly, or from within GFS2 with the * inode locked, so we look to see if the glock is already locked and only * lock the glock if its not already been done. Note that its the NFS * readdirplus operation which causes this to be called (from filldir) * with the glock already held. * * Returns: errno */static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,			struct kstat *stat){	struct inode *inode = dentry->d_inode;	struct gfs2_inode *ip = GFS2_I(inode);	struct gfs2_holder gh;	int error;	int unlock = 0;	if (gfs2_glock_is_locked_by_me(ip->i_gl) == 0) {		error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);		if (error)			return error;		unlock = 1;	}	generic_fillattr(inode, stat);	if (unlock)		gfs2_glock_dq_uninit(&gh);	return 0;}static int gfs2_setxattr(struct dentry *dentry, const char *name,			 const void *data, size_t size, int flags){	struct inode *inode = dentry->d_inode;	struct gfs2_ea_request er;	memset(&er, 0, sizeof(struct gfs2_ea_request));	er.er_type = gfs2_ea_name2type(name, &er.er_name);	if (er.er_type == GFS2_EATYPE_UNUSED)		return -EOPNOTSUPP;	er.er_data = (char *)data;	er.er_name_len = strlen(er.er_name);	er.er_data_len = size;	er.er_flags = flags;	gfs2_assert_warn(GFS2_SB(inode), !(er.er_flags & GFS2_ERF_MODE));	return gfs2_ea_set(GFS2_I(inode), &er);}static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name,			     void *data, size_t size){	struct gfs2_ea_request er;	memset(&er, 0, sizeof(struct gfs2_ea_request));	er.er_type = gfs2_ea_name2type(name, &er.er_name);	if (er.er_type == GFS2_EATYPE_UNUSED)		return -EOPNOTSUPP;	er.er_data = data;	er.er_name_len = strlen(er.er_name);	er.er_data_len = size;	return gfs2_ea_get(GFS2_I(dentry->d_inode), &er);}static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size){	struct gfs2_ea_request er;	memset(&er, 0, sizeof(struct gfs2_ea_request));	er.er_data = (size) ? buffer : NULL;	er.er_data_len = size;	return gfs2_ea_list(GFS2_I(dentry->d_inode), &er);}static int gfs2_removexattr(struct dentry *dentry, const char *name){	struct gfs2_ea_request er;	memset(&er, 0, sizeof(struct gfs2_ea_request));	er.er_type = gfs2_ea_name2type(name, &er.er_name);	if (er.er_type == GFS2_EATYPE_UNUSED)		return -EOPNOTSUPP;	er.er_name_len = strlen(er.er_name);	return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er);}const struct inode_operations gfs2_file_iops = {	.permission = gfs2_permission,	.setattr = gfs2_setattr,	.getattr = gfs2_getattr,	.setxattr = gfs2_setxattr,	.getxattr = gfs2_getxattr,	.listxattr = gfs2_listxattr,	.removexattr = gfs2_removexattr,};const struct inode_operations gfs2_dev_iops = {	.permission = gfs2_permission,	.setattr = gfs2_setattr,	.getattr = gfs2_getattr,	.setxattr = gfs2_setxattr,	.getxattr = gfs2_getxattr,	.listxattr = gfs2_listxattr,	.removexattr = gfs2_removexattr,};const struct inode_operations gfs2_dir_iops = {	.create = gfs2_create,	.lookup = gfs2_lookup,	.link = gfs2_link,	.unlink = gfs2_unlink,	.symlink = gfs2_symlink,	.mkdir = gfs2_mkdir,	.rmdir = gfs2_rmdir,	.mknod = gfs2_mknod,	.rename = gfs2_rename,	.permission = gfs2_permission,	.setattr = gfs2_setattr,	.getattr = gfs2_getattr,	.setxattr = gfs2_setxattr,	.getxattr = gfs2_getxattr,	.listxattr = gfs2_listxattr,	.removexattr = gfs2_removexattr,};const struct inode_operations gfs2_symlink_iops = {	.readlink = gfs2_readlink,	.follow_link = gfs2_follow_link,	.permission = gfs2_permission,	.setattr = gfs2_setattr,	.getattr = gfs2_getattr,	.setxattr = gfs2_setxattr,	.getxattr = gfs2_getxattr,	.listxattr = gfs2_listxattr,	.removexattr = gfs2_removexattr,};

⌨️ 快捷键说明

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