Exemple #1
0
/**
 * Write a jindex file given a list of journal inums.
 * master: Inode of the master directory
 * jnls: List of inum structures relating to previously created journals.
 * nmemb: The number of entries in the list (number of journals).
 * Returns 0 on success or non-zero on error with errno set.
 */
int lgfs2_build_jindex(struct gfs2_inode *master, struct gfs2_inum *jnls, size_t nmemb)
{
	char fname[GFS2_FNAMESIZE + 1];
	struct gfs2_inode *jindex;
	unsigned j;
	int ret;

	if (nmemb == 0 || jnls == NULL) {
		errno = EINVAL;
		return 1;
	}
	jindex = createi(master, "jindex", S_IFDIR | 0700, GFS2_DIF_SYSTEM);
	if (jindex == NULL)
		return 1;

	fname[GFS2_FNAMESIZE] = '\0';

	for (j = 0; j < nmemb; j++) {
		snprintf(fname, GFS2_FNAMESIZE, "journal%u", j);
		ret = dir_add(jindex, fname, strlen(fname), &jnls[j], IF2DT(S_IFREG | 0600));
		if (ret) {
			inode_put(&jindex);
			return 1;
		}
	}

	if (cfg_debug) {
		printf("\nJindex:\n");
		gfs2_dinode_print(&jindex->i_di);
	}

	inode_put(&jindex);
	return 0;
}
Exemple #2
0
int build_jindex(struct gfs2_sbd *sdp)
{
	struct gfs2_inode *jindex;
	unsigned int j;
	int ret;

	jindex = createi(sdp->master_dir, "jindex", S_IFDIR | 0700,
			 GFS2_DIF_SYSTEM);
	if (jindex == NULL) {
		return errno;
	}
	sdp->md.journal = malloc(sdp->md.journals *
				 sizeof(struct gfs2_inode *));
	for (j = 0; j < sdp->md.journals; j++) {
		ret = build_journal(sdp, j, jindex);
		if (ret)
			return ret;
		inode_put(&sdp->md.journal[j]);
	}
	if (cfg_debug) {
		printf("\nJindex:\n");
		gfs2_dinode_print(&jindex->i_di);
	}

	free(sdp->md.journal);
	inode_put(&jindex);
	return 0;
}
Exemple #3
0
int build_master(struct gfs2_sbd *sdp)
{
	struct gfs2_inum inum;
	uint64_t bn;
	struct gfs2_buffer_head *bh = NULL;
	int err = lgfs2_dinode_alloc(sdp, 1, &bn);

	if (err != 0)
		return -1;

	inum.no_formal_ino = sdp->md.next_inum++;
	inum.no_addr = bn;

	err = init_dinode(sdp, &bh, &inum, S_IFDIR | 0755, GFS2_DIF_SYSTEM, &inum);
	if (err != 0)
		return -1;

	sdp->master_dir = lgfs2_inode_get(sdp, bh);
	if (sdp->master_dir == NULL)
		return -1;

	if (cfg_debug) {
		printf("\nMaster dir:\n");
		gfs2_dinode_print(&sdp->master_dir->i_di);
	}
	sdp->master_dir->bh_owned = 1;
	return 0;
}
Exemple #4
0
static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
{
	const struct gfs2_dinode *str = buf;
	struct timespec atime;
	u16 height, depth;

	if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)))
		goto corrupt;
	ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino);
	ip->i_inode.i_mode = be32_to_cpu(str->di_mode);
	ip->i_inode.i_rdev = 0;
	switch (ip->i_inode.i_mode & S_IFMT) {
	case S_IFBLK:
	case S_IFCHR:
		ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major),
					   be32_to_cpu(str->di_minor));
		break;
	};

	ip->i_inode.i_uid = be32_to_cpu(str->di_uid);
	ip->i_inode.i_gid = be32_to_cpu(str->di_gid);
	gfs2_set_nlink(&ip->i_inode, be32_to_cpu(str->di_nlink));
	ip->i_disksize = be64_to_cpu(str->di_size);
	i_size_write(&ip->i_inode, ip->i_disksize);
	gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks));
	atime.tv_sec = be64_to_cpu(str->di_atime);
	atime.tv_nsec = be32_to_cpu(str->di_atime_nsec);
	if (timespec_compare(&ip->i_inode.i_atime, &atime) < 0)
		ip->i_inode.i_atime = atime;
	ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime);
	ip->i_inode.i_mtime.tv_nsec = be32_to_cpu(str->di_mtime_nsec);
	ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime);
	ip->i_inode.i_ctime.tv_nsec = be32_to_cpu(str->di_ctime_nsec);

	ip->i_goal = be64_to_cpu(str->di_goal_meta);
	ip->i_generation = be64_to_cpu(str->di_generation);

	ip->i_diskflags = be32_to_cpu(str->di_flags);
	gfs2_set_inode_flags(&ip->i_inode);
	height = be16_to_cpu(str->di_height);
	if (unlikely(height > GFS2_MAX_META_HEIGHT))
		goto corrupt;
	ip->i_height = (u8)height;

	depth = be16_to_cpu(str->di_depth);
	if (unlikely(depth > GFS2_DIR_MAX_DEPTH))
		goto corrupt;
	ip->i_depth = (u8)depth;
	ip->i_entries = be32_to_cpu(str->di_entries);

	ip->i_eattr = be64_to_cpu(str->di_eattr);
	if (S_ISREG(ip->i_inode.i_mode))
		gfs2_set_aops(&ip->i_inode);

	return 0;
