Example #1
0
/*
 * 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;
}
Example #2
0
/*
 * Guts of jfs_truncate.  Called with locks already held.  Can be called
 * with directory for truncating directory index table.
 */
void jfs_truncate_nolock(struct inode *ip, loff_t length)
{
	loff_t newsize;
	tid_t tid;

	ASSERT(length >= 0);

	if (test_cflag(COMMIT_Nolink, ip)) {
		xtTruncate(0, ip, length, COMMIT_WMAP);
		return;
	}

	do {
		tid = txBegin(ip->i_sb, 0);

		/*
		 * The commit_mutex cannot be taken before txBegin.
		 * txBegin may block and there is a chance the inode
		 * could be marked dirty and need to be committed
		 * before txBegin unblocks
		 */
		mutex_lock(&JFS_IP(ip)->commit_mutex);

		newsize = xtTruncate(tid, ip, length,
				     COMMIT_TRUNCATE | COMMIT_PWMAP);
		if (newsize < 0) {
			txEnd(tid);
			mutex_unlock(&JFS_IP(ip)->commit_mutex);
			break;
		}

		ip->i_mtime = ip->i_ctime = CURRENT_TIME;
		mark_inode_dirty(ip);

		txCommit(tid, 1, &ip, 0);
		txEnd(tid);
		mutex_unlock(&JFS_IP(ip)->commit_mutex);
	} while (newsize > length);	/* Truncate isn't always atomic */
}
Example #3
0
static int jfs_symlink(struct inode *dip, struct dentry *dentry,
                       const char *name)
{
    int rc;
    tid_t tid;
    ino_t ino = 0;
    struct component_name dname;
    int ssize;		/* source pathname size */
    struct btstack btstack;
    struct inode *ip = dentry->d_inode;
    unchar *i_fastsymlink;
    s64 xlen = 0;
    int bmask = 0, xsize;
    s64 extent = 0, xaddr;
    struct metapage *mp;
    struct super_block *sb;
    struct tblock *tblk;

    struct inode *iplist[2];

    jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);

    dquot_initialize(dip);

    ssize = strlen(name) + 1;

    /*
     * search parent directory for entry/freespace
     * (dtSearch() returns parent directory page pinned)
     */

    if ((rc = get_UCSname(&dname, dentry)))
        goto out1;

    /*
     * allocate on-disk/in-memory inode for symbolic link:
     * (iAlloc() returns new, locked inode)
     */
    ip = ialloc(dip, S_IFLNK | 0777);
    if (IS_ERR(ip)) {
        rc = PTR_ERR(ip);
        goto out2;
    }

    tid = txBegin(dip->i_sb, 0);

    mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
    mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);

    rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
    if (rc)
        goto out3;

    tblk = tid_to_tblock(tid);
    tblk->xflag |= COMMIT_CREATE;
    tblk->ino = ip->i_ino;
    tblk->u.ixpxd = JFS_IP(ip)->ixpxd;

    /* fix symlink access permission
     * (dir_create() ANDs in the u.u_cmask,
     * but symlinks really need to be 777 access)
     */
    ip->i_mode |= 0777;

    /*
     * write symbolic link target path name
     */
    xtInitRoot(tid, ip);

    /*
     * write source path name inline in on-disk inode (fast symbolic link)
     */

    if (ssize <= IDATASIZE) {
        ip->i_op = &jfs_fast_symlink_inode_operations;

        i_fastsymlink = JFS_IP(ip)->i_inline;
        memcpy(i_fastsymlink, name, ssize);
        ip->i_size = ssize - 1;

        /*
         * if symlink is > 128 bytes, we don't have the space to
         * store inline extended attributes
         */
        if (ssize > sizeof (JFS_IP(ip)->i_inline))
            JFS_IP(ip)->mode2 &= ~INLINEEA;

        jfs_info("jfs_symlink: fast symlink added  ssize:%d name:%s ",
                 ssize, name);
    }
    /*
     * write source path name in a single extent
     */
    else {
        jfs_info("jfs_symlink: allocate extent ip:0x%p", ip);

        ip->i_op = &jfs_symlink_inode_operations;
        ip->i_mapping->a_ops = &jfs_aops;

        /*
         * even though the data of symlink object (source
         * path name) is treated as non-journaled user data,
         * it is read/written thru buffer cache for performance.
         */
        sb = ip->i_sb;
        bmask = JFS_SBI(sb)->bsize - 1;
        xsize = (ssize + bmask) & ~bmask;
        xaddr = 0;
        xlen = xsize >> JFS_SBI(sb)->l2bsize;
        if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) {
            txAbort(tid, 0);
            goto out3;
        }
        extent = xaddr;
        ip->i_size = ssize - 1;
        while (ssize) {
            /* This is kind of silly since PATH_MAX == 4K */
            int copy_size = min(ssize, PSIZE);

            mp = get_metapage(ip, xaddr, PSIZE, 1);

            if (mp == NULL) {
                xtTruncate(tid, ip, 0, COMMIT_PWMAP);
                rc = -EIO;
                txAbort(tid, 0);
                goto out3;
            }
            memcpy(mp->data, name, copy_size);
            flush_metapage(mp);
            ssize -= copy_size;
            name += copy_size;
            xaddr += JFS_SBI(sb)->nbperpage;
        }
    }

    /*
     * create entry for symbolic link in parent directory
     */
    rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE);
    if (rc == 0) {
        ino = ip->i_ino;
        rc = dtInsert(tid, dip, &dname, &ino, &btstack);
    }
    if (rc) {
        if (xlen)
            xtTruncate(tid, ip, 0, COMMIT_PWMAP);
        txAbort(tid, 0);
        /* discard new inode */
        goto out3;
    }

    mark_inode_dirty(ip);

    dip->i_ctime = dip->i_mtime = CURRENT_TIME;
    mark_inode_dirty(dip);
    /*
     * commit update of parent directory and link object
     */

    iplist[0] = dip;
    iplist[1] = ip;
    rc = txCommit(tid, 2, &iplist[0], 0);

