|
Packit Service |
360c39 |
#include "clusterautoconfig.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include <stdio.h>
|
|
Packit Service |
360c39 |
#include <stdlib.h>
|
|
Packit Service |
360c39 |
#include <string.h>
|
|
Packit Service |
360c39 |
#include <stdint.h>
|
|
Packit Service |
360c39 |
#include <inttypes.h>
|
|
Packit Service |
360c39 |
#include <sys/types.h>
|
|
Packit Service |
360c39 |
#include <sys/stat.h>
|
|
Packit Service |
360c39 |
#include <fcntl.h>
|
|
Packit Service |
360c39 |
#include <unistd.h>
|
|
Packit Service |
360c39 |
#include <errno.h>
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include <linux/types.h>
|
|
Packit Service |
360c39 |
#include "libgfs2.h"
|
|
Packit Service |
360c39 |
#include "rgrp.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static __inline__ uint64_t *metapointer(struct gfs2_buffer_head *bh,
|
|
Packit Service |
360c39 |
unsigned int height,
|
|
Packit Service |
360c39 |
struct metapath *mp)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
unsigned int head_size = (height > 0) ?
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height];
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Detect directory is a stuffed inode */
|
|
Packit Service |
360c39 |
static int inode_is_stuffed(const struct gfs2_inode *ip)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return !ip->i_di.di_height;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct gfs2_inode *lgfs2_inode_get(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_inode *ip;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ip = calloc(1, sizeof(struct gfs2_inode));
|
|
Packit Service |
360c39 |
if (ip == NULL) {
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
gfs2_dinode_in(&ip->i_di, bh->b_data);
|
|
Packit Service |
360c39 |
ip->i_bh = bh;
|
|
Packit Service |
360c39 |
ip->i_sbd = sdp;
|
|
Packit Service |
360c39 |
return ip;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct gfs2_inode *lgfs2_inode_read(struct gfs2_sbd *sdp, uint64_t di_addr)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_inode *ip;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh = bread(sdp, di_addr);
|
|
Packit Service |
360c39 |
if (bh == NULL) {
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
ip = lgfs2_inode_get(sdp, bh);
|
|
Packit Service |
360c39 |
if (ip == NULL) {
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
ip->bh_owned = 1; /* We did the bread so we own the bh */
|
|
Packit Service |
360c39 |
return ip;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct gfs2_inode *is_system_inode(struct gfs2_sbd *sdp, uint64_t block)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int j;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (sdp->md.inum && block == sdp->md.inum->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
return sdp->md.inum;
|
|
Packit Service |
360c39 |
if (sdp->md.statfs && block == sdp->md.statfs->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
return sdp->md.statfs;
|
|
Packit Service |
360c39 |
if (sdp->md.jiinode && block == sdp->md.jiinode->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
return sdp->md.jiinode;
|
|
Packit Service |
360c39 |
if (sdp->md.riinode && block == sdp->md.riinode->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
return sdp->md.riinode;
|
|
Packit Service |
360c39 |
if (sdp->md.qinode && block == sdp->md.qinode->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
return sdp->md.qinode;
|
|
Packit Service |
360c39 |
if (sdp->md.pinode && block == sdp->md.pinode->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
return sdp->md.pinode;
|
|
Packit Service |
360c39 |
if (sdp->md.rooti && block == sdp->md.rooti->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
return sdp->md.rooti;
|
|
Packit Service |
360c39 |
if (sdp->master_dir && block == sdp->master_dir->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
return sdp->master_dir;
|
|
Packit Service |
360c39 |
for (j = 0; j < sdp->md.journals; j++)
|
|
Packit Service |
360c39 |
if (sdp->md.journal && sdp->md.journal[j] &&
|
|
Packit Service |
360c39 |
block == sdp->md.journal[j]->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
return sdp->md.journal[j];
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void inode_put(struct gfs2_inode **ip_in)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_inode *ip = *ip_in;
|
|
Packit Service |
360c39 |
uint64_t block = ip->i_di.di_num.no_addr;
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (ip->i_bh->b_modified) {
|
|
Packit Service |
360c39 |
gfs2_dinode_out(&ip->i_di, ip->i_bh->b_data);
|
|
Packit Service |
360c39 |
if (!ip->bh_owned && is_system_inode(sdp, block))
|
|
Packit Service |
360c39 |
fprintf(stderr, "Warning: Change made to inode "
|
|
Packit Service |
360c39 |
"were discarded.\n");
|
|
Packit Service |
360c39 |
/* This is for debugging only: a convenient place to set
|
|
Packit Service |
360c39 |
a breakpoint. This means a system inode was modified but
|
|
Packit Service |
360c39 |
not written. That's not fatal: some places like
|
|
Packit Service |
360c39 |
adjust_inode in gfs2_convert will do this on purpose.
|
|
Packit Service |
360c39 |
It can also point out a coding problem, but we don't
|
|
Packit Service |
360c39 |
want to raise alarm in the users either. */
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (ip->bh_owned)
|
|
Packit Service |
360c39 |
brelse(ip->i_bh);
|
|
Packit Service |
360c39 |
ip->i_bh = NULL;
|
|
Packit Service |
360c39 |
free(ip);
|
|
Packit Service |
360c39 |
*ip_in = NULL; /* make sure the memory isn't accessed again */
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static uint64_t find_free_block(struct rgrp_tree *rgd)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
unsigned bm;
|
|
Packit Service |
360c39 |
uint64_t blkno = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (rgd == NULL || rgd->rg.rg_free == 0) {
|
|
Packit Service |
360c39 |
errno = ENOSPC;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (bm = 0; bm < rgd->ri.ri_length; bm++) {
|
|
Packit Service |
360c39 |
unsigned long blk = 0;
|
|
Packit Service |
360c39 |
struct gfs2_bitmap *bits = &rgd->bits[bm];
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
blk = gfs2_bitfit((uint8_t *)bits->bi_bh->b_data + bits->bi_offset,
|
|
Packit Service |
360c39 |
bits->bi_len, blk, GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
if (blk != BFITNOENT) {
|
|
Packit Service |
360c39 |
blkno = blk + (bits->bi_start * GFS2_NBBY) + rgd->ri.ri_data0;
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return blkno;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int blk_alloc_in_rg(struct gfs2_sbd *sdp, unsigned state, struct rgrp_tree *rgd, uint64_t blkno, int dinode)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if (blkno == 0)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (gfs2_set_bitmap(rgd, blkno, state))
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (state == GFS2_BLKST_DINODE) {
|
|
Packit Service |
360c39 |
struct gfs_rgrp *gfs1rg = (struct gfs_rgrp *)&rgd->rg;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (dinode)
|
|
Packit Service |
360c39 |
rgd->rg.rg_dinodes++;
|
|
Packit Service |
360c39 |
else if (sdp->gfs1)
|
|
Packit Service |
360c39 |
gfs1rg->rg_usedmeta++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rgd->rg.rg_free--;
|
|
Packit Service |
360c39 |
if (sdp->gfs1)
|
|
Packit Service |
360c39 |
gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
gfs2_rgrp_out(&rgd->rg, rgd->bits[0].bi_bh->b_data);
|
|
Packit Service |
360c39 |
bmodified(rgd->bits[0].bi_bh);
|
|
Packit Service |
360c39 |
sdp->blks_alloced++;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Allocate a block in a bitmap. In order to plan ahead we look for a
|
|
Packit Service |
360c39 |
* resource group with blksreq free blocks but only allocate the one block.
|
|
Packit Service |
360c39 |
* Returns 0 on success with the allocated block number in *blkno or non-zero otherwise.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int block_alloc(struct gfs2_sbd *sdp, const uint64_t blksreq, int state, uint64_t *blkno, int dinode)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int ret;
|
|
Packit Service |
360c39 |
int release = 0;
|
|
Packit Service |
360c39 |
struct rgrp_tree *rgt = NULL;
|
|
Packit Service |
360c39 |
struct osi_node *n = NULL;
|
|
Packit Service |
360c39 |
uint64_t bn = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (n = osi_first(&sdp->rgtree); n; n = osi_next(n)) {
|
|
Packit Service |
360c39 |
rgt = (struct rgrp_tree *)n;
|
|
Packit Service |
360c39 |
if (rgt->rg.rg_free >= blksreq)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (rgt == NULL)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (rgt->bits[0].bi_bh == NULL) {
|
|
Packit Service |
360c39 |
if (gfs2_rgrp_read(sdp, rgt))
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
release = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bn = find_free_block(rgt);
|
|
Packit Service |
360c39 |
ret = blk_alloc_in_rg(sdp, state, rgt, bn, dinode);
|
|
Packit Service |
360c39 |
if (release)
|
|
Packit Service |
360c39 |
gfs2_rgrp_relse(rgt);
|
|
Packit Service |
360c39 |
*blkno = bn;
|
|
Packit Service |
360c39 |
return ret;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int lgfs2_dinode_alloc(struct gfs2_sbd *sdp, const uint64_t blksreq, uint64_t *blkno)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int ret = block_alloc(sdp, blksreq, GFS2_BLKST_DINODE, blkno, TRUE);
|
|
Packit Service |
360c39 |
if (ret == 0)
|
|
Packit Service |
360c39 |
sdp->dinodes_alloced++;
|
|
Packit Service |
360c39 |
return ret;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int lgfs2_meta_alloc(struct gfs2_inode *ip, uint64_t *blkno)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int ret = block_alloc(ip->i_sbd, 1,
|
|
Packit Service |
360c39 |
ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE :
|
|
Packit Service |
360c39 |
GFS2_BLKST_USED, blkno, FALSE);
|
|
Packit Service |
360c39 |
if (ret == 0) {
|
|
Packit Service |
360c39 |
ip->i_di.di_goal_meta = *blkno;
|
|
Packit Service |
360c39 |
bmodified(ip->i_bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return ret;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static __inline__ void buffer_clear_tail(struct gfs2_sbd *sdp,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh, int head)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
memset(bh->b_data + head, 0, sdp->bsize - head);
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static __inline__ void
|
|
Packit Service |
360c39 |
buffer_copy_tail(struct gfs2_sbd *sdp,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *to_bh, int to_head,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *from_bh, int from_head)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
memcpy(to_bh->b_data + to_head, from_bh->b_data + from_head,
|
|
Packit Service |
360c39 |
sdp->bsize - from_head);
|
|
Packit Service |
360c39 |
memset(to_bh->b_data + sdp->bsize + to_head - from_head, 0,
|
|
Packit Service |
360c39 |
from_head - to_head);
|
|
Packit Service |
360c39 |
bmodified(to_bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void unstuff_dinode(struct gfs2_inode *ip)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
uint64_t block = 0;
|
|
Packit Service |
360c39 |
int isdir = S_ISDIR(ip->i_di.di_mode) || is_gfs_dir(&ip->i_di);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (ip->i_di.di_size) {
|
|
Packit Service |
360c39 |
if (lgfs2_meta_alloc(ip, &block))
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
if (isdir) {
|
|
Packit Service |
360c39 |
struct gfs2_meta_header mh;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bh = bget(sdp, block);
|
|
Packit Service |
360c39 |
mh.mh_magic = GFS2_MAGIC;
|
|
Packit Service |
360c39 |
mh.mh_type = GFS2_METATYPE_JD;
|
|
Packit Service |
360c39 |
mh.mh_format = GFS2_FORMAT_JD;
|
|
Packit Service |
360c39 |
gfs2_meta_header_out(&mh, bh->b_data);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
buffer_copy_tail(sdp, bh,
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_meta_header),
|
|
Packit Service |
360c39 |
ip->i_bh, sizeof(struct gfs2_dinode));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
bh = bget(sdp, block);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
buffer_copy_tail(sdp, bh, 0,
|
|
Packit Service |
360c39 |
ip->i_bh, sizeof(struct gfs2_dinode));
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
buffer_clear_tail(sdp, ip->i_bh, sizeof(struct gfs2_dinode));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (ip->i_di.di_size) {
|
|
Packit Service |
360c39 |
*(uint64_t *)(ip->i_bh->b_data + sizeof(struct gfs2_dinode)) = cpu_to_be64(block);
|
|
Packit Service |
360c39 |
/* no need: bmodified(ip->i_bh); buffer_clear_tail does it */
|
|
Packit Service |
360c39 |
ip->i_di.di_blocks++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ip->i_di.di_height = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Calculate the total number of blocks required by a file containing 'bytes' bytes of data.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
uint64_t lgfs2_space_for_data(const struct gfs2_sbd *sdp, const unsigned bsize, const uint64_t bytes)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t blks = (bytes + bsize - 1) / bsize;
|
|
Packit Service |
360c39 |
uint64_t ptrs = blks;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (bytes <= bsize - sizeof(struct gfs2_dinode))
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (ptrs > sdp->sd_diptrs) {
|
|
Packit Service |
360c39 |
ptrs = (ptrs + sdp->sd_inptrs - 1) / sdp->sd_inptrs;
|
|
Packit Service |
360c39 |
blks += ptrs;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return blks + 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Allocate an extent for a file in a resource group's bitmaps.
|
|
Packit Service |
360c39 |
* rg: The resource group in which to allocate the extent
|
|
Packit Service |
360c39 |
* di_size: The size of the file in bytes
|
|
Packit Service |
360c39 |
* ip: A pointer to the inode structure, whose fields will be set appropriately.
|
|
Packit Service |
360c39 |
* If ip->i_di.di_num.no_addr is not 0, the extent search will be skipped and
|
|
Packit Service |
360c39 |
* the file allocated from that address.
|
|
Packit Service |
360c39 |
* flags: GFS2_DIF_* flags
|
|
Packit Service |
360c39 |
* mode: File mode flags, see creat(2)
|
|
Packit Service |
360c39 |
* Returns 0 on success with the contents of ip set accordingly, or non-zero
|
|
Packit Service |
360c39 |
* with errno set on error. If errno is ENOSPC then rg does not contain a
|
|
Packit Service |
360c39 |
* large enough free extent for the given di_size.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int lgfs2_file_alloc(lgfs2_rgrp_t rg, uint64_t di_size, struct gfs2_inode *ip, uint32_t flags, unsigned mode)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
unsigned extlen;
|
|
Packit Service |
360c39 |
struct gfs2_dinode *di = &ip->i_di;
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = rg->rgrps->sdp;
|
|
Packit Service |
360c39 |
struct lgfs2_rbm rbm = { .rgd = rg, .offset = 0, .bii = 0 };
|
|
Packit Service |
360c39 |
uint32_t blocks = lgfs2_space_for_data(sdp, sdp->bsize, di_size);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (ip->i_di.di_num.no_addr != 0) {
|
|
Packit Service |
360c39 |
if (lgfs2_rbm_from_block(&rbm, ip->i_di.di_num.no_addr) != 0)
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
} else if (lgfs2_rbm_find(&rbm, GFS2_BLKST_FREE, &blocks) != 0) {
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
extlen = lgfs2_alloc_extent(&rbm, GFS2_BLKST_DINODE, blocks);
|
|
Packit Service |
360c39 |
if (extlen < blocks) {
|
|
Packit Service |
360c39 |
errno = EINVAL;
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ip->i_sbd = sdp;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
di->di_header.mh_magic = GFS2_MAGIC;
|
|
Packit Service |
360c39 |
di->di_header.mh_type = GFS2_METATYPE_DI;
|
|
Packit Service |
360c39 |
di->di_header.mh_format = GFS2_FORMAT_DI;
|
|
Packit Service |
360c39 |
di->di_size = di_size;
|
|
Packit Service |
360c39 |
di->di_num.no_addr = lgfs2_rbm_to_block(&rbm;;
|
|
Packit Service |
360c39 |
di->di_num.no_formal_ino = sdp->md.next_inum++;
|
|
Packit Service |
360c39 |
di->di_mode = mode;
|
|
Packit Service |
360c39 |
di->di_nlink = 1;
|
|
Packit Service |
360c39 |
di->di_blocks = blocks;
|
|
Packit Service |
360c39 |
di->di_atime = di->di_mtime = di->di_ctime = sdp->time;
|
|
Packit Service |
360c39 |
di->di_goal_data = di->di_num.no_addr + di->di_blocks - 1;
|
|
Packit Service |
360c39 |
di->di_goal_meta = di->di_goal_data - ((di_size + sdp->bsize - 1) / sdp->bsize);
|
|
Packit Service |
360c39 |
di->di_height = calc_tree_height(ip, di_size);
|
|
Packit Service |
360c39 |
di->di_flags = flags;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rg->rg.rg_free -= blocks;
|
|
Packit Service |
360c39 |
rg->rg.rg_dinodes += 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
sdp->dinodes_alloced++;
|
|
Packit Service |
360c39 |
sdp->blks_alloced += blocks;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
unsigned int calc_tree_height(struct gfs2_inode *ip, uint64_t size)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
uint64_t *arr;
|
|
Packit Service |
360c39 |
unsigned int max, height;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (ip->i_di.di_size > size)
|
|
Packit Service |
360c39 |
size = ip->i_di.di_size;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (S_ISDIR(ip->i_di.di_mode)) {
|
|
Packit Service |
360c39 |
arr = sdp->sd_jheightsize;
|
|
Packit Service |
360c39 |
max = sdp->sd_max_jheight;
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
arr = sdp->sd_heightsize;
|
|
Packit Service |
360c39 |
max = sdp->sd_max_height;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (height = 0; height < max; height++)
|
|
Packit Service |
360c39 |
if (arr[height] >= size)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return height;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void build_height(struct gfs2_inode *ip, int height)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
uint64_t block = 0, *bp;
|
|
Packit Service |
360c39 |
unsigned int x;
|
|
Packit Service |
360c39 |
int new_block;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (ip->i_di.di_height < height) {
|
|
Packit Service |
360c39 |
new_block = FALSE;
|
|
Packit Service |
360c39 |
bp = (uint64_t *)(ip->i_bh->b_data + sizeof(struct gfs2_dinode));
|
|
Packit Service |
360c39 |
for (x = 0; x < sdp->sd_diptrs; x++, bp++)
|
|
Packit Service |
360c39 |
if (*bp) {
|
|
Packit Service |
360c39 |
new_block = TRUE;
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (new_block) {
|
|
Packit Service |
360c39 |
struct gfs2_meta_header mh;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (lgfs2_meta_alloc(ip, &block))
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
bh = bget(sdp, block);
|
|
Packit Service |
360c39 |
mh.mh_magic = GFS2_MAGIC;
|
|
Packit Service |
360c39 |
mh.mh_type = GFS2_METATYPE_IN;
|
|
Packit Service |
360c39 |
mh.mh_format = GFS2_FORMAT_IN;
|
|
Packit Service |
360c39 |
gfs2_meta_header_out(&mh, bh->b_data);
|
|
Packit Service |
360c39 |
buffer_copy_tail(sdp, bh,
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_meta_header),
|
|
Packit Service |
360c39 |
ip->i_bh, sizeof(struct gfs2_dinode));
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
buffer_clear_tail(sdp, ip->i_bh, sizeof(struct gfs2_dinode));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (new_block) {
|
|
Packit Service |
360c39 |
*(uint64_t *)(ip->i_bh->b_data + sizeof(struct gfs2_dinode)) = cpu_to_be64(block);
|
|
Packit Service |
360c39 |
/* no need: bmodified(ip->i_bh);*/
|
|
Packit Service |
360c39 |
ip->i_di.di_blocks++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ip->i_di.di_height++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void find_metapath(struct gfs2_inode *ip, uint64_t block, struct metapath *mp)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
const uint32_t inptrs = ip->i_sbd->sd_inptrs;
|
|
Packit Service |
360c39 |
unsigned int i = ip->i_di.di_height;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
memset(mp, 0, sizeof(struct metapath));
|
|
Packit Service |
360c39 |
while (i--) {
|
|
Packit Service |
360c39 |
mp->mp_list[i] = block % inptrs;
|
|
Packit Service |
360c39 |
block /= inptrs;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void lookup_block(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
|
|
Packit Service |
360c39 |
unsigned int height, struct metapath *mp,
|
|
Packit Service |
360c39 |
int create, int *new, uint64_t *block)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t *ptr = metapointer(bh, height, mp);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (*ptr) {
|
|
Packit Service |
360c39 |
*block = be64_to_cpu(*ptr);
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*block = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!create)
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (lgfs2_meta_alloc(ip, block))
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
*ptr = cpu_to_be64(*block);
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
ip->i_di.di_blocks++;
|
|
Packit Service |
360c39 |
bmodified(ip->i_bh);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*new = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
|
|
Packit Service |
360c39 |
uint64_t *dblock, uint32_t *extlen, int prealloc)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
struct metapath mp;
|
|
Packit Service |
360c39 |
int create = *new;
|
|
Packit Service |
360c39 |
unsigned int bsize;
|
|
Packit Service |
360c39 |
unsigned int height;
|
|
Packit Service |
360c39 |
unsigned int end_of_metadata;
|
|
Packit Service |
360c39 |
unsigned int x;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*new = 0;
|
|
Packit Service |
360c39 |
*dblock = 0;
|
|
Packit Service |
360c39 |
if (extlen)
|
|
Packit Service |
360c39 |
*extlen = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (inode_is_stuffed(ip)) {
|
|
Packit Service |
360c39 |
if (!lblock) {
|
|
Packit Service |
360c39 |
*dblock = ip->i_di.di_num.no_addr;
|
|
Packit Service |
360c39 |
if (extlen)
|
|
Packit Service |
360c39 |
*extlen = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bsize = (S_ISDIR(ip->i_di.di_mode)) ? sdp->sd_jbsize : sdp->bsize;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
height = calc_tree_height(ip, (lblock + 1) * bsize);
|
|
Packit Service |
360c39 |
if (ip->i_di.di_height < height) {
|
|
Packit Service |
360c39 |
if (!create)
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
build_height(ip, height);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
find_metapath(ip, lblock, &mp);
|
|
Packit Service |
360c39 |
end_of_metadata = ip->i_di.di_height - 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bh = ip->i_bh;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (x = 0; x < end_of_metadata; x++) {
|
|
Packit Service |
360c39 |
lookup_block(ip, bh, x, &mp, create, new, dblock);
|
|
Packit Service |
360c39 |
if (bh != ip->i_bh)
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
if (!*dblock)
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (*new) {
|
|
Packit Service |
360c39 |
struct gfs2_meta_header mh;
|
|
Packit Service |
360c39 |
bh = bget(sdp, *dblock);
|
|
Packit Service |
360c39 |
mh.mh_magic = GFS2_MAGIC;
|
|
Packit Service |
360c39 |
mh.mh_type = GFS2_METATYPE_IN;
|
|
Packit Service |
360c39 |
mh.mh_format = GFS2_FORMAT_IN;
|
|
Packit Service |
360c39 |
gfs2_meta_header_out(&mh, bh->b_data);
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
if (*dblock == ip->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
bh = ip->i_bh;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
bh = bread(sdp, *dblock);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!prealloc)
|
|
Packit Service |
360c39 |
lookup_block(ip, bh, end_of_metadata, &mp, create, new, dblock);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (extlen && *dblock) {
|
|
Packit Service |
360c39 |
*extlen = 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!*new) {
|
|
Packit Service |
360c39 |
uint64_t tmp_dblock;
|
|
Packit Service |
360c39 |
int tmp_new;
|
|
Packit Service |
360c39 |
unsigned int nptrs;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
nptrs = (end_of_metadata) ? sdp->sd_inptrs : sdp->sd_diptrs;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (++mp.mp_list[end_of_metadata] < nptrs) {
|
|
Packit Service |
360c39 |
lookup_block(ip, bh, end_of_metadata, &mp, FALSE, &tmp_new,
|
|
Packit Service |
360c39 |
&tmp_dblock);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (*dblock + *extlen != tmp_dblock)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
(*extlen)++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (bh != ip->i_bh)
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void
|
|
Packit Service |
360c39 |
copy2mem(struct gfs2_buffer_head *bh, void **buf, unsigned int offset,
|
|
Packit Service |
360c39 |
unsigned int size)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
char **p = (char **)buf;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (bh)
|
|
Packit Service |
360c39 |
memcpy(*p, bh->b_data + offset, size);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
memset(*p, 0, size);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*p += size;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int gfs2_readi(struct gfs2_inode *ip, void *buf,
|
|
Packit Service |
360c39 |
uint64_t offset, unsigned int size)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
uint64_t lblock, dblock;
|
|
Packit Service |
360c39 |
unsigned int o;
|
|
Packit Service |
360c39 |
uint32_t extlen = 0;
|
|
Packit Service |
360c39 |
unsigned int amount;
|
|
Packit Service |
360c39 |
int not_new = 0;
|
|
Packit Service |
360c39 |
int isdir = !!(S_ISDIR(ip->i_di.di_mode));
|
|
Packit Service |
360c39 |
int journaled = ip->i_di.di_flags & GFS2_DIF_JDATA;
|
|
Packit Service |
360c39 |
int copied = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (offset >= ip->i_di.di_size)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if ((offset + size) > ip->i_di.di_size)
|
|
Packit Service |
360c39 |
size = ip->i_di.di_size - offset;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!size)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if ((sdp->gfs1 && journaled) || (!sdp->gfs1 && isdir)) {
|
|
Packit Service |
360c39 |
lblock = offset;
|
|
Packit Service |
360c39 |
o = lblock % sdp->sd_jbsize;
|
|
Packit Service |
360c39 |
lblock /= sdp->sd_jbsize;
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
lblock = offset >> sdp->sd_sb.sb_bsize_shift;
|
|
Packit Service |
360c39 |
o = offset & (sdp->bsize - 1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (inode_is_stuffed(ip))
|
|
Packit Service |
360c39 |
o += sizeof(struct gfs2_dinode);
|
|
Packit Service |
360c39 |
else if ((sdp->gfs1 && journaled) || (!sdp->gfs1 && isdir))
|
|
Packit Service |
360c39 |
o += sizeof(struct gfs2_meta_header);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (copied < size) {
|
|
Packit Service |
360c39 |
amount = size - copied;
|
|
Packit Service |
360c39 |
if (amount > sdp->bsize - o)
|
|
Packit Service |
360c39 |
amount = sdp->bsize - o;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!extlen) {
|
|
Packit Service |
360c39 |
if (sdp->gfs1)
|
|
Packit Service |
360c39 |
gfs1_block_map(ip, lblock, ¬_new, &dblock,
|
|
Packit Service |
360c39 |
&extlen, FALSE);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
block_map(ip, lblock, ¬_new, &dblock,
|
|
Packit Service |
360c39 |
&extlen, FALSE);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (dblock) {
|
|
Packit Service |
360c39 |
if (dblock == ip->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
bh = ip->i_bh;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
bh = bread(sdp, dblock);
|
|
Packit Service |
360c39 |
dblock++;
|
|
Packit Service |
360c39 |
extlen--;
|
|
Packit Service |
360c39 |
} else
|
|
Packit Service |
360c39 |
bh = NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
copy2mem(bh, &buf, o, amount);
|
|
Packit Service |
360c39 |
if (bh && bh != ip->i_bh)
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
copied += amount;
|
|
Packit Service |
360c39 |
lblock++;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (sdp->gfs1)
|
|
Packit Service |
360c39 |
o = (journaled) ? sizeof(struct gfs2_meta_header) : 0;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
o = (isdir) ? sizeof(struct gfs2_meta_header) : 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return copied;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void copy_from_mem(struct gfs2_buffer_head *bh, void **buf,
|
|
Packit Service |
360c39 |
unsigned int offset, unsigned int size)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
char **p = (char **)buf;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
memcpy(bh->b_data + offset, *p, size);
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
*p += size;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int __gfs2_writei(struct gfs2_inode *ip, void *buf,
|
|
Packit Service |
360c39 |
uint64_t offset, unsigned int size, int resize)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
uint64_t lblock, dblock;
|
|
Packit Service |
360c39 |
unsigned int o;
|
|
Packit Service |
360c39 |
uint32_t extlen = 0;
|
|
Packit Service |
360c39 |
unsigned int amount;
|
|
Packit Service |
360c39 |
int new;
|
|
Packit Service |
360c39 |
int isdir = !!(S_ISDIR(ip->i_di.di_mode));
|
|
Packit Service |
360c39 |
const uint64_t start = offset;
|
|
Packit Service |
360c39 |
int copied = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!size)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (inode_is_stuffed(ip) &&
|
|
Packit Service |
360c39 |
((start + size) > (sdp->bsize - sizeof(struct gfs2_dinode))))
|
|
Packit Service |
360c39 |
unstuff_dinode(ip);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (isdir) {
|
|
Packit Service |
360c39 |
lblock = offset;
|
|
Packit Service |
360c39 |
o = lblock % sdp->sd_jbsize;
|
|
Packit Service |
360c39 |
lblock /= sdp->sd_jbsize;
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
lblock = offset >> sdp->sd_sb.sb_bsize_shift;
|
|
Packit Service |
360c39 |
o = offset & (sdp->bsize - 1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (inode_is_stuffed(ip))
|
|
Packit Service |
360c39 |
o += sizeof(struct gfs2_dinode);
|
|
Packit Service |
360c39 |
else if (isdir)
|
|
Packit Service |
360c39 |
o += sizeof(struct gfs2_meta_header);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (copied < size) {
|
|
Packit Service |
360c39 |
amount = size - copied;
|
|
Packit Service |
360c39 |
if (amount > sdp->bsize - o)
|
|
Packit Service |
360c39 |
amount = sdp->bsize - o;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!extlen) {
|
|
Packit Service |
360c39 |
new = TRUE;
|
|
Packit Service |
360c39 |
block_map(ip, lblock, &new, &dblock, &extlen, FALSE);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (new) {
|
|
Packit Service |
360c39 |
bh = bget(sdp, dblock);
|
|
Packit Service |
360c39 |
if (isdir) {
|
|
Packit Service |
360c39 |
struct gfs2_meta_header mh;
|
|
Packit Service |
360c39 |
mh.mh_magic = GFS2_MAGIC;
|
|
Packit Service |
360c39 |
mh.mh_type = GFS2_METATYPE_JD;
|
|
Packit Service |
360c39 |
mh.mh_format = GFS2_FORMAT_JD;
|
|
Packit Service |
360c39 |
gfs2_meta_header_out(&mh, bh->b_data);
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
if (dblock == ip->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
bh = ip->i_bh;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
bh = bread(sdp, dblock);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
copy_from_mem(bh, &buf, o, amount);
|
|
Packit Service |
360c39 |
if (bh != ip->i_bh)
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
copied += amount;
|
|
Packit Service |
360c39 |
lblock++;
|
|
Packit Service |
360c39 |
dblock++;
|
|
Packit Service |
360c39 |
extlen--;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
o = (isdir) ? sizeof(struct gfs2_meta_header) : 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (resize && ip->i_di.di_size < start + copied) {
|
|
Packit Service |
360c39 |
bmodified(ip->i_bh);
|
|
Packit Service |
360c39 |
ip->i_di.di_size = start + copied;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return copied;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *get_file_buf(struct gfs2_inode *ip, uint64_t lbn,
|
|
Packit Service |
360c39 |
int prealloc)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
uint64_t dbn;
|
|
Packit Service |
360c39 |
int new = TRUE;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (inode_is_stuffed(ip))
|
|
Packit Service |
360c39 |
unstuff_dinode(ip);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
block_map(ip, lbn, &new, &dbn, NULL, prealloc);
|
|
Packit Service |
360c39 |
if (!dbn) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "get_file_buf\n");
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!prealloc && new &&
|
|
Packit Service |
360c39 |
ip->i_di.di_size < (lbn + 1) << sdp->sd_sb.sb_bsize_shift) {
|
|
Packit Service |
360c39 |
bmodified(ip->i_bh);
|
|
Packit Service |
360c39 |
ip->i_di.di_size = (lbn + 1) << sdp->sd_sb.sb_bsize_shift;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (dbn == ip->i_di.di_num.no_addr)
|
|
Packit Service |
360c39 |
return ip->i_bh;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
return bread(sdp, dbn);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int gfs2_dirent_first(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
|
|
Packit Service |
360c39 |
struct gfs2_dirent **dent)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_meta_header *h = (struct gfs2_meta_header *)bh->b_data;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (be32_to_cpu(h->mh_type) == GFS2_METATYPE_LF) {
|
|
Packit Service |
360c39 |
*dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_leaf));
|
|
Packit Service |
360c39 |
return IS_LEAF;
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
*dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_dinode));
|
|
Packit Service |
360c39 |
return IS_DINODE;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int gfs2_dirent_next(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
|
|
Packit Service |
360c39 |
struct gfs2_dirent **dent)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
char *bh_end;
|
|
Packit Service |
360c39 |
uint16_t cur_rec_len;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bh_end = bh->b_data + dip->i_sbd->bsize;
|
|
Packit Service |
360c39 |
cur_rec_len = be16_to_cpu((*dent)->de_rec_len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (cur_rec_len == 0 || (char *)(*dent) + cur_rec_len >= bh_end)
|
|
Packit Service |
360c39 |
return -ENOENT;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*dent = (struct gfs2_dirent *)((char *)(*dent) + cur_rec_len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Allocate a gfs2 dirent
|
|
Packit Service |
360c39 |
* Returns 0 on success, with *dent_out pointing to the new dirent,
|
|
Packit Service |
360c39 |
* or -1 on failure, with errno set
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int dirent_alloc(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
|
|
Packit Service |
360c39 |
int name_len, struct gfs2_dirent **dent_out)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_dirent *dent, *new;
|
|
Packit Service |
360c39 |
unsigned int rec_len = GFS2_DIRENT_SIZE(name_len);
|
|
Packit Service |
360c39 |
unsigned int entries = 0, offset = 0;
|
|
Packit Service |
360c39 |
int type;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
type = gfs2_dirent_first(dip, bh, &dent);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (type == IS_LEAF) {
|
|
Packit Service |
360c39 |
struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data;
|
|
Packit Service |
360c39 |
entries = be16_to_cpu(leaf->lf_entries);
|
|
Packit Service |
360c39 |
offset = sizeof(struct gfs2_leaf);
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
struct gfs2_dinode *dinode = (struct gfs2_dinode *)bh->b_data;
|
|
Packit Service |
360c39 |
entries = be32_to_cpu(dinode->di_entries);
|
|
Packit Service |
360c39 |
offset = sizeof(struct gfs2_dinode);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!entries) {
|
|
Packit Service |
360c39 |
dent->de_rec_len = cpu_to_be16(dip->i_sbd->bsize - offset);
|
|
Packit Service |
360c39 |
dent->de_name_len = cpu_to_be16(name_len);
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
*dent_out = dent;
|
|
Packit Service |
360c39 |
dip->i_di.di_entries++;
|
|
Packit Service |
360c39 |
bmodified(dip->i_bh);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
do {
|
|
Packit Service |
360c39 |
uint16_t cur_rec_len;
|
|
Packit Service |
360c39 |
uint16_t cur_name_len;
|
|
Packit Service |
360c39 |
uint16_t new_rec_len;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
cur_rec_len = be16_to_cpu(dent->de_rec_len);
|
|
Packit Service |
360c39 |
cur_name_len = be16_to_cpu(dent->de_name_len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if ((!dent->de_inum.no_formal_ino && cur_rec_len >= rec_len) ||
|
|
Packit Service |
360c39 |
(cur_rec_len >= GFS2_DIRENT_SIZE(cur_name_len) + rec_len)) {
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (dent->de_inum.no_formal_ino) {
|
|
Packit Service |
360c39 |
new = (struct gfs2_dirent *)((char *)dent +
|
|
Packit Service |
360c39 |
GFS2_DIRENT_SIZE(cur_name_len));
|
|
Packit Service |
360c39 |
memset(new, 0, sizeof(struct gfs2_dirent));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
new->de_rec_len = cpu_to_be16(cur_rec_len -
|
|
Packit Service |
360c39 |
GFS2_DIRENT_SIZE(cur_name_len));
|
|
Packit Service |
360c39 |
new->de_name_len = cpu_to_be16(name_len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
new_rec_len = be16_to_cpu(new->de_rec_len);
|
|
Packit Service |
360c39 |
dent->de_rec_len = cpu_to_be16(cur_rec_len - new_rec_len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*dent_out = new;
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
dip->i_di.di_entries++;
|
|
Packit Service |
360c39 |
bmodified(dip->i_bh);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
dent->de_name_len = cpu_to_be16(name_len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*dent_out = dent;
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
dip->i_di.di_entries++;
|
|
Packit Service |
360c39 |
bmodified(dip->i_bh);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
} while (gfs2_dirent_next(dip, bh, &dent) == 0);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
errno = ENOSPC;
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void dirent2_del(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
|
|
Packit Service |
360c39 |
struct gfs2_dirent *prev, struct gfs2_dirent *cur)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint16_t cur_rec_len, prev_rec_len;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
if (gfs2_check_meta(bh, GFS2_METATYPE_LF) == 0) {
|
|
Packit Service |
360c39 |
struct gfs2_leaf *lf = (struct gfs2_leaf *)bh->b_data;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
lf->lf_entries = be16_to_cpu(lf->lf_entries) - 1;
|
|
Packit Service |
360c39 |
lf->lf_entries = cpu_to_be16(lf->lf_entries);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (dip->i_di.di_entries) {
|
|
Packit Service |
360c39 |
bmodified(dip->i_bh);
|
|
Packit Service |
360c39 |
dip->i_di.di_entries--;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (!prev) {
|
|
Packit Service |
360c39 |
cur->de_inum.no_addr = 0;
|
|
Packit Service |
360c39 |
cur->de_inum.no_formal_ino = 0;
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
prev_rec_len = be16_to_cpu(prev->de_rec_len);
|
|
Packit Service |
360c39 |
cur_rec_len = be16_to_cpu(cur->de_rec_len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
prev_rec_len += cur_rec_len;
|
|
Packit Service |
360c39 |
prev->de_rec_len = cpu_to_be16(prev_rec_len);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int lgfs2_get_leaf_ptr(struct gfs2_inode *dip, const uint32_t lindex, uint64_t *ptr)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t leaf_no;
|
|
Packit Service |
360c39 |
int count = gfs2_readi(dip, (char *)&leaf_no, lindex * sizeof(uint64_t), sizeof(uint64_t));
|
|
Packit Service |
360c39 |
if (count != sizeof(uint64_t))
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*ptr = be64_to_cpu(leaf_no);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void dir_split_leaf(struct gfs2_inode *dip, uint32_t start, uint64_t leaf_no,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *obh)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *nbh;
|
|
Packit Service |
360c39 |
struct gfs2_leaf *nleaf, *oleaf;
|
|
Packit Service |
360c39 |
struct gfs2_dirent *dent, *prev = NULL, *next = NULL, *new;
|
|
Packit Service |
360c39 |
uint32_t len, half_len, divider;
|
|
Packit Service |
360c39 |
uint64_t bn, *lp;
|
|
Packit Service |
360c39 |
uint32_t name_len;
|
|
Packit Service |
360c39 |
int x, moved = FALSE;
|
|
Packit Service |
360c39 |
int count;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (lgfs2_meta_alloc(dip, &bn))
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
nbh = bget(dip->i_sbd, bn);
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_meta_header mh;
|
|
Packit Service |
360c39 |
mh.mh_magic = GFS2_MAGIC;
|
|
Packit Service |
360c39 |
mh.mh_type = GFS2_METATYPE_LF;
|
|
Packit Service |
360c39 |
mh.mh_format = GFS2_FORMAT_LF;
|
|
Packit Service |
360c39 |
gfs2_meta_header_out(&mh, nbh->b_data);
|
|
Packit Service |
360c39 |
bmodified(nbh);
|
|
Packit Service |
360c39 |
buffer_clear_tail(dip->i_sbd, nbh,
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_meta_header));
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
nleaf = (struct gfs2_leaf *)nbh->b_data;
|
|
Packit Service |
360c39 |
nleaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
oleaf = (struct gfs2_leaf *)obh->b_data;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth));
|
|
Packit Service |
360c39 |
half_len = len >> 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
lp = calloc(1, half_len * sizeof(uint64_t));
|
|
Packit Service |
360c39 |
if (lp == NULL) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "Out of memory in %s\n", __FUNCTION__);
|
|
Packit Service |
360c39 |
exit(-1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
for (x = 0; x < half_len; x++)
|
|
Packit Service |
360c39 |
lp[x] = cpu_to_be64(bn);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (dip->i_sbd->gfs1)
|
|
Packit Service |
360c39 |
count = gfs1_writei(dip, (char *)lp, start * sizeof(uint64_t),
|
|
Packit Service |
360c39 |
half_len * sizeof(uint64_t));
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
count = gfs2_writei(dip, (char *)lp, start * sizeof(uint64_t),
|
|
Packit Service |
360c39 |
half_len * sizeof(uint64_t));
|
|
Packit Service |
360c39 |
if (count != half_len * sizeof(uint64_t)) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "dir_split_leaf (2)\n");
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
free(lp);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
divider = (start + half_len) << (32 - dip->i_di.di_depth);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_dirent_first(dip, obh, &dent);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
do {
|
|
Packit Service |
360c39 |
next = dent;
|
|
Packit Service |
360c39 |
if (gfs2_dirent_next(dip, obh, &next))
|
|
Packit Service |
360c39 |
next = NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (dent->de_inum.no_formal_ino &&
|
|
Packit Service |
360c39 |
be32_to_cpu(dent->de_hash) < divider) {
|
|
Packit Service |
360c39 |
name_len = be16_to_cpu(dent->de_name_len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (dirent_alloc(dip, nbh, name_len, &new)) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "dir_split_leaf (3)\n");
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
new->de_inum = dent->de_inum;
|
|
Packit Service |
360c39 |
new->de_hash = dent->de_hash;
|
|
Packit Service |
360c39 |
new->de_type = dent->de_type;
|
|
Packit Service |
360c39 |
memcpy((char *)(new + 1), (char *)(dent + 1), name_len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
nleaf->lf_entries = be16_to_cpu(nleaf->lf_entries) + 1;
|
|
Packit Service |
360c39 |
nleaf->lf_entries = cpu_to_be16(nleaf->lf_entries);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
dirent2_del(dip, obh, prev, dent);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!prev)
|
|
Packit Service |
360c39 |
prev = dent;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
moved = TRUE;
|
|
Packit Service |
360c39 |
} else
|
|
Packit Service |
360c39 |
prev = dent;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
dent = next;
|
|
Packit Service |
360c39 |
} while (dent);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!moved) {
|
|
Packit Service |
360c39 |
if (dirent_alloc(dip, nbh, 0, &new)) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "dir_split_leaf (4)\n");
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
new->de_inum.no_formal_ino = 0;
|
|
Packit Service |
360c39 |
/* Don't count the sentinel dirent as an entry */
|
|
Packit Service |
360c39 |
dip->i_di.di_entries--;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
oleaf->lf_depth = be16_to_cpu(oleaf->lf_depth) + 1;
|
|
Packit Service |
360c39 |
oleaf->lf_depth = cpu_to_be16(oleaf->lf_depth);
|
|
Packit Service |
360c39 |
nleaf->lf_depth = oleaf->lf_depth;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#ifdef GFS2_HAS_LEAF_HINTS
|
|
Packit Service |
360c39 |
nleaf->lf_inode = cpu_to_be64(dip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
#endif
|
|
Packit Service |
360c39 |
dip->i_di.di_blocks++;
|
|
Packit Service |
360c39 |
bmodified(dip->i_bh);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bmodified(obh); /* Need to do this in case nothing was moved */
|
|
Packit Service |
360c39 |
bmodified(nbh);
|
|
Packit Service |
360c39 |
brelse(nbh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void dir_double_exhash(struct gfs2_inode *dip)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = dip->i_sbd;
|
|
Packit Service |
360c39 |
uint64_t *buf;
|
|
Packit Service |
360c39 |
uint64_t *from, *to;
|
|
Packit Service |
360c39 |
uint64_t block;
|
|
Packit Service |
360c39 |
int x;
|
|
Packit Service |
360c39 |
int count;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
buf = calloc(1, 3 * sdp->sd_hash_bsize);
|
|
Packit Service |
360c39 |
if (buf == NULL) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "Out of memory in %s\n", __FUNCTION__);
|
|
Packit Service |
360c39 |
exit(-1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) {
|
|
Packit Service |
360c39 |
count = gfs2_readi(dip, (char *)buf,
|
|
Packit Service |
360c39 |
block * sdp->sd_hash_bsize,
|
|
Packit Service |
360c39 |
sdp->sd_hash_bsize);
|
|
Packit Service |
360c39 |
if (count != sdp->sd_hash_bsize) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "dir_double_exhash (1)\n");
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
from = buf;
|
|
Packit Service |
360c39 |
to = (uint64_t *)((char *)buf + sdp->sd_hash_bsize);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (x = sdp->sd_hash_ptrs; x--; from++) {
|
|
Packit Service |
360c39 |
*to++ = *from;
|
|
Packit Service |
360c39 |
*to++ = *from;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (sdp->gfs1)
|
|
Packit Service |
360c39 |
count = gfs1_writei(dip, (char *)buf +
|
|
Packit Service |
360c39 |
sdp->sd_hash_bsize,
|
|
Packit Service |
360c39 |
block * sdp->bsize, sdp->bsize);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
count = gfs2_writei(dip, (char *)buf +
|
|
Packit Service |
360c39 |
sdp->sd_hash_bsize,
|
|
Packit Service |
360c39 |
block * sdp->bsize, sdp->bsize);
|
|
Packit Service |
360c39 |
if (count != sdp->bsize) {
|
|
Packit Service |
360c39 |
fprintf(stderr, "dir_double_exhash (2)\n");
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
free(buf);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
dip->i_di.di_depth++;
|
|
Packit Service |
360c39 |
bmodified(dip->i_bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* get_leaf - Get leaf
|
|
Packit Service |
360c39 |
* @dip:
|
|
Packit Service |
360c39 |
* @leaf_no:
|
|
Packit Service |
360c39 |
* @bh_out:
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 on success, error code otherwise
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int gfs2_get_leaf(struct gfs2_inode *dip, uint64_t leaf_no,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bhp)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int error = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*bhp = bread(dip->i_sbd, leaf_no);
|
|
Packit Service |
360c39 |
error = gfs2_check_meta(*bhp, GFS2_METATYPE_LF);
|
|
Packit Service |
360c39 |
if(error)
|
|
Packit Service |
360c39 |
brelse(*bhp);
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* get_first_leaf - Get first leaf
|
|
Packit Service |
360c39 |
* @dip: The GFS2 inode
|
|
Packit Service |
360c39 |
* @index:
|
|
Packit Service |
360c39 |
* @bh_out:
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 on success, error code otherwise
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int get_first_leaf(struct gfs2_inode *dip, uint32_t lindex, struct gfs2_buffer_head **bh_out)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t leaf_no;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (lgfs2_get_leaf_ptr(dip, lindex, &leaf_no) != 0)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
*bh_out = bread(dip->i_sbd, leaf_no);
|
|
Packit Service |
360c39 |
if (*bh_out == NULL)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* get_next_leaf - Get next leaf
|
|
Packit Service |
360c39 |
* @dip: The GFS2 inode
|
|
Packit Service |
360c39 |
* @bh_in: The buffer
|
|
Packit Service |
360c39 |
* @bh_out:
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 on success, error code otherwise
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int get_next_leaf(struct gfs2_inode *dip,struct gfs2_buffer_head *bh_in,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh_out)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_leaf *leaf;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
leaf = (struct gfs2_leaf *)bh_in->b_data;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!leaf->lf_next)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
/* Check for a leaf that points to itself as "next" */
|
|
Packit Service |
360c39 |
if (be64_to_cpu(leaf->lf_next) == bh_in->b_blocknr)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
*bh_out = bread(dip->i_sbd, be64_to_cpu(leaf->lf_next));
|
|
Packit Service |
360c39 |
if (*bh_out == NULL)
|
|
Packit Service |
360c39 |
return -ENOENT;
|
|
Packit Service |
360c39 |
/* Check for a leaf pointing to a non-leaf */
|
|
Packit Service |
360c39 |
if (gfs2_check_meta(*bh_out, GFS2_METATYPE_LF)) {
|
|
Packit Service |
360c39 |
brelse(*bh_out);
|
|
Packit Service |
360c39 |
*bh_out = NULL;
|
|
Packit Service |
360c39 |
return -ENOENT;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int dir_e_add(struct gfs2_inode *dip, const char *filename, int len,
|
|
Packit Service |
360c39 |
struct gfs2_inum *inum, unsigned int type)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh, *nbh;
|
|
Packit Service |
360c39 |
struct gfs2_leaf *leaf, *nleaf;
|
|
Packit Service |
360c39 |
struct gfs2_dirent *dent;
|
|
Packit Service |
360c39 |
uint32_t lindex, llen;
|
|
Packit Service |
360c39 |
uint32_t hash;
|
|
Packit Service |
360c39 |
uint64_t leaf_no, bn;
|
|
Packit Service |
360c39 |
int err = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
hash = gfs2_disk_hash(filename, len);
|
|
Packit Service |
360c39 |
restart:
|
|
Packit Service |
360c39 |
/* Have to kludge because (hash >> 32) gives hash for some reason. */
|
|
Packit Service |
360c39 |
if (dip->i_di.di_depth)
|
|
Packit Service |
360c39 |
lindex = hash >> (32 - dip->i_di.di_depth);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
lindex = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
err = lgfs2_get_leaf_ptr(dip, lindex, &leaf_no);
|
|
Packit Service |
360c39 |
if (err)
|
|
Packit Service |
360c39 |
return err;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (;;) {
|
|
Packit Service |
360c39 |
bh = bread(dip->i_sbd, leaf_no);
|
|
Packit Service |
360c39 |
leaf = (struct gfs2_leaf *)bh->b_data;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (dirent_alloc(dip, bh, len, &dent)) {
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (be16_to_cpu(leaf->lf_depth) < dip->i_di.di_depth) {
|
|
Packit Service |
360c39 |
llen = 1 << (dip->i_di.di_depth -
|
|
Packit Service |
360c39 |
be16_to_cpu(leaf->lf_depth));
|
|
Packit Service |
360c39 |
dir_split_leaf(dip, lindex & ~(llen - 1),
|
|
Packit Service |
360c39 |
leaf_no, bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
goto restart;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
} else if (dip->i_di.di_depth < GFS2_DIR_MAX_DEPTH) {
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
dir_double_exhash(dip);
|
|
Packit Service |
360c39 |
goto restart;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
} else if (leaf->lf_next) {
|
|
Packit Service |
360c39 |
leaf_no = be64_to_cpu(leaf->lf_next);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
struct gfs2_meta_header mh;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (lgfs2_meta_alloc(dip, &bn))
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
nbh = bget(dip->i_sbd, bn);
|
|
Packit Service |
360c39 |
mh.mh_magic = GFS2_MAGIC;
|
|
Packit Service |
360c39 |
mh.mh_type = GFS2_METATYPE_LF;
|
|
Packit Service |
360c39 |
mh.mh_format = GFS2_FORMAT_LF;
|
|
Packit Service |
360c39 |
gfs2_meta_header_out(&mh, nbh->b_data);
|
|
Packit Service |
360c39 |
bmodified(nbh);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
leaf->lf_next = cpu_to_be64(bn);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
nleaf = (struct gfs2_leaf *)nbh->b_data;
|
|
Packit Service |
360c39 |
nleaf->lf_depth = leaf->lf_depth;
|
|
Packit Service |
360c39 |
nleaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);
|
|
Packit Service |
360c39 |
#ifdef GFS2_HAS_LEAF_HINTS
|
|
Packit Service |
360c39 |
nleaf->lf_inode = cpu_to_be64(dip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
#endif
|
|
Packit Service |
360c39 |
err = dirent_alloc(dip, nbh, len, &dent);
|
|
Packit Service |
360c39 |
if (err)
|
|
Packit Service |
360c39 |
return err;
|
|
Packit Service |
360c39 |
dip->i_di.di_blocks++;
|
|
Packit Service |
360c39 |
bmodified(dip->i_bh);
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
bh = nbh;
|
|
Packit Service |
360c39 |
leaf = nleaf;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_inum_out(inum, (char *)&dent->de_inum);
|
|
Packit Service |
360c39 |
dent->de_hash = cpu_to_be32(hash);
|
|
Packit Service |
360c39 |
dent->de_type = cpu_to_be16(type);
|
|
Packit Service |
360c39 |
memcpy((char *)(dent + 1), filename, len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
leaf->lf_entries = be16_to_cpu(leaf->lf_entries) + 1;
|
|
Packit Service |
360c39 |
leaf->lf_entries = cpu_to_be16(leaf->lf_entries);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
return err;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void dir_make_exhash(struct gfs2_inode *dip)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = dip->i_sbd;
|
|
Packit Service |
360c39 |
struct gfs2_dirent *dent;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
struct gfs2_leaf *leaf;
|
|
Packit Service |
360c39 |
int y;
|
|
Packit Service |
360c39 |
uint32_t x;
|
|
Packit Service |
360c39 |
uint64_t *lp, bn;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (lgfs2_meta_alloc(dip, &bn))
|
|
Packit Service |
360c39 |
exit(1);
|
|
Packit Service |
360c39 |
bh = bget(sdp, bn);
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_meta_header mh;
|
|
Packit Service |
360c39 |
mh.mh_magic = GFS2_MAGIC;
|
|
Packit Service |
360c39 |
mh.mh_type = GFS2_METATYPE_LF;
|
|
Packit Service |
360c39 |
mh.mh_format = GFS2_FORMAT_LF;
|
|
Packit Service |
360c39 |
gfs2_meta_header_out(&mh, bh->b_data);
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
leaf = (struct gfs2_leaf *)bh->b_data;
|
|
Packit Service |
360c39 |
leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);
|
|
Packit Service |
360c39 |
leaf->lf_entries = cpu_to_be16(dip->i_di.di_entries);
|
|
Packit Service |
360c39 |
#ifdef GFS2_HAS_LEAF_HINTS
|
|
Packit Service |
360c39 |
leaf->lf_inode = cpu_to_be64(dip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
#endif
|
|
Packit Service |
360c39 |
buffer_copy_tail(sdp, bh, sizeof(struct gfs2_leaf),
|
|
Packit Service |
360c39 |
dip->i_bh, sizeof(struct gfs2_dinode));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
x = 0;
|
|
Packit Service |
360c39 |
gfs2_dirent_first(dip, bh, &dent);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
do {
|
|
Packit Service |
360c39 |
if (!dent->de_inum.no_formal_ino)
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
if (++x == dip->i_di.di_entries)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
} while (gfs2_dirent_next(dip, bh, &dent) == 0);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
dent->de_rec_len = be16_to_cpu(dent->de_rec_len);
|
|
Packit Service |
360c39 |
dent->de_rec_len = cpu_to_be16(dent->de_rec_len +
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_dinode) - sizeof(struct gfs2_leaf));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* no need to: bmodified(bh); (buffer_copy_tail does it) */
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
buffer_clear_tail(sdp, dip->i_bh, sizeof(struct gfs2_dinode));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
lp = (uint64_t *)(dip->i_bh->b_data + sizeof(struct gfs2_dinode));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (x = sdp->sd_hash_ptrs; x--; lp++)
|
|
Packit Service |
360c39 |
*lp = cpu_to_be64(bn);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
dip->i_di.di_size = sdp->bsize / 2;
|
|
Packit Service |
360c39 |
dip->i_di.di_blocks++;
|
|
Packit Service |
360c39 |
dip->i_di.di_flags |= GFS2_DIF_EXHASH;
|
|
Packit Service |
360c39 |
dip->i_di.di_payload_format = 0;
|
|
Packit Service |
360c39 |
/* no need: bmodified(dip->i_bh); buffer_clear_tail does it. */
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ;
|
|
Packit Service |
360c39 |
dip->i_di.di_depth = y;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_dinode_out(&dip->i_di, dip->i_bh->b_data);
|
|
Packit Service |
360c39 |
bwrite(dip->i_bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int dir_l_add(struct gfs2_inode *dip, const char *filename, int len,
|
|
Packit Service |
360c39 |
struct gfs2_inum *inum, unsigned int type)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_dirent *dent;
|
|
Packit Service |
360c39 |
int err = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (dirent_alloc(dip, dip->i_bh, len, &dent)) {
|
|
Packit Service |
360c39 |
dir_make_exhash(dip);
|
|
Packit Service |
360c39 |
err = dir_e_add(dip, filename, len, inum, type);
|
|
Packit Service |
360c39 |
return err;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_inum_out(inum, (char *)&dent->de_inum);
|
|
Packit Service |
360c39 |
dent->de_hash = gfs2_disk_hash(filename, len);
|
|
Packit Service |
360c39 |
dent->de_hash = cpu_to_be32(dent->de_hash);
|
|
Packit Service |
360c39 |
dent->de_type = cpu_to_be16(type);
|
|
Packit Service |
360c39 |
memcpy((char *)(dent + 1), filename, len);
|
|
Packit Service |
360c39 |
bmodified(dip->i_bh);
|
|
Packit Service |
360c39 |
return err;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int dir_add(struct gfs2_inode *dip, const char *filename, int len,
|
|
Packit Service |
360c39 |
struct gfs2_inum *inum, unsigned int type)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int err = 0;
|
|
Packit Service |
360c39 |
if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
|
|
Packit Service |
360c39 |
err = dir_e_add(dip, filename, len, inum, type);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
err = dir_l_add(dip, filename, len, inum, type);
|
|
Packit Service |
360c39 |
return err;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int __init_dinode(struct gfs2_sbd *sdp, struct gfs2_buffer_head **bhp, struct gfs2_inum *inum,
|
|
Packit Service |
360c39 |
unsigned int mode, uint32_t flags, struct gfs2_inum *parent, int gfs1)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh;
|
|
Packit Service |
360c39 |
struct gfs2_dinode di = {{0}};
|
|
Packit Service |
360c39 |
int is_dir;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (gfs1)
|
|
Packit Service |
360c39 |
is_dir = (IF2DT(mode) == GFS_FILE_DIR);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
is_dir = S_ISDIR(mode);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
errno = EINVAL;
|
|
Packit Service |
360c39 |
if (bhp == NULL)
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (*bhp == NULL) {
|
|
Packit Service |
360c39 |
*bhp = bget(sdp, inum->no_addr);
|
|
Packit Service |
360c39 |
if (*bhp == NULL)
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bh = *bhp;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
di.di_header.mh_magic = GFS2_MAGIC;
|
|
Packit Service |
360c39 |
di.di_header.mh_type = GFS2_METATYPE_DI;
|
|
Packit Service |
360c39 |
di.di_header.mh_format = GFS2_FORMAT_DI;
|
|
Packit Service |
360c39 |
di.di_num = *inum;
|
|
Packit Service |
360c39 |
di.di_mode = mode;
|
|
Packit Service |
360c39 |
di.di_nlink = 1;
|
|
Packit Service |
360c39 |
di.di_blocks = 1;
|
|
Packit Service |
360c39 |
di.di_atime = di.di_mtime = di.di_ctime = sdp->time;
|
|
Packit Service |
360c39 |
di.di_goal_meta = di.di_goal_data = bh->b_blocknr;
|
|
Packit Service |
360c39 |
di.di_flags = flags;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (is_dir) {
|
|
Packit Service |
360c39 |
struct gfs2_dirent de1, de2;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
memset(&de1, 0, sizeof(struct gfs2_dirent));
|
|
Packit Service |
360c39 |
de1.de_inum = di.di_num;
|
|
Packit Service |
360c39 |
de1.de_hash = gfs2_disk_hash(".", 1);
|
|
Packit Service |
360c39 |
de1.de_rec_len = GFS2_DIRENT_SIZE(1);
|
|
Packit Service |
360c39 |
de1.de_name_len = 1;
|
|
Packit Service |
360c39 |
de1.de_type = (gfs1 ? GFS_FILE_DIR : IF2DT(S_IFDIR));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
memset(&de2, 0, sizeof(struct gfs2_dirent));
|
|
Packit Service |
360c39 |
de2.de_inum = *parent;
|
|
Packit Service |
360c39 |
de2.de_hash = gfs2_disk_hash("..", 2);
|
|
Packit Service |
360c39 |
de2.de_rec_len = sdp->bsize - sizeof(struct gfs2_dinode) - de1.de_rec_len;
|
|
Packit Service |
360c39 |
de2.de_name_len = 2;
|
|
Packit Service |
360c39 |
de2.de_type = (gfs1 ? GFS_FILE_DIR : IF2DT(S_IFDIR));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_dirent_out(&de1, bh->b_data + sizeof(struct gfs2_dinode));
|
|
Packit Service |
360c39 |
memcpy(bh->b_data +
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_dinode) +
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_dirent),
|
|
Packit Service |
360c39 |
".", 1);
|
|
Packit Service |
360c39 |
gfs2_dirent_out(&de2, bh->b_data + sizeof(struct gfs2_dinode) + de1.de_rec_len);
|
|
Packit Service |
360c39 |
memcpy(bh->b_data +
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_dinode) +
|
|
Packit Service |
360c39 |
de1.de_rec_len +
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_dirent),
|
|
Packit Service |
360c39 |
"..", 2);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
di.di_nlink = 2;
|
|
Packit Service |
360c39 |
di.di_size = sdp->bsize - sizeof(struct gfs2_dinode);
|
|
Packit Service |
360c39 |
di.di_flags |= GFS2_DIF_JDATA;
|
|
Packit Service |
360c39 |
di.di_payload_format = GFS2_FORMAT_DE;
|
|
Packit Service |
360c39 |
di.di_entries = 2;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
gfs2_dinode_out(&di, bh->b_data);
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int init_dinode(struct gfs2_sbd *sdp, struct gfs2_buffer_head **bhp, struct gfs2_inum *inum,
|
|
Packit Service |
360c39 |
unsigned int mode, uint32_t flags, struct gfs2_inum *parent)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return __init_dinode(sdp, bhp, inum, mode, flags, parent, 0);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void lgfs2_fill_indir(char *start, char *end, uint64_t ptr0, unsigned n, unsigned *p)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
char *bp;
|
|
Packit Service |
360c39 |
memset(start, 0, end - start);
|
|
Packit Service |
360c39 |
for (bp = start; bp < end && *p < n; bp += sizeof(uint64_t)) {
|
|
Packit Service |
360c39 |
uint64_t pn = ptr0 + *p;
|
|
Packit Service |
360c39 |
*(uint64_t *)bp = cpu_to_be64(pn);
|
|
Packit Service |
360c39 |
(*p)++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Calculate and write the indirect blocks for a single-extent file of a given
|
|
Packit Service |
360c39 |
* size.
|
|
Packit Service |
360c39 |
* ip: The inode for which to write indirect blocks, with fields already set
|
|
Packit Service |
360c39 |
* appropriately (see lgfs2_file_alloc).
|
|
Packit Service |
360c39 |
* Returns 0 on success or non-zero with errno set on failure.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int lgfs2_write_filemeta(struct gfs2_inode *ip)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
unsigned height = 0;
|
|
Packit Service |
360c39 |
struct metapath mp;
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
uint64_t dblocks = (ip->i_di.di_size + sdp->bsize - 1) / sdp->bsize;
|
|
Packit Service |
360c39 |
uint64_t ptr0 = ip->i_di.di_num.no_addr + 1;
|
|
Packit Service |
360c39 |
unsigned ptrs = 1;
|
|
Packit Service |
360c39 |
struct gfs2_meta_header mh = {
|
|
Packit Service |
360c39 |
.mh_magic = GFS2_MAGIC,
|
|
Packit Service |
360c39 |
.mh_type = GFS2_METATYPE_IN,
|
|
Packit Service |
360c39 |
.mh_format = GFS2_FORMAT_IN,
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh = bget(sdp, ip->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if (bh == NULL)
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Using find_metapath() to find the last data block in the file will
|
|
Packit Service |
360c39 |
effectively give a remainder for the number of pointers at each
|
|
Packit Service |
360c39 |
height. Just need to add 1 to convert ptr index to quantity later. */
|
|
Packit Service |
360c39 |
find_metapath(ip, dblocks - 1, &mp);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (height = 0; height < ip->i_di.di_height; height++) {
|
|
Packit Service |
360c39 |
unsigned p;
|
|
Packit Service |
360c39 |
/* The number of pointers in this height will be the number of
|
|
Packit Service |
360c39 |
full indirect blocks pointed to by the previous height
|
|
Packit Service |
360c39 |
multiplied by the pointer capacity of an indirect block,
|
|
Packit Service |
360c39 |
plus the remainder which find_metapath() gave us. */
|
|
Packit Service |
360c39 |
ptrs = ((ptrs - 1) * sdp->sd_inptrs) + mp.mp_list[height] + 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (p = 0; p < ptrs; bh->b_blocknr++) {
|
|
Packit Service |
360c39 |
char *start = bh->b_data;
|
|
Packit Service |
360c39 |
if (height == 0) {
|
|
Packit Service |
360c39 |
start += sizeof(struct gfs2_dinode);
|
|
Packit Service |
360c39 |
gfs2_dinode_out(&ip->i_di, bh->b_data);
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
start += sizeof(struct gfs2_meta_header);
|
|
Packit Service |
360c39 |
gfs2_meta_header_out(&mh, bh->b_data);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
lgfs2_fill_indir(start, bh->b_data + sdp->bsize, ptr0, ptrs, &p);
|
|
Packit Service |
360c39 |
if (bwrite(bh)) {
|
|
Packit Service |
360c39 |
free(bh);
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
ptr0 += ptrs;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
free(bh);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static struct gfs2_inode *__createi(struct gfs2_inode *dip,
|
|
Packit Service |
360c39 |
const char *filename, unsigned int mode,
|
|
Packit Service |
360c39 |
uint32_t flags, int if_gfs1)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = dip->i_sbd;
|
|
Packit Service |
360c39 |
uint64_t bn;
|
|
Packit Service |
360c39 |
struct gfs2_inum inum;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh = NULL;
|
|
Packit Service |
360c39 |
struct gfs2_inode *ip;
|
|
Packit Service |
360c39 |
int err = 0;
|
|
Packit Service |
360c39 |
int is_dir;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_lookupi(dip, filename, strlen(filename), &ip);
|
|
Packit Service |
360c39 |
if (!ip) {
|
|
Packit Service |
360c39 |
err = lgfs2_dinode_alloc(sdp, 1, &bn);
|
|
Packit Service |
360c39 |
if (err != 0)
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (if_gfs1)
|
|
Packit Service |
360c39 |
inum.no_formal_ino = bn;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
inum.no_formal_ino = sdp->md.next_inum++;
|
|
Packit Service |
360c39 |
inum.no_addr = bn;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
err = dir_add(dip, filename, strlen(filename), &inum, IF2DT(mode));
|
|
Packit Service |
360c39 |
if (err)
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (if_gfs1)
|
|
Packit Service |
360c39 |
is_dir = (IF2DT(mode) == GFS_FILE_DIR);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
is_dir = S_ISDIR(mode);
|
|
Packit Service |
360c39 |
if (is_dir) {
|
|
Packit Service |
360c39 |
bmodified(dip->i_bh);
|
|
Packit Service |
360c39 |
dip->i_di.di_nlink++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
err = __init_dinode(sdp, &bh, &inum, mode, flags, &dip->i_di.di_num, if_gfs1);
|
|
Packit Service |
360c39 |
if (err != 0)
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ip = lgfs2_inode_get(sdp, bh);
|
|
Packit Service |
360c39 |
if (ip == NULL)
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
bmodified(bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
ip->bh_owned = 1;
|
|
Packit Service |
360c39 |
return ip;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct gfs2_inode *createi(struct gfs2_inode *dip, const char *filename,
|
|
Packit Service |
360c39 |
unsigned int mode, uint32_t flags)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return __createi(dip, filename, mode, flags, 0);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct gfs2_inode *gfs_createi(struct gfs2_inode *dip, const char *filename,
|
|
Packit Service |
360c39 |
unsigned int mode, uint32_t flags)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return __createi(dip, filename, mode, flags, 1);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* gfs2_filecmp - Compare two filenames
|
|
Packit Service |
360c39 |
* @file1: The first filename
|
|
Packit Service |
360c39 |
* @file2: The second filename
|
|
Packit Service |
360c39 |
* @len_of_file2: The length of the second file
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* This routine compares two filenames and returns 1 if they are equal.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 1 if the files are the same, otherwise 0.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int gfs2_filecmp(const char *file1, const char *file2, int len_of_file2)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if (strlen(file1) != len_of_file2)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
if (memcmp(file1, file2, len_of_file2))
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* leaf_search
|
|
Packit Service |
360c39 |
* @bh:
|
|
Packit Service |
360c39 |
* @id:
|
|
Packit Service |
360c39 |
* @dent_out:
|
|
Packit Service |
360c39 |
* @dent_prev:
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns:
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int leaf_search(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
|
|
Packit Service |
360c39 |
const char *filename, int len,
|
|
Packit Service |
360c39 |
struct gfs2_dirent **dent_out,
|
|
Packit Service |
360c39 |
struct gfs2_dirent **dent_prev)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint32_t hash;
|
|
Packit Service |
360c39 |
struct gfs2_dirent *dent, *prev = NULL;
|
|
Packit Service |
360c39 |
unsigned int entries = 0, x = 0;
|
|
Packit Service |
360c39 |
int type;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
type = gfs2_dirent_first(dip, bh, &dent);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (type == IS_LEAF){
|
|
Packit Service |
360c39 |
struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data;
|
|
Packit Service |
360c39 |
entries = be16_to_cpu(leaf->lf_entries);
|
|
Packit Service |
360c39 |
} else if (type == IS_DINODE)
|
|
Packit Service |
360c39 |
entries = dip->i_di.di_entries;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
hash = gfs2_disk_hash(filename, len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
do{
|
|
Packit Service |
360c39 |
if (!dent->de_inum.no_formal_ino){
|
|
Packit Service |
360c39 |
prev = dent;
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (be32_to_cpu(dent->de_hash) == hash &&
|
|
Packit Service |
360c39 |
gfs2_filecmp(filename, (char *)(dent + 1),
|
|
Packit Service |
360c39 |
be16_to_cpu(dent->de_name_len))) {
|
|
Packit Service |
360c39 |
*dent_out = dent;
|
|
Packit Service |
360c39 |
if (dent_prev)
|
|
Packit Service |
360c39 |
*dent_prev = prev;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if(x >= entries)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
x++;
|
|
Packit Service |
360c39 |
prev = dent;
|
|
Packit Service |
360c39 |
} while (gfs2_dirent_next(dip, bh, &dent) == 0);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return -ENOENT;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* linked_leaf_search - Linked leaf search
|
|
Packit Service |
360c39 |
* @dip: The GFS2 inode
|
|
Packit Service |
360c39 |
* @id:
|
|
Packit Service |
360c39 |
* @dent_out:
|
|
Packit Service |
360c39 |
* @dent_prev:
|
|
Packit Service |
360c39 |
* @bh_out:
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 on sucess, error code otherwise
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int linked_leaf_search(struct gfs2_inode *dip, const char *filename,
|
|
Packit Service |
360c39 |
int len, struct gfs2_dirent **dent_out,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh_out)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh = NULL, *bh_next;
|
|
Packit Service |
360c39 |
uint32_t hsize, lindex;
|
|
Packit Service |
360c39 |
uint32_t hash;
|
|
Packit Service |
360c39 |
int error = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
hsize = 1 << dip->i_di.di_depth;
|
|
Packit Service |
360c39 |
if(hsize * sizeof(uint64_t) != dip->i_di.di_size)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Figure out the address of the leaf node. */
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
hash = gfs2_disk_hash(filename, len);
|
|
Packit Service |
360c39 |
lindex = hash >> (32 - dip->i_di.di_depth);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = get_first_leaf(dip, lindex, &bh_next);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
if (bh_next == NULL)
|
|
Packit Service |
360c39 |
return errno;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Find the entry */
|
|
Packit Service |
360c39 |
do{
|
|
Packit Service |
360c39 |
if (bh && bh != dip->i_bh)
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bh = bh_next;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = leaf_search(dip, bh, filename, len, dent_out, NULL);
|
|
Packit Service |
360c39 |
switch (error){
|
|
Packit Service |
360c39 |
case 0:
|
|
Packit Service |
360c39 |
*bh_out = bh;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
case -ENOENT:
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
default:
|
|
Packit Service |
360c39 |
if (bh && bh != dip->i_bh)
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = get_next_leaf(dip, bh, &bh_next);
|
|
Packit Service |
360c39 |
} while (!error && bh_next != NULL);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (bh && bh != dip->i_bh)
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* dir_e_search -
|
|
Packit Service |
360c39 |
* @dip: The GFS2 inode
|
|
Packit Service |
360c39 |
* @id:
|
|
Packit Service |
360c39 |
* @inode:
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns:
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int dir_e_search(struct gfs2_inode *dip, const char *filename,
|
|
Packit Service |
360c39 |
int len, unsigned int *type, struct gfs2_inum *inum)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh = NULL;
|
|
Packit Service |
360c39 |
struct gfs2_dirent *dent;
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = linked_leaf_search(dip, filename, len, &dent, &bh;;
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_inum_in(inum, (char *)&dent->de_inum);
|
|
Packit Service |
360c39 |
if (type)
|
|
Packit Service |
360c39 |
*type = be16_to_cpu(dent->de_type);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* dir_l_search -
|
|
Packit Service |
360c39 |
* @dip: The GFS2 inode
|
|
Packit Service |
360c39 |
* @id:
|
|
Packit Service |
360c39 |
* @inode:
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns:
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int dir_l_search(struct gfs2_inode *dip, const char *filename,
|
|
Packit Service |
360c39 |
int len, unsigned int *type, struct gfs2_inum *inum)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_dirent *dent;
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if(!inode_is_stuffed(dip))
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = leaf_search(dip, dip->i_bh, filename, len, &dent, NULL);
|
|
Packit Service |
360c39 |
if (!error) {
|
|
Packit Service |
360c39 |
gfs2_inum_in(inum, (char *)&dent->de_inum);
|
|
Packit Service |
360c39 |
if(type)
|
|
Packit Service |
360c39 |
*type = be16_to_cpu(dent->de_type);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* dir_search - Search a directory
|
|
Packit Service |
360c39 |
* @dip: The GFS inode
|
|
Packit Service |
360c39 |
* @id
|
|
Packit Service |
360c39 |
* @type:
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* This routine searches a directory for a file or another directory
|
|
Packit Service |
360c39 |
* given its filename. The component of the identifier that is
|
|
Packit Service |
360c39 |
* not being used to search will be filled in and must be freed by
|
|
Packit Service |
360c39 |
* the caller.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 if found, -1 on failure, -ENOENT if not found.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int dir_search(struct gfs2_inode *dip, const char *filename, int len,
|
|
Packit Service |
360c39 |
unsigned int *type, struct gfs2_inum *inum)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if(!S_ISDIR(dip->i_di.di_mode) && !is_gfs_dir(&dip->i_di))
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
|
|
Packit Service |
360c39 |
error = dir_e_search(dip, filename, len, type, inum);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
error = dir_l_search(dip, filename, len, type, inum);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int dir_e_del(struct gfs2_inode *dip, const char *filename, int len)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int lindex;
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
int found = 0;
|
|
Packit Service |
360c39 |
uint64_t leaf_no;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh = NULL;
|
|
Packit Service |
360c39 |
struct gfs2_dirent *cur, *prev;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
lindex = (1 << (dip->i_di.di_depth))-1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for(; (lindex >= 0) && !found; lindex--){
|
|
Packit Service |
360c39 |
error = lgfs2_get_leaf_ptr(dip, lindex, &leaf_no);
|
|
Packit Service |
360c39 |
if (error)
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while(leaf_no && !found){
|
|
Packit Service |
360c39 |
bh = bread(dip->i_sbd, leaf_no);
|
|
Packit Service |
360c39 |
error = leaf_search(dip, bh, filename, len, &cur, &prev;;
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
if(error != -ENOENT){
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
leaf_no = be64_to_cpu(((struct gfs2_leaf *)bh->b_data)->lf_next);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
} else
|
|
Packit Service |
360c39 |
found = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if(!found)
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (bh) {
|
|
Packit Service |
360c39 |
dirent2_del(dip, bh, prev, cur);
|
|
Packit Service |
360c39 |
brelse(bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int dir_l_del(struct gfs2_inode *dip, const char *filename, int len)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int error=0;
|
|
Packit Service |
360c39 |
struct gfs2_dirent *cur, *prev;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if(!inode_is_stuffed(dip))
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = leaf_search(dip, dip->i_bh, filename, len, &cur, &prev;;
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
if (error == -ENOENT)
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
dirent2_del(dip, dip->i_bh, prev, cur);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/*
|
|
Packit Service |
360c39 |
* gfs2_dirent_del
|
|
Packit Service |
360c39 |
* @dip
|
|
Packit Service |
360c39 |
* filename
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Delete a directory entry from a directory. This _only_
|
|
Packit Service |
360c39 |
* removes the directory entry - leaving the dinode in
|
|
Packit Service |
360c39 |
* place. (Likely without a link.)
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 on success (or if it doesn't already exist), -1 on failure
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int gfs2_dirent_del(struct gfs2_inode *dip, const char *filename, int len)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if(!S_ISDIR(dip->i_di.di_mode) && !is_gfs_dir(&dip->i_di))
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
|
|
Packit Service |
360c39 |
error = dir_e_del(dip, filename, len);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
error = dir_l_del(dip, filename, len);
|
|
Packit Service |
360c39 |
bmodified(dip->i_bh);
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* gfs2_lookupi - Look up a filename in a directory and return its inode
|
|
Packit Service |
360c39 |
* @dip: The directory to search
|
|
Packit Service |
360c39 |
* @name: The name of the inode to look for
|
|
Packit Service |
360c39 |
* @ipp: Used to return the found inode if any
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 on success, -EXXXX on failure
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int gfs2_lookupi(struct gfs2_inode *dip, const char *filename, int len,
|
|
Packit Service |
360c39 |
struct gfs2_inode **ipp)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = dip->i_sbd;
|
|
Packit Service |
360c39 |
int error = 0;
|
|
Packit Service |
360c39 |
struct gfs2_inum inum;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
*ipp = NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!len || len > GFS2_FNAMESIZE)
|
|
Packit Service |
360c39 |
return -ENAMETOOLONG;
|
|
Packit Service |
360c39 |
if (gfs2_filecmp(filename, (char *)".", 1)) {
|
|
Packit Service |
360c39 |
*ipp = dip;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
error = dir_search(dip, filename, len, NULL, &inum);
|
|
Packit Service |
360c39 |
if (!error)
|
|
Packit Service |
360c39 |
*ipp = lgfs2_inode_read(sdp, inum.no_addr);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* gfs2_free_block - free up a block given its block number
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
void gfs2_free_block(struct gfs2_sbd *sdp, uint64_t block)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct rgrp_tree *rgd;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Adjust the free space count for the freed block */
|
|
Packit Service |
360c39 |
rgd = gfs2_blk2rgrpd(sdp, block); /* find the rg for indir block */
|
|
Packit Service |
360c39 |
if (rgd) {
|
|
Packit Service |
360c39 |
gfs2_set_bitmap(rgd, block, GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
rgd->rg.rg_free++; /* adjust the free count */
|
|
Packit Service |
360c39 |
if (sdp->gfs1)
|
|
Packit Service |
360c39 |
gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
gfs2_rgrp_out(&rgd->rg, rgd->bits[0].bi_bh->b_data);
|
|
Packit Service |
360c39 |
bmodified(rgd->bits[0].bi_bh);
|
|
Packit Service |
360c39 |
sdp->blks_alloced--;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* gfs2_freedi - unlink a disk inode by block number.
|
|
Packit Service |
360c39 |
* Note: currently only works for regular files.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int gfs2_freedi(struct gfs2_sbd *sdp, uint64_t diblock)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_inode *ip;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh, *nbh;
|
|
Packit Service |
360c39 |
int h, head_size;
|
|
Packit Service |
360c39 |
uint64_t *ptr, block;
|
|
Packit Service |
360c39 |
struct rgrp_tree *rgd;
|
|
Packit Service |
360c39 |
uint32_t height;
|
|
Packit Service |
360c39 |
osi_list_t metalist[GFS2_MAX_META_HEIGHT];
|
|
Packit Service |
360c39 |
osi_list_t *cur_list, *next_list, *tmp;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (h = 0; h < GFS2_MAX_META_HEIGHT; h++)
|
|
Packit Service |
360c39 |
osi_list_init(&metalist[h]);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bh = bread(sdp, diblock);
|
|
Packit Service |
360c39 |
if (bh == NULL)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
ip = lgfs2_inode_get(sdp, bh);
|
|
Packit Service |
360c39 |
if (ip == NULL)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
height = ip->i_di.di_height;
|
|
Packit Service |
360c39 |
osi_list_add(&bh->b_altlist, &metalist[0]);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (h = 0; h < height; h++){
|
|
Packit Service |
360c39 |
cur_list = &metalist[h];
|
|
Packit Service |
360c39 |
next_list = &metalist[h + 1];
|
|
Packit Service |
360c39 |
head_size = (h > 0 ? sizeof(struct gfs2_meta_header) :
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_dinode));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (tmp = cur_list->next; tmp != cur_list; tmp = tmp->next){
|
|
Packit Service |
360c39 |
bh = osi_list_entry(tmp, struct gfs2_buffer_head,
|
|
Packit Service |
360c39 |
b_altlist);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (ptr = (uint64_t *)(bh->b_data + head_size);
|
|
Packit Service |
360c39 |
(char *)ptr < (bh->b_data + sdp->bsize); ptr++) {
|
|
Packit Service |
360c39 |
if (!*ptr)
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
block = be64_to_cpu(*ptr);
|
|
Packit Service |
360c39 |
gfs2_free_block(sdp, block);
|
|
Packit Service |
360c39 |
if (h == height - 1) /* if not metadata */
|
|
Packit Service |
360c39 |
continue; /* don't queue it up */
|
|
Packit Service |
360c39 |
/* Read the next metadata block in the chain */
|
|
Packit Service |
360c39 |
nbh = bread(sdp, block);
|
|
Packit Service |
360c39 |
osi_list_add(&nbh->b_altlist, next_list);
|
|
Packit Service |
360c39 |
brelse(nbh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
rgd = gfs2_blk2rgrpd(sdp, diblock);
|
|
Packit Service |
360c39 |
gfs2_set_bitmap(rgd, diblock, GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
inode_put(&ip);
|
|
Packit Service |
360c39 |
/* inode_put deallocated the extra block used by the disk inode, */
|
|
Packit Service |
360c39 |
/* so adjust it in the superblock struct */
|
|
Packit Service |
360c39 |
sdp->blks_alloced--;
|
|
Packit Service |
360c39 |
rgd->rg.rg_free++;
|
|
Packit Service |
360c39 |
rgd->rg.rg_dinodes--;
|
|
Packit Service |
360c39 |
if (sdp->gfs1)
|
|
Packit Service |
360c39 |
gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
gfs2_rgrp_out(&rgd->rg, rgd->bits[0].bi_bh->b_data);
|
|
Packit Service |
360c39 |
bmodified(rgd->bits[0].bi_bh);
|
|
Packit Service |
360c39 |
sdp->dinodes_alloced--;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|