corrupt:
	if (gfs2_consist_inode(ip))
		gfs2_dinode_print(ip);
	return -EIO;
}
Exemple #5
0
int build_root(struct gfs2_sbd *sdp)
{
	struct gfs2_inum inum;
	uint64_t bn;
	struct gfs2_buffer_head *bh = NULL;
	int err = lgfs2_dinode_alloc(sdp, 1, &bn);

	if (err != 0)
		return -1;

	inum.no_formal_ino = sdp->md.next_inum++;
	inum.no_addr = bn;

	err = init_dinode(sdp, &bh, &inum, S_IFDIR | 0755, 0, &inum);
	if (err != 0)
		return -1;

	sdp->md.rooti = lgfs2_inode_get(sdp, bh);
	if (sdp->md.rooti == NULL)
		return -1;

	if (cfg_debug) {
		printf("\nRoot directory:\n");
		gfs2_dinode_print(&sdp->md.rooti->i_di);
	}
	sdp->md.rooti->bh_owned = 1;
	return 0;
}
Exemple #6
0
int build_per_node(struct gfs2_sbd *sdp)
{
	struct gfs2_inode *per_node;
	unsigned int j;
	int err;

	per_node = createi(sdp->master_dir, "per_node", S_IFDIR | 0700,
			   GFS2_DIF_SYSTEM);
	if (per_node == NULL) {
		return errno;
	}

	for (j = 0; j < sdp->md.journals; j++) {
		err = build_inum_range(per_node, j);
		if (err) {
			return err;
		}
		err = build_statfs_change(per_node, j);
		if (err) {
			return err;
		}
		err = build_quota_change(per_node, j);
		if (err) {
			return err;
		}
	}

	if (cfg_debug) {
		printf("\nper_node:\n");
		gfs2_dinode_print(&per_node->i_di);
	}

	inode_put(&per_node);
	return 0;
}
Exemple #7
0
int gfs2_dinode_dealloc(struct gfs2_inode *ip)
{
    struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
    struct gfs2_alloc *al;
    struct gfs2_rgrpd *rgd;
    int error;

    if (gfs2_get_inode_blocks(&ip->i_inode) != 1) {
        if (gfs2_consist_inode(ip))
            gfs2_dinode_print(ip);
        return -EIO;
    }

    al = gfs2_alloc_get(ip);
    if (!al)
        return -ENOMEM;

    error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
    if (error)
        goto out;

    error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
    if (error)
        goto out_qs;

    rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
    if (!rgd) {
        gfs2_consist_inode(ip);
        error = -EIO;
        goto out_rindex_relse;
    }

    error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0,
                   &al->al_rgd_gh);
    if (error)
        goto out_rindex_relse;

    error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1);
    if (error)
        goto out_rg_gunlock;

    set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
    set_bit(GLF_LFLUSH, &ip->i_gl->gl_flags);

    gfs2_free_di(rgd, ip);

    gfs2_trans_end(sdp);
    clear_bit(GLF_STICKY, &ip->i_gl->gl_flags);

