int jfs_umount(struct super_block *sb)
{
	struct jfs_sb_info *sbi = JFS_SBI(sb);
	struct inode *ipbmap = sbi->ipbmap;
	struct inode *ipimap = sbi->ipimap;
	struct inode *ipaimap = sbi->ipaimap;
	struct inode *ipaimap2 = sbi->ipaimap2;
	struct jfs_log *log;
	int rc = 0;

	jfs_info("UnMount JFS: sb:0x%p", sb);

	if ((log = sbi->log))
		/*
		 * Wait for outstanding transactions to be written to log:
		 */
		jfs_flush_journal(log, 2);

	diUnmount(ipimap, 0);

	diFreeSpecial(ipimap);
	sbi->ipimap = NULL;

	ipaimap2 = sbi->ipaimap2;
	if (ipaimap2) {
		diUnmount(ipaimap2, 0);
		diFreeSpecial(ipaimap2);
		sbi->ipaimap2 = NULL;
	}

	ipaimap = sbi->ipaimap;
	diUnmount(ipaimap, 0);
	diFreeSpecial(ipaimap);
	sbi->ipaimap = NULL;

	dbUnmount(ipbmap, 0);

	diFreeSpecial(ipbmap);
	sbi->ipimap = NULL;

	filemap_write_and_wait(sbi->direct_inode->i_mapping);

	if (log) {		
		updateSuper(sb, FM_CLEAN);

		rc = lmLogClose(sb);
	}
	jfs_info("UnMount JFS Complete: rc = %d", rc);
	return rc;
}
示例#2
0
void jfs_delete_inode(struct inode *inode)
{
	jfs_info("In jfs_delete_inode, inode = 0x%p", inode);

	if (!is_bad_inode(inode))
		dquot_initialize(inode);

	if (!is_bad_inode(inode) &&
	    (JFS_IP(inode)->fileset == FILESYSTEM_I)) {
		truncate_inode_pages(&inode->i_data, 0);

		if (test_cflag(COMMIT_Freewmap, inode))
			jfs_free_zero_link(inode);

		diFree(inode);

		/*
		 * Free the inode from the quota allocation.
		 */
		dquot_initialize(inode);
		dquot_free_inode(inode);
		dquot_drop(inode);
	}

	clear_inode(inode);
}
示例#3
0
void jfs_evict_inode(struct inode *inode)
{
	jfs_info("In jfs_evict_inode, inode = 0x%p", inode);

	if (!inode->i_nlink && !is_bad_inode(inode)) {
		dquot_initialize(inode);

		if (JFS_IP(inode)->fileset == FILESYSTEM_I) {
			truncate_inode_pages(&inode->i_data, 0);

			if (test_cflag(COMMIT_Freewmap, inode))
				jfs_free_zero_link(inode);

			diFree(inode);

			/*
			 * Free the inode from the quota allocation.
			 */
			dquot_initialize(inode);
			dquot_free_inode(inode);
		}
	} else {
		truncate_inode_pages(&inode->i_data, 0);
	}
	end_writeback(inode);
	dquot_drop(inode);
}
示例#4
0
void jfs_clear_inode(struct inode *inode)
{
	struct jfs_inode_info *ji = JFS_IP(inode);

	if (is_bad_inode(inode))
		/*
		 * We free the fs-dependent structure before making the
		 * inode bad
		 */
		return;

	jfs_info("jfs_clear_inode called ip = 0x%p", inode);

	if (ji->active_ag != -1) {
		struct bmap *bmap = JFS_SBI(inode->i_sb)->bmap;
		atomic_dec(&bmap->db_active[ji->active_ag]);
	}

	ASSERT(list_empty(&ji->anon_inode_list));

	if (ji->atlhead) {
		jfs_err("jfs_clear_inode: inode %p has anonymous tlocks",
			inode);
		jfs_err("i_state = 0x%lx, cflag = 0x%lx", inode->i_state,
			ji->cflag);
	}

	free_jfs_inode(inode);
}
示例#5
0
static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struct nameidata *nd)
{
	struct btstack btstack;
	ino_t inum;
	struct inode *ip;
	struct component_name key;
	int rc;

	jfs_info("jfs_lookup: name = %s", dentry->d_name.name);

	if ((rc = get_UCSname(&key, dentry)))
		return ERR_PTR(rc);
	rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
	free_UCSname(&key);
	if (rc == -ENOENT) {
		ip = NULL;
	} else if (rc) {
		jfs_err("jfs_lookup: dtSearch returned %d", rc);
		ip = ERR_PTR(rc);
	} else {
		ip = jfs_iget(dip->i_sb, inum);
		if (IS_ERR(ip))
			jfs_err("jfs_lookup: iget failed on inum %d", (uint)inum);
	}

	return d_splice_alias(ip, dentry);
}
示例#6
0
void jfs_truncate(struct inode *ip)
{
	jfs_info("jfs_truncate: size = 0x%lx", (ulong) ip->i_size);

	nobh_truncate_page(ip->i_mapping, ip->i_size, jfs_get_block);

	IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
	jfs_truncate_nolock(ip, ip->i_size);
	IWRITE_UNLOCK(ip);
}
示例#7
0
/*
 * NAME:	commitZeroLink()
 *
 * FUNCTION:	for non-directory, called by jfs_remove(),
 *		truncate a regular file, directory or symbolic
 *		link to zero length. return 0 if type is not
 *		one of these.
 *
 *		if the file is currently associated with a VM segment
 *		only permanent disk and inode map resources are freed,
 *		and neither the inode nor indirect blocks are modified
 *		so that the resources can be later freed in the work
 *		map by ctrunc1.
 *		if there is no VM segment on entry, the resources are
 *		freed in both work and permanent map.
 *		(? for temporary file - memory object is cached even
 *		after no reference:
 *		reference count > 0 -   )
 *
 * PARAMETERS:	cd	- pointer to commit data structure.
 *			  current inode is the one to truncate.
 *
 * RETURN:	Errors from subroutines
 */
