xfs_vnodeops.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,550 行 · 第 1/5 页
C
2,550 行
/* * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 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. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU General Public License along * with this program; if not, write the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston MA 02111-1307, USA. * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */#include "xfs.h"#include "xfs_macros.h"#include "xfs_types.h"#include "xfs_inum.h"#include "xfs_log.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_alloc_btree.h"#include "xfs_bmap_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_itable.h"#include "xfs_btree.h"#include "xfs_ialloc.h"#include "xfs_alloc.h"#include "xfs_attr_sf.h"#include "xfs_dir_sf.h"#include "xfs_dir2_sf.h"#include "xfs_dinode.h"#include "xfs_inode_item.h"#include "xfs_inode.h"#include "xfs_bmap.h"#include "xfs_da_btree.h"#include "xfs_attr.h"#include "xfs_rw.h"#include "xfs_refcache.h"#include "xfs_error.h"#include "xfs_bit.h"#include "xfs_rtalloc.h"#include "xfs_quota.h"#include "xfs_utils.h"#include "xfs_trans_space.h"#include "xfs_dir_leaf.h"#include "xfs_mac.h"#include "xfs_log_priv.h"/* * 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 2/* * For xfs, we check that the file isn't too big to be opened by this kernel. * No other open action is required for regular files. Devices are handled * through the specfs file system, pipes through fifofs. Device and * fifo vnodes are "wrapped" by specfs and fifofs vnodes, respectively, * when a new vnode is first looked up or created. */STATIC intxfs_open( bhv_desc_t *bdp, cred_t *credp){ int mode; vnode_t *vp; xfs_inode_t *ip; vp = BHV_TO_VNODE(bdp); ip = XFS_BHVTOI(bdp); 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 (vp->v_type == VDIR && 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 */STATIC intxfs_getattr( bhv_desc_t *bdp, vattr_t *vap, int flags, cred_t *credp){ xfs_inode_t *ip; xfs_mount_t *mp; vnode_t *vp; vp = BHV_TO_VNODE(bdp); vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); ip = XFS_BHVTOI(bdp); mp = ip->i_mount; if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); if (!(flags & ATTR_LAZY)) xfs_ilock(ip, XFS_ILOCK_SHARED); vap->va_size = ip->i_d.di_size; 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_type = vp->v_type; vap->va_mode = ip->i_d.di_mode & MODEMASK; 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. * Do it with bitmask because that's faster than looking * for multiple values individually. */ if (((1 << vp->v_type) & ((1<<VBLK) | (1<<VCHR))) == 0) { vap->va_rdev = 0; if (!(ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) {#if 0 /* Large block sizes confuse various * user space programs, so letting the * stripe size through is not a good * idea for now. */ vap->va_blocksize = mp->m_swidth ? /* * If the underlying volume is a stripe, then * return the stripe width in bytes as the * recommended I/O size. */ (mp->m_swidth << mp->m_sb.sb_blocklog) : /* * Return the largest of the preferred buffer * sizes since doing small I/Os into larger * buffers causes buffers to be decommissioned. * The value returned is in bytes. */ (1 << (int)MAX(mp->m_readio_log, mp->m_writeio_log));#else vap->va_blocksize = /* * Return the largest of the preferred buffer * sizes since doing small I/Os into larger * buffers causes buffers to be decommissioned. * The value returned is in bytes. */ 1 << (int)MAX(mp->m_readio_log, mp->m_writeio_log);#endif } 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 = ip->i_d.di_extsize ? (ip->i_d.di_extsize << mp->m_sb.sb_blocklog) : (mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog); } } else { vap->va_rdev = ip->i_df.if_u2.if_rdev; vap->va_blocksize = BLKDEV_IOSIZE; } vap->va_atime.tv_sec = ip->i_d.di_atime.t_sec; vap->va_atime.tv_nsec = ip->i_d.di_atime.t_nsec; 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_dic2xflags(&ip->i_d, ARCH_NOCONVERT); /* * 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( bhv_desc_t *bdp, vattr_t *vap, int flags, cred_t *credp){ xfs_inode_t *ip; xfs_trans_t *tp; xfs_mount_t *mp; 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; vnode_t *vp; 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 = (flags & ATTR_DMI) == 0; vp = BHV_TO_VNODE(bdp); vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); if (vp->v_vfsp->vfs_flag & VFS_RDONLY) return XFS_ERROR(EROFS); /* * Cannot set certain attributes. */ mask = vap->va_mask; if (mask & XFS_AT_NOSET) { return XFS_ERROR(EINVAL); } ip = XFS_BHVTOI(bdp); mp = ip->i_mount; 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))) { uint qflags = 0; if (mask & XFS_AT_UID) { uid = vap->va_uid; qflags |= XFS_QMOPT_UQUOTA; } else { uid = ip->i_d.di_uid; } if (mask & XFS_AT_GID) { gid = vap->va_gid; qflags |= XFS_QMOPT_GQUOTA; } else { gid = ip->i_d.di_gid; } /* * 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, 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 (!(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 (vp->v_vfsp, 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) && vp->v_type != VDIR) 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. * * XXX: How does restricted_chown affect projid? */ 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 or gid is actually
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?