out_rg_gunlock:
    gfs2_glock_dq_uninit(&al->al_rgd_gh);
out_rindex_relse:
    gfs2_glock_dq_uninit(&al->al_ri_gh);
out_qs:
    gfs2_quota_unhold(ip);
out:
    gfs2_alloc_put(ip);
    return error;
}
Exemple #8
0
static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
{
    struct gfs2_dinode_host *di = &ip->i_di;
    const struct gfs2_dinode *str = buf;

    if (ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)) {
        if (gfs2_consist_inode(ip))
            gfs2_dinode_print(ip);
        return -EIO;
    }
    ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino);
    ip->i_inode.i_mode = be32_to_cpu(str->di_mode);
    ip->i_inode.i_rdev = 0;
    switch (ip->i_inode.i_mode & S_IFMT) {
    case S_IFBLK:
    case S_IFCHR:
        ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major),
                                   be32_to_cpu(str->di_minor));
        break;
    };

    ip->i_inode.i_uid = be32_to_cpu(str->di_uid);
    ip->i_inode.i_gid = be32_to_cpu(str->di_gid);
    /*
     * We will need to review setting the nlink count here in the
     * light of the forthcoming ro bind mount work. This is a reminder
     * to do that.
     */
    ip->i_inode.i_nlink = be32_to_cpu(str->di_nlink);
    di->di_size = be64_to_cpu(str->di_size);
    i_size_write(&ip->i_inode, di->di_size);
    di->di_blocks = be64_to_cpu(str->di_blocks);
    gfs2_set_inode_blocks(&ip->i_inode);
    ip->i_inode.i_atime.tv_sec = be64_to_cpu(str->di_atime);
    ip->i_inode.i_atime.tv_nsec = be32_to_cpu(str->di_atime_nsec);
    ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime);
    ip->i_inode.i_mtime.tv_nsec = be32_to_cpu(str->di_mtime_nsec);
    ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime);
    ip->i_inode.i_ctime.tv_nsec = be32_to_cpu(str->di_ctime_nsec);

    di->di_goal_meta = be64_to_cpu(str->di_goal_meta);
    di->di_goal_data = be64_to_cpu(str->di_goal_data);
    di->di_generation = be64_to_cpu(str->di_generation);

    di->di_flags = be32_to_cpu(str->di_flags);
    gfs2_set_inode_flags(&ip->i_inode);
    di->di_height = be16_to_cpu(str->di_height);

    di->di_depth = be16_to_cpu(str->di_depth);
    di->di_entries = be32_to_cpu(str->di_entries);

    di->di_eattr = be64_to_cpu(str->di_eattr);
    if (S_ISREG(ip->i_inode.i_mode))
        gfs2_set_aops(&ip->i_inode);

    return 0;
}
Exemple #9
0
static int gfs2_rmdir(struct inode *dir, struct dentry *dentry)
{
	struct gfs2_inode *dip = GFS2_I(dir);
	struct gfs2_sbd *sdp = GFS2_SB(dir);
	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
	struct gfs2_holder ghs[3];
	struct gfs2_rgrpd *rgd;
	struct gfs2_holder ri_gh;
	int error;


	error = gfs2_rindex_hold(sdp, &ri_gh);
	if (error)
		return error;
	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);

	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
	gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);

	error = gfs2_glock_nq_m(3, ghs);
	if (error)
		goto out;

	error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
	if (error)
		goto out_gunlock;

	if (ip->i_di.di_entries < 2) {
		if (gfs2_consist_inode(ip))
			gfs2_dinode_print(ip);
		error = -EIO;
		goto out_gunlock;
	}
	if (ip->i_di.di_entries > 2) {
		error = -ENOTEMPTY;
		goto out_gunlock;
	}

	error = gfs2_trans_begin(sdp, 2 * RES_DINODE + 3 * RES_LEAF + RES_RG_BIT, 0);
	if (error)
		goto out_gunlock;

	error = gfs2_rmdiri(dip, &dentry->d_name, ip);

	gfs2_trans_end(sdp);