static s64 commitZeroLink(tid_t tid, struct inode *ip)
{
    int filetype;
    struct tblock *tblk;

    jfs_info("commitZeroLink: tid = %d, ip = 0x%p", tid, ip);

    filetype = ip->i_mode & S_IFMT;
    switch (filetype) {
    case S_IFREG:
        break;
    case S_IFLNK:
        /* fast symbolic link */
        if (ip->i_size < IDATASIZE) {
            ip->i_size = 0;
            return 0;
        }
        break;
    default:
        assert(filetype != S_IFDIR);
        return 0;
    }

    set_cflag(COMMIT_Freewmap, ip);

    /* mark transaction of block map update type */
    tblk = tid_to_tblock(tid);
    tblk->xflag |= COMMIT_PMAP;

    /*
     * free EA
     */
    if (JFS_IP(ip)->ea.flag & DXD_EXTENT)
        /* acquire maplock on EA to be freed from block map */
        txEA(tid, ip, &JFS_IP(ip)->ea, NULL);

    /*
     * free ACL
     */
    if (JFS_IP(ip)->acl.flag & DXD_EXTENT)
        /* acquire maplock on EA to be freed from block map */
        txEA(tid, ip, &JFS_IP(ip)->acl, NULL);

    /*
     * free xtree/data (truncate to zero length):
     * free xtree/data pages from cache if COMMIT_PWMAP,
     * free xtree/data blocks from persistent block map, and
     * free xtree/data blocks from working block map if COMMIT_PWMAP;
     */
    if (ip->i_size)
        return xtTruncate_pmap(tid, ip, 0);

    return 0;
}
示例#8
0
void jfs_delete_inode(struct inode *inode)
{
	jfs_info("In jfs_delete_inode, inode = 0x%p", inode);

	if (test_cflag(COMMIT_Freewmap, inode))
		freeZeroLink(inode);

	diFree(inode);

	clear_inode(inode);
}
示例#9
0
static void txLockFree(lid_t lid)
{
	TxLock[lid].tid = 0;
	TxLock[lid].next = TxAnchor.freelock;
	TxAnchor.freelock = lid;
	TxAnchor.tlocksInUse--;
	if (jfs_tlocks_low && (TxAnchor.tlocksInUse < TxLockLWM)) {
		jfs_info("txLockFree jfs_tlocks_low no more");
		jfs_tlocks_low = 0;
		TXN_WAKEUP(&TxAnchor.lowlockwait);
	}
	TXN_WAKEUP(&TxAnchor.freelockwait);
}
示例#10
0
文件: namei.c 项目: kzlin129/tt-gpl
static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struct nameidata *nd)
{
	struct btstack btstack;
	ino_t inum;
	struct inode *ip;
	struct component_name key;
	const char *name = dentry->d_name.name;
	int len = dentry->d_name.len;
	int rc;

	jfs_info("jfs_lookup: name = %s", name);


	if ((name[0] == '.') && (len == 1))
		inum = dip->i_ino;
	else if (strcmp(name, "..") == 0)
		inum = PARENT(dip);
	else {
		if ((rc = get_UCSname(&key, dentry)))
			return ERR_PTR(rc);
		rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
		free_UCSname(&key);
		if (rc == -ENOENT) {
			d_add(dentry, NULL);
			return ERR_PTR(0);
		} else if (rc) {
			jfs_err("jfs_lookup: dtSearch returned %d", rc);
			return ERR_PTR(rc);
		}
	}

	ip = iget(dip->i_sb, inum);
	if (ip == NULL || is_bad_inode(ip)) {
		jfs_err("jfs_lookup: iget failed on inum %d", (uint) inum);
		if (ip)
			iput(ip);
		return ERR_PTR(-EACCES);
	}

	if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)
		dentry->d_op = &jfs_ci_dentry_operations;

	dentry = d_splice_alias(ip, dentry);

	if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2))
		dentry->d_op = &jfs_ci_dentry_operations;

	return dentry;
}
示例#11
0
static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry)
{
	struct btstack btstack;
	ino_t inum;
	struct inode *ip;
	struct component_name key;
	const char *name = dentry->d_name.name;
	int len = dentry->d_name.len;
	int rc;

	jfs_info("jfs_lookup: name = %s", name);


	if ((name[0] == '.') && (len == 1))
		inum = dip->i_ino;
	else if (strcmp(name, "..") == 0)
		inum = PARENT(dip);
	else {
		if ((rc =
		     get_UCSname(&key, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
			return ERR_PTR(rc);
		rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
		free_UCSname(&key);
		if (rc == -ENOENT) {
			d_add(dentry, NULL);
			return ERR_PTR(0);
		} else if (rc) {
			jfs_err("jfs_lookup: dtSearch returned %d", rc);
			return ERR_PTR(rc);
		}
	}

	ip = iget(dip->i_sb, inum);
	if (ip == NULL) {
		jfs_err("jfs_lookup: iget failed on inum %d", (uint) inum);
		return ERR_PTR(-EACCES);
	}
	if (is_bad_inode(ip)) {
		jfs_err("jfs_lookup: iget returned bad inode, inum = %d",
			(uint) inum);
		iput(ip);
		return ERR_PTR(-EACCES);
	}

	d_add(dentry, ip);

	return ERR_PTR(0);
}
示例#12
0
void jfs_delete_inode(struct inode *inode)
{
	jfs_info("In jfs_delete_inode, inode = 0x%p", inode);

	if (test_cflag(COMMIT_Freewmap, inode))
		freeZeroLink(inode);

	diFree(inode);

	/*
	 * Free the inode from the quota allocation.
	 */
	DQUOT_INIT(inode);
	DQUOT_FREE_INODE(inode);
	DQUOT_DROP(inode);

	clear_inode(inode);
}
示例#13
0
void jfs_read_inode(struct inode *inode)
{
	int rc;

	rc = alloc_jfs_inode(inode);
	if (rc) {
		jfs_warn("In jfs_read_inode, alloc_jfs_inode failed");
		goto bad_inode;
	}
	jfs_info("In jfs_read_inode, inode = 0x%p", inode);

	if (diRead(inode))
		goto bad_inode_free;

	if (S_ISREG(inode->i_mode)) {
		inode->i_op = &jfs_file_inode_operations;
		inode->i_fop = &jfs_file_operations;
		inode->i_mapping->a_ops = &jfs_aops;
	} else if (S_ISDIR(inode->i_mode)) {
		inode->i_op = &jfs_dir_inode_operations;
		inode->i_fop = &jfs_dir_operations;
		inode->i_mapping->a_ops = &jfs_aops;
		inode->i_mapping->gfp_mask = GFP_NOFS;
	} else if (S_ISLNK(inode->i_mode)) {
		if (inode->i_size >= IDATASIZE) {
			inode->i_op = &page_symlink_inode_operations;
			inode->i_mapping->a_ops = &jfs_aops;
		} else
			inode->i_op = &jfs_symlink_inode_operations;
	} else {
		inode->i_op = &jfs_file_inode_operations;
		init_special_inode(inode, inode->i_mode,
				   kdev_t_to_nr(inode->i_rdev));
	}

	return;

      bad_inode_free:
	free_jfs_inode(inode);
      bad_inode:
	make_bad_inode(inode);
}
示例#14
0
/*
 * Workhorse of both fsync & write_inode
 */
int jfs_commit_inode(struct inode *inode, int wait)
{
	int rc = 0;
	tid_t tid;
	static int noisy = 5;

	jfs_info("In jfs_commit_inode, inode = 0x%p", inode);

	/*
	 * Don't commit if inode has been committed since last being
	 * marked dirty, or if it has been deleted.
	 */
	if (inode->i_nlink == 0 || !test_cflag(COMMIT_Dirty, inode))
		return 0;

	if (isReadOnly(inode)) {
		/* kernel allows writes to devices on read-only
		 * partitions and may think inode is dirty
		 */
		if (!special_file(inode->i_mode) && noisy) {
			jfs_err("jfs_commit_inode(0x%p) called on "
				   "read-only volume", inode);
			jfs_err("Is remount racy?");
			noisy--;
		}
		return 0;
	}

	tid = txBegin(inode->i_sb, COMMIT_INODE);
	mutex_lock(&JFS_IP(inode)->commit_mutex);

	/*
	 * Retest inode state after taking commit_mutex
	 */
	if (inode->i_nlink && test_cflag(COMMIT_Dirty, inode))
		rc = txCommit(tid, 1, &inode, wait ? COMMIT_SYNC : 0);

	txEnd(tid);
	mutex_unlock(&JFS_IP(inode)->commit_mutex);
	return rc;
}
示例#15
0
/*
 * Get a transaction lock from the free list.  If the number in use is
 * greater than the high water mark, wake up the sync daemon.  This should
 * free some anonymous transaction locks.  (TXN_LOCK must be held.)
 */
static lid_t txLockAlloc(void)
{
	lid_t lid;

	INCREMENT(TxStat.txLockAlloc);
	if (!TxAnchor.freelock) {
		INCREMENT(TxStat.txLockAlloc_freelock);
	}

	while (!(lid = TxAnchor.freelock))
		TXN_SLEEP(&TxAnchor.freelockwait);
	TxAnchor.freelock = TxLock[lid].next;
	HIGHWATERMARK(stattx.maxlid, lid);
	if ((++TxAnchor.tlocksInUse > TxLockHWM) && (jfs_tlocks_low == 0)) {
		jfs_info("txLockAlloc tlocks low");
		jfs_tlocks_low = 1;
		wake_up_process(jfsSyncThread);
	}

	return lid;
}
示例#16
0
void jfs_clear_inode(struct inode *inode)
{
	struct jfs_inode_info *ji = JFS_IP(inode);

	if (is_bad_inode(inode))
		/*
		 * We free the fs-dependent structure before making the
		 * inode bad
		 */
		return;

	jfs_info("jfs_clear_inode called ip = 0x%p", inode);

	if (ji->active_ag != -1) {
		struct bmap *bmap = JFS_SBI(inode->i_sb)->bmap;
		atomic_dec(&bmap->db_active[ji->active_ag]);
	}

	ASSERT(list_empty(&ji->anon_inode_list));

#ifdef CONFIG_JFS_POSIX_ACL
	if (ji->i_acl != JFS_ACL_NOT_CACHED) {
		posix_acl_release(ji->i_acl);
		ji->i_acl = JFS_ACL_NOT_CACHED;
	}
	if (ji->i_default_acl != JFS_ACL_NOT_CACHED) {
		posix_acl_release(ji->i_default_acl);
		ji->i_default_acl = JFS_ACL_NOT_CACHED;
	}
#endif

	if (ji->atlhead) {
		jfs_err("jfs_clear_inode: inode %p has anonymous tlocks",
			inode);
		jfs_err("i_state = 0x%lx, cflag = 0x%lx", inode->i_state,
			ji->cflag);
	}

	free_jfs_inode(inode);
}
示例#17
0
static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struct nameidata *nd)
{
    struct btstack btstack;
    ino_t inum;
    struct inode *ip;
    struct component_name key;
    const char *name = dentry->d_name.name;
    int len = dentry->d_name.len;
    int rc;

    jfs_info("jfs_lookup: name = %s", name);

    if ((name[0] == '.') && (len == 1))
        inum = dip->i_ino;
    else if (strcmp(name, "..") == 0)
        inum = PARENT(dip);
    else {
        if ((rc = get_UCSname(&key, dentry)))
            return ERR_PTR(rc);
        rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
        free_UCSname(&key);
        if (rc == -ENOENT) {
            d_add(dentry, NULL);
            return NULL;
        } else if (rc) {
            jfs_err("jfs_lookup: dtSearch returned %d", rc);
            return ERR_PTR(rc);
        }
    }

    ip = jfs_iget(dip->i_sb, inum);
    if (IS_ERR(ip)) {
        jfs_err("jfs_lookup: iget failed on inum %d", (uint) inum);
        return ERR_CAST(ip);
    }

    return d_splice_alias(ip, dentry);
}
示例#18
0
/*
 * NAME:	jfs_mknod
 *
 * FUNCTION:	Create a special file (device)
 */
static int jfs_mknod(struct inode *dir, struct dentry *dentry,
                     int mode, dev_t rdev)
{
    struct jfs_inode_info *jfs_ip;
    struct btstack btstack;
    struct component_name dname;
    ino_t ino;
    struct inode *ip;
    struct inode *iplist[2];
    int rc;
    tid_t tid;
    struct tblock *tblk;

    if (!new_valid_dev(rdev))
        return -EINVAL;

    jfs_info("jfs_mknod: %s", dentry->d_name.name);

    dquot_initialize(dir);

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

    ip = ialloc(dir, mode);
    if (IS_ERR(ip)) {
        rc = PTR_ERR(ip);
        goto out1;
    }
    jfs_ip = JFS_IP(ip);

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

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

    rc = jfs_init_acl(tid, ip, dir);
    if (rc)
        goto out3;

    rc = jfs_init_security(tid, ip, dir, &dentry->d_name);
    if (rc) {
        txAbort(tid, 0);
        goto out3;
    }

    if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) {
        txAbort(tid, 0);
        goto out3;
    }

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

    ino = ip->i_ino;
    if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) {
        txAbort(tid, 0);
        goto out3;
    }

    ip->i_op = &jfs_file_inode_operations;
    jfs_ip->dev = new_encode_dev(rdev);
    init_special_inode(ip, ip->i_mode, rdev);

    mark_inode_dirty(ip);

    dir->i_ctime = dir->i_mtime = CURRENT_TIME;

    mark_inode_dirty(dir);

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

out3:
    txEnd(tid);
    mutex_unlock(&JFS_IP(ip)->commit_mutex);
    mutex_unlock(&JFS_IP(dir)->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);
    }

