Move the pointers stored in the superblock into a separate
fs_summary_info structure. This change was originally done by the CheriBSD project as they need larger pointers that do not fit in the existing superblock. This cleanup of the superblock eases the task of the commit that immediately follows this one. Suggested by: brooks Reviewed by: kib PR: 246983 Sponsored by: Netflix
This commit is contained in:
parent
349eddbd07
commit
34816cb9ae
@ -134,6 +134,10 @@ mkfs(struct partition *pp, char *fsys)
|
|||||||
utime = 1000000000;
|
utime = 1000000000;
|
||||||
else
|
else
|
||||||
time(&utime);
|
time(&utime);
|
||||||
|
if ((sblock.fs_si = malloc(sizeof(struct fs_summary_info))) == NULL) {
|
||||||
|
printf("Superblock summary info allocation failed.\n");
|
||||||
|
exit(18);
|
||||||
|
}
|
||||||
sblock.fs_old_flags = FS_FLAGS_UPDATED;
|
sblock.fs_old_flags = FS_FLAGS_UPDATED;
|
||||||
sblock.fs_flags = 0;
|
sblock.fs_flags = 0;
|
||||||
if (Uflag)
|
if (Uflag)
|
||||||
@ -548,6 +552,10 @@ mkfs(struct partition *pp, char *fsys)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* Reference the summary information so it will also be written.
|
||||||
|
*/
|
||||||
|
sblock.fs_csp = fscs;
|
||||||
if (!Nflag && sbput(disk.d_fd, &disk.d_fs, 0) != 0)
|
if (!Nflag && sbput(disk.d_fd, &disk.d_fs, 0) != 0)
|
||||||
err(1, "sbput: %s", disk.d_error);
|
err(1, "sbput: %s", disk.d_error);
|
||||||
if (Xflag == 1) {
|
if (Xflag == 1) {
|
||||||
@ -611,10 +619,6 @@ mkfs(struct partition *pp, char *fsys)
|
|||||||
printf("** Exiting on Xflag 3\n");
|
printf("** Exiting on Xflag 3\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Reference the summary information so it will also be written.
|
|
||||||
*/
|
|
||||||
sblock.fs_csp = fscs;
|
|
||||||
if (sbput(disk.d_fd, &disk.d_fs, 0) != 0)
|
if (sbput(disk.d_fd, &disk.d_fs, 0) != 0)
|
||||||
err(1, "sbput: %s", disk.d_error);
|
err(1, "sbput: %s", disk.d_error);
|
||||||
/*
|
/*
|
||||||
|
@ -678,7 +678,11 @@ ufs_open(upath, f)
|
|||||||
if (rc) {
|
if (rc) {
|
||||||
if (fp->f_buf)
|
if (fp->f_buf)
|
||||||
free(fp->f_buf);
|
free(fp->f_buf);
|
||||||
|
if (fp->f_fs != NULL) {
|
||||||
|
free(fp->f_fs->fs_csp);
|
||||||
|
free(fp->f_fs->fs_si);
|
||||||
free(fp->f_fs);
|
free(fp->f_fs);
|
||||||
|
}
|
||||||
free(fp);
|
free(fp);
|
||||||
}
|
}
|
||||||
return (rc);
|
return (rc);
|
||||||
@ -723,7 +727,11 @@ ufs_close(f)
|
|||||||
}
|
}
|
||||||
if (fp->f_buf)
|
if (fp->f_buf)
|
||||||
free(fp->f_buf);
|
free(fp->f_buf);
|
||||||
|
if (fp->f_fs != NULL) {
|
||||||
|
free(fp->f_fs->fs_csp);
|
||||||
|
free(fp->f_fs->fs_si);
|
||||||
free(fp->f_fs);
|
free(fp->f_fs);
|
||||||
|
}
|
||||||
free(fp);
|
free(fp);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@ g_journal_ufs_clean(struct mount *mp)
|
|||||||
static void
|
static void
|
||||||
g_journal_ufs_dirty(struct g_consumer *cp)
|
g_journal_ufs_dirty(struct g_consumer *cp)
|
||||||
{
|
{
|
||||||
|
struct fs_summary_info *fs_si;
|
||||||
struct fs *fs;
|
struct fs *fs;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@ -83,8 +84,12 @@ g_journal_ufs_dirty(struct g_consumer *cp)
|
|||||||
GJ_DEBUG(0, "clean=%d flags=0x%x", fs->fs_clean, fs->fs_flags);
|
GJ_DEBUG(0, "clean=%d flags=0x%x", fs->fs_clean, fs->fs_flags);
|
||||||
fs->fs_clean = 0;
|
fs->fs_clean = 0;
|
||||||
fs->fs_flags |= FS_NEEDSFSCK | FS_UNCLEAN;
|
fs->fs_flags |= FS_NEEDSFSCK | FS_UNCLEAN;
|
||||||
|
fs_si = fs->fs_si;
|
||||||
|
fs->fs_si = NULL;
|
||||||
error = ffs_sbput(cp, fs, fs->fs_sblockloc, g_use_g_write_data);
|
error = ffs_sbput(cp, fs, fs->fs_sblockloc, g_use_g_write_data);
|
||||||
|
fs->fs_si = fs_si;
|
||||||
g_free(fs->fs_csp);
|
g_free(fs->fs_csp);
|
||||||
|
g_free(fs->fs_si);
|
||||||
g_free(fs);
|
g_free(fs);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
GJ_DEBUG(0, "Cannot mark file system %s as dirty "
|
GJ_DEBUG(0, "Cannot mark file system %s as dirty "
|
||||||
|
@ -122,6 +122,7 @@ g_label_ufs_taste_common(struct g_consumer *cp, char *label, size_t size, int wh
|
|||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
g_free(fs->fs_csp);
|
g_free(fs->fs_csp);
|
||||||
|
g_free(fs->fs_si);
|
||||||
g_free(fs);
|
g_free(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,6 +480,8 @@ ffs_snapshot(mp, snapfile)
|
|||||||
*/
|
*/
|
||||||
copy_fs = malloc((u_long)fs->fs_bsize, M_UFSMNT, M_WAITOK);
|
copy_fs = malloc((u_long)fs->fs_bsize, M_UFSMNT, M_WAITOK);
|
||||||
bcopy(fs, copy_fs, fs->fs_sbsize);
|
bcopy(fs, copy_fs, fs->fs_sbsize);
|
||||||
|
copy_fs->fs_si = malloc(sizeof(struct fs_summary_info), M_UFSMNT,
|
||||||
|
M_ZERO | M_WAITOK);
|
||||||
if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0)
|
if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0)
|
||||||
copy_fs->fs_clean = 1;
|
copy_fs->fs_clean = 1;
|
||||||
size = fs->fs_bsize < SBLOCKSIZE ? fs->fs_bsize : SBLOCKSIZE;
|
size = fs->fs_bsize < SBLOCKSIZE ? fs->fs_bsize : SBLOCKSIZE;
|
||||||
@ -501,6 +503,7 @@ ffs_snapshot(mp, snapfile)
|
|||||||
len, KERNCRED, &bp)) != 0) {
|
len, KERNCRED, &bp)) != 0) {
|
||||||
brelse(bp);
|
brelse(bp);
|
||||||
free(copy_fs->fs_csp, M_UFSMNT);
|
free(copy_fs->fs_csp, M_UFSMNT);
|
||||||
|
free(copy_fs->fs_si, M_UFSMNT);
|
||||||
free(copy_fs, M_UFSMNT);
|
free(copy_fs, M_UFSMNT);
|
||||||
copy_fs = NULL;
|
copy_fs = NULL;
|
||||||
goto out1;
|
goto out1;
|
||||||
@ -611,6 +614,7 @@ ffs_snapshot(mp, snapfile)
|
|||||||
vdrop(xvp);
|
vdrop(xvp);
|
||||||
if (error) {
|
if (error) {
|
||||||
free(copy_fs->fs_csp, M_UFSMNT);
|
free(copy_fs->fs_csp, M_UFSMNT);
|
||||||
|
free(copy_fs->fs_si, M_UFSMNT);
|
||||||
free(copy_fs, M_UFSMNT);
|
free(copy_fs, M_UFSMNT);
|
||||||
copy_fs = NULL;
|
copy_fs = NULL;
|
||||||
MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
|
MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
|
||||||
@ -624,6 +628,7 @@ ffs_snapshot(mp, snapfile)
|
|||||||
error = softdep_journal_lookup(mp, &xvp);
|
error = softdep_journal_lookup(mp, &xvp);
|
||||||
if (error) {
|
if (error) {
|
||||||
free(copy_fs->fs_csp, M_UFSMNT);
|
free(copy_fs->fs_csp, M_UFSMNT);
|
||||||
|
free(copy_fs->fs_si, M_UFSMNT);
|
||||||
free(copy_fs, M_UFSMNT);
|
free(copy_fs, M_UFSMNT);
|
||||||
copy_fs = NULL;
|
copy_fs = NULL;
|
||||||
goto out1;
|
goto out1;
|
||||||
@ -842,6 +847,7 @@ ffs_snapshot(mp, snapfile)
|
|||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
free(copy_fs->fs_csp, M_UFSMNT);
|
free(copy_fs->fs_csp, M_UFSMNT);
|
||||||
|
free(copy_fs->fs_si, M_UFSMNT);
|
||||||
free(copy_fs, M_UFSMNT);
|
free(copy_fs, M_UFSMNT);
|
||||||
copy_fs = NULL;
|
copy_fs = NULL;
|
||||||
out:
|
out:
|
||||||
|
@ -158,6 +158,7 @@ ffs_sbget(void *devfd, struct fs **fsp, off_t altsblock,
|
|||||||
int (*readfunc)(void *devfd, off_t loc, void **bufp, int size))
|
int (*readfunc)(void *devfd, off_t loc, void **bufp, int size))
|
||||||
{
|
{
|
||||||
struct fs *fs;
|
struct fs *fs;
|
||||||
|
struct fs_summary_info *fs_si;
|
||||||
int i, error, size, blks;
|
int i, error, size, blks;
|
||||||
uint8_t *space;
|
uint8_t *space;
|
||||||
int32_t *lp;
|
int32_t *lp;
|
||||||
@ -201,7 +202,14 @@ ffs_sbget(void *devfd, struct fs **fsp, off_t altsblock,
|
|||||||
size += fs->fs_ncg * sizeof(int32_t);
|
size += fs->fs_ncg * sizeof(int32_t);
|
||||||
size += fs->fs_ncg * sizeof(u_int8_t);
|
size += fs->fs_ncg * sizeof(u_int8_t);
|
||||||
/* When running in libufs or libsa, UFS_MALLOC may fail */
|
/* When running in libufs or libsa, UFS_MALLOC may fail */
|
||||||
|
if ((fs_si = UFS_MALLOC(sizeof(*fs_si), filltype, M_WAITOK)) == NULL) {
|
||||||
|
UFS_FREE(fs, filltype);
|
||||||
|
return (ENOSPC);
|
||||||
|
}
|
||||||
|
bzero(fs_si, sizeof(*fs_si));
|
||||||
|
fs->fs_si = fs_si;
|
||||||
if ((space = UFS_MALLOC(size, filltype, M_WAITOK)) == NULL) {
|
if ((space = UFS_MALLOC(size, filltype, M_WAITOK)) == NULL) {
|
||||||
|
UFS_FREE(fs->fs_si, filltype);
|
||||||
UFS_FREE(fs, filltype);
|
UFS_FREE(fs, filltype);
|
||||||
return (ENOSPC);
|
return (ENOSPC);
|
||||||
}
|
}
|
||||||
@ -217,6 +225,7 @@ ffs_sbget(void *devfd, struct fs **fsp, off_t altsblock,
|
|||||||
if (buf != NULL)
|
if (buf != NULL)
|
||||||
UFS_FREE(buf, filltype);
|
UFS_FREE(buf, filltype);
|
||||||
UFS_FREE(fs->fs_csp, filltype);
|
UFS_FREE(fs->fs_csp, filltype);
|
||||||
|
UFS_FREE(fs->fs_si, filltype);
|
||||||
UFS_FREE(fs, filltype);
|
UFS_FREE(fs, filltype);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
@ -299,7 +308,7 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk,
|
|||||||
/* Have to set for old filesystems that predate this field */
|
/* Have to set for old filesystems that predate this field */
|
||||||
fs->fs_sblockactualloc = sblockloc;
|
fs->fs_sblockactualloc = sblockloc;
|
||||||
/* Not yet any summary information */
|
/* Not yet any summary information */
|
||||||
fs->fs_csp = NULL;
|
fs->fs_si = NULL;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
return (ENOENT);
|
return (ENOENT);
|
||||||
@ -325,7 +334,7 @@ ffs_sbput(void *devfd, struct fs *fs, off_t loc,
|
|||||||
* If there is summary information, write it first, so if there
|
* If there is summary information, write it first, so if there
|
||||||
* is an error, the superblock will not be marked as clean.
|
* is an error, the superblock will not be marked as clean.
|
||||||
*/
|
*/
|
||||||
if (fs->fs_csp != NULL) {
|
if (fs->fs_si != NULL && fs->fs_csp != NULL) {
|
||||||
blks = howmany(fs->fs_cssize, fs->fs_fsize);
|
blks = howmany(fs->fs_cssize, fs->fs_fsize);
|
||||||
space = (uint8_t *)fs->fs_csp;
|
space = (uint8_t *)fs->fs_csp;
|
||||||
for (i = 0; i < blks; i += fs->fs_frag) {
|
for (i = 0; i < blks; i += fs->fs_frag) {
|
||||||
|
@ -885,14 +885,11 @@ ffs_reload(struct mount *mp, struct thread *td, int flags)
|
|||||||
return (EIO); /* XXX needs translation */
|
return (EIO); /* XXX needs translation */
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Copy pointer fields back into superblock before copying in XXX
|
* Preserve the summary information, read-only status, and
|
||||||
* new superblock. These should really be in the ufsmount. XXX
|
* superblock location by copying these fields into our new
|
||||||
* Note that important parameters (eg fs_ncg) are unchanged.
|
* superblock before using it to update the existing superblock.
|
||||||
*/
|
*/
|
||||||
newfs->fs_csp = fs->fs_csp;
|
newfs->fs_si = fs->fs_si;
|
||||||
newfs->fs_maxcluster = fs->fs_maxcluster;
|
|
||||||
newfs->fs_contigdirs = fs->fs_contigdirs;
|
|
||||||
newfs->fs_active = fs->fs_active;
|
|
||||||
newfs->fs_ronly = fs->fs_ronly;
|
newfs->fs_ronly = fs->fs_ronly;
|
||||||
sblockloc = fs->fs_sblockloc;
|
sblockloc = fs->fs_sblockloc;
|
||||||
bcopy(newfs, fs, (u_int)fs->fs_sbsize);
|
bcopy(newfs, fs, (u_int)fs->fs_sbsize);
|
||||||
@ -1309,6 +1306,7 @@ ffs_mountfs(odevvp, mp, td)
|
|||||||
out:
|
out:
|
||||||
if (fs != NULL) {
|
if (fs != NULL) {
|
||||||
free(fs->fs_csp, M_UFSMNT);
|
free(fs->fs_csp, M_UFSMNT);
|
||||||
|
free(fs->fs_si, M_UFSMNT);
|
||||||
free(fs, M_UFSMNT);
|
free(fs, M_UFSMNT);
|
||||||
}
|
}
|
||||||
if (cp != NULL) {
|
if (cp != NULL) {
|
||||||
@ -1546,6 +1544,7 @@ ffs_unmount(mp, mntflags)
|
|||||||
mp->mnt_gjprovider = NULL;
|
mp->mnt_gjprovider = NULL;
|
||||||
}
|
}
|
||||||
free(fs->fs_csp, M_UFSMNT);
|
free(fs->fs_csp, M_UFSMNT);
|
||||||
|
free(fs->fs_si, M_UFSMNT);
|
||||||
free(fs, M_UFSMNT);
|
free(fs, M_UFSMNT);
|
||||||
if (ump->um_fsfail_task != NULL)
|
if (ump->um_fsfail_task != NULL)
|
||||||
free(ump->um_fsfail_task, M_UFSMNT);
|
free(ump->um_fsfail_task, M_UFSMNT);
|
||||||
@ -2294,10 +2293,7 @@ ffs_use_bwrite(void *devfd, off_t loc, void *buf, int size)
|
|||||||
bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
|
bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
|
||||||
fs = (struct fs *)bp->b_data;
|
fs = (struct fs *)bp->b_data;
|
||||||
ffs_oldfscompat_write(fs, ump);
|
ffs_oldfscompat_write(fs, ump);
|
||||||
/*
|
/* Recalculate the superblock hash */
|
||||||
* Because we may have made changes to the superblock, we need to
|
|
||||||
* recompute its check-hash.
|
|
||||||
*/
|
|
||||||
fs->fs_ckhash = ffs_calc_sbhash(fs);
|
fs->fs_ckhash = ffs_calc_sbhash(fs);
|
||||||
if (devfdp->suspended)
|
if (devfdp->suspended)
|
||||||
bp->b_flags |= B_VALIDSUSPWRT;
|
bp->b_flags |= B_VALIDSUSPWRT;
|
||||||
|
@ -132,16 +132,18 @@
|
|||||||
* of pointers to blocks of struct csum; now there are just a few
|
* of pointers to blocks of struct csum; now there are just a few
|
||||||
* pointers and the remaining space is padded with fs_ocsp[].
|
* pointers and the remaining space is padded with fs_ocsp[].
|
||||||
*
|
*
|
||||||
* NOCSPTRS determines the size of this padding. One pointer (fs_csp)
|
* NOCSPTRS determines the size of this padding. Historically this
|
||||||
* is taken away to point to a contiguous array of struct csum for
|
* space was used to store pointers to structures that summaried
|
||||||
* all cylinder groups; a second (fs_maxcluster) points to an array
|
* filesystem usage and layout information. However, these pointers
|
||||||
* of cluster sizes that is computed as cylinder groups are inspected,
|
* left various kernel pointers in the superblock which made otherwise
|
||||||
* and the third points to an array that tracks the creation of new
|
* identical superblocks appear to have differences. So, all the
|
||||||
* directories. A fourth pointer, fs_active, is used when creating
|
* pointers in the superblock were moved to a fs_summary_info structure
|
||||||
* snapshots; it points to a bitmap of cylinder groups for which the
|
* reducing the superblock to having only a single pointer to this
|
||||||
* free-block bitmap has changed since the snapshot operation began.
|
* structure. When writing the superblock to disk, this pointer is
|
||||||
|
* temporarily NULL'ed out so that the kernel pointer will not appear
|
||||||
|
* in the on-disk copy of the superblock.
|
||||||
*/
|
*/
|
||||||
#define NOCSPTRS ((128 / sizeof(void *)) - 4)
|
#define NOCSPTRS ((128 / sizeof(void *)) - 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A summary of contiguous blocks of various sizes is maintained
|
* A summary of contiguous blocks of various sizes is maintained
|
||||||
@ -269,6 +271,32 @@ struct csum_total {
|
|||||||
int64_t cs_spare[3]; /* future expansion */
|
int64_t cs_spare[3]; /* future expansion */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pointers to super block summary information. Placed in a separate
|
||||||
|
* structure so there is just one pointer in the superblock.
|
||||||
|
*
|
||||||
|
* The pointers in this structure are used as follows:
|
||||||
|
* fs_contigdirs references an array that tracks the creation of new
|
||||||
|
* directories
|
||||||
|
* fs_csp references a contiguous array of struct csum for
|
||||||
|
* all cylinder groups
|
||||||
|
* fs_maxcluster references an array of cluster sizes that is computed
|
||||||
|
* as cylinder groups are inspected
|
||||||
|
* fs_active is used when creating snapshots; it points to a bitmap
|
||||||
|
* of cylinder groups for which the free-block bitmap has changed
|
||||||
|
* since the snapshot operation began.
|
||||||
|
*/
|
||||||
|
struct fs_summary_info {
|
||||||
|
uint8_t *si_contigdirs; /* (u) # of contig. allocated dirs */
|
||||||
|
struct csum *si_csp; /* (u) cg summary info buffer */
|
||||||
|
int32_t *si_maxcluster; /* (u) max cluster in each cyl group */
|
||||||
|
u_int *si_active; /* (u) used by snapshots to track fs */
|
||||||
|
};
|
||||||
|
#define fs_contigdirs fs_si->si_contigdirs
|
||||||
|
#define fs_csp fs_si->si_csp
|
||||||
|
#define fs_maxcluster fs_si->si_maxcluster
|
||||||
|
#define fs_active fs_si->si_active
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Super block for an FFS filesystem.
|
* Super block for an FFS filesystem.
|
||||||
*/
|
*/
|
||||||
@ -340,10 +368,7 @@ struct fs {
|
|||||||
/* these fields retain the current block allocation info */
|
/* these fields retain the current block allocation info */
|
||||||
int32_t fs_cgrotor; /* last cg searched */
|
int32_t fs_cgrotor; /* last cg searched */
|
||||||
void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */
|
void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */
|
||||||
u_int8_t *fs_contigdirs; /* (u) # of contig. allocated dirs */
|
struct fs_summary_info *fs_si;/* In-core pointer to summary info */
|
||||||
struct csum *fs_csp; /* (u) cg summary info buffer */
|
|
||||||
int32_t *fs_maxcluster; /* (u) max cluster in each cyl group */
|
|
||||||
u_int *fs_active; /* (u) used by snapshots to track fs */
|
|
||||||
int32_t fs_old_cpc; /* cyl per cycle in postbl */
|
int32_t fs_old_cpc; /* cyl per cycle in postbl */
|
||||||
int32_t fs_maxbsize; /* maximum blocking factor permitted */
|
int32_t fs_maxbsize; /* maximum blocking factor permitted */
|
||||||
int64_t fs_unrefs; /* number of unreferenced inodes */
|
int64_t fs_unrefs; /* number of unreferenced inodes */
|
||||||
|
@ -53,6 +53,9 @@ fstyp_ufs(FILE *fp, char *label, size_t labelsize)
|
|||||||
switch (sbget(fileno(fp), &fs, STDSB)) {
|
switch (sbget(fileno(fp), &fs, STDSB)) {
|
||||||
case 0:
|
case 0:
|
||||||
strlcpy(label, fs->fs_volname, labelsize);
|
strlcpy(label, fs->fs_volname, labelsize);
|
||||||
|
free(fs->fs_csp);
|
||||||
|
free(fs->fs_si);
|
||||||
|
free(fs);
|
||||||
return (0);
|
return (0);
|
||||||
case ENOENT:
|
case ENOENT:
|
||||||
/* Cannot find file system superblock */
|
/* Cannot find file system superblock */
|
||||||
|
@ -567,6 +567,9 @@ quot(char *name, char *mp)
|
|||||||
printf(" (%s)",mp);
|
printf(" (%s)",mp);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
(*func)(fd, fs, name);
|
(*func)(fd, fs, name);
|
||||||
|
free(fs->fs_csp);
|
||||||
|
free(fs->fs_si);
|
||||||
|
free(fs);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user