out_gunlock:
	gfs2_glock_dq_m(3, ghs);
out:
	gfs2_holder_uninit(ghs);
	gfs2_holder_uninit(ghs + 1);
	gfs2_holder_uninit(ghs + 2);
	gfs2_glock_dq_uninit(&ri_gh);
	return error;
}
Exemple #10
0
int build_statfs(struct gfs2_sbd *sdp)
{
	struct gfs2_inode *ip;

	ip = createi(sdp->master_dir, "statfs", S_IFREG | 0600,
		     GFS2_DIF_SYSTEM | GFS2_DIF_JDATA);
	if (ip == NULL) {
		return errno;
	}

	if (cfg_debug) {
		printf("\nStatFS Inode:\n");
		gfs2_dinode_print(&ip->i_di);
	}

	inode_put(&ip);
	return 0;
}
Exemple #11
0
int build_quota_change(struct gfs2_inode *per_node, unsigned int j)
{
	struct gfs2_sbd *sdp = per_node->i_sbd;
	struct gfs2_meta_header mh;
	char name[256];
	struct gfs2_inode *ip;
	unsigned int blocks = sdp->qcsize << (20 - sdp->sd_sb.sb_bsize_shift);
	unsigned int x;
	unsigned int hgt;
	struct gfs2_buffer_head *bh;

	memset(&mh, 0, sizeof(struct gfs2_meta_header));
	mh.mh_magic = GFS2_MAGIC;
	mh.mh_type = GFS2_METATYPE_QC;
	mh.mh_format = GFS2_FORMAT_QC;

	sprintf(name, "quota_change%u", j);
	ip = createi(per_node, name, S_IFREG | 0600, GFS2_DIF_SYSTEM);
	if (ip == NULL) {
		return errno;
	}

	hgt = calc_tree_height(ip, (blocks + 1) * sdp->bsize);
	build_height(ip, hgt);

	for (x = 0; x < blocks; x++) {
		bh = get_file_buf(ip, x, FALSE);
		if (!bh)
			return -1;

		memset(bh->b_data, 0, sdp->bsize);
		gfs2_meta_header_out(&mh, bh->b_data);
		bmodified(bh);
		brelse(bh);
	}

	if (cfg_debug) {
		printf("\nQuota Change %u:\n", j);
		gfs2_dinode_print(&ip->i_di);
	}

	inode_put(&ip);
	return 0;
}
static int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
		       struct gfs2_inode *ip)
{
	struct qstr dotname;
	int error;

	if (ip->i_entries != 2) {
		if (gfs2_consist_inode(ip))
			gfs2_dinode_print(ip);
		return -EIO;
	}

	error = gfs2_dir_del(dip, name);
	if (error)
		return error;

	error = gfs2_change_nlink(dip, -1);
	if (error)
		return error;

	gfs2_str2qstr(&dotname, ".");
	error = gfs2_dir_del(ip, &dotname);
	if (error)
		return error;

	gfs2_str2qstr(&dotname, "..");
	error = gfs2_dir_del(ip, &dotname);
	if (error)
		return error;

	/* It looks odd, but it really should be done twice */
	error = gfs2_change_nlink(ip, -1);
	if (error)
		return error;

	error = gfs2_change_nlink(ip, -1);
	if (error)
		return error;