out1:
    free_UCSname(&dname);

out:
    jfs_info("jfs_mknod: returning %d", rc);
    return rc;
}
示例#19
0
/*
 * NAME:	ialloc()
 *
 * FUNCTION:	Allocate a new inode
 *
 */
struct inode *ialloc(struct inode *parent, umode_t mode)
{
	struct super_block *sb = parent->i_sb;
	struct inode *inode;
	struct jfs_inode_info *jfs_inode;
	int rc;

	inode = new_inode(sb);
	if (!inode) {
		jfs_warn("ialloc: new_inode returned NULL!");
		return ERR_PTR(-ENOMEM);
	}

	jfs_inode = JFS_IP(inode);

	rc = diAlloc(parent, S_ISDIR(mode), inode);
	if (rc) {
		jfs_warn("ialloc: diAlloc returned %d!", rc);
		if (rc == -EIO)
			make_bad_inode(inode);
		iput(inode);
		return ERR_PTR(rc);
	}

	inode->i_uid = current_fsuid();
	if (parent->i_mode & S_ISGID) {
		inode->i_gid = parent->i_gid;
		if (S_ISDIR(mode))
			mode |= S_ISGID;
	} else
		inode->i_gid = current_fsgid();

	/*
	 * New inodes need to save sane values on disk when
	 * uid & gid mount options are used
	 */
	jfs_inode->saved_uid = inode->i_uid;
	jfs_inode->saved_gid = inode->i_gid;

	/*
	 * Allocate inode to quota.
	 */
	if (DQUOT_ALLOC_INODE(inode)) {
		DQUOT_DROP(inode);
		inode->i_flags |= S_NOQUOTA;
		inode->i_nlink = 0;
		iput(inode);
		return ERR_PTR(-EDQUOT);
	}

	inode->i_mode = mode;
	/* inherit flags from parent */
	jfs_inode->mode2 = JFS_IP(parent)->mode2 & JFS_FL_INHERIT;

	if (S_ISDIR(mode)) {
		jfs_inode->mode2 |= IDIRECTORY;
		jfs_inode->mode2 &= ~JFS_DIRSYNC_FL;
	}
	else {
		jfs_inode->mode2 |= INLINEEA | ISPARSE;
		if (S_ISLNK(mode))
			jfs_inode->mode2 &= ~(JFS_IMMUTABLE_FL|JFS_APPEND_FL);
	}
	jfs_inode->mode2 |= mode;

	inode->i_blocks = 0;
	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
	jfs_inode->otime = inode->i_ctime.tv_sec;
	inode->i_generation = JFS_SBI(sb)->gengen++;

	jfs_inode->cflag = 0;

