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

📄 inode.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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/sched.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <linux/completion.h>#include <linux/buffer_head.h>#include <linux/posix_acl.h>#include <linux/sort.h>#include <linux/gfs2_ondisk.h>#include <linux/crc32.h>#include <linux/lm_interface.h>#include <linux/security.h>#include "gfs2.h"#include "incore.h"#include "acl.h"#include "bmap.h"#include "dir.h"#include "eattr.h"#include "glock.h"#include "glops.h"#include "inode.h"#include "log.h"#include "meta_io.h"#include "ops_address.h"#include "ops_file.h"#include "ops_inode.h"#include "quota.h"#include "rgrp.h"#include "trans.h"#include "util.h"struct gfs2_inum_range_host {	u64 ir_start;	u64 ir_length;};static int iget_test(struct inode *inode, void *opaque){	struct gfs2_inode *ip = GFS2_I(inode);	u64 *no_addr = opaque;	if (ip->i_no_addr == *no_addr &&	    inode->i_private != NULL)		return 1;	return 0;}static int iget_set(struct inode *inode, void *opaque){	struct gfs2_inode *ip = GFS2_I(inode);	u64 *no_addr = opaque;	inode->i_ino = (unsigned long)*no_addr;	ip->i_no_addr = *no_addr;	return 0;}struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr){	unsigned long hash = (unsigned long)no_addr;	return ilookup5(sb, hash, iget_test, &no_addr);}static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr){	unsigned long hash = (unsigned long)no_addr;	return iget5_locked(sb, hash, iget_test, iget_set, &no_addr);}struct gfs2_skip_data {	u64	no_addr;	int	skipped;};static int iget_skip_test(struct inode *inode, void *opaque){	struct gfs2_inode *ip = GFS2_I(inode);	struct gfs2_skip_data *data = opaque;	if (ip->i_no_addr == data->no_addr && inode->i_private != NULL){		if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){			data->skipped = 1;			return 0;		}		return 1;	}	return 0;}static int iget_skip_set(struct inode *inode, void *opaque){	struct gfs2_inode *ip = GFS2_I(inode);	struct gfs2_skip_data *data = opaque;	if (data->skipped)		return 1;	inode->i_ino = (unsigned long)(data->no_addr);	ip->i_no_addr = data->no_addr;	return 0;}static struct inode *gfs2_iget_skip(struct super_block *sb,				    u64 no_addr){	struct gfs2_skip_data data;	unsigned long hash = (unsigned long)no_addr;	data.no_addr = no_addr;	data.skipped = 0;	return iget5_locked(sb, hash, iget_skip_test, iget_skip_set, &data);}/** * GFS2 lookup code fills in vfs inode contents based on info obtained * from directory entry inside gfs2_inode_lookup(). This has caused issues * with NFS code path since its get_dentry routine doesn't have the relevant * directory entry when gfs2_inode_lookup() is invoked. Part of the code * segment inside gfs2_inode_lookup code needs to get moved around. * * Clean up I_LOCK and I_NEW as well. **/void gfs2_set_iop(struct inode *inode){	umode_t mode = inode->i_mode;	if (S_ISREG(mode)) {		inode->i_op = &gfs2_file_iops;		inode->i_fop = &gfs2_file_fops;		inode->i_mapping->a_ops = &gfs2_file_aops;	} else if (S_ISDIR(mode)) {		inode->i_op = &gfs2_dir_iops;		inode->i_fop = &gfs2_dir_fops;	} else if (S_ISLNK(mode)) {		inode->i_op = &gfs2_symlink_iops;	} else {		inode->i_op = &gfs2_dev_iops;	}	unlock_new_inode(inode);}/** * gfs2_inode_lookup - Lookup an inode * @sb: The super block * @no_addr: The inode number * @type: The type of the inode * @skip_freeing: set this not return an inode if it is currently being freed. * * Returns: A VFS inode, or an error */struct inode *gfs2_inode_lookup(struct super_block *sb, 				unsigned int type,				u64 no_addr,				u64 no_formal_ino, int skip_freeing){	struct inode *inode;	struct gfs2_inode *ip;	struct gfs2_glock *io_gl;	int error;	if (skip_freeing)		inode = gfs2_iget_skip(sb, no_addr);	else		inode = gfs2_iget(sb, no_addr);	ip = GFS2_I(inode);	if (!inode)		return ERR_PTR(-ENOBUFS);	if (inode->i_state & I_NEW) {		struct gfs2_sbd *sdp = GFS2_SB(inode);		inode->i_private = ip;		ip->i_no_formal_ino = no_formal_ino;		error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);		if (unlikely(error))			goto fail;		ip->i_gl->gl_object = ip;		error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl);		if (unlikely(error))			goto fail_put;		set_bit(GIF_INVALID, &ip->i_flags);		error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);		if (unlikely(error))			goto fail_iopen;		ip->i_iopen_gh.gh_gl->gl_object = ip;		gfs2_glock_put(io_gl);		if ((type == DT_UNKNOWN) && (no_formal_ino == 0))			goto gfs2_nfsbypass;		inode->i_mode = DT2IF(type);		/*		 * We must read the inode in order to work out its type in		 * this case. Note that this doesn't happen often as we normally		 * know the type beforehand. This code path only occurs during		 * unlinked inode recovery (where it is safe to do this glock,		 * which is not true in the general case).		 */		if (type == DT_UNKNOWN) {			struct gfs2_holder gh;			error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);			if (unlikely(error))				goto fail_glock;			/* Inode is now uptodate */			gfs2_glock_dq_uninit(&gh);		}		gfs2_set_iop(inode);	}gfs2_nfsbypass:	return inode;fail_glock:	gfs2_glock_dq(&ip->i_iopen_gh);fail_iopen:	gfs2_glock_put(io_gl);fail_put:	ip->i_gl->gl_object = NULL;	gfs2_glock_put(ip->i_gl);fail:	iput(inode);	return ERR_PTR(error);}static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf){	struct gfs2_dinode_host *di = &ip->i_di;	const struct gfs2_dinode *str = buf;	if (ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)) {		if (gfs2_consist_inode(ip))			gfs2_dinode_print(ip);		return -EIO;	}	ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino);	ip->i_inode.i_mode = be32_to_cpu(str->di_mode);	ip->i_inode.i_rdev = 0;	switch (ip->i_inode.i_mode & S_IFMT) {	case S_IFBLK:	case S_IFCHR:		ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major),					   be32_to_cpu(str->di_minor));		break;	};	ip->i_inode.i_uid = be32_to_cpu(str->di_uid);	ip->i_inode.i_gid = be32_to_cpu(str->di_gid);	/*	 * We will need to review setting the nlink count here in the	 * light of the forthcoming ro bind mount work. This is a reminder	 * to do that.	 */	ip->i_inode.i_nlink = be32_to_cpu(str->di_nlink);	di->di_size = be64_to_cpu(str->di_size);	i_size_write(&ip->i_inode, di->di_size);	di->di_blocks = be64_to_cpu(str->di_blocks);	gfs2_set_inode_blocks(&ip->i_inode);	ip->i_inode.i_atime.tv_sec = be64_to_cpu(str->di_atime);	ip->i_inode.i_atime.tv_nsec = be32_to_cpu(str->di_atime_nsec);	ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime);	ip->i_inode.i_mtime.tv_nsec = be32_to_cpu(str->di_mtime_nsec);	ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime);	ip->i_inode.i_ctime.tv_nsec = be32_to_cpu(str->di_ctime_nsec);	di->di_goal_meta = be64_to_cpu(str->di_goal_meta);	di->di_goal_data = be64_to_cpu(str->di_goal_data);	di->di_generation = be64_to_cpu(str->di_generation);	di->di_flags = be32_to_cpu(str->di_flags);	gfs2_set_inode_flags(&ip->i_inode);	di->di_height = be16_to_cpu(str->di_height);	di->di_depth = be16_to_cpu(str->di_depth);	di->di_entries = be32_to_cpu(str->di_entries);	di->di_eattr = be64_to_cpu(str->di_eattr);	return 0;}static void gfs2_inode_bh(struct gfs2_inode *ip, struct buffer_head *bh){	ip->i_cache[0] = bh;}/** * gfs2_inode_refresh - Refresh the incore copy of the dinode * @ip: The GFS2 inode * * Returns: errno */int gfs2_inode_refresh(struct gfs2_inode *ip){	struct buffer_head *dibh;	int error;	error = gfs2_meta_inode_buffer(ip, &dibh);	if (error)		return error;	if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), dibh, GFS2_METATYPE_DI)) {		brelse(dibh);		return -EIO;	}	error = gfs2_dinode_in(ip, dibh->b_data);	brelse(dibh);	clear_bit(GIF_INVALID, &ip->i_flags);	return error;}int gfs2_dinode_dealloc(struct gfs2_inode *ip){	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);	struct gfs2_alloc *al;	struct gfs2_rgrpd *rgd;	int error;	if (ip->i_di.di_blocks != 1) {		if (gfs2_consist_inode(ip))			gfs2_dinode_print(ip);		return -EIO;	}	al = gfs2_alloc_get(ip);	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);	if (error)		goto out;	error = gfs2_rindex_hold(sdp, &al->al_ri_gh);	if (error)		goto out_qs;	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);	if (!rgd) {		gfs2_consist_inode(ip);		error = -EIO;		goto out_rindex_relse;	}	error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0,				   &al->al_rgd_gh);	if (error)		goto out_rindex_relse;	error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1);	if (error)		goto out_rg_gunlock;	gfs2_trans_add_gl(ip->i_gl);	gfs2_free_di(rgd, ip);	gfs2_trans_end(sdp);	clear_bit(GLF_STICKY, &ip->i_gl->gl_flags);out_rg_gunlock:	gfs2_glock_dq_uninit(&al->al_rgd_gh);out_rindex_relse:	gfs2_glock_dq_uninit(&al->al_ri_gh);out_qs:	gfs2_quota_unhold(ip);out:	gfs2_alloc_put(ip);	return error;}/** * gfs2_change_nlink - Change nlink count on inode * @ip: The GFS2 inode * @diff: The change in the nlink count required * * Returns: errno */int gfs2_change_nlink(struct gfs2_inode *ip, int diff){	struct buffer_head *dibh;	u32 nlink;	int error;	BUG_ON(diff != 1 && diff != -1);	nlink = ip->i_inode.i_nlink + diff;	/* If we are reducing the nlink count, but the new value ends up being	   bigger than the old one, we must have underflowed. */	if (diff < 0 && nlink > ip->i_inode.i_nlink) {		if (gfs2_consist_inode(ip))			gfs2_dinode_print(ip);		return -EIO;	}	error = gfs2_meta_inode_buffer(ip, &dibh);	if (error)		return error;	if (diff > 0)		inc_nlink(&ip->i_inode);	else		drop_nlink(&ip->i_inode);	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);	mark_inode_dirty(&ip->i_inode);	if (ip->i_inode.i_nlink == 0)		gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */	return error;}struct inode *gfs2_lookup_simple(struct inode *dip, const char *name){	struct qstr qstr;	struct inode *inode;	gfs2_str2qstr(&qstr, name);	inode = gfs2_lookupi(dip, &qstr, 1, NULL);	/* gfs2_lookupi has inconsistent callers: vfs	 * related routines expect NULL for no entry found,	 * gfs2_lookup_simple callers expect ENOENT	 * and do not check for NULL.	 */	if (inode == NULL)		return ERR_PTR(-ENOENT);	else		return inode;}/** * gfs2_lookupi - Look up a filename in a directory and return its inode * @d_gh: An initialized holder for the directory glock * @name: The name of the inode to look for * @is_root: If 1, ignore the caller's permissions * @i_gh: An uninitialized holder for the new inode glock * * This can be called via the VFS filldir function when NFS is doing * a readdirplus and the inode which its intending to stat isn't * already in cache. In this case we must not take the directory glock * again, since the readdir call will have already taken that lock. * * Returns: errno */struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,			   int is_root, struct nameidata *nd){	struct super_block *sb = dir->i_sb;	struct gfs2_inode *dip = GFS2_I(dir);	struct gfs2_holder d_gh;	int error = 0;	struct inode *inode = NULL;	int unlock = 0;	if (!name->len || name->len > GFS2_FNAMESIZE)		return ERR_PTR(-ENAMETOOLONG);

⌨️ 快捷键说明

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