	return error;
}
Exemple #13
0
int build_rindex(struct gfs2_sbd *sdp)
{
	struct gfs2_inode *ip;
	struct osi_node *n, *next = NULL;
	struct rgrp_tree *rl;
	char buf[sizeof(struct gfs2_rindex)];
	int count;

	ip = createi(sdp->master_dir, "rindex", S_IFREG | 0600,
		     GFS2_DIF_SYSTEM | GFS2_DIF_JDATA);
	if (ip == NULL) {
		return errno;
	}
	ip->i_di.di_payload_format = GFS2_FORMAT_RI;
	bmodified(ip->i_bh);

	for (n = osi_first(&sdp->rgtree); n; n = next) {
		next = osi_next(n);
		rl = (struct rgrp_tree *)n;

		gfs2_rindex_out(&rl->ri, buf);

		count = gfs2_writei(ip, buf, ip->i_di.di_size,
				    sizeof(struct gfs2_rindex));
		if (count != sizeof(struct gfs2_rindex))
			return -1;
	}
	memset(buf, 0, sizeof(struct gfs2_rindex));
	count = __gfs2_writei(ip, buf, ip->i_di.di_size,
			      sizeof(struct gfs2_rindex), 0);
	if (count != sizeof(struct gfs2_rindex))
		return -1;

	if (cfg_debug) {
		printf("\nResource Index:\n");
		gfs2_dinode_print(&ip->i_di);
	}

	inode_put(&ip);
	return 0;
}
Exemple #14
0
int build_statfs_change(struct gfs2_inode *per_node, unsigned int j)
{
	char name[256];
	struct gfs2_inode *ip;

	sprintf(name, "statfs_change%u", j);
	ip = createi(per_node, name, S_IFREG | 0600,
		     GFS2_DIF_SYSTEM | GFS2_DIF_JDATA);
	if (ip == NULL) {
		return errno;
	}
	ip->i_di.di_size = sizeof(struct gfs2_statfs_change);
	gfs2_dinode_out(&ip->i_di, ip->i_bh->b_data);
	bmodified(ip->i_bh);
	if (cfg_debug) {
		printf("\nStatFS Change %u:\n", j);
		gfs2_dinode_print(&ip->i_di);
	}

	inode_put(&ip);
	return 0;
}
Exemple #15
0
/**
 * gfs2_change_nlink - Change nlink count on inode
 * @ip: The GFS2 inode
 * @diff: The change in the nlink count required
 *
 * Returns: errno
 */
int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
{
	struct buffer_head *dibh;
	u32 nlink;
	int error;

	BUG_ON(diff != 1 && diff != -1);
	nlink = ip->i_inode.i_nlink + diff;

	/* If we are reducing the nlink count, but the new value ends up being
	   bigger than the old one, we must have underflowed. */
	if (diff < 0 && nlink > ip->i_inode.i_nlink) {
		if (gfs2_consist_inode(ip))
			gfs2_dinode_print(ip);
		return -EIO;
	}

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (error)
		return error;

	if (diff > 0)
		inc_nlink(&ip->i_inode);
	else
		drop_nlink(&ip->i_inode);

	ip->i_inode.i_ctime = CURRENT_TIME;

	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
	gfs2_dinode_out(ip, dibh->b_data);
	brelse(dibh);
	mark_inode_dirty(&ip->i_inode);

	if (ip->i_inode.i_nlink == 0)
		gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */

	return error;
}
Exemple #16
0
static int gfs2_rename(struct inode *odir, struct dentry *odentry,
		       struct inode *ndir, struct dentry *ndentry)
{
	struct gfs2_inode *odip = GFS2_I(odir);
	struct gfs2_inode *ndip = GFS2_I(ndir);
	struct gfs2_inode *ip = GFS2_I(odentry->d_inode);
	struct gfs2_inode *nip = NULL;
	struct gfs2_sbd *sdp = GFS2_SB(odir);
	struct gfs2_holder ghs[5], r_gh;
	struct gfs2_rgrpd *nrgd;
	unsigned int num_gh;
	int dir_rename = 0;
	int alloc_required;
	unsigned int x;
	int error;

	if (ndentry->d_inode) {
		nip = GFS2_I(ndentry->d_inode);
		if (ip == nip)
			return 0;
	}

	/* Make sure we aren't trying to move a dirctory into it's subdir */