	/* Zero remaining fields */
	memset(&jfs_inode->acl, 0, sizeof(dxd_t));
	memset(&jfs_inode->ea, 0, sizeof(dxd_t));
	jfs_inode->next_index = 0;
	jfs_inode->acltype = 0;
	jfs_inode->btorder = 0;
	jfs_inode->btindex = 0;
	jfs_inode->bxflag = 0;
	jfs_inode->blid = 0;
	jfs_inode->atlhead = 0;
	jfs_inode->atltail = 0;
	jfs_inode->xtlid = 0;
	jfs_set_inode_flags(inode);

	jfs_info("ialloc returns inode = 0x%p\n", inode);

	return inode;
}
示例#20
0
/*
 * NAME:	jfs_mount(sb)
 *
 * FUNCTION:	vfs_mount()
 *
 * PARAMETER:	sb	- super block
 *
 * RETURN:	-EBUSY	- device already mounted or open for write
 *		-EBUSY	- cvrdvp already mounted;
 *		-EBUSY	- mount table full
 *		-ENOTDIR- cvrdvp not directory on a device mount
 *		-ENXIO	- device open failure
 */
int jfs_mount(struct super_block *sb)
{
	int rc = 0;		/* Return code          */
	struct jfs_sb_info *sbi = JFS_SBI(sb);
	struct inode *ipaimap = NULL;
	struct inode *ipaimap2 = NULL;
	struct inode *ipimap = NULL;
	struct inode *ipbmap = NULL;

	/*
	 * read/validate superblock 
	 * (initialize mount inode from the superblock)
	 */
	if ((rc = chkSuper(sb))) {
		goto errout20;
	}

	ipaimap = diReadSpecial(sb, AGGREGATE_I, 0);
	if (ipaimap == NULL) {
		jfs_err("jfs_mount: Faild to read AGGREGATE_I");
		rc = -EIO;
		goto errout20;
	}
	sbi->ipaimap = ipaimap;

	jfs_info("jfs_mount: ipaimap:0x%p", ipaimap);

	/*
	 * initialize aggregate inode allocation map
	 */
	if ((rc = diMount(ipaimap))) {
		jfs_err("jfs_mount: diMount(ipaimap) failed w/rc = %d", rc);
		goto errout21;
	}

	/*
	 * open aggregate block allocation map
	 */
	ipbmap = diReadSpecial(sb, BMAP_I, 0);
	if (ipbmap == NULL) {
		rc = -EIO;
		goto errout22;
	}

	jfs_info("jfs_mount: ipbmap:0x%p", ipbmap);

	sbi->ipbmap = ipbmap;

	/*
	 * initialize aggregate block allocation map
	 */
	if ((rc = dbMount(ipbmap))) {
		jfs_err("jfs_mount: dbMount failed w/rc = %d", rc);
		goto errout22;
	}

	/*
	 * open the secondary aggregate inode allocation map
	 *
	 * This is a duplicate of the aggregate inode allocation map.
	 *
	 * hand craft a vfs in the same fashion as we did to read ipaimap.
	 * By adding INOSPEREXT (32) to the inode number, we are telling
	 * diReadSpecial that we are reading from the secondary aggregate
	 * inode table.  This also creates a unique entry in the inode hash
	 * table.
	 */
	if ((sbi->mntflag & JFS_BAD_SAIT) == 0) {
		ipaimap2 = diReadSpecial(sb, AGGREGATE_I, 1);
		if (ipaimap2 == 0) {
			jfs_err("jfs_mount: Faild to read AGGREGATE_I");
			rc = -EIO;
			goto errout35;
		}
		sbi->ipaimap2 = ipaimap2;

		jfs_info("jfs_mount: ipaimap2:0x%p", ipaimap2);

		/*
		 * initialize secondary aggregate inode allocation map
		 */
		if ((rc = diMount(ipaimap2))) {
			jfs_err("jfs_mount: diMount(ipaimap2) failed, rc = %d",
				rc);
			goto errout35;
		}
	} else
		/* Secondary aggregate inode table is not valid */
		sbi->ipaimap2 = NULL;

	/*
	 *      mount (the only/single) fileset
	 */
	/*
	 * open fileset inode allocation map (aka fileset inode)
	 */
	ipimap = diReadSpecial(sb, FILESYSTEM_I, 0);
	if (ipimap == NULL) {
		jfs_err("jfs_mount: Failed to read FILESYSTEM_I");
		/* open fileset secondary inode allocation map */
		rc = -EIO;
		goto errout40;
	}
	jfs_info("jfs_mount: ipimap:0x%p", ipimap);

	/* map further access of per fileset inodes by the fileset inode */
	sbi->ipimap = ipimap;

	/* initialize fileset inode allocation map */
	if ((rc = diMount(ipimap))) {
		jfs_err("jfs_mount: diMount failed w/rc = %d", rc);
		goto errout41;
	}

	goto out;

	/*
	 *      unwind on error
	 */
      errout41:		/* close fileset inode allocation map inode */
	diFreeSpecial(ipimap);

      errout40:		/* fileset closed */

	/* close secondary aggregate inode allocation map */
	if (ipaimap2) {
		diUnmount(ipaimap2, 1);
		diFreeSpecial(ipaimap2);
	}

      errout35:

	/* close aggregate block allocation map */
	dbUnmount(ipbmap, 1);
	diFreeSpecial(ipbmap);

      errout22:		/* close aggregate inode allocation map */

	diUnmount(ipaimap, 1);

      errout21:		/* close aggregate inodes */
	diFreeSpecial(ipaimap);
      errout20:		/* aggregate closed */

      out:

	if (rc)
		jfs_err("Mount JFS Failure: %d", rc);

	return rc;
}
示例#21
0
/*
 *	chkSuper()
 *
 * validate the superblock of the file system to be mounted and 
 * get the file system parameters.
 *
 * returns
 *	0 with fragsize set if check successful
 *	error code if not successful
 */
