/** * 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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
/** * 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; }
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; }
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; }
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); }