	if (S_ISDIR(ip->i_inode.i_mode) && odip != ndip) {
		dir_rename = 1;

		error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, 0,
					   &r_gh);
		if (error)
			goto out;

		error = gfs2_ok_to_move(ip, ndip);
		if (error)
			goto out_gunlock_r;
	}

	num_gh = 1;
	gfs2_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
	if (odip != ndip) {
		gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
		num_gh++;
	}
	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
	num_gh++;

	if (nip) {
		gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
		num_gh++;
		/* grab the resource lock for unlink flag twiddling 
		 * this is the case of the target file already existing
		 * so we unlink before doing the rename
		 */
		nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr);
		if (nrgd)
			gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++);
	}

	error = gfs2_glock_nq_m(num_gh, ghs);
	if (error)
		goto out_uninit;

	/* Check out the old directory */

	error = gfs2_unlink_ok(odip, &odentry->d_name, ip);
	if (error)
		goto out_gunlock;

	/* Check out the new directory */

	if (nip) {
		error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip);
		if (error)
			goto out_gunlock;

		if (S_ISDIR(nip->i_inode.i_mode)) {
			if (nip->i_di.di_entries < 2) {
				if (gfs2_consist_inode(nip))
					gfs2_dinode_print(nip);
				error = -EIO;
				goto out_gunlock;
			}
			if (nip->i_di.di_entries > 2) {
				error = -ENOTEMPTY;
				goto out_gunlock;
			}
		}
	} else {
		error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC);
		if (error)
			goto out_gunlock;

		error = gfs2_dir_check(ndir, &ndentry->d_name, NULL);
		switch (error) {
		case -ENOENT:
			error = 0;
			break;
		case 0:
			error = -EEXIST;
		default:
			goto out_gunlock;
		};

		if (odip != ndip) {
			if (!ndip->i_inode.i_nlink) {
				error = -EINVAL;
				goto out_gunlock;
			}
			if (ndip->i_di.di_entries == (u32)-1) {
				error = -EFBIG;
				goto out_gunlock;
			}
			if (S_ISDIR(ip->i_inode.i_mode) &&
			    ndip->i_inode.i_nlink == (u32)-1) {
				error = -EMLINK;
				goto out_gunlock;
			}
		}
	}

	/* Check out the dir to be renamed */

	if (dir_rename) {
		error = gfs2_permission(odentry->d_inode, MAY_WRITE);
		if (error)
			goto out_gunlock;
	}

	alloc_required = error = gfs2_diradd_alloc_required(ndir, &ndentry->d_name);
	if (error < 0)
		goto out_gunlock;
	error = 0;

	if (alloc_required) {
		struct gfs2_alloc *al = gfs2_alloc_get(ndip);
		if (!al) {
			error = -ENOMEM;
			goto out_gunlock;
		}

		error = gfs2_quota_lock_check(ndip);
		if (error)
			goto out_alloc;

		al->al_requested = sdp->sd_max_dirres;

		error = gfs2_inplace_reserve(ndip);
		if (error)
			goto out_gunlock_q;

		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
					 al->al_rgd->rd_length +
					 4 * RES_DINODE + 4 * RES_LEAF +
					 RES_STATFS + RES_QUOTA + 4, 0);
		if (error)
			goto out_ipreserv;
	} else {
		error = gfs2_trans_begin(sdp, 4 * RES_DINODE +
					 5 * RES_LEAF + 4, 0);
		if (error)
			goto out_gunlock;
	}

	/* Remove the target file, if it exists */

	if (nip) {
		if (S_ISDIR(nip->i_inode.i_mode))
			error = gfs2_rmdiri(ndip, &ndentry->d_name, nip);
		else {
			error = gfs2_dir_del(ndip, &ndentry->d_name);
			if (error)
				goto out_end_trans;
			error = gfs2_change_nlink(nip, -1);
		}
		if (error)
			goto out_end_trans;
	}

	if (dir_rename) {
		struct qstr name;
		gfs2_str2qstr(&name, "..");

		error = gfs2_change_nlink(ndip, +1);
		if (error)
			goto out_end_trans;
		error = gfs2_change_nlink(odip, -1);
		if (error)
			goto out_end_trans;

		error = gfs2_dir_mvino(ip, &name, ndip, DT_DIR);
		if (error)
			goto out_end_trans;
	} else {
		struct buffer_head *dibh;
		error = gfs2_meta_inode_buffer(ip, &dibh);
		if (error)
			goto out_end_trans;
		ip->i_inode.i_ctime = CURRENT_TIME;
		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
		gfs2_dinode_out(ip, dibh->b_data);
		brelse(dibh);
	}

	error = gfs2_dir_del(odip, &odentry->d_name);
	if (error)
		goto out_end_trans;

	error = gfs2_dir_add(ndir, &ndentry->d_name, ip, IF2DT(ip->i_inode.i_mode));
	if (error)
		goto out_end_trans;