static int chkSuper(struct super_block *sb)
{
	int rc = 0;
	struct jfs_sb_info *sbi = JFS_SBI(sb);
	struct jfs_superblock *j_sb;
	struct buffer_head *bh;
	int AIM_bytesize, AIT_bytesize;
	int expected_AIM_bytesize, expected_AIT_bytesize;
	s64 AIM_byte_addr, AIT_byte_addr, fsckwsp_addr;
	s64 byte_addr_diff0, byte_addr_diff1;
	s32 bsize;

	if ((rc = readSuper(sb, &bh)))
		return rc;
	j_sb = (struct jfs_superblock *)bh->b_data;

	/*
	 * validate superblock
	 */
	/* validate fs signature */
	if (strncmp(j_sb->s_magic, JFS_MAGIC, 4) ||
	    le32_to_cpu(j_sb->s_version) > JFS_VERSION) {
		rc = -EINVAL;
		goto out;
	}

	bsize = le32_to_cpu(j_sb->s_bsize);
#ifdef _JFS_4K
	if (bsize != PSIZE) {
		jfs_err("Currently only 4K block size supported!");
		rc = -EINVAL;
		goto out;
	}
#endif				/* _JFS_4K */

	jfs_info("superblock: flag:0x%08x state:0x%08x size:0x%Lx",
		 le32_to_cpu(j_sb->s_flag), le32_to_cpu(j_sb->s_state),
		 (unsigned long long) le64_to_cpu(j_sb->s_size));

	/* validate the descriptors for Secondary AIM and AIT */
	if ((j_sb->s_flag & cpu_to_le32(JFS_BAD_SAIT)) !=
	    cpu_to_le32(JFS_BAD_SAIT)) {
		expected_AIM_bytesize = 2 * PSIZE;
		AIM_bytesize = lengthPXD(&(j_sb->s_aim2)) * bsize;
		expected_AIT_bytesize = 4 * PSIZE;
		AIT_bytesize = lengthPXD(&(j_sb->s_ait2)) * bsize;
		AIM_byte_addr = addressPXD(&(j_sb->s_aim2)) * bsize;
		AIT_byte_addr = addressPXD(&(j_sb->s_ait2)) * bsize;
		byte_addr_diff0 = AIT_byte_addr - AIM_byte_addr;
		fsckwsp_addr = addressPXD(&(j_sb->s_fsckpxd)) * bsize;
		byte_addr_diff1 = fsckwsp_addr - AIT_byte_addr;
		if ((AIM_bytesize != expected_AIM_bytesize) ||
		    (AIT_bytesize != expected_AIT_bytesize) ||
		    (byte_addr_diff0 != AIM_bytesize) ||
		    (byte_addr_diff1 <= AIT_bytesize))
			j_sb->s_flag |= cpu_to_le32(JFS_BAD_SAIT);
	}

	if ((j_sb->s_flag & cpu_to_le32(JFS_GROUPCOMMIT)) !=
	    cpu_to_le32(JFS_GROUPCOMMIT))
		j_sb->s_flag |= cpu_to_le32(JFS_GROUPCOMMIT);

	/* validate fs state */
	if (j_sb->s_state != cpu_to_le32(FM_CLEAN) &&
	    !(sb->s_flags & MS_RDONLY)) {
		jfs_err("jfs_mount: Mount Failure: File System Dirty.");
		rc = -EINVAL;
		goto out;
	}

	sbi->state = le32_to_cpu(j_sb->s_state);
	sbi->mntflag = le32_to_cpu(j_sb->s_flag);

	/*
	 * JFS always does I/O by 4K pages.  Don't tell the buffer cache
	 * that we use anything else (leave s_blocksize alone).
	 */
	sbi->bsize = bsize;
	sbi->l2bsize = le16_to_cpu(j_sb->s_l2bsize);

	/*
	 * For now, ignore s_pbsize, l2bfactor.  All I/O going through buffer
	 * cache.
	 */
	sbi->nbperpage = PSIZE >> sbi->l2bsize;
	sbi->l2nbperpage = L2PSIZE - sbi->l2bsize;
	sbi->l2niperblk = sbi->l2bsize - L2DISIZE;
	if (sbi->mntflag & JFS_INLINELOG)
		sbi->logpxd = j_sb->s_logpxd;
	else {
		sbi->logdev = new_decode_dev(le32_to_cpu(j_sb->s_logdev));
		memcpy(sbi->uuid, j_sb->s_uuid, sizeof(sbi->uuid));
		memcpy(sbi->loguuid, j_sb->s_loguuid, sizeof(sbi->uuid));
	}
	sbi->fsckpxd = j_sb->s_fsckpxd;
	sbi->ait2 = j_sb->s_ait2;

      out:
	brelse(bh);
	return rc;
}
示例#22
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;
}
示例#23
0
/*
 * NAME:	jfs_link(vp, dvp, name, crp)
 *
 * FUNCTION:	create a link to <vp> by the name = <name>
 *		in the parent directory <dvp>
 *
 * PARAMETER:	vp	- target object
 *		dvp	- parent directory of new link
 *		name	- name of new link to target object
 *		crp	- credential
 *
 * RETURN:	Errors from subroutines
 *
 * note:
 * JFS does NOT support link() on directories (to prevent circular
 * path in the directory hierarchy);
 * EPERM: the target object is a directory, and either the caller
 * does not have appropriate privileges or the implementation prohibits
 * using link() on directories [XPG4.2].
 *
 * JFS does NOT support links between file systems:
 * EXDEV: target object and new link are on different file systems and
 * implementation does not support links between file systems [XPG4.2].
 */
static int jfs_link(struct dentry *old_dentry,
                    struct inode *dir, struct dentry *dentry)
{
    int rc;
    tid_t tid;
    struct inode *ip = old_dentry->d_inode;
    ino_t ino;
    struct component_name dname;
    struct btstack btstack;
    struct inode *iplist[2];

    jfs_info("jfs_link: %s %s", old_dentry->d_name.name,
             dentry->d_name.name);

    if (ip->i_nlink == JFS_LINK_MAX)
        return -EMLINK;

    dquot_initialize(dir);

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

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

    /*
     * scan parent directory for entry/freespace
     */
    if ((rc = get_UCSname(&dname, dentry)))
        goto out;

    if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
        goto free_dname;

    /*
     * create entry for new link in parent directory
     */
    ino = ip->i_ino;
    if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack)))
        goto free_dname;

    /* update object inode */
    inc_nlink(ip);		/* for new link */
    ip->i_ctime = CURRENT_TIME;
    dir->i_ctime = dir->i_mtime = CURRENT_TIME;
    mark_inode_dirty(dir);
    ihold(ip);

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

    if (rc) {
        ip->i_nlink--; /* never instantiated */
        iput(ip);
    } else
        d_instantiate(dentry, ip);

free_dname:
    free_UCSname(&dname);

out:
    txEnd(tid);

    mutex_unlock(&JFS_IP(ip)->commit_mutex);
    mutex_unlock(&JFS_IP(dir)->commit_mutex);

    jfs_info("jfs_link: rc:%d", rc);
    return rc;
}
示例#24
0
/*
 * NAME:	jfs_create(dip, dentry, mode)
 *
 * FUNCTION:	create a regular file in the parent directory <dip>
 *		with name = <from dentry> and mode = <mode>
 *
 * PARAMETER:	dip	- parent directory vnode
 *		dentry	- dentry of new file
 *		mode	- create mode (rwxrwxrwx).
 *		nd- nd struct
 *
 * RETURN:	Errors from subroutines
 *
 */
static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
                      struct nameidata *nd)
{
    int rc = 0;
    tid_t tid;		/* transaction id */
    struct inode *ip = NULL;	/* child directory inode */
    ino_t ino;
    struct component_name dname;	/* child directory name */
    struct btstack btstack;
    struct inode *iplist[2];
    struct tblock *tblk;

    jfs_info("jfs_create: dip:0x%p name:%s", dip, dentry->d_name.name);

    dquot_initialize(dip);

    /*
     * search parent directory for entry/freespace
     * (dtSearch() returns parent directory page pinned)
     */
    if ((rc = get_UCSname(&dname, dentry)))
        goto out1;

    /*
     * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
     * block there while holding dtree page, so we allocate the inode &
     * begin the transaction before we search the directory.
     */
    ip = ialloc(dip, mode);
    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_acl(tid, ip, dip);
    if (rc)
        goto out3;

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

