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

📄 xfs_vnodeops.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. * * 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. * * This program is distributed in the hope that it would 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 the Free Software Foundation, * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_types.h"#include "xfs_bit.h"#include "xfs_log.h"#include "xfs_inum.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_da_btree.h"#include "xfs_bmap_btree.h"#include "xfs_alloc_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_inode_item.h"#include "xfs_itable.h"#include "xfs_btree.h"#include "xfs_ialloc.h"#include "xfs_alloc.h"#include "xfs_bmap.h"#include "xfs_attr.h"#include "xfs_rw.h"#include "xfs_error.h"#include "xfs_quota.h"#include "xfs_utils.h"#include "xfs_rtalloc.h"#include "xfs_refcache.h"#include "xfs_trans_space.h"#include "xfs_log_priv.h"#include "xfs_filestream.h"#include "xfs_vnodeops.h"intxfs_open(	xfs_inode_t	*ip){	int		mode;	if (XFS_FORCED_SHUTDOWN(ip->i_mount))		return XFS_ERROR(EIO);	/*	 * If it's a directory with any blocks, read-ahead block 0	 * as we're almost certain to have the next operation be a read there.	 */	if (S_ISDIR(ip->i_d.di_mode) && ip->i_d.di_nextents > 0) {		mode = xfs_ilock_map_shared(ip);		if (ip->i_d.di_nextents > 0)			(void)xfs_da_reada_buf(NULL, ip, 0, XFS_DATA_FORK);		xfs_iunlock(ip, mode);	}	return 0;}/* * xfs_getattr */intxfs_getattr(	xfs_inode_t	*ip,	bhv_vattr_t	*vap,	int		flags){	bhv_vnode_t	*vp = XFS_ITOV(ip);	xfs_mount_t	*mp = ip->i_mount;	vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address);	if (XFS_FORCED_SHUTDOWN(mp))		return XFS_ERROR(EIO);	if (!(flags & ATTR_LAZY))		xfs_ilock(ip, XFS_ILOCK_SHARED);	vap->va_size = XFS_ISIZE(ip);	if (vap->va_mask == XFS_AT_SIZE)		goto all_done;	vap->va_nblocks =		XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks);	vap->va_nodeid = ip->i_ino;#if XFS_BIG_INUMS	vap->va_nodeid += mp->m_inoadd;#endif	vap->va_nlink = ip->i_d.di_nlink;	/*	 * Quick exit for non-stat callers	 */	if ((vap->va_mask &	    ~(XFS_AT_SIZE|XFS_AT_FSID|XFS_AT_NODEID|	      XFS_AT_NLINK|XFS_AT_BLKSIZE)) == 0)		goto all_done;	/*	 * Copy from in-core inode.	 */	vap->va_mode = ip->i_d.di_mode;	vap->va_uid = ip->i_d.di_uid;	vap->va_gid = ip->i_d.di_gid;	vap->va_projid = ip->i_d.di_projid;	/*	 * Check vnode type block/char vs. everything else.	 */	switch (ip->i_d.di_mode & S_IFMT) {	case S_IFBLK:	case S_IFCHR:		vap->va_rdev = ip->i_df.if_u2.if_rdev;		vap->va_blocksize = BLKDEV_IOSIZE;		break;	default:		vap->va_rdev = 0;		if (!(ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) {			vap->va_blocksize = xfs_preferred_iosize(mp);		} else {			/*			 * If the file blocks are being allocated from a			 * realtime partition, then return the inode's			 * realtime extent size or the realtime volume's			 * extent size.			 */			vap->va_blocksize =				xfs_get_extsz_hint(ip) << mp->m_sb.sb_blocklog;		}		break;	}	vn_atime_to_timespec(vp, &vap->va_atime);	vap->va_mtime.tv_sec = ip->i_d.di_mtime.t_sec;	vap->va_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec;	vap->va_ctime.tv_sec = ip->i_d.di_ctime.t_sec;	vap->va_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec;	/*	 * Exit for stat callers.  See if any of the rest of the fields	 * to be filled in are needed.	 */	if ((vap->va_mask &	     (XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|	      XFS_AT_GENCOUNT|XFS_AT_VCODE)) == 0)		goto all_done;	/*	 * Convert di_flags to xflags.	 */	vap->va_xflags = xfs_ip2xflags(ip);	/*	 * Exit for inode revalidate.  See if any of the rest of	 * the fields to be filled in are needed.	 */	if ((vap->va_mask &	     (XFS_AT_EXTSIZE|XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|	      XFS_AT_GENCOUNT|XFS_AT_VCODE)) == 0)		goto all_done;	vap->va_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog;	vap->va_nextents =		(ip->i_df.if_flags & XFS_IFEXTENTS) ?			ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t) :			ip->i_d.di_nextents;	if (ip->i_afp)		vap->va_anextents =			(ip->i_afp->if_flags & XFS_IFEXTENTS) ?				ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t) :				 ip->i_d.di_anextents;	else		vap->va_anextents = 0;	vap->va_gen = ip->i_d.di_gen; all_done:	if (!(flags & ATTR_LAZY))		xfs_iunlock(ip, XFS_ILOCK_SHARED);	return 0;}/* * xfs_setattr */intxfs_setattr(	xfs_inode_t		*ip,	bhv_vattr_t		*vap,	int			flags,	cred_t			*credp){	bhv_vnode_t		*vp = XFS_ITOV(ip);	xfs_mount_t		*mp = ip->i_mount;	xfs_trans_t		*tp;	int			mask;	int			code;	uint			lock_flags;	uint			commit_flags=0;	uid_t			uid=0, iuid=0;	gid_t			gid=0, igid=0;	int			timeflags = 0;	xfs_prid_t		projid=0, iprojid=0;	int			mandlock_before, mandlock_after;	struct xfs_dquot	*udqp, *gdqp, *olddquot1, *olddquot2;	int			file_owner;	int			need_iolock = 1;	vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address);	if (mp->m_flags & XFS_MOUNT_RDONLY)		return XFS_ERROR(EROFS);	/*	 * Cannot set certain attributes.	 */	mask = vap->va_mask;	if (mask & XFS_AT_NOSET) {		return XFS_ERROR(EINVAL);	}	if (XFS_FORCED_SHUTDOWN(mp))		return XFS_ERROR(EIO);	/*	 * Timestamps do not need to be logged and hence do not	 * need to be done within a transaction.	 */	if (mask & XFS_AT_UPDTIMES) {		ASSERT((mask & ~XFS_AT_UPDTIMES) == 0);		timeflags = ((mask & XFS_AT_UPDATIME) ? XFS_ICHGTIME_ACC : 0) |			    ((mask & XFS_AT_UPDCTIME) ? XFS_ICHGTIME_CHG : 0) |			    ((mask & XFS_AT_UPDMTIME) ? XFS_ICHGTIME_MOD : 0);		xfs_ichgtime(ip, timeflags);		return 0;	}	olddquot1 = olddquot2 = NULL;	udqp = gdqp = NULL;	/*	 * If disk quotas is on, we make sure that the dquots do exist on disk,	 * before we start any other transactions. Trying to do this later	 * is messy. We don't care to take a readlock to look at the ids	 * in inode here, because we can't hold it across the trans_reserve.	 * If the IDs do change before we take the ilock, we're covered	 * because the i_*dquot fields will get updated anyway.	 */	if (XFS_IS_QUOTA_ON(mp) &&	    (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID))) {		uint	qflags = 0;		if ((mask & XFS_AT_UID) && XFS_IS_UQUOTA_ON(mp)) {			uid = vap->va_uid;			qflags |= XFS_QMOPT_UQUOTA;		} else {			uid = ip->i_d.di_uid;		}		if ((mask & XFS_AT_GID) && XFS_IS_GQUOTA_ON(mp)) {			gid = vap->va_gid;			qflags |= XFS_QMOPT_GQUOTA;		}  else {			gid = ip->i_d.di_gid;		}		if ((mask & XFS_AT_PROJID) && XFS_IS_PQUOTA_ON(mp)) {			projid = vap->va_projid;			qflags |= XFS_QMOPT_PQUOTA;		}  else {			projid = ip->i_d.di_projid;		}		/*		 * We take a reference when we initialize udqp and gdqp,		 * so it is important that we never blindly double trip on		 * the same variable. See xfs_create() for an example.		 */		ASSERT(udqp == NULL);		ASSERT(gdqp == NULL);		code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, projid, qflags,					 &udqp, &gdqp);		if (code)			return code;	}	/*	 * For the other attributes, we acquire the inode lock and	 * first do an error checking pass.	 */	tp = NULL;	lock_flags = XFS_ILOCK_EXCL;	if (flags & ATTR_NOLOCK)		need_iolock = 0;	if (!(mask & XFS_AT_SIZE)) {		if ((mask != (XFS_AT_CTIME|XFS_AT_ATIME|XFS_AT_MTIME)) ||		    (mp->m_flags & XFS_MOUNT_WSYNC)) {			tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);			commit_flags = 0;			if ((code = xfs_trans_reserve(tp, 0,						     XFS_ICHANGE_LOG_RES(mp), 0,						     0, 0))) {				lock_flags = 0;				goto error_return;			}		}	} else {		if (DM_EVENT_ENABLED(ip, DM_EVENT_TRUNCATE) &&		    !(flags & ATTR_DMI)) {			int dmflags = AT_DELAY_FLAG(flags) | DM_SEM_FLAG_WR;			code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, vp,				vap->va_size, 0, dmflags, NULL);			if (code) {				lock_flags = 0;				goto error_return;			}		}		if (need_iolock)			lock_flags |= XFS_IOLOCK_EXCL;	}	xfs_ilock(ip, lock_flags);	/* boolean: are we the file owner? */	file_owner = (current_fsuid(credp) == ip->i_d.di_uid);	/*	 * Change various properties of a file.	 * Only the owner or users with CAP_FOWNER	 * capability may do these things.	 */	if (mask &	    (XFS_AT_MODE|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_UID|	     XFS_AT_GID|XFS_AT_PROJID)) {		/*		 * CAP_FOWNER overrides the following restrictions:		 *		 * The user ID of the calling process must be equal		 * to the file owner ID, except in cases where the		 * CAP_FSETID capability is applicable.		 */		if (!file_owner && !capable(CAP_FOWNER)) {			code = XFS_ERROR(EPERM);			goto error_return;		}		/*		 * CAP_FSETID overrides the following restrictions:		 *		 * The effective user ID of the calling process shall match		 * the file owner when setting the set-user-ID and		 * set-group-ID bits on that file.		 *		 * The effective group ID or one of the supplementary group		 * IDs of the calling process shall match the group owner of		 * the file when setting the set-group-ID bit on that file		 */		if (mask & XFS_AT_MODE) {			mode_t m = 0;			if ((vap->va_mode & S_ISUID) && !file_owner)				m |= S_ISUID;			if ((vap->va_mode & S_ISGID) &&			    !in_group_p((gid_t)ip->i_d.di_gid))				m |= S_ISGID;#if 0			/* Linux allows this, Irix doesn't. */			if ((vap->va_mode & S_ISVTX) && !VN_ISDIR(vp))				m |= S_ISVTX;#endif			if (m && !capable(CAP_FSETID))				vap->va_mode &= ~m;		}	}	/*	 * Change file ownership.  Must be the owner or privileged.	 * If the system was configured with the "restricted_chown"	 * option, the owner is not permitted to give away the file,	 * and can change the group id only to a group of which he	 * or she is a member.	 */	if (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID)) {		/*		 * These IDs could have changed since we last looked at them.		 * But, we're assured that if the ownership did change		 * while we didn't have the inode locked, inode's dquot(s)		 * would have changed also.		 */		iuid = ip->i_d.di_uid;		iprojid = ip->i_d.di_projid;		igid = ip->i_d.di_gid;		gid = (mask & XFS_AT_GID) ? vap->va_gid : igid;		uid = (mask & XFS_AT_UID) ? vap->va_uid : iuid;		projid = (mask & XFS_AT_PROJID) ? (xfs_prid_t)vap->va_projid :			 iprojid;		/*		 * CAP_CHOWN overrides the following restrictions:		 *		 * If _POSIX_CHOWN_RESTRICTED is defined, this capability		 * shall override the restriction that a process cannot		 * change the user ID of a file it owns and the restriction		 * that the group ID supplied to the chown() function		 * shall be equal to either the group ID or one of the		 * supplementary group IDs of the calling process.		 */		if (restricted_chown &&		    (iuid != uid || (igid != gid &&				     !in_group_p((gid_t)gid))) &&		    !capable(CAP_CHOWN)) {			code = XFS_ERROR(EPERM);			goto error_return;		}		/*		 * Do a quota reservation only if uid/projid/gid is actually		 * going to change.		 */		if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||		    (XFS_IS_PQUOTA_ON(mp) && iprojid != projid) ||		    (XFS_IS_GQUOTA_ON(mp) && igid != gid)) {			ASSERT(tp);			code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,						capable(CAP_FOWNER) ?						XFS_QMOPT_FORCE_RES : 0);			if (code)	/* out of quota */				goto error_return;		}	}	/*	 * Truncate file.  Must have write permission and not be a directory.	 */	if (mask & XFS_AT_SIZE) {		/* Short circuit the truncate case for zero length files */		if ((vap->va_size == 0) &&		   (ip->i_size == 0) && (ip->i_d.di_nextents == 0)) {			xfs_iunlock(ip, XFS_ILOCK_EXCL);			lock_flags &= ~XFS_ILOCK_EXCL;			if (mask & XFS_AT_CTIME)				xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);			code = 0;			goto error_return;		}		if (VN_ISDIR(vp)) {			code = XFS_ERROR(EISDIR);			goto error_return;		} else if (!VN_ISREG(vp)) {			code = XFS_ERROR(EINVAL);			goto error_return;		}		/*		 * Make sure that the dquots are attached to the inode.		 */		if ((code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED)))			goto error_return;	}	/*	 * Change file access or modified times.	 */	if (mask & (XFS_AT_ATIME|XFS_AT_MTIME)) {		if (!file_owner) {			if ((flags & ATTR_UTIME) &&			    !capable(CAP_FOWNER)) {				code = XFS_ERROR(EPERM);				goto error_return;			}		}	}	/*	 * Change extent size or realtime flag.	 */	if (mask & (XFS_AT_EXTSIZE|XFS_AT_XFLAGS)) {		/*		 * Can't change extent size if any extents are allocated.		 */		if (ip->i_d.di_nextents && (mask & XFS_AT_EXTSIZE) &&		    ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) !=

⌨️ 快捷键说明

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