aboutsummaryrefslogtreecommitdiff
path: root/sys/gnu/fs/xfs/xfs_vnodeops.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/gnu/fs/xfs/xfs_vnodeops.c')
-rw-r--r--sys/gnu/fs/xfs/xfs_vnodeops.c911
1 files changed, 431 insertions, 480 deletions
diff --git a/sys/gnu/fs/xfs/xfs_vnodeops.c b/sys/gnu/fs/xfs/xfs_vnodeops.c
index b35950e30078..41442ee1f60f 100644
--- a/sys/gnu/fs/xfs/xfs_vnodeops.c
+++ b/sys/gnu/fs/xfs/xfs_vnodeops.c
@@ -1,40 +1,27 @@
/*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 version 2 of the GNU General Public License as
+ * 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.
+ * 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.
*
- * 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/
+ * 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_macros.h"
+#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_inum.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"
@@ -42,37 +29,35 @@
#include "xfs_dir2.h"
#include "xfs_dmapi.h"
#include "xfs_mount.h"
-#include "xfs_alloc_btree.h"
+#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
+#include "xfs_alloc_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_attr_sf.h"
#include "xfs_dinode.h"
-#include "xfs_inode_item.h"
#include "xfs_inode.h"
+#include "xfs_inode_item.h"
+#include "xfs_dir_leaf.h"
+#include "xfs_itable.h"
+#include "xfs_btree.h"
+#include "xfs_ialloc.h"
+#include "xfs_alloc.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_rtalloc.h"
+#include "xfs_refcache.h"
#include "xfs_trans_space.h"
-#include "xfs_dir_leaf.h"
-#include "xfs_mac.h"
#include "xfs_log_priv.h"
+#include "xfs_mac.h"
#include "xfs_fs.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
@@ -106,7 +91,7 @@ xfs_open(
* 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) {
+ if (VN_ISDIR(vp) && 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);
@@ -165,55 +150,25 @@ xfs_getattr(
/*
* Copy from in-core inode.
*/
- vap->va_type = vp->v_type;
- vap->va_mode = ip->i_d.di_mode & MODEMASK;
+ 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.
- * Do it with bitmask because that's faster than looking
- * for multiple values individually.
*/
- if (((1 << vp->v_type) & ((1<<VBLK) | (1<<VCHR))) == 0) {
+ 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)) {
-
-#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
+ vap->va_blocksize = xfs_preferred_iosize(mp);
} else {
/*
@@ -226,13 +181,10 @@ xfs_getattr(
(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;
+ break;
}
- vap->va_atime.tv_sec = ip->i_d.di_atime.t_sec;
- vap->va_atime.tv_nsec = ip->i_d.di_atime.t_nsec;
+ 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;
@@ -248,25 +200,10 @@ xfs_getattr(
goto all_done;
/*
- * convert di_flags to xflags
+ * Convert di_flags to xflags.
*/
- vap->va_xflags = 0;
- if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)
- vap->va_xflags |= XFS_XFLAG_REALTIME;
- if (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC)
- vap->va_xflags |= XFS_XFLAG_PREALLOC;
- if (ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE)
- vap->va_xflags |= XFS_XFLAG_IMMUTABLE;
- if (ip->i_d.di_flags & XFS_DIFLAG_APPEND)
- vap->va_xflags |= XFS_XFLAG_APPEND;
- if (ip->i_d.di_flags & XFS_DIFLAG_SYNC)
- vap->va_xflags |= XFS_XFLAG_SYNC;
- if (ip->i_d.di_flags & XFS_DIFLAG_NOATIME)
- vap->va_xflags |= XFS_XFLAG_NOATIME;
- if (ip->i_d.di_flags & XFS_DIFLAG_NODUMP)
- vap->va_xflags |= XFS_XFLAG_NODUMP;
- if (XFS_IFORK_Q(ip))
- vap->va_xflags |= XFS_XFLAG_HASATTR;
+ 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.
@@ -300,7 +237,7 @@ xfs_getattr(
/*
* xfs_setattr
*/
-STATIC int
+int
xfs_setattr(
bhv_desc_t *bdp,
xfs_vattr_t *vap,
@@ -322,6 +259,7 @@ xfs_setattr(
int mandlock_before, mandlock_after;
struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2;
int file_owner;
+ int need_iolock = 1;
vp = BHV_TO_VNODE(bdp);
vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
@@ -367,21 +305,28 @@ xfs_setattr(
* 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))) {
+ if (XFS_IS_QUOTA_ON(mp) &&
+ (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID))) {
uint qflags = 0;
- if (mask & XFS_AT_UID) {
+ 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) {
+ 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
@@ -389,9 +334,10 @@ xfs_setattr(
*/
ASSERT(udqp == NULL);
ASSERT(gdqp == NULL);
- code = XFS_QM_DQVOPALLOC(mp, ip, uid,gid, qflags, &udqp, &gdqp);
+ code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, projid, qflags,
+ &udqp, &gdqp);
if (code)
- return (code);
+ return code;
}
/*
@@ -400,6 +346,9 @@ xfs_setattr(
*/
tp = NULL;
lock_flags = XFS_ILOCK_EXCL;
+ ASSERT(flags & ATTR_NOLOCK ? flags & ATTR_DMI : 1);
+ 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)) {
@@ -423,16 +372,12 @@ xfs_setattr(
goto error_return;
}
}
- lock_flags |= XFS_IOLOCK_EXCL;
+ if (need_iolock)
+ lock_flags |= XFS_IOLOCK_EXCL;
}
xfs_ilock(ip, lock_flags);
- if (_MAC_XFS_IACCESS(ip, MACWRITE, credp)) {
- code = XFS_ERROR(EACCES);
- goto error_return;
- }
-
/* boolean: are we the file owner? */
#if 0
file_owner = (current_fsuid(credp) == ip->i_d.di_uid);
@@ -477,9 +422,9 @@ xfs_setattr(
if ((vap->va_mode & S_ISGID) &&
!groupmember((gid_t)ip->i_d.di_gid, credp))
m |= S_ISGID;
-#if 0
+#if 1
/* Linux allows this, Irix doesn't. */
- if ((vap->va_mode & S_ISVTX) && vp->v_type != VDIR)
+ if ((vap->va_mode & S_ISVTX) && !VN_ISDIR(vp))
m |= S_ISVTX;
#endif
if (m && !capable(CAP_FSETID))
@@ -519,8 +464,6 @@ xfs_setattr(
* 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 &&
@@ -530,10 +473,11 @@ xfs_setattr(
goto error_return;
}
/*
- * Do a quota reservation only if uid or gid is actually
+ * 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,
@@ -559,10 +503,10 @@ xfs_setattr(
goto error_return;
}
- if (vp->v_type == VDIR) {
+ if (VN_ISDIR(vp)) {
code = XFS_ERROR(EISDIR);
goto error_return;
- } else if (vp->v_type != VREG) {
+ } else if (!VN_ISREG(vp)) {
code = XFS_ERROR(EINVAL);
goto error_return;
}
@@ -593,35 +537,17 @@ xfs_setattr(
/*
* Can't change extent size if any extents are allocated.
*/
- if ((ip->i_d.di_nextents || ip->i_delayed_blks) &&
- (mask & XFS_AT_EXTSIZE) &&
+ if (ip->i_d.di_nextents && (mask & XFS_AT_EXTSIZE) &&
((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) !=
vap->va_extsize) ) {
code = XFS_ERROR(EINVAL); /* EFBIG? */
goto error_return;
}
/*
- * Can't set extent size unless the file is marked, or
- * about to be marked as a realtime file.
- *
- * This check will be removed when fixed size extents
- * with buffered data writes is implemented.
- *
- */
- if ((mask & XFS_AT_EXTSIZE) &&
- ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) !=
- vap->va_extsize) &&
- (!((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ||
- ((mask & XFS_AT_XFLAGS) &&
- (vap->va_xflags & XFS_XFLAG_REALTIME))))) {
- code = XFS_ERROR(EINVAL);
- goto error_return;
- }
-
- /*
* Can't change realtime flag if any extents are allocated.
*/
- if (ip->i_d.di_nextents && (mask & XFS_AT_XFLAGS) &&
+ 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? */
@@ -685,18 +611,15 @@ xfs_setattr(
* once it is a part of the transaction.
*/
if (mask & XFS_AT_SIZE) {
- if (vap->va_size > ip->i_d.di_size) {
+ code = 0;
+ if ((vap->va_size > ip->i_d.di_size) &&
+ (flags & ATTR_NOSIZETOK) == 0) {
code = xfs_igrow_start(ip, vap->va_size, credp);
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- } else if (vap->va_size <= ip->i_d.di_size) {
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
- (xfs_fsize_t)vap->va_size);
- code = 0;
- } else {
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- code = 0;
}
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ vn_iowait(vp); /* wait for the completion of any pending DIOs */
+ if (!code)
+ code = xfs_itruncate_data(ip, vap->va_size);
if (code) {
ASSERT(tp == NULL);
lock_flags &= ~XFS_ILOCK_EXCL;
@@ -709,7 +632,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;
@@ -799,6 +723,7 @@ xfs_setattr(
}
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,
@@ -807,6 +732,13 @@ xfs_setattr(
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
@@ -830,7 +762,7 @@ xfs_setattr(
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;
+ //timeflags &= ~XFS_ICHGTIME_ACC;
}
if (mask & XFS_AT_MTIME) {
ip->i_d.di_mtime.t_sec = vap->va_mtime.tv_sec;
@@ -854,22 +786,40 @@ 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_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 (vap->va_xflags & XFS_XFLAG_PROJINHERIT)
+ di_flags |= XFS_DIFLAG_PROJINHERIT;
+ 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;
@@ -900,7 +850,7 @@ xfs_setattr(
* 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 filesytems.
+ * 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
@@ -1037,10 +987,6 @@ xfs_readlink(
goto error_return;
}
- if (!(ioflags & IO_INVIS)) {
- xfs_ichgtime(ip, XFS_ICHGTIME_ACC);
- }
-
/*
* See if the symlink is stored inline.
*/
@@ -1056,7 +1002,7 @@ xfs_readlink(
nmaps = SYMLINK_MAPS;
error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen),
- 0, NULL, 0, mval, &nmaps, NULL);
+ 0, NULL, 0, mval, &nmaps, NULL, NULL);
if (error) {
goto error_return;
@@ -1084,11 +1030,8 @@ xfs_readlink(
}
-
error_return:
-
xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
return error;
}
@@ -1111,14 +1054,12 @@ xfs_fsync(
xfs_off_t stop)
{
xfs_inode_t *ip;
- int error;
- int error2;
- int syncall;
- xfs_vnode_t *vp;
xfs_trans_t *tp;
+ int error;
+ int log_flushed = 0, changed = 1;
- vp = BHV_TO_VNODE(bdp);
- vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
+ vn_trace_entry(BHV_TO_VNODE(bdp),
+ __FUNCTION__, (inst_t *)__return_address);
ip = XFS_BHVTOI(bdp);
@@ -1127,44 +1068,6 @@ xfs_fsync(
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return XFS_ERROR(EIO);
- xfs_ilock(ip, XFS_IOLOCK_EXCL);
-
- syncall = error = error2 = 0;
-
- if (stop == -1) {
- ASSERT(start >= 0);
- if (start == 0)
- syncall = 1;
- stop = xfs_file_last_byte(ip);
- }
-
- /*
- * If we're invalidating, always flush since we want to
- * tear things down. Otherwise, don't flush anything if
- * we're not dirty.
- */
- if (flag & FSYNC_INVAL) {
- if (ip->i_df.if_flags & XFS_IFEXTENTS &&
- ip->i_df.if_bytes > 0) {
- XVOP_FLUSHINVAL_PAGES(vp, start, -1, FI_REMAPF_LOCKED);
- }
- ASSERT(syncall == 0 || (VN_CACHED(vp) == 0));
- } else {
- /*
- * In the non-invalidating case, calls to fsync() do not
- * flush all the dirty mmap'd pages. That requires a
- * call to msync().
- */
- XVOP_FLUSH_PAGES(vp, start, -1,
- (flag & FSYNC_WAIT) ? 0 : XFS_B_ASYNC,
- FI_NONE, error2);
- }
-
- if (error2) {
- xfs_iunlock(ip, XFS_IOLOCK_EXCL);
- return XFS_ERROR(error2);
- }
-
/*
* We always need to make sure that the required inode state
* is safe on disk. The vnode might be clean but because
@@ -1204,13 +1107,21 @@ xfs_fsync(
* be pinned. If it is, force the log.
*/
- xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_SHARED);
+ xfs_iunlock(ip, XFS_ILOCK_SHARED);
if (xfs_ipincount(ip)) {
- xfs_log_force(ip->i_mount, (xfs_lsn_t)0,
+ _xfs_log_force(ip->i_mount, (xfs_lsn_t)0,
XFS_LOG_FORCE |
((flag & FSYNC_WAIT)
- ? XFS_LOG_SYNC : 0));
+ ? XFS_LOG_SYNC : 0),
+ &log_flushed);
+ } else {
+ /*
+ * If the inode is not pinned and nothing
+ * has changed we don't need to flush the
+ * cache.
+ */
+ changed = 0;
}
error = 0;
} else {
@@ -1227,7 +1138,6 @@ xfs_fsync(
XFS_FSYNC_TS_LOG_RES(ip->i_mount),
0, 0, 0))) {
xfs_trans_cancel(tp, 0);
- xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return error;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
@@ -1242,15 +1152,32 @@ xfs_fsync(
* inode in another recent transaction. So we
* play it safe and fire off the transaction anyway.
*/
- xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
xfs_trans_ihold(tp, ip);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
if (flag & FSYNC_WAIT)
xfs_trans_set_sync(tp);
- error = xfs_trans_commit(tp, 0, NULL);
+ error = _xfs_trans_commit(tp, 0, NULL, &log_flushed);
+
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ }
- xfs_iunlock(ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL);
+ if ((ip->i_mount->m_flags & XFS_MOUNT_BARRIER) && changed) {
+ /*
+ * If the log write didn't issue an ordered tag we need
+ * to flush the disk cache for the data device now.
+ */
+ if (!log_flushed)
+ xfs_blkdev_issue_flush(ip->i_mount->m_ddev_targp);
+
+ /*
+ * If this inode is on the RT dev we need to flush that
+ * cache as well.
+ */
+ if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)
+ xfs_blkdev_issue_flush(ip->i_mount->m_rtdev_targp);
}
+
return error;
}
@@ -1279,21 +1206,22 @@ xfs_inactive_free_eofblocks(
last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
map_len = last_fsb - end_fsb;
if (map_len <= 0)
- return (0);
+ return 0;
nimaps = 1;
xfs_ilock(ip, XFS_ILOCK_SHARED);
- error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0,
- NULL, 0, &imap, &nimaps, NULL);
+ error = XFS_BMAPI(mp, NULL, &ip->i_iocore, end_fsb, map_len, 0,
+ NULL, 0, &imap, &nimaps, NULL, NULL);
xfs_iunlock(ip, XFS_ILOCK_SHARED);
if (!error && (nimaps != 0) &&
- (imap.br_startblock != HOLESTARTBLOCK)) {
+ (imap.br_startblock != HOLESTARTBLOCK ||
+ ip->i_delayed_blks)) {
/*
* Attach the dquots to the inode up front.
*/
if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
- return (error);
+ return error;
/*
* There are blocks after the end of file.
@@ -1321,7 +1249,7 @@ xfs_inactive_free_eofblocks(
ASSERT(XFS_FORCED_SHUTDOWN(mp));
xfs_trans_cancel(tp, 0);
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
- return (error);
+ return error;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
@@ -1349,7 +1277,7 @@ xfs_inactive_free_eofblocks(
}
xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
}
- return (error);
+ return error;
}
/*
@@ -1412,7 +1340,7 @@ xfs_inactive_symlink_rmt(
nmaps = sizeof(mval) / sizeof(mval[0]);
if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size),
XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps,
- &free_list)))
+ &free_list, NULL)))
goto error0;
/*
* Invalidate the block(s).
@@ -1427,7 +1355,7 @@ xfs_inactive_symlink_rmt(
* Unmap the dead block(s) to the free_list.
*/
if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps,
- &first_block, &free_list, &done)))
+ &first_block, &free_list, NULL, &done)))
goto error1;
ASSERT(done);
/*
@@ -1454,7 +1382,7 @@ xfs_inactive_symlink_rmt(
*/
ntp = xfs_trans_dup(tp);
/*
- * Commit the transaction containing extent freeing and EFD's.
+ * Commit the transaction containing extent freeing and EFDs.
* If we get an error on the commit here or on the reserve below,
* we need to unlock the inode since the new transaction doesn't
* have the inode attached.
@@ -1527,7 +1455,7 @@ xfs_inactive_symlink_local(
if (error) {
xfs_trans_cancel(*tpp, 0);
*tpp = NULL;
- return (error);
+ return error;
}
xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
@@ -1540,7 +1468,7 @@ xfs_inactive_symlink_local(
XFS_DATA_FORK);
ASSERT(ip->i_df.if_bytes == 0);
}
- return (0);
+ return 0;
}
/*
@@ -1566,7 +1494,7 @@ xfs_inactive_attrs(
if (error) {
*tpp = NULL;
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
- return (error); /* goto out*/
+ return error; /* goto out */
}
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
@@ -1579,7 +1507,7 @@ xfs_inactive_attrs(
xfs_trans_cancel(tp, 0);
*tpp = NULL;
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
- return (error);
+ return error;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
@@ -1590,7 +1518,7 @@ xfs_inactive_attrs(
ASSERT(ip->i_d.di_anextents == 0);
*tpp = tp;
- return (0);
+ return 0;
}
STATIC int
@@ -1605,7 +1533,7 @@ xfs_release(
vp = BHV_TO_VNODE(bdp);
ip = XFS_BHVTOI(bdp);
- if ((vp->v_type != VREG) || (ip->i_d.di_mode == 0)) {
+ if (!VN_ISREG(vp) || (ip->i_d.di_mode == 0)) {
return 0;
}
@@ -1623,11 +1551,18 @@ xfs_release(
if (ip->i_d.di_nlink != 0) {
if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&
- ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) &&
+ ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0 ||
+ ip->i_delayed_blks > 0)) &&
(ip->i_df.if_flags & XFS_IFEXTENTS)) &&
- (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)))) {
+ (!(ip->i_d.di_flags &
+ (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) {
if ((error = xfs_inactive_free_eofblocks(mp, ip)))
- return (error);
+ return error;
+
+#ifdef RMC /* Update linux inode block count after free above */
+ vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,
+ ip->i_d.di_nblocks + ip->i_delayed_blks);
+#endif
}
}
@@ -1667,7 +1602,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;
@@ -1680,7 +1615,8 @@ xfs_inactive(
* only one with a reference to the inode.
*/
truncate = ((ip->i_d.di_nlink == 0) &&
- ((ip->i_d.di_size != 0) || (ip->i_d.di_nextents > 0)) &&
+ ((ip->i_d.di_size != 0) || (ip->i_d.di_nextents > 0) ||
+ (ip->i_delayed_blks > 0)) &&
((ip->i_d.di_mode & S_IFMT) == S_IFREG));
mp = ip->i_mount;
@@ -1698,12 +1634,19 @@ xfs_inactive(
if (ip->i_d.di_nlink != 0) {
if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&
- ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) &&
- (ip->i_df.if_flags & XFS_IFEXTENTS)) &&
- (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)) ||
- (ip->i_delayed_blks != 0))) {
+ ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0 ||
+ ip->i_delayed_blks > 0)) &&
+ (ip->i_df.if_flags & XFS_IFEXTENTS) &&
+ (!(ip->i_d.di_flags &
+ (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||
+ (ip->i_delayed_blks != 0)))) {
if ((error = xfs_inactive_free_eofblocks(mp, ip)))
- return (VN_INACTIVE_CACHE);
+ return VN_INACTIVE_CACHE;
+#ifdef RMC
+ /* Update linux inode block count after free above */
+ vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,
+ ip->i_d.di_nblocks + ip->i_delayed_blks);
+#endif
}
goto out;
}
@@ -1711,7 +1654,7 @@ xfs_inactive(
ASSERT(ip->i_d.di_nlink == 0);
if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
- return (VN_INACTIVE_CACHE);
+ return VN_INACTIVE_CACHE;
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
if (truncate) {
@@ -1734,7 +1677,7 @@ xfs_inactive(
ASSERT(XFS_FORCED_SHUTDOWN(mp));
xfs_trans_cancel(tp, 0);
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
- return (VN_INACTIVE_CACHE);
+ return VN_INACTIVE_CACHE;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
@@ -1755,7 +1698,7 @@ xfs_inactive(
xfs_trans_cancel(tp,
XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
- return (VN_INACTIVE_CACHE);
+ return VN_INACTIVE_CACHE;
}
} else if ((ip->i_d.di_mode & S_IFMT) == S_IFLNK) {
@@ -1769,7 +1712,7 @@ xfs_inactive(
if (error) {
ASSERT(tp == NULL);
- return (VN_INACTIVE_CACHE);
+ return VN_INACTIVE_CACHE;
}
xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
@@ -1782,7 +1725,7 @@ xfs_inactive(
if (error) {
ASSERT(XFS_FORCED_SHUTDOWN(mp));
xfs_trans_cancel(tp, 0);
- return (VN_INACTIVE_CACHE);
+ return VN_INACTIVE_CACHE;
}
xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
@@ -1804,7 +1747,7 @@ xfs_inactive(
* cancelled, and the inode is unlocked. Just get out.
*/
if (error)
- return (VN_INACTIVE_CACHE);
+ return VN_INACTIVE_CACHE;
} else if (ip->i_afp) {
xfs_idestroy_fork(ip, XFS_ATTR_FORK);
}
@@ -1890,8 +1833,6 @@ xfs_lookup(
}
-#define XFS_CREATE_NEW_MAXTRIES 10000
-
/*
* xfs_create (create a new file).
*/
@@ -1930,7 +1871,7 @@ xfs_create(
dp = XFS_BHVTOI(dir_bdp);
mp = dp->i_mount;
- dm_di_mode = vap->va_mode|VTTOIF(vap->va_type);
+ dm_di_mode = vap->va_mode;
namelen = VNAMELEN(dentry);
if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) {
@@ -1951,7 +1892,9 @@ xfs_create(
udqp = gdqp = NULL;
- if (vap->va_mask & XFS_AT_PROJID)
+ if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
+ prid = dp->i_d.di_projid;
+ else if (vap->va_mask & XFS_AT_PROJID)
prid = (xfs_prid_t)vap->va_projid;
else
prid = (xfs_prid_t)dfltprid;
@@ -1960,7 +1903,7 @@ xfs_create(
* Make sure that we have allocated dquot(s) on disk.
*/
error = XFS_QM_DQVOPALLOC(mp, dp,
- current_fsuid(credp), current_fsgid(credp),
+ current_fsuid(credp), current_fsgid(credp), prid,
XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp);
if (error)
goto std_return;
@@ -2007,8 +1950,7 @@ xfs_create(
(error = XFS_DIR_CANENTER(mp, tp, dp, name, namelen)))
goto error_return;
rdev = (vap->va_mask & XFS_AT_RDEV) ? vap->va_rdev : 0;
- error = xfs_dir_ialloc(&tp, dp,
- MAKEIMODE(vap->va_type,vap->va_mode), 1,
+ error = xfs_dir_ialloc(&tp, dp, vap->va_mode, 1,
rdev, credp, prid, resblks > 0,
&ip, &committed);
if (error) {
@@ -2051,7 +1993,7 @@ xfs_create(
* create transaction goes to disk before returning to
* the user.
*/
- if (mp->m_flags & XFS_MOUNT_WSYNC) {
+ if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
xfs_trans_set_sync(tp);
}
@@ -2089,7 +2031,7 @@ xfs_create(
XFS_QM_DQRELE(mp, gdqp);
/*
- * Propogate the fact that the vnode changed after the
+ * Propagate the fact that the vnode changed after the
* xfs_inode locks have been released.
*/
XVOP_VNODE_CHANGE(vp, VCHANGE_FLAGS_TRUNCATED, 3);
@@ -2113,8 +2055,8 @@ std_return:
abort_return:
cancel_flags |= XFS_TRANS_ABORT;
/* FALLTHROUGH */
- error_return:
+ error_return:
if (tp != NULL)
xfs_trans_cancel(tp, cancel_flags);
@@ -2379,18 +2321,20 @@ int remove_which_error_return = 0;
#define REMOVE_DEBUG_TRACE(x)
#endif /* ! DEBUG */
-
+extern int xfs_remove(bhv_desc_t *, bhv_desc_t *, vname_t *, cred_t *);
/*
* xfs_remove
*
*/
-STATIC int
+int
xfs_remove(
bhv_desc_t *dir_bdp,
+ bhv_desc_t *vp_bdp,
vname_t *dentry,
cred_t *credp)
{
xfs_vnode_t *dir_vp;
+ xfs_vnode_t *xvp;
char *name = VNAME(dentry);
xfs_inode_t *dp, *ip;
xfs_trans_t *tp = NULL;
@@ -2406,6 +2350,9 @@ xfs_remove(
int namelen;
dir_vp = BHV_TO_VNODE(dir_bdp);
+ xvp = BHV_TO_VNODE(vp_bdp);
+
+ printf("xfs_remove: dvp %p vp %p\n",dir_vp,xvp);
vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address);
dp = XFS_BHVTOI(dir_bdp);
@@ -2436,10 +2383,16 @@ xfs_remove(
* for a log reservation. Since we'll have to wait for the
* inactive code to complete before returning from xfs_iget,
* we need to make sure that we don't have log space reserved
- * when we call xfs_iget. Instead we get an unlocked referece
+ * when we call xfs_iget. Instead we get an unlocked reference
* to the inode before getting our log reservation.
*/
+#ifdef RMC
error = xfs_get_dir_entry(dentry, &ip);
+#endif
+ /* FreeBSD has already done the lookup */
+ ip = xvp->v_inode;
+ VN_HOLD(xvp);
+
if (error) {
REMOVE_DEBUG_TRACE(__LINE__);
goto std_return;
@@ -2510,11 +2463,6 @@ xfs_remove(
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
}
- if ((error = _MAC_XFS_IACCESS(ip, MACWRITE, credp))) {
- REMOVE_DEBUG_TRACE(__LINE__);
- goto error_return;
- }
-
/*
* Entry must exist since we did a lookup in xfs_lock_dir_and_entry.
*/
@@ -2553,7 +2501,7 @@ xfs_remove(
* remove transaction goes to disk before returning to
* the user.
*/
- if (mp->m_flags & XFS_MOUNT_WSYNC) {
+ if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
xfs_trans_set_sync(tp);
}
@@ -2600,8 +2548,6 @@ xfs_remove(
error1:
xfs_bmap_cancel(&free_list);
cancel_flags |= XFS_TRANS_ABORT;
-
- error_return:
xfs_trans_cancel(tp, cancel_flags);
goto std_return;
@@ -2651,7 +2597,6 @@ xfs_link(
int cancel_flags;
int committed;
xfs_vnode_t *target_dir_vp;
- bhv_desc_t *src_bdp;
int resblks;
char *target_name = VNAME(dentry);
int target_namelen;
@@ -2661,21 +2606,10 @@ xfs_link(
vn_trace_entry(src_vp, __FUNCTION__, (inst_t *)__return_address);
target_namelen = VNAMELEN(dentry);
- if (src_vp->v_type == VDIR)
+ if (VN_ISDIR(src_vp))
return XFS_ERROR(EPERM);
- /*
- * For now, manually find the XFS behavior descriptor for
- * the source vnode. If it doesn't exist then something
- * is wrong and we should just return an error.
- * Eventually we need to figure out how link is going to
- * work in the face of stacked vnodes.
- */
- src_bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(src_vp), &xfs_vnodeops);
- if (src_bdp == NULL) {
- return XFS_ERROR(EXDEV);
- }
- sip = XFS_BHVTOI(src_bdp);
+ sip = xfs_vtoi(src_vp);
tdp = XFS_BHVTOI(target_dir_bdp);
mp = tdp->i_mount;
if (XFS_FORCED_SHUTDOWN(mp))
@@ -2741,6 +2675,17 @@ xfs_link(
goto error_return;
}
+ /*
+ * If we are using project inheritance, we only allow hard link
+ * creation in our tree when the project IDs are the same; else
+ * the tree quota mechanism could be circumvented.
+ */
+ if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
+ (tdp->i_d.di_projid != sip->i_d.di_projid))) {
+ error = XFS_ERROR(EPERM);
+ goto error_return;
+ }
+
if (resblks == 0 &&
(error = XFS_DIR_CANENTER(mp, tp, tdp, target_name,
target_namelen)))
@@ -2767,7 +2712,7 @@ xfs_link(
* link transaction goes to disk before returning to
* the user.
*/
- if (mp->m_flags & XFS_MOUNT_WSYNC) {
+ if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
xfs_trans_set_sync(tp);
}
@@ -2796,9 +2741,9 @@ std_return:
abort_return:
cancel_flags |= XFS_TRANS_ABORT;
/* FALLTHROUGH */
+
error_return:
xfs_trans_cancel(tp, cancel_flags);
-
goto std_return;
}
/*
@@ -2845,7 +2790,7 @@ xfs_mkdir(
tp = NULL;
dp_joined_to_trans = B_FALSE;
- dm_di_mode = vap->va_mode|VTTOIF(vap->va_type);
+ dm_di_mode = vap->va_mode;
if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) {
error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
@@ -2864,7 +2809,9 @@ xfs_mkdir(
mp = dp->i_mount;
udqp = gdqp = NULL;
- if (vap->va_mask & XFS_AT_PROJID)
+ if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
+ prid = dp->i_d.di_projid;
+ else if (vap->va_mask & XFS_AT_PROJID)
prid = (xfs_prid_t)vap->va_projid;
else
prid = (xfs_prid_t)dfltprid;
@@ -2873,7 +2820,7 @@ xfs_mkdir(
* Make sure that we have allocated dquot(s) on disk.
*/
error = XFS_QM_DQVOPALLOC(mp, dp,
- current_fsuid(credp), current_fsgid(credp),
+ current_fsuid(credp), current_fsgid(credp), prid,
XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
if (error)
goto std_return;
@@ -2918,8 +2865,7 @@ xfs_mkdir(
/*
* create the directory inode.
*/
- error = xfs_dir_ialloc(&tp, dp,
- MAKEIMODE(vap->va_type,vap->va_mode), 2,
+ error = xfs_dir_ialloc(&tp, dp, vap->va_mode, 2,
0, credp, prid, resblks > 0,
&cdp, NULL);
if (error) {
@@ -2985,7 +2931,7 @@ xfs_mkdir(
* mkdir transaction goes to disk before returning to
* the user.
*/
- if (mp->m_flags & XFS_MOUNT_WSYNC) {
+ if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
xfs_trans_set_sync(tp);
}
@@ -3094,7 +3040,7 @@ xfs_rmdir(
* for a log reservation. Since we'll have to wait for the
* inactive code to complete before returning from xfs_iget,
* we need to make sure that we don't have log space reserved
- * when we call xfs_iget. Instead we get an unlocked referece
+ * when we call xfs_iget. Instead we get an unlocked reference
* to the inode before getting our log reservation.
*/
error = xfs_get_dir_entry(dentry, &cdp);
@@ -3170,10 +3116,6 @@ xfs_rmdir(
ITRACE(cdp);
xfs_trans_ijoin(tp, cdp, XFS_ILOCK_EXCL);
- if ((error = _MAC_XFS_IACCESS(cdp, MACWRITE, credp))) {
- goto error_return;
- }
-
ASSERT(cdp->i_d.di_nlink >= 2);
if (cdp->i_d.di_nlink != 2) {
error = XFS_ERROR(ENOTEMPTY);
@@ -3236,7 +3178,7 @@ xfs_rmdir(
* rmdir transaction goes to disk before returning to
* the user.
*/
- if (mp->m_flags & XFS_MOUNT_WSYNC) {
+ if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
xfs_trans_set_sync(tp);
}
@@ -3265,7 +3207,7 @@ xfs_rmdir(
/* Fall through to std_return with error = 0 or the errno
* from xfs_trans_commit. */
-std_return:
+ std_return:
if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_POSTREMOVE)) {
(void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE,
dir_vp, DM_RIGHT_NULL,
@@ -3278,6 +3220,8 @@ std_return:
error1:
xfs_bmap_cancel(&free_list);
cancel_flags |= XFS_TRANS_ABORT;
+ /* FALLTHROUGH */
+
error_return:
xfs_trans_cancel(tp, cancel_flags);
goto std_return;
@@ -3301,7 +3245,6 @@ xfs_readdir(
xfs_trans_t *tp = NULL;
int error = 0;
uint lock_mode;
- xfs_off_t start_offset;
vn_trace_entry(BHV_TO_VNODE(dir_bdp), __FUNCTION__,
(inst_t *)__return_address);
@@ -3312,11 +3255,7 @@ xfs_readdir(
}
lock_mode = xfs_ilock_map_shared(dp);
- start_offset = uiop->uio_offset;
error = XFS_DIR_GETDENTS(dp->i_mount, tp, dp, uiop, eofp);
- if (start_offset != uiop->uio_offset) {
- xfs_ichgtime(dp, XFS_ICHGTIME_ACC);
- }
xfs_iunlock_map_shared(dp, lock_mode);
return error;
}
@@ -3425,7 +3364,9 @@ xfs_symlink(
udqp = gdqp = NULL;
#ifdef XXXKAN
- if (vap->va_mask & XFS_AT_PROJID)
+ if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
+ prid = dp->i_d.di_projid;
+ else if (vap->va_mask & XFS_AT_PROJID)
prid = (xfs_prid_t)vap->va_projid;
else
#endif
@@ -3435,9 +3376,10 @@ xfs_symlink(
* Make sure that we have allocated dquot(s) on disk.
*/
error = XFS_QM_DQVOPALLOC(mp, dp,
- current->td_ucred->cr_uid,
- current->td_ucred->cr_groups[0],
- XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
+ current->td_ucred->cr_uid,
+ current->td_ucred->cr_groups[0],
+ prid,
+ XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
if (error)
goto std_return;
@@ -3468,6 +3410,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.
*/
error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
@@ -3533,7 +3483,7 @@ xfs_symlink(
error = xfs_bmapi(tp, ip, first_fsb, fs_blocks,
XFS_BMAPI_WRITE | XFS_BMAPI_METADATA,
&first_block, resblks, mval, &nmaps,
- &free_list);
+ &free_list, NULL);
if (error) {
goto error1;
}
@@ -3585,7 +3535,7 @@ xfs_symlink(
* symlink transaction goes to disk before returning to
* the user.
*/
- if (mp->m_flags & XFS_MOUNT_WSYNC) {
+ if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
xfs_trans_set_sync(tp);
}
@@ -3688,15 +3638,15 @@ xfs_rwlock(
xfs_vnode_t *vp;
vp = BHV_TO_VNODE(bdp);
- if (vp->v_type == VDIR)
+ if (VN_ISDIR(vp))
return 1;
ip = XFS_BHVTOI(bdp);
if (locktype == VRWLOCK_WRITE) {
xfs_ilock(ip, XFS_IOLOCK_EXCL);
} else if (locktype == VRWLOCK_TRY_READ) {
- return (xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED));
+ return xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED);
} else if (locktype == VRWLOCK_TRY_WRITE) {
- return (xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL));
+ return xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL);
} else {
ASSERT((locktype == VRWLOCK_READ) ||
(locktype == VRWLOCK_WRITE_DIRECT));
@@ -3719,7 +3669,7 @@ xfs_rwunlock(
xfs_vnode_t *vp;
vp = BHV_TO_VNODE(bdp);
- if (vp->v_type == VDIR)
+ if (VN_ISDIR(vp))
return;
ip = XFS_BHVTOI(bdp);
if (locktype == VRWLOCK_WRITE) {
@@ -3746,27 +3696,27 @@ xfs_inode_flush(
{
xfs_inode_t *ip;
xfs_mount_t *mp;
+ xfs_inode_log_item_t *iip;
int error = 0;
ip = XFS_BHVTOI(bdp);
mp = ip->i_mount;
+ iip = ip->i_itemp;
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
- /* Bypass inodes which have already been cleaned by
+ /*
+ * Bypass inodes which have already been cleaned by
* the inode flush clustering code inside xfs_iflush
*/
if ((ip->i_update_core == 0) &&
- ((ip->i_itemp == NULL) ||
- !(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL)))
+ ((iip == NULL) || !(iip->ili_format.ilf_fields & XFS_ILOG_ALL)))
return 0;
if (flags & FLUSH_LOG) {
- xfs_inode_log_item_t *iip = ip->i_itemp;
-
if (iip && iip->ili_last_lsn) {
- xlog_t *log = mp->m_log;
+ xlog_t *log = mp->m_log;
xfs_lsn_t sync_lsn;
int s, log_flags = XFS_LOG_FORCE;
@@ -3779,12 +3729,12 @@ xfs_inode_flush(
if (flags & FLUSH_SYNC)
log_flags |= XFS_LOG_SYNC;
- return xfs_log_force(mp, iip->ili_last_lsn,
- log_flags);
+ return xfs_log_force(mp, iip->ili_last_lsn, log_flags);
}
}
- /* We make this non-blocking if the inode is contended,
+ /*
+ * We make this non-blocking if the inode is contended,
* return EAGAIN to indicate to the caller that they
* did not succeed. This prevents the flush path from
* blocking on inodes inside another operation right
@@ -3873,57 +3823,27 @@ xfs_reclaim(
xfs_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);
- if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
- if (ip->i_d.di_size > 0) {
- /*
- * Flush and invalidate any data left around that is
- * a part of this file.
- *
- * Get the inode's i/o lock so that buffers are pushed
- * out while holding the proper lock. We can't hold
- * the inode lock here since flushing out buffers may
- * cause us to try to get the lock in xfs_strategy().
- *
- * We don't have to call remapf() here, because there
- * cannot be any mapped file references to this vnode
- * since it is being reclaimed.
- */
- xfs_ilock(ip, XFS_IOLOCK_EXCL);
+ /* bad inode, get out here ASAP */
+ if (VN_BAD(vp)) {
+ xfs_ireclaim(ip);
+ return 0;
+ }
- /*
- * If we hit an IO error, we need to make sure that the
- * buffer and page caches of file data for
- * the file are tossed away. We don't want to use
- * VOP_FLUSHINVAL_PAGES here because we don't want dirty
- * pages to stay attached to the vnode, but be
- * marked P_BAD. pdflush/vnode_pagebad
- * hates that.
- */
- if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
- XVOP_FLUSHINVAL_PAGES(vp, 0, -1, FI_NONE);
- } else {
- XVOP_TOSS_PAGES(vp, 0, -1, FI_NONE);
- }
+ vn_iowait(vp);
- ASSERT(VN_CACHED(vp) == 0);
- ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) ||
- ip->i_delayed_blks == 0);
- xfs_iunlock(ip, XFS_IOLOCK_EXCL);
- } else if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
- /*
- * di_size field may not be quite accurate if we're
- * shutting down.
- */
- XVOP_TOSS_PAGES(vp, 0, -1, FI_NONE);
- ASSERT(VN_CACHED(vp) == 0);
- }
- }
+ ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0);
+
+ /*
+ * Make sure the atime in the XFS inode is correct before freeing the
+ * Linux inode.
+ */
+ xfs_synchronize_atime(ip);
vnode_destroy_vobject(vp->v_vnode);
@@ -3957,8 +3877,12 @@ xfs_finish_reclaim(
int sync_mode)
{
xfs_ihash_t *ih = ip->i_hash;
+ xfs_vnode_t *vp = XFS_ITOV_NULL(ip);
int error;
+ if (vp && VN_BAD(vp))
+ goto reclaim;
+
/* 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
@@ -3966,14 +3890,13 @@ 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);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
}
- return(1);
+ return 1;
}
ip->i_flags |= XFS_IRECLAIM;
write_unlock(&ih->ih_lock);
@@ -4006,8 +3929,7 @@ xfs_finish_reclaim(
*/
if (error) {
xfs_iunlock(ip, XFS_ILOCK_EXCL);
- xfs_ireclaim(ip);
- return (0);
+ goto reclaim;
}
xfs_iflock(ip); /* synchronize with xfs_iflush_done */
}
@@ -4026,6 +3948,7 @@ xfs_finish_reclaim(
xfs_iunlock(ip, XFS_ILOCK_EXCL);
}
+ reclaim:
xfs_ireclaim(ip);
return 0;
}
@@ -4033,10 +3956,11 @@ xfs_finish_reclaim(
int
xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock)
{
+#ifdef RMC
int purged;
- struct xfs_inode *curr, *next;
- xfs_inode_t *ip;
+ xfs_inode_t *ip, *n;
int done = 0;
+
while (!done) {
purged = 0;
XFS_MOUNT_ILOCK(mp);
@@ -4052,8 +3976,9 @@ xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock)
}
}
XFS_MOUNT_IUNLOCK(mp);
- xfs_finish_reclaim(ip, noblock,
- XFS_IFLUSH_DELWRI_ELSE_ASYNC);
+ if (xfs_finish_reclaim(ip, noblock,
+ XFS_IFLUSH_DELWRI_ELSE_ASYNC))
+ delay(1);
purged = 1;
break;
}
@@ -4062,6 +3987,7 @@ xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock)
}
XFS_MOUNT_IUNLOCK(mp);
+#endif
return 0;
}
@@ -4092,42 +4018,36 @@ xfs_alloc_file_space(
int alloc_type,
int attr_flags)
{
+ xfs_mount_t *mp = ip->i_mount;
+ xfs_off_t count;
xfs_filblks_t allocated_fsb;
xfs_filblks_t allocatesize_fsb;
- int committed;
- xfs_off_t count;
- xfs_filblks_t datablocks;
- int error;
+ xfs_extlen_t extsz, temp;
+ xfs_fileoff_t startoffset_fsb;
xfs_fsblock_t firstfsb;
- xfs_bmap_free_t free_list;
- xfs_bmbt_irec_t *imapp;
- xfs_bmbt_irec_t imaps[1];
- xfs_mount_t *mp;
- int numrtextents;
- int reccount;
- uint resblks;
+ int nimaps;
+ int bmapi_flag;
+ int quota_flag;
int rt;
- int rtextsize;
- xfs_fileoff_t startoffset_fsb;
xfs_trans_t *tp;
- int xfs_bmapi_flags;
+ xfs_bmbt_irec_t imaps[1], *imapp;
+ xfs_bmap_free_t free_list;
+ uint qblocks, resblks, resrtextents;
+ int committed;
+ int error;
vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address);
- mp = ip->i_mount;
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
- /*
- * determine if this is a realtime file
- */
- if ((rt = XFS_IS_REALTIME_INODE(ip)) != 0) {
- if (ip->i_d.di_extsize)
- rtextsize = ip->i_d.di_extsize;
- else
- rtextsize = mp->m_sb.sb_rextsize;
- } else
- rtextsize = 0;
+ rt = XFS_IS_REALTIME_INODE(ip);
+ if (unlikely(rt)) {
+ if (!(extsz = ip->i_d.di_extsize))
+ extsz = mp->m_sb.sb_rextsize;
+ } else {
+ extsz = ip->i_d.di_extsize;
+ }
if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
return error;
@@ -4138,8 +4058,8 @@ xfs_alloc_file_space(
count = len;
error = 0;
imapp = &imaps[0];
- reccount = 1;
- xfs_bmapi_flags = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0);
+ nimaps = 1;
+ bmapi_flag = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0);
startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
allocatesize_fsb = XFS_B_TO_FSB(mp, count);
@@ -4156,47 +4076,55 @@ xfs_alloc_file_space(
offset, end_dmi_offset - offset,
0, NULL);
if (error)
- return(error);
+ return error;
}
/*
- * allocate file space until done or until there is an error
+ * Allocate file space until done or until there is an error
*/
retry:
while (allocatesize_fsb && !error) {
+ xfs_fileoff_t s, e;
+
/*
- * determine if reserving space on
- * the data or realtime partition.
+ * Determine space reservations for data/realtime.
*/
- if (rt) {
- xfs_fileoff_t s, e;
-
+ if (unlikely(extsz)) {
s = startoffset_fsb;
- do_div(s, rtextsize);
- s *= rtextsize;
- e = roundup_64(startoffset_fsb + allocatesize_fsb,
- rtextsize);
- numrtextents = (int)(e - s) / mp->m_sb.sb_rextsize;
- datablocks = 0;
+ do_div(s, extsz);
+ s *= extsz;
+ e = startoffset_fsb + allocatesize_fsb;
+ if ((temp = do_mod(startoffset_fsb, extsz)))
+ e += temp;
+ if ((temp = do_mod(e, extsz)))
+ e += extsz - temp;
} else {
- datablocks = allocatesize_fsb;
- numrtextents = 0;
+ s = 0;
+ e = allocatesize_fsb;
+ }
+
+ if (unlikely(rt)) {
+ resrtextents = qblocks = (uint)(e - s);
+ resrtextents /= mp->m_sb.sb_rextsize;
+ resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
+ quota_flag = XFS_QMOPT_RES_RTBLKS;
+ } else {
+ resrtextents = 0;
+ resblks = qblocks = \
+ XFS_DIOSTRAT_SPACE_RES(mp, (uint)(e - s));
+ quota_flag = XFS_QMOPT_RES_REGBLKS;
}
/*
- * allocate and setup the transaction
+ * Allocate and setup the transaction.
*/
tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
- resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks);
- error = xfs_trans_reserve(tp,
- resblks,
- XFS_WRITE_LOG_RES(mp),
- numrtextents,
+ error = xfs_trans_reserve(tp, resblks,
+ XFS_WRITE_LOG_RES(mp), resrtextents,
XFS_TRANS_PERM_LOG_RES,
XFS_WRITE_LOG_COUNT);
-
/*
- * check for running out of space
+ * Check for running out of space
*/
if (error) {
/*
@@ -4207,9 +4135,8 @@ retry:
break;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
- error = XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp,
- ip->i_udquot, ip->i_gdquot, resblks, 0, rt ?
- XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS);
+ error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip,
+ qblocks, 0, quota_flag);
if (error)
goto error1;
@@ -4217,19 +4144,19 @@ retry:
xfs_trans_ihold(tp, ip);
/*
- * issue the bmapi() call to allocate the blocks
+ * Issue the xfs_bmapi() call to allocate the blocks
*/
XFS_BMAP_INIT(&free_list, &firstfsb);
- error = xfs_bmapi(tp, ip, startoffset_fsb,
- allocatesize_fsb, xfs_bmapi_flags,
- &firstfsb, 0, imapp, &reccount,
- &free_list);
+ error = XFS_BMAPI(mp, tp, &ip->i_iocore, startoffset_fsb,
+ allocatesize_fsb, bmapi_flag,
+ &firstfsb, 0, imapp, &nimaps,
+ &free_list, NULL);
if (error) {
goto error0;
}
/*
- * complete the transaction
+ * Complete the transaction
*/
error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed);
if (error) {
@@ -4244,7 +4171,7 @@ retry:
allocated_fsb = imapp->br_blockcount;
- if (reccount == 0) {
+ if (nimaps == 0) {
error = XFS_ERROR(ENOSPC);
break;
}
@@ -4267,9 +4194,11 @@ dmapi_enospc_check:
return error;
- error0:
+error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
xfs_bmap_cancel(&free_list);
- error1:
+ XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag);
+
+error1: /* Just cancel transaction */
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
goto dmapi_enospc_check;
@@ -4301,8 +4230,8 @@ xfs_zero_remaining_bytes(
for (offset = startoff; offset <= endoff; offset = lastoffset + 1) {
offset_fsb = XFS_B_TO_FSBT(mp, offset);
nimap = 1;
- error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0, NULL, 0, &imap,
- &nimap, NULL);
+ error = XFS_BMAPI(mp, NULL, &ip->i_iocore, offset_fsb, 1, 0,
+ NULL, 0, &imap, &nimap, NULL, NULL);
if (error || nimap < 1)
break;
ASSERT(imap.br_blockcount >= 1);
@@ -4361,6 +4290,7 @@ xfs_free_file_space(
xfs_off_t len,
int attr_flags)
{
+ xfs_vnode_t *vp;
int committed;
int done;
xfs_off_t end_dmi_offset;
@@ -4379,10 +4309,13 @@ xfs_free_file_space(
int rt;
xfs_fileoff_t startoffset_fsb;
xfs_trans_t *tp;
+ int need_iolock = 1;
- vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address);
+ vp = XFS_ITOV(ip);
mp = ip->i_mount;
+ vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
+
if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
return error;
@@ -4399,21 +4332,35 @@ xfs_free_file_space(
DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) {
if (end_dmi_offset > ip->i_d.di_size)
end_dmi_offset = ip->i_d.di_size;
- error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOV(ip),
+ error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, vp,
offset, end_dmi_offset - offset,
AT_DELAY_FLAG(attr_flags), NULL);
if (error)
- return(error);
+ return error;
+ }
+
+ ASSERT(attr_flags & ATTR_NOLOCK ? attr_flags & ATTR_DMI : 1);
+ if (attr_flags & ATTR_NOLOCK)
+ need_iolock = 0;
+ if (need_iolock) {
+ xfs_ilock(ip, XFS_IOLOCK_EXCL);
+ vn_iowait(vp); /* wait for the completion of any pending DIOs */
}
- xfs_ilock(ip, XFS_IOLOCK_EXCL);
rounding = MAX((__uint8_t)(1 << mp->m_sb.sb_blocklog),
(__uint8_t)NBPP);
ilen = len + (offset & (rounding - 1));
ioffset = offset & ~(rounding - 1);
if (ilen & (rounding - 1))
ilen = (ilen + rounding) & ~(rounding - 1);
- xfs_inval_cached_pages(XFS_ITOV(ip), &(ip->i_iocore), ioffset, 0, 0);
+
+ if (VN_CACHED(vp) != 0) {
+ xfs_inval_cached_trace(&ip->i_iocore, ioffset, -1,
+ ctooff(offtoct(ioffset)), -1);
+ XVOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(ioffset)),
+ -1, FI_REMAPF_LOCKED);
+ }
+
/*
* Need to zero the stuff we're not freeing, on disk.
* If its a realtime file & can't use unwritten extents then we
@@ -4422,10 +4369,10 @@ xfs_free_file_space(
*/
if (rt && !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) {
nimap = 1;
- error = xfs_bmapi(NULL, ip, startoffset_fsb, 1, 0, NULL, 0,
- &imap, &nimap, NULL);
+ error = XFS_BMAPI(mp, NULL, &ip->i_iocore, startoffset_fsb,
+ 1, 0, NULL, 0, &imap, &nimap, NULL, NULL);
if (error)
- return error;
+ goto out_unlock_iolock;
ASSERT(nimap == 0 || nimap == 1);
if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
xfs_daddr_t block;
@@ -4437,10 +4384,10 @@ xfs_free_file_space(
startoffset_fsb += mp->m_sb.sb_rextsize - mod;
}
nimap = 1;
- error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, 1, 0, NULL, 0,
- &imap, &nimap, NULL);
+ error = XFS_BMAPI(mp, NULL, &ip->i_iocore, endoffset_fsb - 1,
+ 1, 0, NULL, 0, &imap, &nimap, NULL, 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);
@@ -4498,8 +4445,8 @@ xfs_free_file_space(
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
error = XFS_TRANS_RESERVE_QUOTA(mp, tp,
- ip->i_udquot, ip->i_gdquot, resblks, 0, rt ?
- XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS);
+ ip->i_udquot, ip->i_gdquot, resblks, 0,
+ XFS_QMOPT_RES_REGBLKS);
if (error)
goto error1;
@@ -4510,9 +4457,9 @@ xfs_free_file_space(
* issue the bunmapi() call to free the blocks
*/
XFS_BMAP_INIT(&free_list, &firstfsb);
- error = xfs_bunmapi(tp, ip, startoffset_fsb,
+ error = XFS_BUNMAPI(mp, tp, &ip->i_iocore, startoffset_fsb,
endoffset_fsb - startoffset_fsb,
- 0, 2, &firstfsb, &free_list, &done);
+ 0, 2, &firstfsb, &free_list, NULL, &done);
if (error) {
goto error0;
}
@@ -4529,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;
}
@@ -4581,7 +4531,7 @@ xfs_change_file_space(
/*
* must be a regular file and have write permission
*/
- if (vp->v_type != VREG)
+ if (!VN_ISREG(vp))
return XFS_ERROR(EINVAL);
xfs_ilock(ip, XFS_ILOCK_SHARED);
@@ -4693,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)