    if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
        jfs_err("jfs_create: dtSearch returned %d", rc);
        txAbort(tid, 0);
        goto out3;
    }

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

    iplist[0] = dip;
    iplist[1] = ip;

    /*
     * initialize the child XAD tree root in-line in inode
     */
    xtInitRoot(tid, ip);

    /*
     * create entry in parent directory for child directory
     * (dtInsert() releases parent directory page)
     */
    ino = ip->i_ino;
    if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
        if (rc == -EIO) {
            jfs_err("jfs_create: dtInsert returned -EIO");
            txAbort(tid, 1);	/* Marks Filesystem dirty */
        } else
            txAbort(tid, 0);	/* Filesystem full */
        goto out3;
    }

    ip->i_op = &jfs_file_inode_operations;
    ip->i_fop = &jfs_file_operations;
    ip->i_mapping->a_ops = &jfs_aops;

    mark_inode_dirty(ip);

    dip->i_ctime = dip->i_mtime = CURRENT_TIME;

    mark_inode_dirty(dip);

    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_create: rc:%d", rc);
    return rc;
}
示例#25
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);
}
示例#26
0
/*
 * NAME:	jfs_umount(vfsp, flags, crp)
 *
 * FUNCTION:	vfs_umount()
 *
 * PARAMETERS:	vfsp	- virtual file system pointer
 *		flags	- unmount for shutdown
 *		crp	- credential
 *
 * RETURN :	EBUSY	- device has open files
 */
int jfs_umount(struct super_block *sb)
{
	struct jfs_sb_info *sbi = JFS_SBI(sb);
	struct inode *ipbmap = sbi->ipbmap;
	struct inode *ipimap = sbi->ipimap;
	struct inode *ipaimap = sbi->ipaimap;
	struct inode *ipaimap2 = sbi->ipaimap2;
	struct jfs_log *log;
	int rc = 0;

	jfs_info("UnMount JFS: sb:0x%p", sb);

	/*
	 *	update superblock and close log
	 *
	 * if mounted read-write and log based recovery was enabled
	 */
	if ((log = sbi->log))
		/*
		 * Wait for outstanding transactions to be written to log:
		 */
		jfs_flush_journal(log, 1);

	/*
	 * close fileset inode allocation map (aka fileset inode)
	 */
	diUnmount(ipimap, 0);

	diFreeSpecial(ipimap);
	sbi->ipimap = NULL;

	/*
	 * close secondary aggregate inode allocation map
	 */
	ipaimap2 = sbi->ipaimap2;
	if (ipaimap2) {
		diUnmount(ipaimap2, 0);
		diFreeSpecial(ipaimap2);
		sbi->ipaimap2 = NULL;
	}

	/*
	 * close aggregate inode allocation map
	 */
	ipaimap = sbi->ipaimap;
	diUnmount(ipaimap, 0);
	diFreeSpecial(ipaimap);
	sbi->ipaimap = NULL;

	/*
	 * close aggregate block allocation map
	 */
	dbUnmount(ipbmap, 0);

	diFreeSpecial(ipbmap);
	sbi->ipimap = NULL;

	/*
	 * Make sure all metadata makes it to disk before we mark
	 * the superblock as clean
	 */
	filemap_write_and_wait(sbi->direct_inode->i_mapping);

	/*
	 * ensure all file system file pages are propagated to their
	 * home blocks on disk (and their in-memory buffer pages are
	 * invalidated) BEFORE updating file system superblock state
	 * (to signify file system is unmounted cleanly, and thus in
	 * consistent state) and log superblock active file system
	 * list (to signify skip logredo()).
	 */
	if (log) {		/* log = NULL if read-only mount */
		updateSuper(sb, FM_CLEAN);

		/*
		 * close log:
		 *
		 * remove file system from log active file system list.
		 */
		rc = lmLogClose(sb);
	}
	jfs_info("UnMount JFS Complete: rc = %d", rc);
	return rc;
}
示例#27
0
/*
 * NAME:	jfs_unlink(dip, dentry)
 *
 * FUNCTION:	remove a link to object <vp> named by <name>
 *		from parent directory <dvp>
 *
 * PARAMETER:	dip	- inode of parent directory
 *		dentry	- dentry of object to be removed
 *
 * RETURN:	errors from subroutines
 *
 * note:
 * temporary file: if one or more processes have the file open
 * when the last link is removed, the link will be removed before
 * unlink() returns, but the removal of the file contents will be
 * postponed until all references to the files are closed.
 *
 * JFS does NOT support unlink() on directories.
 *
 */
static int jfs_unlink(struct inode *dip, struct dentry *dentry)
{
    int rc;
    tid_t tid;		/* transaction id */
    struct inode *ip = dentry->d_inode;
    ino_t ino;
    struct component_name dname;	/* object name */
    struct inode *iplist[2];
    struct tblock *tblk;
    s64 new_size = 0;
    int commit_flag;

    jfs_info("jfs_unlink: dip:0x%p name:%s", dip, dentry->d_name.name);

    /* Init inode for quota operations. */
    dquot_initialize(dip);
    dquot_initialize(ip);

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

    IWRITE_LOCK(ip, RDWRLOCK_NORMAL);

    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);

    iplist[0] = dip;
    iplist[1] = ip;

    /*
     * delete the entry of target file from parent directory
     */
    ino = ip->i_ino;
    if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
        jfs_err("jfs_unlink: dtDelete returned %d", rc);
        if (rc == -EIO)
            txAbort(tid, 1);	/* Marks FS Dirty */
        txEnd(tid);
        mutex_unlock(&JFS_IP(ip)->commit_mutex);
        mutex_unlock(&JFS_IP(dip)->commit_mutex);
        IWRITE_UNLOCK(ip);
        goto out1;
    }

    ASSERT(ip->i_nlink);

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

    /* update target's inode */
    inode_dec_link_count(ip);

    /*
     *	commit zero link count object
     */
    if (ip->i_nlink == 0) {
        assert(!test_cflag(COMMIT_Nolink, ip));
        /* free block resources */
        if ((new_size = commitZeroLink(tid, ip)) < 0) {
            txAbort(tid, 1);	/* Marks FS Dirty */
            txEnd(tid);
            mutex_unlock(&JFS_IP(ip)->commit_mutex);
            mutex_unlock(&JFS_IP(dip)->commit_mutex);
            IWRITE_UNLOCK(ip);
            rc = new_size;
            goto out1;
        }
        tblk = tid_to_tblock(tid);
        tblk->xflag |= COMMIT_DELETE;
        tblk->u.ip = ip;
    }

    /*
     * Incomplete truncate of file data can
     * result in timing problems unless we synchronously commit the
     * transaction.
     */
    if (new_size)
        commit_flag = COMMIT_SYNC;
    else
        commit_flag = 0;

    /*
     * If xtTruncate was incomplete, commit synchronously to avoid
     * timing complications
     */
    rc = txCommit(tid, 2, &iplist[0], commit_flag);

    txEnd(tid);

    mutex_unlock(&JFS_IP(ip)->commit_mutex);
    mutex_unlock(&JFS_IP(dip)->commit_mutex);

    while (new_size && (rc == 0)) {
        tid = txBegin(dip->i_sb, 0);
        mutex_lock(&JFS_IP(ip)->commit_mutex);
        new_size = xtTruncate_pmap(tid, ip, new_size);
        if (new_size < 0) {
            txAbort(tid, 1);	/* Marks FS Dirty */
            rc = new_size;
        } else
            rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC);
        txEnd(tid);
        mutex_unlock(&JFS_IP(ip)->commit_mutex);
    }

    if (ip->i_nlink == 0)
        set_cflag(COMMIT_Nolink, ip);

    IWRITE_UNLOCK(ip);

    /*
     * Truncating the directory index table is not guaranteed.  It
     * may need to be done iteratively
     */
    if (test_cflag(COMMIT_Stale, dip)) {
        if (dip->i_size > 1)
            jfs_truncate_nolock(dip, 0);

        clear_cflag(COMMIT_Stale, dip);
    }

out1:
    free_UCSname(&dname);