out3:
    txEnd(tid);
    mutex_unlock(&JFS_IP(ip)->commit_mutex);
    mutex_unlock(&JFS_IP(dip)->commit_mutex);
    if (rc) {
        free_ea_wmap(ip);
        ip->i_nlink = 0;
        unlock_new_inode(ip);
        iput(ip);
    } else {
        d_instantiate(dentry, ip);
        unlock_new_inode(ip);
    }

out2:
    free_UCSname(&dname);

out1:
    jfs_info("jfs_symlink: rc:%d", rc);
    return rc;
}
Example #4
0
/*
 * NAME:	jfs_free_zero_link()
 *
 * FUNCTION:	for non-directory, called by iClose(),
 *		free resources of a file from cache and WORKING map
 *		for a file previously committed with zero link count
 *		while associated with a pager object,
 *
 * PARAMETER:	ip	- pointer to inode of file.
 */
void jfs_free_zero_link(struct inode *ip)
{
    int type;

    jfs_info("jfs_free_zero_link: ip = 0x%p", ip);

    /* return if not reg or symbolic link or if size is
     * already ok.
     */
    type = ip->i_mode & S_IFMT;

    switch (type) {
    case S_IFREG:
        break;
    case S_IFLNK:
        /* if its contained in inode nothing to do */
        if (ip->i_size < IDATASIZE)
            return;
        break;
    default:
        return;
    }

    /*
     * free EA
     */
    if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
        s64 xaddr = addressDXD(&JFS_IP(ip)->ea);
        int xlen = lengthDXD(&JFS_IP(ip)->ea);
        struct maplock maplock;	/* maplock for COMMIT_WMAP */
        struct pxd_lock *pxdlock;	/* maplock for COMMIT_WMAP */

        /* free EA pages from cache */
        invalidate_dxd_metapages(ip, JFS_IP(ip)->ea);

        /* free EA extent from working block map */
        maplock.index = 1;
        pxdlock = (struct pxd_lock *) & maplock;
        pxdlock->flag = mlckFREEPXD;
        PXDaddress(&pxdlock->pxd, xaddr);
        PXDlength(&pxdlock->pxd, xlen);
        txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
    }

    /*
     * free ACL
     */
    if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
        s64 xaddr = addressDXD(&JFS_IP(ip)->acl);
        int xlen = lengthDXD(&JFS_IP(ip)->acl);
        struct maplock maplock;	/* maplock for COMMIT_WMAP */
        struct pxd_lock *pxdlock;	/* maplock for COMMIT_WMAP */

        invalidate_dxd_metapages(ip, JFS_IP(ip)->acl);

        /* free ACL extent from working block map */
        maplock.index = 1;
        pxdlock = (struct pxd_lock *) & maplock;
        pxdlock->flag = mlckFREEPXD;
        PXDaddress(&pxdlock->pxd, xaddr);
        PXDlength(&pxdlock->pxd, xlen);
        txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
    }

    /*
     * free xtree/data (truncate to zero length):
     * free xtree/data pages from cache, and
     * free xtree/data blocks from working block map;
     */
    if (ip->i_size)
        xtTruncate(0, ip, 0, COMMIT_WMAP);
}