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

📄 xfs_vnodeops.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		     vap->va_extsize) ) {			code = XFS_ERROR(EINVAL);	/* EFBIG? */			goto error_return;		}		/*		 * Can't change realtime flag if any extents are allocated.		 */		if ((ip->i_d.di_nextents || ip->i_delayed_blks) &&		    (mask & XFS_AT_XFLAGS) &&		    (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) !=		    (vap->va_xflags & XFS_XFLAG_REALTIME)) {			code = XFS_ERROR(EINVAL);	/* EFBIG? */			goto error_return;		}		/*		 * Extent size must be a multiple of the appropriate block		 * size, if set at all.		 */		if ((mask & XFS_AT_EXTSIZE) && vap->va_extsize != 0) {			xfs_extlen_t	size;			if ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ||			    ((mask & XFS_AT_XFLAGS) &&			    (vap->va_xflags & XFS_XFLAG_REALTIME))) {				size = mp->m_sb.sb_rextsize <<				       mp->m_sb.sb_blocklog;			} else {				size = mp->m_sb.sb_blocksize;			}			if (vap->va_extsize % size) {				code = XFS_ERROR(EINVAL);				goto error_return;			}		}		/*		 * If realtime flag is set then must have realtime data.		 */		if ((mask & XFS_AT_XFLAGS) &&		    (vap->va_xflags & XFS_XFLAG_REALTIME)) {			if ((mp->m_sb.sb_rblocks == 0) ||			    (mp->m_sb.sb_rextsize == 0) ||			    (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) {				code = XFS_ERROR(EINVAL);				goto error_return;			}		}		/*		 * Can't modify an immutable/append-only file unless		 * we have appropriate permission.		 */		if ((mask & XFS_AT_XFLAGS) &&		    (ip->i_d.di_flags &				(XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND) ||		     (vap->va_xflags &				(XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) &&		    !capable(CAP_LINUX_IMMUTABLE)) {			code = XFS_ERROR(EPERM);			goto error_return;		}	}	/*	 * Now we can make the changes.  Before we join the inode	 * to the transaction, if XFS_AT_SIZE is set then take care of	 * the part of the truncation that must be done without the	 * inode lock.  This needs to be done before joining the inode	 * to the transaction, because the inode cannot be unlocked	 * once it is a part of the transaction.	 */	if (mask & XFS_AT_SIZE) {		code = 0;		if ((vap->va_size > ip->i_size) &&		    (flags & ATTR_NOSIZETOK) == 0) {			code = xfs_igrow_start(ip, vap->va_size, credp);		}		xfs_iunlock(ip, XFS_ILOCK_EXCL);		/*		 * We are going to log the inode size change in this		 * transaction so any previous writes that are beyond the on		 * disk EOF and the new EOF that have not been written out need		 * to be written here. If we do not write the data out, we		 * expose ourselves to the null files problem.		 *		 * Only flush from the on disk size to the smaller of the in		 * memory file size or the new size as that's the range we		 * really care about here and prevents waiting for other data		 * not within the range we care about here.		 */		if (!code &&		    (ip->i_size != ip->i_d.di_size) &&		    (vap->va_size > ip->i_d.di_size)) {			code = xfs_flush_pages(ip,					ip->i_d.di_size, vap->va_size,					XFS_B_ASYNC, FI_NONE);		}		/* wait for all I/O to complete */		vn_iowait(ip);		if (!code)			code = xfs_itruncate_data(ip, vap->va_size);		if (code) {			ASSERT(tp == NULL);			lock_flags &= ~XFS_ILOCK_EXCL;			ASSERT(lock_flags == XFS_IOLOCK_EXCL);			goto error_return;		}		tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);		if ((code = xfs_trans_reserve(tp, 0,					     XFS_ITRUNCATE_LOG_RES(mp), 0,					     XFS_TRANS_PERM_LOG_RES,					     XFS_ITRUNCATE_LOG_COUNT))) {			xfs_trans_cancel(tp, 0);			if (need_iolock)				xfs_iunlock(ip, XFS_IOLOCK_EXCL);			return code;		}		commit_flags = XFS_TRANS_RELEASE_LOG_RES;		xfs_ilock(ip, XFS_ILOCK_EXCL);	}	if (tp) {		xfs_trans_ijoin(tp, ip, lock_flags);		xfs_trans_ihold(tp, ip);	}	/* determine whether mandatory locking mode changes */	mandlock_before = MANDLOCK(vp, ip->i_d.di_mode);	/*	 * Truncate file.  Must have write permission and not be a directory.	 */	if (mask & XFS_AT_SIZE) {		if (vap->va_size > ip->i_size) {			xfs_igrow_finish(tp, ip, vap->va_size,			    !(flags & ATTR_DMI));		} else if ((vap->va_size <= ip->i_size) ||			   ((vap->va_size == 0) && ip->i_d.di_nextents)) {			/*			 * signal a sync transaction unless			 * we're truncating an already unlinked			 * file on a wsync filesystem			 */			code = xfs_itruncate_finish(&tp, ip,					    (xfs_fsize_t)vap->va_size,					    XFS_DATA_FORK,					    ((ip->i_d.di_nlink != 0 ||					      !(mp->m_flags & XFS_MOUNT_WSYNC))					     ? 1 : 0));			if (code)				goto abort_return;			/*			 * Truncated "down", so we're removing references			 * to old data here - if we now delay flushing for			 * a long time, we expose ourselves unduly to the			 * notorious NULL files problem.  So, we mark this			 * vnode and flush it when the file is closed, and			 * do not wait the usual (long) time for writeout.			 */			xfs_iflags_set(ip, XFS_ITRUNCATED);		}		/*		 * Have to do this even if the file's size doesn't change.		 */		timeflags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;	}	/*	 * Change file access modes.	 */	if (mask & XFS_AT_MODE) {		ip->i_d.di_mode &= S_IFMT;		ip->i_d.di_mode |= vap->va_mode & ~S_IFMT;		xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE);		timeflags |= XFS_ICHGTIME_CHG;	}	/*	 * 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)) {		/*		 * CAP_FSETID overrides the following restrictions:		 *		 * The set-user-ID and set-group-ID bits of a file will be		 * cleared upon successful return from chown()		 */		if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) &&		    !capable(CAP_FSETID)) {			ip->i_d.di_mode &= ~(S_ISUID|S_ISGID);		}		/*		 * Change the ownerships and register quota modifications		 * in the transaction.		 */		if (iuid != uid) {			if (XFS_IS_UQUOTA_ON(mp)) {				ASSERT(mask & XFS_AT_UID);				ASSERT(udqp);				olddquot1 = XFS_QM_DQVOPCHOWN(mp, tp, ip,							&ip->i_udquot, udqp);			}			ip->i_d.di_uid = uid;		}		if (igid != gid) {			if (XFS_IS_GQUOTA_ON(mp)) {				ASSERT(!XFS_IS_PQUOTA_ON(mp));				ASSERT(mask & XFS_AT_GID);				ASSERT(gdqp);				olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip,							&ip->i_gdquot, gdqp);			}			ip->i_d.di_gid = gid;		}		if (iprojid != projid) {			if (XFS_IS_PQUOTA_ON(mp)) {				ASSERT(!XFS_IS_GQUOTA_ON(mp));				ASSERT(mask & XFS_AT_PROJID);				ASSERT(gdqp);				olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip,							&ip->i_gdquot, gdqp);			}			ip->i_d.di_projid = projid;			/*			 * We may have to rev the inode as well as			 * the superblock version number since projids didn't			 * exist before DINODE_VERSION_2 and SB_VERSION_NLINK.			 */			if (ip->i_d.di_version == XFS_DINODE_VERSION_1)				xfs_bump_ino_vers2(tp, ip);		}		xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE);		timeflags |= XFS_ICHGTIME_CHG;	}	/*	 * Change file access or modified times.	 */	if (mask & (XFS_AT_ATIME|XFS_AT_MTIME)) {		if (mask & XFS_AT_ATIME) {			ip->i_d.di_atime.t_sec = vap->va_atime.tv_sec;			ip->i_d.di_atime.t_nsec = vap->va_atime.tv_nsec;			ip->i_update_core = 1;			timeflags &= ~XFS_ICHGTIME_ACC;		}		if (mask & XFS_AT_MTIME) {			ip->i_d.di_mtime.t_sec = vap->va_mtime.tv_sec;			ip->i_d.di_mtime.t_nsec = vap->va_mtime.tv_nsec;			timeflags &= ~XFS_ICHGTIME_MOD;			timeflags |= XFS_ICHGTIME_CHG;		}		if (tp && (flags & ATTR_UTIME))			xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE);	}	/*	 * Change XFS-added attributes.	 */	if (mask & (XFS_AT_EXTSIZE|XFS_AT_XFLAGS)) {		if (mask & XFS_AT_EXTSIZE) {			/*			 * Converting bytes to fs blocks.			 */			ip->i_d.di_extsize = vap->va_extsize >>				mp->m_sb.sb_blocklog;		}		if (mask & XFS_AT_XFLAGS) {			uint	di_flags;			/* can't set PREALLOC this way, just preserve it */			di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);			if (vap->va_xflags & XFS_XFLAG_IMMUTABLE)				di_flags |= XFS_DIFLAG_IMMUTABLE;			if (vap->va_xflags & XFS_XFLAG_APPEND)				di_flags |= XFS_DIFLAG_APPEND;			if (vap->va_xflags & XFS_XFLAG_SYNC)				di_flags |= XFS_DIFLAG_SYNC;			if (vap->va_xflags & XFS_XFLAG_NOATIME)				di_flags |= XFS_DIFLAG_NOATIME;			if (vap->va_xflags & XFS_XFLAG_NODUMP)				di_flags |= XFS_DIFLAG_NODUMP;			if (vap->va_xflags & XFS_XFLAG_PROJINHERIT)				di_flags |= XFS_DIFLAG_PROJINHERIT;			if (vap->va_xflags & XFS_XFLAG_NODEFRAG)				di_flags |= XFS_DIFLAG_NODEFRAG;			if (vap->va_xflags & XFS_XFLAG_FILESTREAM)				di_flags |= XFS_DIFLAG_FILESTREAM;			if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {				if (vap->va_xflags & XFS_XFLAG_RTINHERIT)					di_flags |= XFS_DIFLAG_RTINHERIT;				if (vap->va_xflags & XFS_XFLAG_NOSYMLINKS)					di_flags |= XFS_DIFLAG_NOSYMLINKS;				if (vap->va_xflags & XFS_XFLAG_EXTSZINHERIT)					di_flags |= XFS_DIFLAG_EXTSZINHERIT;			} else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {				if (vap->va_xflags & XFS_XFLAG_REALTIME) {					di_flags |= XFS_DIFLAG_REALTIME;					ip->i_iocore.io_flags |= XFS_IOCORE_RT;				} else {					ip->i_iocore.io_flags &= ~XFS_IOCORE_RT;				}				if (vap->va_xflags & XFS_XFLAG_EXTSIZE)					di_flags |= XFS_DIFLAG_EXTSIZE;			}			ip->i_d.di_flags = di_flags;		}		xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);		timeflags |= XFS_ICHGTIME_CHG;	}	/*	 * Change file inode change time only if XFS_AT_CTIME set	 * AND we have been called by a DMI function.	 */	if ( (flags & ATTR_DMI) && (mask & XFS_AT_CTIME) ) {		ip->i_d.di_ctime.t_sec = vap->va_ctime.tv_sec;		ip->i_d.di_ctime.t_nsec = vap->va_ctime.tv_nsec;		ip->i_update_core = 1;		timeflags &= ~XFS_ICHGTIME_CHG;	}	/*	 * Send out timestamp changes that need to be set to the	 * current time.  Not done when called by a DMI function.	 */	if (timeflags && !(flags & ATTR_DMI))		xfs_ichgtime(ip, timeflags);	XFS_STATS_INC(xs_ig_attrchg);	/*	 * If this is a synchronous mount, make sure that the	 * transaction goes to disk before returning to the user.	 * This is slightly sub-optimal in that truncates require	 * two sync transactions instead of one for wsync filesystems.	 * One for the truncate and one for the timestamps since we	 * don't want to change the timestamps unless we're sure the	 * truncate worked.  Truncates are less than 1% of the laddis	 * mix so this probably isn't worth the trouble to optimize.	 */	code = 0;	if (tp) {		if (mp->m_flags & XFS_MOUNT_WSYNC)			xfs_trans_set_sync(tp);		code = xfs_trans_commit(tp, commit_flags);	}	/*	 * If the (regular) file's mandatory locking mode changed, then	 * notify the vnode.  We do this under the inode lock to prevent	 * racing calls to vop_vnode_change.	 */	mandlock_after = MANDLOCK(vp, ip->i_d.di_mode);	xfs_iunlock(ip, lock_flags);	/*	 * Release any dquot(s) the inode had kept before chown.	 */	XFS_QM_DQRELE(mp, olddquot1);	XFS_QM_DQRELE(mp, olddquot2);	XFS_QM_DQRELE(mp, udqp);	XFS_QM_DQRELE(mp, gdqp);	if (code) {		return code;	}	if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE) &&	    !(flags & ATTR_DMI)) {		(void) XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, vp, DM_RIGHT_NULL,					NULL, DM_RIGHT_NULL, NULL, NULL,					0, 0, AT_DELAY_FLAG(flags));	}	return 0; abort_return:	commit_flags |= XFS_TRANS_ABORT;	/* FALLTHROUGH */ error_return:	XFS_QM_DQRELE(mp, udqp);	XFS_QM_DQRELE(mp, gdqp);	if (tp) {		xfs_trans_cancel(tp, commit_flags);	}	if (lock_flags != 0) {		xfs_iunlock(ip, lock_flags);	}	return code;}/* * xfs_access * Null conversion from vnode mode bits to inode mode bits, as in efs. */intxfs_access(	xfs_inode_t	*ip,	int		mode,	cred_t		*credp){	int		error;	vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address);	xfs_ilock(ip, XFS_ILOCK_SHARED);	error = xfs_iaccess(ip, mode, credp);	xfs_iunlock(ip, XFS_ILOCK_SHARED);	return error;}/* * The maximum pathlen is 1024 bytes. Since the minimum file system * blocksize is 512 bytes, we can get a max of 2 extents back from * bmapi. */#define SYMLINK_MAPS 2STATIC intxfs_readlink_bmap(	xfs_inode_t	*ip,	char		*link){	xfs_mount_t	*mp = ip->i_mount;	int		pathlen = ip->i_d.di_size;	int             nmaps = SYMLINK_MAPS;	xfs_bmbt_irec_t mval[SYMLINK_MAPS];	xfs_daddr_t	d;	int		byte_cnt;	int		n;	xfs_buf_t	*bp;	int		error = 0;	error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), 0, NULL, 0,			mval, &nmaps, NULL, NULL);	if (error)		goto out;	for (n = 0; n < nmaps; n++) {		d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);		byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);		bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0);		error = XFS_BUF_GETERROR(bp);		if (error) {			xfs_ioerror_alert("xfs_readlink",				  ip->i_mount, bp, XFS_BUF_ADDR(bp));			xfs_buf_relse(bp);			goto out;		}		if (pathlen < byte_cnt)			byte_cnt = pathlen;		pathlen -= byte_cnt;		memcpy(link, XFS_BUF_PTR(bp), byte_cnt);		xfs_buf_relse(bp);	}	link[ip->i_d.di_size] = '\0';	error = 0; out:	return error;}intxfs_readlink(	xfs_inode_t     *ip,	char		*link){	xfs_mount_t	*mp = ip->i_mount;	int		pathlen;	int		error = 0;	vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address);	if (XFS_FORCED_SHUTDOWN(mp))		return XFS_ERROR(EIO);	xfs_ilock(ip, XFS_ILOCK_SHARED);	ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK);	ASSERT(ip->i_d.di_size <= MAXPATHLEN);	pathlen = ip->i_d.di_size;

⌨️ 快捷键说明

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