out:
    jfs_info("jfs_unlink: rc:%d", rc);
    return rc;
}
示例#28
0
/*
 * NAME:	jfs_rmdir(dip, dentry)
 *
 * FUNCTION:	remove a link to child directory
 *
 * PARAMETER:	dip	- parent inode
 *		dentry	- child directory dentry
 *
 * RETURN:	-EINVAL	- if name is . or ..
 *		-EINVAL - if . or .. exist but are invalid.
 *		errors from subroutines
 *
 * note:
 * if other threads have the directory open when the last link
 * is removed, the "." and ".." entries, if present, are removed before
 * rmdir() returns and no new entries may be created in the directory,
 * but the directory is not removed until the last reference to
 * the directory is released (cf.unlink() of regular file).
 */
static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
{
    int rc;
    tid_t tid;		/* transaction id */
    struct inode *ip = dentry->d_inode;
    ino_t ino;
    struct component_name dname;
    struct inode *iplist[2];
    struct tblock *tblk;

    jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);

    /* Init inode for quota operations. */
    dquot_initialize(dip);
    dquot_initialize(ip);

    /* directory must be empty to be removed */
    if (!dtEmpty(ip)) {
        rc = -ENOTEMPTY;
        goto out;
    }

    if ((rc = get_UCSname(&dname, dentry))) {
        goto out;
    }

    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);

    iplist[0] = dip;
    iplist[1] = ip;

    tblk = tid_to_tblock(tid);
    tblk->xflag |= COMMIT_DELETE;
    tblk->u.ip = ip;

    /*
     * delete the entry of target directory from parent directory
     */
    ino = ip->i_ino;
    if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
        jfs_err("jfs_rmdir: dtDelete returned %d", rc);
        if (rc == -EIO)
            txAbort(tid, 1);
        txEnd(tid);
        mutex_unlock(&JFS_IP(ip)->commit_mutex);
        mutex_unlock(&JFS_IP(dip)->commit_mutex);

        goto out2;
    }

    /* update parent directory's link count corresponding
     * to ".." entry of the target directory deleted
     */
    dip->i_ctime = dip->i_mtime = CURRENT_TIME;
    inode_dec_link_count(dip);

    /*
     * OS/2 could have created EA and/or ACL
     */
    /* free EA from both persistent and working map */
    if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
        /* free EA pages */
        txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
    }
    JFS_IP(ip)->ea.flag = 0;

    /* free ACL from both persistent and working map */
    if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
        /* free ACL pages */
        txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
    }
    JFS_IP(ip)->acl.flag = 0;

    /* mark the target directory as deleted */
    clear_nlink(ip);
    mark_inode_dirty(ip);

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

    txEnd(tid);

    mutex_unlock(&JFS_IP(ip)->commit_mutex);
    mutex_unlock(&JFS_IP(dip)->commit_mutex);

    /*
     * Truncating the directory index table is not guaranteed.  It
     * may need to be done iteratively
     */
    if (test_cflag(COMMIT_Stale, dip)) {
        if (dip->i_size > 1)
            jfs_truncate_nolock(dip, 0);

        clear_cflag(COMMIT_Stale, dip);
    }

out2:
    free_UCSname(&dname);

out:
    jfs_info("jfs_rmdir: rc:%d", rc);
    return rc;
}
示例#29
0
/*
 * NAME:	ialloc()
 *
 * FUNCTION:	Allocate a new inode
 *
 */
struct inode *ialloc(struct inode *parent, umode_t mode)
{
	struct super_block *sb = parent->i_sb;
	struct inode *inode;
	struct jfs_inode_info *jfs_inode;
	int rc;

	inode = new_inode(sb);
	if (!inode) {
		jfs_warn("ialloc: new_inode returned NULL!");
		rc = -ENOMEM;
		goto fail;
	}

	jfs_inode = JFS_IP(inode);

	rc = diAlloc(parent, S_ISDIR(mode), inode);
	if (rc) {
		jfs_warn("ialloc: diAlloc returned %d!", rc);
		if (rc == -EIO)
			make_bad_inode(inode);
		goto fail_put;
	}

	if (insert_inode_locked(inode) < 0) {
		rc = -EINVAL;
		goto fail_unlock;
	}

	inode_init_owner(inode, parent, mode);
	/*
	 * New inodes need to save sane values on disk when
	 * uid & gid mount options are used
	 */
	jfs_inode->saved_uid = inode->i_uid;
	jfs_inode->saved_gid = inode->i_gid;

	/*
	 * Allocate inode to quota.
	 */
	dquot_initialize(inode);
	rc = dquot_alloc_inode(inode);
	if (rc)
		goto fail_drop;

	/* inherit flags from parent */
	jfs_inode->mode2 = JFS_IP(parent)->mode2 & JFS_FL_INHERIT;

	if (S_ISDIR(mode)) {
		jfs_inode->mode2 |= IDIRECTORY;
		jfs_inode->mode2 &= ~JFS_DIRSYNC_FL;
	}
	else {
		jfs_inode->mode2 |= INLINEEA | ISPARSE;
		if (S_ISLNK(mode))
			jfs_inode->mode2 &= ~(JFS_IMMUTABLE_FL|JFS_APPEND_FL);
	}
	jfs_inode->mode2 |= inode->i_mode;

	inode->i_blocks = 0;
	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
	jfs_inode->otime = inode->i_ctime.tv_sec;
	inode->i_generation = JFS_SBI(sb)->gengen++;

	jfs_inode->cflag = 0;

	/* Zero remaining fields */
	memset(&jfs_inode->acl, 0, sizeof(dxd_t));
	memset(&jfs_inode->ea, 0, sizeof(dxd_t));
	jfs_inode->next_index = 0;
	jfs_inode->acltype = 0;
	jfs_inode->btorder = 0;
	jfs_inode->btindex = 0;
	jfs_inode->bxflag = 0;
	jfs_inode->blid = 0;
	jfs_inode->atlhead = 0;
	jfs_inode->atltail = 0;
	jfs_inode->xtlid = 0;
	jfs_set_inode_flags(inode);

	jfs_info("ialloc returns inode = 0x%p\n", inode);

	return inode;

fail_drop:
	dquot_drop(inode);
	inode->i_flags |= S_NOQUOTA;
fail_unlock:
	inode->i_nlink = 0;
	unlock_new_inode(inode);
fail_put:
	iput(inode);
fail:
	return ERR_PTR(rc);
}
示例#30
0
/*
 * NAME:	jfs_rename
 *
 * FUNCTION:	rename a file or directory
 */
