X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fxfs%2Fxfs_vnodeops.c;h=95fea44c4a60df157c66a1c07bd8101a7a5a5976;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=05ab682c6cca91de0060ae313697f5d5ad9bb562;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 05ab682c6..95fea44c4 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -283,7 +283,7 @@ xfs_getattr( /* * xfs_setattr */ -STATIC int +int xfs_setattr( bhv_desc_t *bdp, vattr_t *vap, @@ -305,6 +305,7 @@ xfs_setattr( 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); @@ -406,7 +407,8 @@ xfs_setattr( goto error_return; } } - lock_flags |= XFS_IOLOCK_EXCL; + if (need_iolock) + lock_flags |= XFS_IOLOCK_EXCL; } xfs_ilock(ip, lock_flags); @@ -678,7 +680,8 @@ xfs_setattr( XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) { xfs_trans_cancel(tp, 0); - xfs_iunlock(ip, XFS_IOLOCK_EXCL); + if (need_iolock) + xfs_iunlock(ip, XFS_IOLOCK_EXCL); return code; } commit_flags = XFS_TRANS_RELEASE_LOG_RES; @@ -823,26 +826,38 @@ xfs_setattr( mp->m_sb.sb_blocklog; } if (mask & XFS_AT_XFLAGS) { - ip->i_d.di_flags = 0; - if (vap->va_xflags & XFS_XFLAG_REALTIME) { - ip->i_d.di_flags |= XFS_DIFLAG_REALTIME; - ip->i_iocore.io_flags |= XFS_IOCORE_RT; - } + 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) - ip->i_d.di_flags |= XFS_DIFLAG_IMMUTABLE; + di_flags |= XFS_DIFLAG_IMMUTABLE; if (vap->va_xflags & XFS_XFLAG_IUNLINK) - ip->i_d.di_flags |= XFS_DIFLAG_IUNLINK; + di_flags |= XFS_DIFLAG_IUNLINK; if (vap->va_xflags & XFS_XFLAG_BARRIER) - ip->i_d.di_flags |= XFS_DIFLAG_BARRIER; + di_flags |= XFS_DIFLAG_BARRIER; if (vap->va_xflags & XFS_XFLAG_APPEND) - ip->i_d.di_flags |= XFS_DIFLAG_APPEND; + di_flags |= XFS_DIFLAG_APPEND; if (vap->va_xflags & XFS_XFLAG_SYNC) - ip->i_d.di_flags |= XFS_DIFLAG_SYNC; + di_flags |= XFS_DIFLAG_SYNC; if (vap->va_xflags & XFS_XFLAG_NOATIME) - ip->i_d.di_flags |= XFS_DIFLAG_NOATIME; + di_flags |= XFS_DIFLAG_NOATIME; if (vap->va_xflags & XFS_XFLAG_NODUMP) - ip->i_d.di_flags |= XFS_DIFLAG_NODUMP; - /* can't set PREALLOC this way, just ignore it */ + di_flags |= XFS_DIFLAG_NODUMP; + 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; + } else { + 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; + } + } + ip->i_d.di_flags = di_flags; } xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); timeflags |= XFS_ICHGTIME_CHG; @@ -1600,7 +1615,7 @@ xfs_inactive( * If the inode is already free, then there can be nothing * to clean up here. */ - if (ip->i_d.di_mode == 0) { + if (ip->i_d.di_mode == 0 || VN_BAD(vp)) { ASSERT(ip->i_df.if_real_bytes == 0); ASSERT(ip->i_df.if_broot_bytes == 0); return VN_INACTIVE_CACHE; @@ -1826,8 +1841,6 @@ xfs_lookup( } -#define XFS_CREATE_NEW_MAXTRIES 10000 - /* * xfs_create (create a new file). */ @@ -3385,6 +3398,14 @@ xfs_symlink( xfs_ilock(dp, XFS_ILOCK_EXCL); + /* + * Check whether the directory allows new symlinks or not. + */ + if (dp->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) { + error = XFS_ERROR(EPERM); + goto error_return; + } + /* * Reserve disk quota : blocks and inode. */ @@ -3791,11 +3812,17 @@ xfs_reclaim( vnode_t *vp; vp = BHV_TO_VNODE(bdp); + ip = XFS_BHVTOI(bdp); vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); ASSERT(!VN_MAPPED(vp)); - ip = XFS_BHVTOI(bdp); + + /* bad inode, get out here ASAP */ + if (VN_BAD(vp)) { + xfs_ireclaim(ip); + return 0; + } if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) { if (ip->i_d.di_size > 0) { @@ -3873,8 +3900,12 @@ xfs_finish_reclaim( int sync_mode) { xfs_ihash_t *ih = ip->i_hash; + vnode_t *vp = XFS_ITOV_NULL(ip); int error; + if (vp && VN_BAD(vp)) + return 0; + /* The hash lock here protects a thread in xfs_iget_core from * racing with us on linking the inode back with a vnode. * Once we have the XFS_IRECLAIM flag set it will not touch @@ -3882,8 +3913,7 @@ xfs_finish_reclaim( */ write_lock(&ih->ih_lock); if ((ip->i_flags & XFS_IRECLAIM) || - (!(ip->i_flags & XFS_IRECLAIMABLE) && - (XFS_ITOV_NULL(ip) == NULL))) { + (!(ip->i_flags & XFS_IRECLAIMABLE) && vp == NULL)) { write_unlock(&ih->ih_lock); if (locked) { xfs_ifunlock(ip); @@ -3950,15 +3980,13 @@ int xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock) { int purged; - struct list_head *curr, *next; - xfs_inode_t *ip; + xfs_inode_t *ip, *n; int done = 0; while (!done) { purged = 0; XFS_MOUNT_ILOCK(mp); - list_for_each_safe(curr, next, &mp->m_del_inodes) { - ip = list_entry(curr, xfs_inode_t, i_reclaim); + list_for_each_entry_safe(ip, n, &mp->m_del_inodes, i_reclaim) { if (noblock) { if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) continue; @@ -4296,6 +4324,7 @@ xfs_free_file_space( int rt; xfs_fileoff_t startoffset_fsb; xfs_trans_t *tp; + int need_iolock = (attr_flags & ATTR_DMI) == 0; vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address); mp = ip->i_mount; @@ -4323,7 +4352,8 @@ xfs_free_file_space( return(error); } - xfs_ilock(ip, XFS_IOLOCK_EXCL); + if (need_iolock) + xfs_ilock(ip, XFS_IOLOCK_EXCL); rounding = MAX((__uint8_t)(1 << mp->m_sb.sb_blocklog), (__uint8_t)NBPP); ilen = len + (offset & (rounding - 1)); @@ -4342,7 +4372,7 @@ xfs_free_file_space( error = xfs_bmapi(NULL, ip, startoffset_fsb, 1, 0, NULL, 0, &imap, &nimap, NULL); if (error) - return error; + goto out_unlock_iolock; ASSERT(nimap == 0 || nimap == 1); if (nimap && imap.br_startblock != HOLESTARTBLOCK) { xfs_daddr_t block; @@ -4357,7 +4387,7 @@ xfs_free_file_space( error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, 1, 0, NULL, 0, &imap, &nimap, NULL); if (error) - return error; + goto out_unlock_iolock; ASSERT(nimap == 0 || nimap == 1); if (nimap && imap.br_startblock != HOLESTARTBLOCK) { ASSERT(imap.br_startblock != DELAYSTARTBLOCK); @@ -4446,14 +4476,17 @@ xfs_free_file_space( xfs_iunlock(ip, XFS_ILOCK_EXCL); } - xfs_iunlock(ip, XFS_IOLOCK_EXCL); + out_unlock_iolock: + if (need_iolock) + xfs_iunlock(ip, XFS_IOLOCK_EXCL); return error; error0: xfs_bmap_cancel(&free_list); error1: xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); - xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_iunlock(ip, need_iolock ? (XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL) : + XFS_ILOCK_EXCL); return error; } @@ -4610,20 +4643,21 @@ xfs_change_file_space( xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ihold(tp, ip); - ip->i_d.di_mode &= ~S_ISUID; - - /* - * Note that we don't have to worry about mandatory - * file locking being disabled here because we only - * clear the S_ISGID bit if the Group execute bit is - * on, but if it was on then mandatory locking wouldn't - * have been enabled. - */ - if (ip->i_d.di_mode & S_IXGRP) - ip->i_d.di_mode &= ~S_ISGID; + if ((attr_flags & ATTR_DMI) == 0) { + ip->i_d.di_mode &= ~S_ISUID; - xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + /* + * Note that we don't have to worry about mandatory + * file locking being disabled here because we only + * clear the S_ISGID bit if the Group execute bit is + * on, but if it was on then mandatory locking wouldn't + * have been enabled. + */ + if (ip->i_d.di_mode & S_IXGRP) + ip->i_d.di_mode &= ~S_ISGID; + xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + } if (setprealloc) ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; else if (clrprealloc)