/* * NAME: jfs_ftruncate(vp, flags, length, vinfo, crp) * * FUNCTION: truncate regular file <vp> to the specified size <length>. * * PARAMETER: vp _ file to be truncated. * flags - open flags * length - new length * vinfo - unused * crp - credential * * RETURN: * * note: EINVAL: JFS does NOT support ftruncate() on file types * other than regular filei: the effect of ftruncate()/truncate() * on file types other than regular file is unspecified. [XPG4.2]. * * LFS validation ?: the file must be open for writing. */ jfs_ftruncate( struct vnode *vp, /* file */ int32 flags, /* open flags */ offset_t length, /* new length */ caddr_t vinfo, /* Gfs specific inofo */ struct ucred *crp) /* credential structure */ { int64 orig_nblocks; // F226941 int32 rc = 0; int32 tid; inode_t *ip = VP2IP(vp); extern int iwritelockx(); extern int iwriteunlockx(); if ((ip->i_mode & IFMT) != IFREG) return EINVAL; IWRITE_LOCK(ip); /* * verify mandatory/enforcement-mode file section locking */ /* if (ENF_LOCK(ip->i_mode)) { struct eflock bf; bf.l_type = F_WRLCK; bf.l_whence = 0; bf.l_start = length; bf.l_len = 0; bf.l_pid = U.U_procp->p_pid; bf.l_sysid = 0; bf.l_vfs = MNT_XJFS; if ((rc = common_reclock(IP2GP(ip), ip->i_size, length, &bf, ((flags & (FNDELAY|FNONBLOCK)) ? INOFLCK : SLPFLCK|INOFLCK), 0, 0, iwritelockx, iwriteunlockx)) || bf.l_type != F_UNLCK) { rc = rc ? rc : EAGAIN; goto out; } } */ /* * truncate down */ if (length < ip->i_size) { // BEGIN D230860 /* * All inodes must be locked before beginning transaction */ if (ip->i_dasdlim && (ip->i_dasdlim->flag & DLIM_DIRS_LOCKED) == 0) dasd_write_lock(0, ip->i_dasdlim); // END D230860 txBegin(ip->i_ipmnt, &tid, 0); orig_nblocks = ip->i_nblocks; // F226941 if (rc = iTruncate(tid, ip, (int64)length)) { txEnd(tid); goto out; } ip->i_flag |= IFSYNC; DLIM_UPDATE(tid, ip , ip->i_nblocks - orig_nblocks); // F226941 rc = DLIM_TXCOMMIT(tid, ip, 0); // F226941 txEnd(tid); goto out; } /* * truncate up (extension) */ else if (length > ip->i_size) { #ifndef _JFS_OS2 /* check u_limit */ if (length > U.U_limit) { rc = EFBIG; goto out; } #endif /* _JFS_OS2 */ // BEGIN F226941 orig_nblocks = ip->i_nblocks; // D233382 #ifndef _JFS_FASTDASD // D233382 if (ip->i_dasdlim) { /* * All inodes must be locked before begining * transaction */ if ((ip->i_dasdlim->flag & DLIM_DIRS_LOCKED) == 0) // D230860 dasd_write_lock(0, ip->i_dasdlim); // D230860 txBegin(ip->i_ipmnt, &tid, 1); } else #endif /* _JFS_FASTDASD */ // D233382 { #ifdef _JFS_LAZYCOMMIT txBeginAnon(ip->i_ipmnt); // D233382 #endif tid = 0; } // END F226941 if (rc = iExtend(tid, ip, (int64)length)) { #ifndef _JFS_FASTDASD // D233382 if (tid) // F226941 txEnd(tid); // F226941 #endif // D233382 goto out; } ip->i_flag |= IFSYNC; // BEGIN F226941 DLIM_UPDATE(tid, ip, ip->i_nblocks - orig_nblocks); #ifndef _JFS_FASTDASD // D233382 if (tid) { rc = DLIM_TXCOMMIT(tid, ip, 0); txEnd(tid); } else #endif /* _JFS_FASTDASD */ // D233382 // END F226941 /* if available tlocks are scarce and inode has anonymous * tlocks, OR if we modified a metadata page that is on the * synclist, commit inode. */ if ((TlocksLow && ip->i_atlhead) || (ip->i_flag & ISYNCLIST)) { txBegin(ip->i_ipmnt, &tid, COMMIT_FORCE); rc = txCommit(tid, 1, &ip, 0); // F226941 txEnd(tid); } } /* * no change in size */ else /* (length == ip->i_size) */ /* mark the inode as changed and updated (ala BSD) */ imark(ip, ICHG|IUPD); out: DLIM_WRITE_UNLOCK(ip, ip->i_dasdlim); // F226941 return rc; }
/* * NAME: iOpen() * * FUNCTION: common function that opens a file. * called by jfs_open() and jfs_create(). * * PARAMETER: ip - inode to open * flag - open flags from the file pointer. * ext - external data used by the device driver. * crp - credential * * RETURN: EBUSY - if truncating a mapped file * errors from subroutines * * note: at most a single commit may occur in jfs_open() and jfs_create() * as FEXEC and FTRUNC are mutually exclusive. */ int32 iOpen( inode_t *ip, /* inode of file to open */ int32 flag, /* open(2) flags */ int32 tflag, /* trucation flag */ FEALIST *pfealist, /* EAs if truncating */ struct ucred *crp) /* credential */ { int32 rc = 0; struct gnode *gp; /* gnode pointer from inode */ int64 orig_nblocks; // F226941 int32 tid; /* bind the newly opened file to a cache control object */ if ((ip->i_mode & IFMT) == IFREG && ip->i_cacheid == NULL) { if (rc = iBindCache(ip)) return rc; } /* if open/create FTRUNC, truncate to zero length */ if (tflag & OPEN_ACTION_REPLACE_IF_EXISTS) { if (isReadOnly(ip)) return EROFS; orig_nblocks = ip->i_nblocks; // F226941 // BEGIN D230860 /* * Cannot begin transaction until all inodes are locked */ if (ip->i_dasdlim && (ip->i_dasdlim->flag & DLIM_DIRS_LOCKED) == 0) dasd_write_lock(0, ip->i_dasdlim); // END D230860 txBegin(ip->i_ipmnt, &tid, 0); if (rc = iTruncate(tid, ip, 0)) { txEnd(tid); return rc; } imark(ip, IACC|ICHG|IUPD|IFSYNC); // D233382 #ifdef _JFS_OS2 rc = jfs_InitializeFEAList(ip, tid, pfealist); /* If we successfully truncated the file, but failed adding the * EA's, we are in a bad state. Punt... */ if (rc) { txAbort(tid, 0); txEnd(tid); return rc; } #endif /* _JFS_OS2 */ DLIM_UPDATE(tid, ip, ip->i_nblocks - orig_nblocks); // F226941 rc = DLIM_TXCOMMIT(tid, ip, 0); // F226941 txEnd(tid); if (rc) return rc; } /* * update per open counters */ gp = IP2GP(ip); #ifdef _JFS_OS2 /* keep count of opens by type */ switch (flag & (OPEN_ACCESS_READWRITE | OPEN_ACCESS_WRITEONLY)) { case (OPEN_ACCESS_READWRITE): gp->gn_wrcnt++; gp->gn_rdcnt++; break; case (OPEN_ACCESS_WRITEONLY): gp->gn_wrcnt++; break; default: gp->gn_rdcnt++; } /* set up sharing mode */ switch (flag & (OPEN_SHARE_DENYREAD)) { case(OPEN_SHARE_DENYWRITE): gp->gn_dwcnt++; break; case(OPEN_SHARE_DENYREAD): gp->gn_drcnt++; break; case(OPEN_SHARE_DENYREADWRITE): gp->gn_flags |= GNF_NSHARE; break; } if ((flag & OPEN_FLAGS_LARGEFILE) == 0) gp->gn_lgcnt++; #endif /* _JFS_OS2 */ return rc; }