static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                      struct inode *new_dir, struct dentry *new_dentry)
{
    struct btstack btstack;
    ino_t ino;
    struct component_name new_dname;
    struct inode *new_ip;
    struct component_name old_dname;
    struct inode *old_ip;
    int rc;
    tid_t tid;
    struct tlock *tlck;
    struct dt_lock *dtlck;
    struct lv *lv;
    int ipcount;
    struct inode *iplist[4];
    struct tblock *tblk;
    s64 new_size = 0;
    int commit_flag;


    jfs_info("jfs_rename: %s %s", old_dentry->d_name.name,
             new_dentry->d_name.name);

    dquot_initialize(old_dir);
    dquot_initialize(new_dir);

    old_ip = old_dentry->d_inode;
    new_ip = new_dentry->d_inode;

    if ((rc = get_UCSname(&old_dname, old_dentry)))
        goto out1;

    if ((rc = get_UCSname(&new_dname, new_dentry)))
        goto out2;

    /*
     * Make sure source inode number is what we think it is
     */
    rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP);
    if (rc || (ino != old_ip->i_ino)) {
        rc = -ENOENT;
        goto out3;
    }

    /*
     * Make sure dest inode number (if any) is what we think it is
     */
    rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP);
    if (!rc) {
        if ((!new_ip) || (ino != new_ip->i_ino)) {
            rc = -ESTALE;
            goto out3;
        }
    } else if (rc != -ENOENT)
        goto out3;
    else if (new_ip) {
        /* no entry exists, but one was expected */
        rc = -ESTALE;
        goto out3;
    }

    if (S_ISDIR(old_ip->i_mode)) {
        if (new_ip) {
            if (!dtEmpty(new_ip)) {
                rc = -ENOTEMPTY;
                goto out3;
            }
        } else if ((new_dir != old_dir) &&
                   (new_dir->i_nlink == JFS_LINK_MAX)) {
            rc = -EMLINK;
            goto out3;
        }
    } else if (new_ip) {
        IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
        /* Init inode for quota operations. */
        dquot_initialize(new_ip);
    }

    /*
     * The real work starts here
     */
    tid = txBegin(new_dir->i_sb, 0);

    /*
     * How do we know the locking is safe from deadlocks?
     * The vfs does the hard part for us.  Any time we are taking nested
     * commit_mutexes, the vfs already has i_mutex held on the parent.
     * Here, the vfs has already taken i_mutex on both old_dir and new_dir.
     */
    mutex_lock_nested(&JFS_IP(new_dir)->commit_mutex, COMMIT_MUTEX_PARENT);
    mutex_lock_nested(&JFS_IP(old_ip)->commit_mutex, COMMIT_MUTEX_CHILD);
    if (old_dir != new_dir)
        mutex_lock_nested(&JFS_IP(old_dir)->commit_mutex,
                          COMMIT_MUTEX_SECOND_PARENT);

    if (new_ip) {
        mutex_lock_nested(&JFS_IP(new_ip)->commit_mutex,
                          COMMIT_MUTEX_VICTIM);
        /*
         * Change existing directory entry to new inode number
         */
        ino = new_ip->i_ino;
        rc = dtModify(tid, new_dir, &new_dname, &ino,
                      old_ip->i_ino, JFS_RENAME);
        if (rc)
            goto out4;
        drop_nlink(new_ip);
        if (S_ISDIR(new_ip->i_mode)) {
            drop_nlink(new_ip);
            if (new_ip->i_nlink) {
                mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
                if (old_dir != new_dir)
                    mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
                mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
                mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
                if (!S_ISDIR(old_ip->i_mode) && new_ip)
                    IWRITE_UNLOCK(new_ip);
                jfs_error(new_ip->i_sb,
                          "jfs_rename: new_ip->i_nlink != 0");
                return -EIO;
            }
            tblk = tid_to_tblock(tid);
            tblk->xflag |= COMMIT_DELETE;
            tblk->u.ip = new_ip;
        } else if (new_ip->i_nlink == 0) {
            assert(!test_cflag(COMMIT_Nolink, new_ip));
            /* free block resources */
            if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
                txAbort(tid, 1);	/* Marks FS Dirty */
                rc = new_size;
                goto out4;
            }
            tblk = tid_to_tblock(tid);
            tblk->xflag |= COMMIT_DELETE;
            tblk->u.ip = new_ip;
        } else {
            new_ip->i_ctime = CURRENT_TIME;
            mark_inode_dirty(new_ip);
        }
    } else {
        /*
         * Add new directory entry
         */
        rc = dtSearch(new_dir, &new_dname, &ino, &btstack,
                      JFS_CREATE);
        if (rc) {
            jfs_err("jfs_rename didn't expect dtSearch to fail "
                    "w/rc = %d", rc);
            goto out4;
        }

        ino = old_ip->i_ino;
        rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack);
        if (rc) {
            if (rc == -EIO)
                jfs_err("jfs_rename: dtInsert returned -EIO");
            goto out4;
        }
        if (S_ISDIR(old_ip->i_mode))
            inc_nlink(new_dir);
    }
    /*
     * Remove old directory entry
     */

    ino = old_ip->i_ino;
    rc = dtDelete(tid, old_dir, &old_dname, &ino, JFS_REMOVE);
    if (rc) {
        jfs_err("jfs_rename did not expect dtDelete to return rc = %d",
                rc);
        txAbort(tid, 1);	/* Marks Filesystem dirty */
        goto out4;
    }
    if (S_ISDIR(old_ip->i_mode)) {
        drop_nlink(old_dir);
        if (old_dir != new_dir) {
            /*
             * Change inode number of parent for moved directory
             */

            JFS_IP(old_ip)->i_dtroot.header.idotdot =
                cpu_to_le32(new_dir->i_ino);

            /* Linelock header of dtree */
            tlck = txLock(tid, old_ip,
                          (struct metapage *) &JFS_IP(old_ip)->bxflag,
                          tlckDTREE | tlckBTROOT | tlckRELINK);
            dtlck = (struct dt_lock *) & tlck->lock;
            ASSERT(dtlck->index == 0);
            lv = & dtlck->lv[0];
            lv->offset = 0;
            lv->length = 1;
            dtlck->index++;
        }
    }

    /*
     * Update ctime on changed/moved inodes & mark dirty
     */
    old_ip->i_ctime = CURRENT_TIME;
    mark_inode_dirty(old_ip);

    new_dir->i_ctime = new_dir->i_mtime = current_fs_time(new_dir->i_sb);
    mark_inode_dirty(new_dir);

    /* Build list of inodes modified by this transaction */
    ipcount = 0;
    iplist[ipcount++] = old_ip;
    if (new_ip)
        iplist[ipcount++] = new_ip;
    iplist[ipcount++] = old_dir;

    if (old_dir != new_dir) {
        iplist[ipcount++] = new_dir;
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
        mark_inode_dirty(old_dir);
    }

    /*
     * Incomplete truncate of file data can
     * result in timing problems unless we synchronously commit the
     * transaction.
     */
    if (new_size)
        commit_flag = COMMIT_SYNC;
    else
        commit_flag = 0;

    rc = txCommit(tid, ipcount, iplist, commit_flag);

out4:
    txEnd(tid);
    if (new_ip)
        mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
    if (old_dir != new_dir)
        mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
    mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
    mutex_unlock(&JFS_IP(new_dir)->commit_mutex);

    while (new_size && (rc == 0)) {
        tid = txBegin(new_ip->i_sb, 0);
        mutex_lock(&JFS_IP(new_ip)->commit_mutex);
        new_size = xtTruncate_pmap(tid, new_ip, new_size);
        if (new_size < 0) {
            txAbort(tid, 1);
            rc = new_size;
        } else
            rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
        txEnd(tid);
        mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
    }
    if (new_ip && (new_ip->i_nlink == 0))
        set_cflag(COMMIT_Nolink, new_ip);
out3:
    free_UCSname(&new_dname);
out2:
    free_UCSname(&old_dname);
out1:
    if (new_ip && !S_ISDIR(new_ip->i_mode))
        IWRITE_UNLOCK(new_ip);
    /*
     * Truncating the directory index table is not guaranteed.  It
     * may need to be done iteratively
     */
    if (test_cflag(COMMIT_Stale, old_dir)) {
        if (old_dir->i_size > 1)
            jfs_truncate_nolock(old_dir, 0);

        clear_cflag(COMMIT_Stale, old_dir);
    }

    jfs_info("jfs_rename: returning %d", rc);
    return rc;
}