out_end_trans:
	gfs2_trans_end(sdp);
out_ipreserv:
	if (alloc_required)
		gfs2_inplace_release(ndip);
out_gunlock_q:
	if (alloc_required)
		gfs2_quota_unlock(ndip);
out_alloc:
	if (alloc_required)
		gfs2_alloc_put(ndip);
out_gunlock:
	gfs2_glock_dq_m(num_gh, ghs);
out_uninit:
	for (x = 0; x < num_gh; x++)
		gfs2_holder_uninit(ghs + x);
out_gunlock_r:
	if (dir_rename)
		gfs2_glock_dq_uninit(&r_gh);
out:
	return error;
}
Exemple #17
0
struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
			   unsigned int mode, dev_t dev)
{
	struct inode *inode = NULL;
	struct gfs2_inode *dip = ghs->gh_gl->gl_object;
	struct inode *dir = &dip->i_inode;
	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
	struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
	int error;
	u64 generation;

	if (!name->len || name->len > GFS2_FNAMESIZE)
		return ERR_PTR(-ENAMETOOLONG);

	gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs);
	error = gfs2_glock_nq(ghs);
	if (error)
		goto fail;

	error = create_ok(dip, name, mode);
	if (error)
		goto fail_gunlock;

	error = pick_formal_ino(sdp, &inum.no_formal_ino);
	if (error)
		goto fail_gunlock;

	error = alloc_dinode(dip, &inum.no_addr, &generation);
	if (error)
		goto fail_gunlock;

	error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops,
				  LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
	if (error)
		goto fail_gunlock;

	error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev);
	if (error)
		goto fail_gunlock2;

	inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode),
					inum.no_addr,
					inum.no_formal_ino);
	if (IS_ERR(inode))
		goto fail_gunlock2;

	error = gfs2_inode_refresh(GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	error = gfs2_acl_create(dip, GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	error = gfs2_security_init(dip, GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	error = link_dinode(dip, name, GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	if (!inode)
		return ERR_PTR(-ENOMEM);
	return inode;

fail_gunlock2:
	gfs2_glock_dq_uninit(ghs + 1);
	if (inode)
		iput(inode);
fail_gunlock:
	gfs2_glock_dq(ghs);
fail:
	return ERR_PTR(error);
}

/**
 * gfs2_rmdiri - Remove a directory
 * @dip: The parent directory of the directory to be removed
 * @name: The name of the directory to be removed
 * @ip: The GFS2 inode of the directory to be removed
 *
 * Assumes Glocks on dip and ip are held
 *
 * Returns: errno
 */

int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
		struct gfs2_inode *ip)
{
	struct qstr dotname;
	int error;

	if (ip->i_di.di_entries != 2) {
		if (gfs2_consist_inode(ip))
			gfs2_dinode_print(ip);
		return -EIO;
	}

	error = gfs2_dir_del(dip, name);
	if (error)
		return error;

	error = gfs2_change_nlink(dip, -1);
	if (error)
		return error;

	gfs2_str2qstr(&dotname, ".");
	error = gfs2_dir_del(ip, &dotname);
	if (error)
		return error;

	gfs2_str2qstr(&dotname, "..");
	error = gfs2_dir_del(ip, &dotname);
	if (error)
		return error;

	/* It looks odd, but it really should be done twice */
	error = gfs2_change_nlink(ip, -1);
	if (error)
		return error;

	error = gfs2_change_nlink(ip, -1);
	if (error)
		return error;

	return error;
}

/*
 * gfs2_unlink_ok - check to see that a inode is still in a directory
 * @dip: the directory
 * @name: the name of the file
 * @ip: the inode
 *
 * Assumes that the lock on (at least) @dip is held.
 *
 * Returns: 0 if the parent/child relationship is correct, errno if it isn't
 */

int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
		   const struct gfs2_inode *ip)
{
	int error;

	if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
		return -EPERM;

	if ((dip->i_inode.i_mode & S_ISVTX) &&
	    dip->i_inode.i_uid != current->fsuid &&
	    ip->i_inode.i_uid != current->fsuid && !capable(CAP_FOWNER))
		return -EPERM;

	if (IS_APPEND(&dip->i_inode))
		return -EPERM;

	error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL);
	if (error)
		return error;

	error = gfs2_dir_check(&dip->i_inode, name, ip);
	if (error)
		return error;

	return 0;
}
Exemple #18
0
int display_gfs2(struct gfs2_buffer_head *dbh)
{
	struct gfs2_meta_header mh;
	struct gfs2_rgrp rg;
	struct gfs2_leaf lf;
	struct gfs_log_header lh1;
	struct gfs2_log_header lh;
	struct gfs2_log_descriptor ld;
	struct gfs2_quota_change qc;

	uint32_t magic;

	magic = be32_to_cpu(*(uint32_t *)dbh->b_data);

	switch (magic)
	{
	case GFS2_MAGIC:
		gfs2_meta_header_in(&mh, dbh);
		if (mh.mh_type > GFS2_METATYPE_QC)
			print_gfs2("Unknown metadata type");
		else
			print_gfs2("%s:", block_type_str[mh.mh_type]);
		eol(0);

		switch (mh.mh_type)
		{
		case GFS2_METATYPE_SB:
			gfs2_sb_in(&sbd.sd_sb, dbh);
			gfs2_sb_print2(&sbd.sd_sb);
			break;

		case GFS2_METATYPE_RG:
			if (sbd.gfs1) {
				struct gfs_rgrp rg1;

				gfs1_rgrp_in(&rg1, dbh);
				gfs1_rgrp_print(&rg1);
			} else {
				gfs2_rgrp_in(&rg, dbh);
				gfs2_rgrp_print(&rg);
			}
			break;

		case GFS2_METATYPE_RB:
			gfs2_meta_header_print(&mh);
			break;

		case GFS2_METATYPE_DI:
			gfs2_dinode_print(&di);
			break;

		case GFS2_METATYPE_IN:
			gfs2_meta_header_print(&mh);
			break;

		case GFS2_METATYPE_LF:
			gfs2_leaf_in(&lf, dbh);
			gfs2_leaf_print(&lf);
			break;

		case GFS2_METATYPE_JD:
			gfs2_meta_header_print(&mh);
			break;

		case GFS2_METATYPE_LH:
			if (sbd.gfs1) {
				gfs_log_header_in(&lh1, dbh);
				gfs_log_header_print(&lh1);
			} else {
				gfs2_log_header_in(&lh, dbh);
				gfs2_log_header_print(&lh);
			}
			break;

		case GFS2_METATYPE_LD:
			gfs2_log_descriptor_in(&ld, dbh);
			gfs2_log_descriptor_print(&ld);
			break;

		case GFS2_METATYPE_EA:
			do_eattr_extended(dbh);
			break;

		case GFS2_METATYPE_ED:
			gfs2_meta_header_print(&mh);
			break;

		case GFS2_METATYPE_LB:
			gfs2_meta_header_print(&mh);
			break;

		case GFS2_METATYPE_QC:
			gfs2_quota_change_in(&qc, dbh);
			gfs2_quota_change_print(&qc);
			break;

		default:
			break;
		}
		break;

	default:
		print_gfs2("Unknown block type");
		eol(0);
		break;
	};
	return(0);
}