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

📄 ops_inode.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved. * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License version 2. */#include <linux/slab.h>#include <linux/spinlock.h>#include <linux/completion.h>#include <linux/buffer_head.h>#include <linux/namei.h>#include <linux/utsname.h>#include <linux/mm.h>#include <linux/xattr.h>#include <linux/posix_acl.h>#include <linux/gfs2_ondisk.h>#include <linux/crc32.h>#include <linux/lm_interface.h>#include <asm/uaccess.h>#include "gfs2.h"#include "incore.h"#include "acl.h"#include "bmap.h"#include "dir.h"#include "eaops.h"#include "eattr.h"#include "glock.h"#include "inode.h"#include "meta_io.h"#include "ops_dentry.h"#include "ops_inode.h"#include "quota.h"#include "rgrp.h"#include "trans.h"#include "util.h"/** * gfs2_create - Create a file * @dir: The directory in which to create the file * @dentry: The dentry of the new file * @mode: The mode of the new file * * Returns: errno */static int gfs2_create(struct inode *dir, struct dentry *dentry,		       int mode, struct nameidata *nd){	struct gfs2_inode *dip = GFS2_I(dir);	struct gfs2_sbd *sdp = GFS2_SB(dir);	struct gfs2_holder ghs[2];	struct inode *inode;	gfs2_holder_init(dip->i_gl, 0, 0, ghs);	for (;;) {		inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0);		if (!IS_ERR(inode)) {			gfs2_trans_end(sdp);			if (dip->i_alloc.al_rgd)				gfs2_inplace_release(dip);			gfs2_quota_unlock(dip);			gfs2_alloc_put(dip);			gfs2_glock_dq_uninit_m(2, ghs);			mark_inode_dirty(inode);			break;		} else if (PTR_ERR(inode) != -EEXIST ||			   (nd && (nd->intent.open.flags & O_EXCL))) {			gfs2_holder_uninit(ghs);			return PTR_ERR(inode);		}		inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);		if (inode) {			if (!IS_ERR(inode)) {				gfs2_holder_uninit(ghs);				break;			} else {				gfs2_holder_uninit(ghs);				return PTR_ERR(inode);			}		}	}	d_instantiate(dentry, inode);	return 0;}/** * gfs2_lookup - Look up a filename in a directory and return its inode * @dir: The directory inode * @dentry: The dentry of the new inode * @nd: passed from Linux VFS, ignored by us * * Called by the VFS layer. Lock dir and call gfs2_lookupi() * * Returns: errno */static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,				  struct nameidata *nd){	struct inode *inode = NULL;	dentry->d_op = &gfs2_dops;	inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);	if (inode && IS_ERR(inode))		return ERR_PTR(PTR_ERR(inode));	if (inode)		return d_splice_alias(inode, dentry);	d_add(dentry, inode);	return NULL;}/** * gfs2_link - Link to a file * @old_dentry: The inode to link * @dir: Add link to this directory * @dentry: The name of the link * * Link the inode in "old_dentry" into the directory "dir" with the * name in "dentry". * * Returns: errno */static int gfs2_link(struct dentry *old_dentry, struct inode *dir,		     struct dentry *dentry){	struct gfs2_inode *dip = GFS2_I(dir);	struct gfs2_sbd *sdp = GFS2_SB(dir);	struct inode *inode = old_dentry->d_inode;	struct gfs2_inode *ip = GFS2_I(inode);	struct gfs2_holder ghs[2];	int alloc_required;	int error;	if (S_ISDIR(inode->i_mode))		return -EPERM;	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);	error = gfs2_glock_nq_m(2, ghs);	if (error)		goto out;	error = permission(dir, MAY_WRITE | MAY_EXEC, NULL);	if (error)		goto out_gunlock;	error = gfs2_dir_check(dir, &dentry->d_name, NULL);	switch (error) {	case -ENOENT:		break;	case 0:		error = -EEXIST;	default:		goto out_gunlock;	}	error = -EINVAL;	if (!dip->i_inode.i_nlink)		goto out_gunlock;	error = -EFBIG;	if (dip->i_di.di_entries == (u32)-1)		goto out_gunlock;	error = -EPERM;	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))		goto out_gunlock;	error = -EINVAL;	if (!ip->i_inode.i_nlink)		goto out_gunlock;	error = -EMLINK;	if (ip->i_inode.i_nlink == (u32)-1)		goto out_gunlock;	alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name);	if (error < 0)		goto out_gunlock;	error = 0;	if (alloc_required) {		struct gfs2_alloc *al = gfs2_alloc_get(dip);		error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);		if (error)			goto out_alloc;		error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid);		if (error)			goto out_gunlock_q;		al->al_requested = sdp->sd_max_dirres;		error = gfs2_inplace_reserve(dip);		if (error)			goto out_gunlock_q;		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +					 al->al_rgd->rd_length +					 2 * RES_DINODE + RES_STATFS +					 RES_QUOTA, 0);		if (error)			goto out_ipres;	} else {		error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0);		if (error)			goto out_ipres;	}	error = gfs2_dir_add(dir, &dentry->d_name, ip, IF2DT(inode->i_mode));	if (error)		goto out_end_trans;	error = gfs2_change_nlink(ip, +1);out_end_trans:	gfs2_trans_end(sdp);out_ipres:	if (alloc_required)		gfs2_inplace_release(dip);out_gunlock_q:	if (alloc_required)		gfs2_quota_unlock(dip);out_alloc:	if (alloc_required)		gfs2_alloc_put(dip);out_gunlock:	gfs2_glock_dq_m(2, ghs);out:	gfs2_holder_uninit(ghs);	gfs2_holder_uninit(ghs + 1);	if (!error) {		atomic_inc(&inode->i_count);		d_instantiate(dentry, inode);		mark_inode_dirty(inode);	}	return error;}/** * gfs2_unlink - Unlink a file * @dir: The inode of the directory containing the file to unlink * @dentry: The file itself * * Unlink a file.  Call gfs2_unlinki() * * Returns: errno */static int gfs2_unlink(struct inode *dir, struct dentry *dentry){	struct gfs2_inode *dip = GFS2_I(dir);	struct gfs2_sbd *sdp = GFS2_SB(dir);	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);	struct gfs2_holder ghs[3];	struct gfs2_rgrpd *rgd;	struct gfs2_holder ri_gh;	int error;	error = gfs2_rindex_hold(sdp, &ri_gh);	if (error)		return error;	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);	gfs2_holder_init(ip->i_gl,  LM_ST_EXCLUSIVE, 0, ghs + 1);	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);	gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);	error = gfs2_glock_nq(ghs); /* parent */	if (error)		goto out_parent;	error = gfs2_glock_nq(ghs + 1); /* child */	if (error)		goto out_child;	error = gfs2_glock_nq(ghs + 2); /* rgrp */	if (error)		goto out_rgrp;	error = gfs2_unlink_ok(dip, &dentry->d_name, ip);	if (error)		goto out_rgrp;	error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0);	if (error)		goto out_rgrp;	error = gfs2_dir_del(dip, &dentry->d_name);        if (error)                goto out_end_trans;	error = gfs2_change_nlink(ip, -1);out_end_trans:	gfs2_trans_end(sdp);	gfs2_glock_dq(ghs + 2);out_rgrp:	gfs2_holder_uninit(ghs + 2);	gfs2_glock_dq(ghs + 1);out_child:	gfs2_holder_uninit(ghs + 1);	gfs2_glock_dq(ghs);out_parent:	gfs2_holder_uninit(ghs);	gfs2_glock_dq_uninit(&ri_gh);	return error;}/** * gfs2_symlink - Create a symlink * @dir: The directory to create the symlink in * @dentry: The dentry to put the symlink in * @symname: The thing which the link points to * * Returns: errno */static int gfs2_symlink(struct inode *dir, struct dentry *dentry,			const char *symname){	struct gfs2_inode *dip = GFS2_I(dir), *ip;	struct gfs2_sbd *sdp = GFS2_SB(dir);	struct gfs2_holder ghs[2];	struct inode *inode;	struct buffer_head *dibh;	int size;	int error;	/* Must be stuffed with a null terminator for gfs2_follow_link() */	size = strlen(symname);	if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1)		return -ENAMETOOLONG;	gfs2_holder_init(dip->i_gl, 0, 0, ghs);	inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO, 0);	if (IS_ERR(inode)) {		gfs2_holder_uninit(ghs);		return PTR_ERR(inode);	}	ip = ghs[1].gh_gl->gl_object;	ip->i_di.di_size = size;	error = gfs2_meta_inode_buffer(ip, &dibh);	if (!gfs2_assert_withdraw(sdp, !error)) {		gfs2_dinode_out(ip, dibh->b_data);		memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname,		       size);		brelse(dibh);	}	gfs2_trans_end(sdp);	if (dip->i_alloc.al_rgd)		gfs2_inplace_release(dip);	gfs2_quota_unlock(dip);	gfs2_alloc_put(dip);	gfs2_glock_dq_uninit_m(2, ghs);	d_instantiate(dentry, inode);	mark_inode_dirty(inode);	return 0;}/** * gfs2_mkdir - Make a directory * @dir: The parent directory of the new one * @dentry: The dentry of the new directory * @mode: The mode of the new directory * * Returns: errno */static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode){	struct gfs2_inode *dip = GFS2_I(dir), *ip;	struct gfs2_sbd *sdp = GFS2_SB(dir);	struct gfs2_holder ghs[2];	struct inode *inode;	struct buffer_head *dibh;	int error;	gfs2_holder_init(dip->i_gl, 0, 0, ghs);	inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode, 0);	if (IS_ERR(inode)) {		gfs2_holder_uninit(ghs);		return PTR_ERR(inode);	}	ip = ghs[1].gh_gl->gl_object;	ip->i_inode.i_nlink = 2;	ip->i_di.di_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode);	ip->i_di.di_flags |= GFS2_DIF_JDATA;	ip->i_di.di_entries = 2;	error = gfs2_meta_inode_buffer(ip, &dibh);	if (!gfs2_assert_withdraw(sdp, !error)) {		struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;		struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1);		struct qstr str;		gfs2_str2qstr(&str, ".");		gfs2_trans_add_bh(ip->i_gl, dibh, 1);		gfs2_qstr2dirent(&str, GFS2_DIRENT_SIZE(str.len), dent);		dent->de_inum = di->di_num; /* already GFS2 endian */		dent->de_type = cpu_to_be16(DT_DIR);		di->di_entries = cpu_to_be32(1);		gfs2_str2qstr(&str, "..");		dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1));		gfs2_qstr2dirent(&str, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent);		gfs2_inum_out(dip, dent);		dent->de_type = cpu_to_be16(DT_DIR);		gfs2_dinode_out(ip, di);		brelse(dibh);	}	error = gfs2_change_nlink(dip, +1);	gfs2_assert_withdraw(sdp, !error); /* dip already pinned */	gfs2_trans_end(sdp);	if (dip->i_alloc.al_rgd)		gfs2_inplace_release(dip);	gfs2_quota_unlock(dip);	gfs2_alloc_put(dip);	gfs2_glock_dq_uninit_m(2, ghs);	d_instantiate(dentry, inode);	mark_inode_dirty(inode);	return 0;}/** * gfs2_rmdir - Remove a directory * @dir: The parent directory of the directory to be removed * @dentry: The dentry of the directory to remove * * Remove a directory. Call gfs2_rmdiri() * * Returns: errno */static int gfs2_rmdir(struct inode *dir, struct dentry *dentry){	struct gfs2_inode *dip = GFS2_I(dir);	struct gfs2_sbd *sdp = GFS2_SB(dir);	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);	struct gfs2_holder ghs[3];	struct gfs2_rgrpd *rgd;	struct gfs2_holder ri_gh;	int error;	error = gfs2_rindex_hold(sdp, &ri_gh);	if (error)		return error;	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);	gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);	error = gfs2_glock_nq_m(3, ghs);	if (error)		goto out;	error = gfs2_unlink_ok(dip, &dentry->d_name, ip);	if (error)		goto out_gunlock;	if (ip->i_di.di_entries < 2) {		if (gfs2_consist_inode(ip))			gfs2_dinode_print(ip);		error = -EIO;		goto out_gunlock;	}	if (ip->i_di.di_entries > 2) {		error = -ENOTEMPTY;		goto out_gunlock;	}	error = gfs2_trans_begin(sdp, 2 * RES_DINODE + 3 * RES_LEAF + RES_RG_BIT, 0);	if (error)		goto out_gunlock;	error = gfs2_rmdiri(dip, &dentry->d_name, ip);	gfs2_trans_end(sdp);out_gunlock:	gfs2_glock_dq_m(3, ghs);out:	gfs2_holder_uninit(ghs);	gfs2_holder_uninit(ghs + 1);	gfs2_holder_uninit(ghs + 2);	gfs2_glock_dq_uninit(&ri_gh);	return error;}/** * gfs2_mknod - Make a special file * @dir: The directory in which the special file will reside * @dentry: The dentry of the special file * @mode: The mode of the special file * @rdev: The device specification of the special file * */static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,		      dev_t dev){	struct gfs2_inode *dip = GFS2_I(dir);	struct gfs2_sbd *sdp = GFS2_SB(dir);	struct gfs2_holder ghs[2];	struct inode *inode;	gfs2_holder_init(dip->i_gl, 0, 0, ghs);	inode = gfs2_createi(ghs, &dentry->d_name, mode, dev);	if (IS_ERR(inode)) {		gfs2_holder_uninit(ghs);		return PTR_ERR(inode);	}	gfs2_trans_end(sdp);	if (dip->i_alloc.al_rgd)		gfs2_inplace_release(dip);	gfs2_quota_unlock(dip);	gfs2_alloc_put(dip);	gfs2_glock_dq_uninit_m(2, ghs);	d_instantiate(dentry, inode);	mark_inode_dirty(inode);	return 0;}/** * gfs2_rename - Rename a file * @odir: Parent directory of old file name * @odentry: The old dentry of the file * @ndir: Parent directory of new file name * @ndentry: The new dentry of the file * * Returns: errno */static int gfs2_rename(struct inode *odir, struct dentry *odentry,		       struct inode *ndir, struct dentry *ndentry){	struct gfs2_inode *odip = GFS2_I(odir);	struct gfs2_inode *ndip = GFS2_I(ndir);	struct gfs2_inode *ip = GFS2_I(odentry->d_inode);	struct gfs2_inode *nip = NULL;	struct gfs2_sbd *sdp = GFS2_SB(odir);	struct gfs2_holder ghs[5], r_gh;	struct gfs2_rgrpd *nrgd;	unsigned int num_gh;	int dir_rename = 0;	int alloc_required;	unsigned int x;	int error;	if (ndentry->d_inode) {		nip = GFS2_I(ndentry->d_inode);

⌨️ 快捷键说明

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