/* * NAME: iTruncate(tid, ip, newsize) * * FUNCTION: truncate up/down a regular file to specified size, or * truncate down directory or symbolic link to zero length * (length is ignored and assumed to be zero if the object * is a directory or symbolic link). * if length is > 0, the file must be open (i.e.bound to a * VM segment). * return 0 if type is not one of these. * * PARAMETER: ip - inode to truncate * newsize - new size of the file * * RETURN: * * SERIALIZATION: the IWRITE_LOCK is held on entry/exit. */ int32 iTruncate( int32 tid, inode_t *ip, int64 newsize) { int32 rc; int64 nbytes; int64 pfirst, bfirst; /* printf("iTruncate: ip:0x%08x eof:0x%08x:0x%08x\n", ip, newsize); */ if ((ip->i_mode & IFMT) != IFREG) return EINVAL; /* if truncating to a non-zero newsize, make sure * file is bound to its cache control object. */ if (newsize != 0 && ip->i_cacheid == NULL) { if (rc = iBindCache(ip)) return rc; } /* * if the newsize is not an integral number of pages, * the file between newsize and next page boundary will * be cleared. * if truncating into a file hole, it will cause * a full block to be allocated for the logical block. */ /* * if the file was commited with zero link count before * (temporary file), its persistent resources were already * freed at that time: just truncate/free working resources; */ if (ip->i_cflag & COMMIT_NOLINK) { rc = xtTruncate(0, ip, newsize, COMMIT_WMAP); return rc; } /* * delete pages and set new size. */ rc = xtTruncate(tid, ip, newsize, COMMIT_TRUNCATE|COMMIT_PWMAP); imark(ip, ICHG|IUPD); return rc; }
/* * NAME: jfs_defragfs() * * FUNCTION: relocate specified extent for defragfs() * optionally commiting the operation. */ int32 jfs_defragfs( char *pData, /* pointer to buffer containing plist */ uint32 lenData, /* length of buffer */ uint16 *pbufsize) /* pointer of buffer length */ { int32 rc = 0; defragfs_t pList, *p = &pList; uint32 xtype; int64 offset, xoff, oxaddr, nxaddr; int32 xlen; inode_t *ipmnt, *ipimap, *ipbmap; inode_t *ip = NULL; xad_t oxad; pxd_t opxd; mode_t imode; int32 tid; inode_t *iplist[1]; struct vfs *vfsp; if (rc = KernCopyIn(&pList, pData, lenData)) return rc; /* get the 'mount' inode */ for (vfsp = vfs_anchor; vfsp != NULL; vfsp = vfsp->vfs_next) if (vfsp->vfs_vpfsi->vpi_drive == pList.dev) break; if (vfsp == NULL) return EINVAL; xtype = pList.flag; /* sync at start of defragfs ? */ if (xtype & DEFRAGFS_SYNC) { jEVENT(0,("jfs_defragfs: DEFRAGFS_SYNC\n")); if ((vfsp->vfs_flag & VFS_READONLY) || (vfsp->vfs_flag & VFS_ACCEPT)) return 0; ipimap = (inode_t *)vfsp->vfs_data; ipmnt = ipimap->i_ipmnt; ipbmap = ipmnt->i_ipbmap; /* sync the file system */ iSyncFS(vfsp); /* write dirty pages of imap */ diSync(ipimap); /* write dirty pages of bmap */ dbSync(ipbmap); return 0; } else if (!(xtype & DEFRAGFS_RELOCATE)) return EINVAL; if (vfsp->vfs_flag & VFS_READONLY) return EROFS; if (vfsp->vfs_flag & VFS_ACCEPT) return EINVAL; /* get the relocation parameter */ xoff = pList.xoff; oxaddr = pList.old_xaddr; nxaddr = pList.new_xaddr; xlen = pList.xlen; jEVENT(0,("jfs_defragfs: i:%d xtype:0x%08x xoff:%lld xlen:%d xaddr:%lld:%lld\n", pList.ino, xtype, xoff, xlen, oxaddr, nxaddr)); /* get the object inode if it exist */ ICACHE_LOCK(); rc = iget(vfsp, pList.ino, &ip, 0); ICACHE_UNLOCK(); if(rc) { jEVENT(0,("jfs_defragfs: stale target object.\n")); rc = ESTALE; /* stale object ENOENT */ goto out1; } IWRITE_LOCK(ip); /* validate inode */ if (ip->i_nlink == 0 || ip->i_gen != pList.gen || ip->i_fileset != pList.fileset || ip->i_inostamp != pList.inostamp) { jEVENT(0,("jfs_defragfs: stale target object.\n")); rc = ESTALE; /* stale object ENOENT */ goto out1; } /* validate object type: regular file or directory */ imode = ip->i_mode & IFMT; switch(imode) { case IFREG: case IFDIR: break; default: rc = ESTALE; /* invalid object type ENOENT */ goto out1; } /* * try to allocate new destination extent */ if (rc = dbAllocExact(ip, nxaddr, xlen)) { jEVENT(0,("jfs_defragfs: stale destination extent.\n")); rc = ENOSPC; goto out1; } iBindCache(ip); /* * regular file: */ if (imode == IFREG) { /* * automatic commit before and after each relocation * may be skipped after more experience; */ /* * commit any update before relocation */ if (ip->i_flag & IUPD) { ip->i_flag |= IFSYNC; txBegin(ip->i_ipmnt, &tid, 0); iplist[0] = ip; rc = txCommit(tid, 1, &iplist[0], 0); if (rc) goto out2; txEnd(tid); } /* * relocate either xtpage or data extent */ txBegin(ip->i_ipmnt, &tid, 0); /* source extent xad */ XADoffset(&oxad, xoff); XADaddress(&oxad, oxaddr); XADlength(&oxad, xlen); rc = xtRelocate(tid, ip, &oxad, nxaddr, xtype); if (rc) goto out2; iplist[0] = ip; rc = txCommit(tid, 1, &iplist[0], 0); if (rc) goto out2; txEnd(tid); goto out1; } /* * directory: */ else /* IFDIR */ { /* * relocate dtpage */ txBegin(ip->i_ipmnt, &tid, 0); /* source extent pxd */ PXDaddress(&opxd, oxaddr); PXDlength(&opxd, xlen); rc = dtRelocate(tid, ip, xoff, &opxd, nxaddr); if (rc) goto out2; iplist[0] = ip; rc = txCommit(tid, 1, &iplist[0], 0); if (rc) goto out2; txEnd(tid); goto out1; } out2: dbFree(ip, nxaddr, xlen) ; out1: if (ip) { IWRITE_UNLOCK(ip); ICACHE_LOCK(); iput(ip, NULL); ICACHE_UNLOCK(); } jEVENT(0,("jfs_defragfs: rc=%d\n", rc)); 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; }