Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3152024
pass1.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
20 KB
Referenced Files
None
Subscribers
None
pass1.c
View Options
/* pass1 checks inodes for format & type, duplicate blocks, & incorrect
* block count.
*
* It builds up tables that contains the state of each block (free,
* block in use, metadata type, etc), as well as bad blocks and
* duplicate blocks. (See block_list.[ch] for more info)
*
*/
#include <stdio.h>
#include "fsck_incore.h"
#include "fsck.h"
#include "bio.h"
#include "fs_dir.h"
#include "fs_inode.h"
#include "util.h"
#include "block_list.h"
#include "log.h"
#include "inode_hash.h"
#include "inode.h"
#include "link.h"
#include "metawalk.h"
struct block_count {
uint64_t indir_count;
uint64_t data_count;
uint64_t ea_count;
};
static int leaf(struct fsck_inode *ip, uint64_t block, osi_buf_t *bh,
void *private)
{
struct fsck_sb *sdp = ip->i_sbd;
struct block_count *bc = (struct block_count *) private;
log_debug("\tLeaf block at %15"PRIu64"\n", BH_BLKNO(bh));
block_set(sdp->bl, BH_BLKNO(bh), leaf_blk);
bc->indir_count++;
return 0;
}
static int check_metalist(struct fsck_inode *ip, uint64_t block,
osi_buf_t **bh, void *private)
{
struct fsck_sb *sdp = ip->i_sbd;
struct block_query q = {0};
int found_dup = 0;
osi_buf_t *nbh;
struct block_count *bc = (struct block_count *)private;
*bh = NULL;
if (check_range(ip->i_sbd, block)){ /* blk outside of FS */
block_set(sdp->bl, ip->i_di.di_num.no_addr, bad_block);
log_debug("Bad indirect block pointer (out of range).\n");
return 1;
}
if(block_check(sdp->bl, block, &q)) {
stack;
return -1;
}
if(q.block_type != block_free) {
log_debug("Found duplicate block in indirect block -"
" was marked %d\n", q.block_type);
block_mark(sdp->bl, block, dup_block);
found_dup = 1;
}
get_and_read_buf(ip->i_sbd, block, &nbh, 0);
/** Attention -- experimental code **/
if (check_meta(nbh, GFS_METATYPE_IN)){
log_debug("Bad indirect block pointer "
"(points to something that is not an indirect block).\n");
if(!found_dup) {
block_set(sdp->bl, block, meta_inval);
relse_buf(ip->i_sbd, nbh);
return 1;
}
relse_buf(ip->i_sbd, nbh);
}else{ /* blk check ok */
*bh = nbh;
}
/** Attention -- experimental code end **/
block_set(sdp->bl, block, indir_blk);
bc->indir_count++;
return 0;
}
static int check_data(struct fsck_inode *ip, uint64_t block, void *private)
{
struct fsck_sb *sdp = ip->i_sbd;
struct block_query q = {0};
osi_buf_t *data_bh;
struct block_count *bc = (struct block_count *) private;
if (check_range(ip->i_sbd, block)) {
log_err( "Bad data block pointer (out of range)\n");
/* Mark the owner of this block with the bad_block
* designator so we know to check it for out of range
* blocks later */
block_set(ip->i_sbd->bl, ip->i_di.di_num.no_addr, bad_block);
return 1;
}
if (ip->i_di.di_flags & GFS_DIF_JDATA){
/* Journaled data *is* metadata */
if(get_and_read_buf(ip->i_sbd, block, &data_bh, 0)) {
stack;
block_set(sdp->bl, ip->i_di.di_num.no_addr, meta_inval);
return 1;
}
if(check_meta(data_bh, GFS_METATYPE_JD)) {
log_err("Block #%"PRIu64" in inode %"PRIu64" does not have "
"correct meta header. is %u should be %u\n",
block, ip->i_di.di_num.no_addr,
gfs32_to_cpu(((struct gfs_meta_header *)
BH_DATA((data_bh)))->mh_type),
GFS_METATYPE_JD);
relse_buf(sdp, data_bh);
block_set(sdp->bl, ip->i_di.di_num.no_addr, meta_inval);
return 1;
}
if(block_check(sdp->bl, block, &q)) {
stack;
relse_buf(sdp, data_bh);
return -1;
}
if(q.block_type != block_free) {
log_debug("Found duplicate block at %"
PRIu64"\n", block);
block_mark(sdp->bl, block, dup_block);
bc->data_count++;
relse_buf(sdp, data_bh);
return 1;
}
log_debug("Setting %"PRIu64 " to journal block\n", block);
block_set(sdp->bl, block, journal_blk);
bc->data_count++;
relse_buf(sdp, data_bh);
}
else {
if(block_check(sdp->bl, block, &q)) {
stack;
return -1;
}
if(q.block_type != block_free) {
log_debug("Found duplicate block at %"
PRIu64"\n", block);
block_mark(sdp->bl, block, dup_block);
bc->data_count++;
return 1;
}
log_debug("Setting %"PRIu64 " to data block\n", block);
block_set(sdp->bl, block, block_used);
bc->data_count++;
}
return 0;
}
static int check_eattr_indir(struct fsck_inode *ip, uint64_t indirect,
uint64_t parent, osi_buf_t **bh, void *private)
{
struct fsck_sb *sdp = ip->i_sbd;
int ret = 0;
struct block_query q = {0};
struct block_count *bc = (struct block_count *) private;
/* This inode contains an eattr - it may be invalid, but the
* eattr attributes points to a non-zero block */
block_set(sdp->bl, ip->i_num.no_addr, eattr_block);
if(check_range(sdp, indirect)) {
/*log_warn("EA indirect block #%"PRIu64" is out of range.\n",
indirect);
block_set(sdp->bl, parent, bad_block);*/
/* Doesn't help to mark this here - this gets checked
* in pass1c */
ret = 1;
}
else if(block_check(sdp->bl, indirect, &q)) {
stack;
ret = -1;
}
else if(q.block_type != block_free) {
log_debug("Duplicate block found at #%"PRIu64".\n",
indirect);
block_set(sdp->bl, indirect, dup_block);
bc->ea_count++;
ret = 1;
}
else if(get_and_read_buf(sdp, indirect, bh, 0)) {
log_warn("Unable to read EA indirect block #%"PRIu64".\n",
indirect);
block_set(sdp->bl, indirect, meta_inval);
ret = 1;
}
else if(check_meta(*bh, GFS_METATYPE_IN)) {
log_warn("EA indirect block has incorrect type.\n");
block_set(sdp->bl, BH_BLKNO(*bh), meta_inval);
ret = 1;
}
else {
/* FIXME: do i need to differentiate this as an ea_indir? */
block_set(sdp->bl, BH_BLKNO(*bh), indir_blk);
bc->ea_count++;
}
return ret;
}
/**
* check_extended_leaf_eattr
* @ip
* @el_blk: block number of the extended leaf
*
* An EA leaf block can contain EA's with pointers to blocks
* where the data for that EA is kept. Those blocks still
* have the gfs meta header of type GFS_METATYPE_EA
*
* Returns: 0 if correct[able], -1 if removal is needed
*/
static int check_extended_leaf_eattr(struct fsck_inode *ip, uint64_t *data_ptr,
osi_buf_t *leaf_bh,
struct gfs_ea_header *ea_hdr,
struct gfs_ea_header *ea_hdr_prev,
void *private)
{
osi_buf_t *el_buf;
struct fsck_sb *sdp = ip->i_sbd;
struct block_query q;
uint64_t el_blk = gfs64_to_cpu(*data_ptr);
struct block_count *bc = (struct block_count *) private;
if(check_range(sdp, el_blk)){
log_err("EA extended leaf block #%"PRIu64" "
"is out of range.\n",
el_blk);
block_set(sdp->bl, ip->i_di.di_eattr, bad_block);
return 1;
}
if(block_check(sdp->bl, el_blk, &q)) {
stack;
return -1;
}
if(q.block_type != block_free) {
block_set(sdp->bl, el_blk, dup_block);
bc->ea_count++;
return 1;
}
if(get_and_read_buf(sdp, el_blk, &el_buf, 0)){
log_err("Unable to check extended leaf block.\n");
block_set(sdp->bl, el_blk, meta_inval);
return 1;
}
if(check_meta(el_buf, GFS_METATYPE_ED)) {
log_err("EA extended leaf block has incorrect type.\n");
relse_buf(sdp, el_buf);
block_set(sdp->bl, el_blk, meta_inval);
return 1;
}
block_set(sdp->bl, el_blk, meta_eattr);
bc->ea_count++;
relse_buf(sdp, el_buf);
return 0;
}
static int check_eattr_leaf(struct fsck_inode *ip, uint64_t block,
uint64_t parent, osi_buf_t **bh, void *private)
{
struct fsck_sb *sdp = ip->i_sbd;
osi_buf_t *leaf_bh;
int ret = 0;
struct block_query q = {0};
struct block_count *bc = (struct block_count *) private;
/* This inode contains an eattr - it may be invalid, but the
* eattr attributes points to a non-zero block */
block_set(sdp->bl, ip->i_num.no_addr, eattr_block);
if(check_range(sdp, block)){
log_warn("EA leaf block #%"PRIu64" in inode %"PRIu64
" is out of range.\n",
ip->i_num.no_addr, block);
block_set(sdp->bl, ip->i_di.di_eattr, bad_block);
ret = 1;
}
else if(block_check(sdp->bl, block, &q)) {
stack;
return -1;
}
else if(q.block_type != block_free) {
log_debug("Duplicate block found at #%"PRIu64".\n",
block);
block_set(sdp->bl, block, dup_block);
bc->ea_count++;
}
else if(get_and_read_buf(sdp, block, &leaf_bh, 0)){
log_warn("Unable to read EA leaf block #%"PRIu64".\n",
block);
block_set(sdp->bl, block, meta_inval);
ret = 1;
} else if(check_meta(leaf_bh, GFS_METATYPE_EA)) {
log_warn("EA leaf block has incorrect type.\n");
block_set(sdp->bl, BH_BLKNO(leaf_bh), meta_inval);
relse_buf(sdp, leaf_bh);
ret = 1;
}
else {
block_set(sdp->bl, BH_BLKNO(leaf_bh), meta_eattr);
bc->ea_count++;
}
*bh = leaf_bh;
return ret;
}
static int check_eattr_entries(struct fsck_inode *ip,
osi_buf_t *leaf_bh,
struct gfs_ea_header *ea_hdr,
struct gfs_ea_header *ea_hdr_prev,
void *private)
{
struct fsck_sb *sdp = ip->i_sbd;
char ea_name[256];
if(!ea_hdr->ea_name_len){
/* Skip this entry for now */
return 1;
}
memset(ea_name, 0, sizeof(ea_name));
strncpy(ea_name, (char *)ea_hdr + sizeof(struct gfs_ea_header),
ea_hdr->ea_name_len);
if(!GFS_EATYPE_VALID(ea_hdr->ea_type) &&
((ea_hdr_prev) || (!ea_hdr_prev && ea_hdr->ea_type))){
/* Skip invalid entry */
return 1;
}
if(ea_hdr->ea_num_ptrs){
uint32 avail_size;
int max_ptrs;
avail_size = sdp->sb.sb_bsize - sizeof(struct gfs_meta_header);
max_ptrs = (gfs32_to_cpu(ea_hdr->ea_data_len)+avail_size-1)/avail_size;
if(max_ptrs > ea_hdr->ea_num_ptrs) {
return 1;
} else {
log_debug(" Pointers Required: %d\n"
" Pointers Reported: %d\n",
max_ptrs,
ea_hdr->ea_num_ptrs);
}
}
return 0;
}
struct metawalk_fxns pass1_fxns = {
.private = NULL,
.check_leaf = leaf,
.check_metalist = check_metalist,
.check_data = check_data,
.check_eattr_indir = check_eattr_indir,
.check_eattr_leaf = check_eattr_leaf,
.check_dentry = NULL,
.check_eattr_entry = check_eattr_entries,
.check_eattr_extentry = check_extended_leaf_eattr,
};
int clear_metalist(struct fsck_inode *ip, uint64_t block,
osi_buf_t **bh, void *private)
{
struct fsck_sb *sdp = ip->i_sbd;
struct block_query q = {0};
*bh = NULL;
if(block_check(sdp->bl, block, &q)) {
stack;
return -1;
}
if(!q.dup_block) {
block_set(sdp->bl, block, block_free);
return 0;
}
return 0;
}
int clear_data(struct fsck_inode *ip, uint64_t block, void *private)
{
struct fsck_sb *sdp = ip->i_sbd;
struct block_query q = {0};
if(block_check(sdp->bl, block, &q)) {
stack;
return -1;
}
if(!q.dup_block) {
block_set(sdp->bl, block, block_free);
return 0;
}
return 0;
}
int clear_leaf(struct fsck_inode *ip, uint64_t block,
osi_buf_t *bh, void *private)
{
struct fsck_sb *sdp = ip->i_sbd;
struct block_query q = {0};
log_crit("Clearing leaf %"PRIu64"\n", block);
if(block_check(sdp->bl, block, &q)) {
stack;
return -1;
}
if(!q.dup_block) {
log_crit("Setting leaf invalid\n");
if(block_set(sdp->bl, block, block_free)) {
stack;
return -1;
}
return 0;
}
return 0;
}
int add_to_dir_list(struct fsck_sb *sbp, uint64_t block)
{
struct dir_info *di = NULL;
struct dir_info *newdi;
/* FIXME: This list should probably be a b-tree or
* something...but since most of the time we're going to be
* tacking the directory onto the end of the list, it doesn't
* matter too much */
find_di(sbp, block, &di);
if(di) {
log_err("Attempting to add directory block %"PRIu64
" which is already in list\n", block);
return -1;
}
if(!(newdi = (struct dir_info *) malloc(sizeof(*newdi)))) {
log_crit("Unable to allocate dir_info structure\n");
return -1;
}
if(!memset(newdi, 0, sizeof(*newdi))) {
log_crit("error while zeroing dir_info structure\n");
return -1;
}
newdi->dinode = block;
dinode_hash_insert(sbp->dir_hash, block, newdi);
return 0;
}
int handle_di(struct fsck_sb *sdp, osi_buf_t *bh, uint64_t block, int mfree)
{
struct block_query q = {0};
struct fsck_inode *ip;
int error;
struct block_count bc = {0};
struct metawalk_fxns invalidate_metatree = {0};
invalidate_metatree.check_metalist = clear_metalist;
invalidate_metatree.check_data = clear_data;
invalidate_metatree.check_leaf = clear_leaf;
if(copyin_inode(sdp, bh, &ip)) {
stack;
return -1;
}
if (ip->i_di.di_flags & GFS_DIF_UNUSED){
if(mfree) {
if(block_set(sdp->bl, block, meta_free)) {
stack;
goto fail;
}
goto success;
} else {
log_err("Found unused inode marked in-use\n");
if(query(sdp, "Clear unused inode at block %"
PRIu64"? (y/n) ", block)) {
if(block_set(sdp->bl, block, meta_inval)) {
stack;
goto fail;
}
goto success;
} else {
log_err("Unused inode still marked in-use\n");
}
}
} else {
if(mfree) {
if(block_set(sdp->bl, block, meta_free)) {
stack;
goto fail;
}
goto success;
}
}
if (ip->i_di.di_num.no_addr != block) {
log_err("Bad dinode Address. "
"Found %"PRIu64", "
"Expected %"PRIu64"\n",
ip->i_di.di_num.no_addr, block);
if(query(sdp, "Fix address in inode at block %"
PRIu64"? (y/n) ", block)) {
ip->i_di.di_num.no_addr =
ip->i_di.di_num.no_formal_ino =
block;
if(fs_copyout_dinode(ip)){
log_crit("Bad dinode address can not be reset.\n");
goto fail;
} else {
log_err("Bad dinode address reset.\n");
}
} else {
log_err("Address in inode at block %"PRIu64
" not fixed\n", block);
}
}
if(block_check(sdp->bl, block, &q)) {
stack;
goto fail;
}
if(q.block_type != block_free) {
log_debug("Found duplicate block at %"PRIu64"\n",
block);
if(block_mark(sdp->bl, block, dup_block)) {
stack;
goto fail;
}
goto success;
}
switch(ip->i_di.di_type) {
case GFS_FILE_DIR:
if(block_set(sdp->bl, block, inode_dir)) {
stack;
goto fail;
}
if(add_to_dir_list(sdp, block)) {
stack;
goto fail;
}
break;
case GFS_FILE_REG:
if(block_set(sdp->bl, block, inode_file)) {
stack;
goto fail;
}
break;
case GFS_FILE_LNK:
if(block_set(sdp->bl, block, inode_lnk)) {
stack;
goto fail;
}
break;
case GFS_FILE_BLK:
if(block_set(sdp->bl, block, inode_blk)) {
stack;
goto fail;
}
break;
case GFS_FILE_CHR:
if(block_set(sdp->bl, block, inode_chr)) {
stack;
goto fail;
}
break;
case GFS_FILE_FIFO:
if(block_set(sdp->bl, block, inode_fifo)) {
stack;
goto fail;
}
break;
case GFS_FILE_SOCK:
if(block_set(sdp->bl, block, inode_sock)) {
stack;
goto fail;
}
break;
default:
if(block_set(sdp->bl, block, meta_inval)) {
stack;
goto fail;
}
goto success;
}
if(set_link_count(ip->i_sbd, ip->i_num.no_formal_ino,
ip->i_di.di_nlink)) {
stack;
goto fail;
}
/* FIXME: fix height and depth here - wasn't implemented in
* old fsck either, so no biggy... */
if (ip->i_di.di_height < compute_height(sdp, ip->i_di.di_size)){
log_warn("Dinode #%"PRIu64" has bad height "
"Found %u, Expected >= %u\n",
ip->i_di.di_num.no_addr, ip->i_di.di_height,
compute_height(sdp, ip->i_di.di_size));
/* once implemented, remove continue statement */
log_warn("Marking inode invalid\n");
if(block_set(sdp->bl, block, meta_inval)) {
stack;
goto fail;
}
goto success;
}
if (ip->i_di.di_type == (GFS_FILE_DIR &&
(ip->i_di.di_flags & GFS_DIF_EXHASH)))
{
if (((1 << ip->i_di.di_depth) * sizeof(uint64_t)) !=
ip->i_di.di_size)
{
log_warn("Directory dinode #%"PRIu64" has bad depth. "
"Found %u, Expected %u\n",
ip->i_di.di_num.no_addr, ip->i_di.di_depth,
(1 >> (ip->i_di.di_size/sizeof(uint64))));
/* once implemented, remove continue statement */
log_warn("Marking inode invalid\n");
if(block_set(sdp->bl, block, meta_inval)) {
stack;
goto fail;
}
goto success;
}
}
pass1_fxns.private = &bc;
error = check_metatree(ip, &pass1_fxns);
if(error < 0) {
return 0;
}
if(error > 0) {
log_warn("Marking inode invalid\n");
/* FIXME: Must set all leaves invalid as well */
check_metatree(ip, &invalidate_metatree);
block_set(ip->i_sbd->bl, ip->i_di.di_num.no_addr, meta_inval);
return 0;
}
/* FIXME: is this correct? */
if(check_inode_eattr(ip, &pass1_fxns) < 0){
osi_buf_t *di_bh;
ip->i_di.di_eattr = 0;
if(get_and_read_buf(sdp, ip->i_di.di_num.no_addr, &di_bh, 0)){
stack;
log_crit("Bad EA reference remains.\n");
} else {
gfs_dinode_out(&ip->i_di, BH_DATA(di_bh));
if(write_buf(ip->i_sbd, di_bh, 0) < 0){
stack;
log_crit("Bad EA reference remains.\n");
} else {
log_warn("Bad EA reference cleared.\n");
}
relse_buf(sdp, di_bh);
}
}
if(ip->i_di.di_blocks != (1 + bc.indir_count + bc.data_count + bc.ea_count)) {
osi_buf_t *di_bh;
log_err("Ondisk block count does not match what fsck"
" found for inode %"PRIu64"\n", ip->i_di.di_num.no_addr);
if(query(sdp, "Fix ondisk block count? (y/n) ")) {
ip->i_di.di_blocks = 1 + bc.indir_count +
bc.data_count +
bc.ea_count;
if(get_and_read_buf(sdp, ip->i_di.di_num.no_addr,
&di_bh, 0)){
stack;
log_crit("Bad block count remains\n");
} else {
gfs_dinode_out(&ip->i_di, BH_DATA(di_bh));
if(write_buf(ip->i_sbd, di_bh, 0) < 0){
stack;
log_crit("Bad block count remains\n");
} else {
log_warn("Bad block count fixed\n");
}
relse_buf(sdp, di_bh);
}
} else {
log_err("Bad block count for %"PRIu64" not fixed\n",
ip->i_di.di_num.no_addr);
}
}
success:
free(ip);
return 0;
fail:
free(ip);
return -1;
}
int scan_meta(struct fsck_sb *sdp, osi_buf_t *bh, uint64_t block, int mfree)
{
if (check_meta(bh, 0)) {
log_debug("Found invalid metadata at %"PRIu64"\n", block);
if(block_set(sdp->bl, block, meta_inval)) {
stack;
return -1;
}
return 0;
}
log_debug("Checking metadata block %"PRIu64"\n", block);
if (!check_type(bh, GFS_METATYPE_DI)) {
if(handle_di(sdp, bh, block, mfree)) {
stack;
return -1;
}
}
else if (!check_type(bh, GFS_METATYPE_NONE)) {
if(block_set(sdp->bl, block, meta_free)) {
stack;
return -1;
}
} else {
log_debug("Metadata block %"PRIu64
" not an inode or free metadata\n",
block);
}
/* Ignore everything else - they should be hit by the
* handle_di step */
return 0;
}
/**
* pass1 - walk through inodes and check inode state
*
* this walk can be done using root inode and depth first search,
* watching for repeat inode numbers
*
* format & type
* link count
* duplicate blocks
* bad blocks
* inodes size
* dir info
*/
int pass1(struct fsck_sb *sbp)
{
osi_buf_t *bh;
osi_list_t *tmp;
uint64_t block;
struct fsck_rgrp *rgd;
int first;
uint64_t i;
uint64_t j;
uint64_t blk_count;
uint64_t offset;
uint64_t rg_count = 0;
int mfree = 0;
/* FIXME: What other metadata should we look for? */
/* Mark the journal blocks as 'other metadata' */
for (i = 0; i < sbp->journals; i++) {
struct gfs_jindex *ji;
ji = &sbp->jindex[i];
for(j = ji->ji_addr;
j < ji->ji_addr + (ji->ji_nsegment * sbp->sb.sb_seg_size);
j++) {
if(block_set(sbp->bl, j, journal_blk)) {
stack;
return -1;
}
}
}
/* So, do we do a depth first search starting at the root
* inode, or use the rg bitmaps, or just read every fs block
* to find the inodes? If we use the depth first search, why
* have pass3 at all - if we use the rg bitmaps, pass5 is at
* least partially invalidated - if we read every fs block,
* things will probably be intolerably slow. The current fsck
* uses the rg bitmaps, so maybe that's the best way to start
* things - we can change the method later if necessary.
*/
for (tmp = sbp->rglist.next; tmp != &sbp->rglist;
tmp = tmp->next, rg_count++){
log_info("Checking metadata in Resource Group %"PRIu64"\n",
rg_count);
rgd = osi_list_entry(tmp, struct fsck_rgrp, rd_list);
if(fs_rgrp_read(rgd, FALSE)){
stack;
return -1;
}
log_debug("RG at %"PRIu64" is %u long\n", rgd->rd_ri.ri_addr,
rgd->rd_ri.ri_length);
for (i = 0; i < rgd->rd_ri.ri_length; i++) {
if(block_set(sbp->bl, rgd->rd_ri.ri_addr + i,
meta_other)){
stack;
return -1;
}
}
offset = sizeof(struct gfs_rgrp);
blk_count = 1;
first = 1;
while (1) {
/* "block" is relative to the entire file system */
if(next_rg_meta_free(rgd, &block, first, &mfree))
break;
warm_fuzzy_stuff(block);
if (fsck_abort) /* if asked to abort */
return 0;
if (skip_this_pass) {
printf("Skipping pass 1 is not a good idea.\n");
skip_this_pass = FALSE;
fflush(stdout);
}
if(get_and_read_buf(sbp, block, &bh, 0)){
stack;
log_crit("Unable to retrieve block %"PRIu64
"\n", block);
fs_rgrp_relse(rgd);
return -1;
}
if(scan_meta(sbp, bh, block, mfree)) {
stack;
relse_buf(sbp, bh);
fs_rgrp_relse(rgd);
return -1;
}
relse_buf(sbp, bh);
first = 0;
}
fs_rgrp_relse(rgd);
}
return 0;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Mon, Feb 24, 2:50 PM (8 h, 50 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1464273
Default Alt Text
pass1.c (20 KB)
Attached To
Mode
rF Fence Agents
Attached
Detach File
Event Timeline
Log In to Comment