Add gjournal specific code to the UFS file system:
- Add FS_GJOURNAL flag which enables gjournal support on a file system. - Add cg_unrefs field to the cylinder group structure which holds number of unreferenced (orphaned) inodes in the given cylinder group. - Add fs_unrefs field to the super block structure which holds total number of unreferenced (orphaned) inodes. - When file or a directory is orphaned (last reference is removed, but object is still open), increase fs_unrefs and cg_unrefs fields, which is a hint for fsck in which cylinder groups looks for such (orphaned) objects. - When file is last closed, decrease {fs,cg}_unrefs fields. - Add VV_DELETED vnode flag which points at orphaned objects. Sponsored by: home.pl
This commit is contained in:
parent
99eebd2a7c
commit
1a60c7fc8e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=163841
@ -2530,6 +2530,8 @@ vn_printf(struct vnode *vp, const char *fmt, ...)
|
||||
strcat(buf, "|VV_TEXT");
|
||||
if (vp->v_vflag & VV_SYSTEM)
|
||||
strcat(buf, "|VV_SYSTEM");
|
||||
if (vp->v_vflag & VV_DELETED)
|
||||
strcat(buf, "|VV_DELETED");
|
||||
if (vp->v_iflag & VI_DOOMED)
|
||||
strcat(buf, "|VI_DOOMED");
|
||||
if (vp->v_iflag & VI_FREE)
|
||||
|
@ -253,6 +253,7 @@ struct xvnode {
|
||||
#define VV_SYSTEM 0x0080 /* vnode being used by kernel */
|
||||
#define VV_PROCDEP 0x0100 /* vnode is process dependent */
|
||||
#define VV_NOKNOTE 0x0200 /* don't activate knotes on this vnode */
|
||||
#define VV_DELETED 0x0400 /* should be removed */
|
||||
|
||||
/*
|
||||
* Vnode attributes. A field value of VNOVAL represents a field whose value
|
||||
|
@ -72,6 +72,7 @@ int ffs_mountroot(void);
|
||||
int ffs_reallocblks(struct vop_reallocblks_args *);
|
||||
int ffs_realloccg(struct inode *, ufs2_daddr_t, ufs2_daddr_t,
|
||||
ufs2_daddr_t, int, int, struct ucred *, struct buf **);
|
||||
int ffs_sbupdate(struct ufsmount *, int, int);
|
||||
void ffs_setblock(struct fs *, u_char *, ufs1_daddr_t);
|
||||
int ffs_snapblkfree(struct fs *, struct vnode *, ufs2_daddr_t, long, ino_t);
|
||||
void ffs_snapremove(struct vnode *vp);
|
||||
|
@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <security/mac/mac_framework.h>
|
||||
|
||||
#include <ufs/ufs/extattr.h>
|
||||
#include <ufs/ufs/gjournal.h>
|
||||
#include <ufs/ufs/quota.h>
|
||||
#include <ufs/ufs/ufsmount.h>
|
||||
#include <ufs/ufs/inode.h>
|
||||
@ -71,7 +72,6 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
static uma_zone_t uma_inode, uma_ufs1, uma_ufs2;
|
||||
|
||||
static int ffs_sbupdate(struct ufsmount *, int, int);
|
||||
static int ffs_reload(struct mount *, struct thread *);
|
||||
static int ffs_mountfs(struct vnode *, struct mount *, struct thread *);
|
||||
static void ffs_oldfscompat_read(struct fs *, struct ufsmount *,
|
||||
@ -696,6 +696,35 @@ ffs_mountfs(devvp, mp, td)
|
||||
fs->fs_pendingblocks = 0;
|
||||
fs->fs_pendinginodes = 0;
|
||||
}
|
||||
if ((fs->fs_flags & FS_GJOURNAL) != 0) {
|
||||
#ifdef UFS_GJOURNAL
|
||||
/*
|
||||
* Get journal provider name.
|
||||
*/
|
||||
size = 1024;
|
||||
mp->mnt_gjprovider = malloc(size, M_UFSMNT, M_WAITOK);
|
||||
if (g_io_getattr("GJOURNAL::provider", cp, &size,
|
||||
mp->mnt_gjprovider) == 0) {
|
||||
mp->mnt_gjprovider = realloc(mp->mnt_gjprovider, size,
|
||||
M_UFSMNT, M_WAITOK);
|
||||
MNT_ILOCK(mp);
|
||||
mp->mnt_flag |= MNT_GJOURNAL;
|
||||
MNT_IUNLOCK(mp);
|
||||
} else {
|
||||
printf(
|
||||
"WARNING: %s: GJOURNAL flag on fs but no gjournal provider below\n",
|
||||
mp->mnt_stat.f_mntonname);
|
||||
free(mp->mnt_gjprovider, M_UFSMNT);
|
||||
mp->mnt_gjprovider = NULL;
|
||||
}
|
||||
#else
|
||||
printf(
|
||||
"WARNING: %s: GJOURNAL flag on fs but no UFS_GJOURNAL support\n",
|
||||
mp->mnt_stat.f_mntonname);
|
||||
#endif
|
||||
} else {
|
||||
mp->mnt_gjprovider = NULL;
|
||||
}
|
||||
ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO);
|
||||
ump->um_cp = cp;
|
||||
ump->um_bo = &devvp->v_bufobj;
|
||||
@ -871,6 +900,10 @@ ffs_mountfs(devvp, mp, td)
|
||||
}
|
||||
if (ump) {
|
||||
mtx_destroy(UFS_MTX(ump));
|
||||
if (mp->mnt_gjprovider != NULL) {
|
||||
free(mp->mnt_gjprovider, M_UFSMNT);
|
||||
mp->mnt_gjprovider = NULL;
|
||||
}
|
||||
free(ump->um_fs, M_UFSMNT);
|
||||
free(ump, M_UFSMNT);
|
||||
mp->mnt_data = (qaddr_t)0;
|
||||
@ -1030,6 +1063,10 @@ ffs_unmount(mp, mntflags, td)
|
||||
PICKUP_GIANT();
|
||||
vrele(ump->um_devvp);
|
||||
mtx_destroy(UFS_MTX(ump));
|
||||
if (mp->mnt_gjprovider != NULL) {
|
||||
free(mp->mnt_gjprovider, M_UFSMNT);
|
||||
mp->mnt_gjprovider = NULL;
|
||||
}
|
||||
free(fs->fs_csp, M_UFSMNT);
|
||||
free(fs, M_UFSMNT);
|
||||
free(ump, M_UFSMNT);
|
||||
@ -1514,7 +1551,7 @@ ffs_uninit(vfsp)
|
||||
/*
|
||||
* Write a superblock and associated information back to disk.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
ffs_sbupdate(mp, waitfor, suspended)
|
||||
struct ufsmount *mp;
|
||||
int waitfor;
|
||||
|
@ -323,7 +323,8 @@ struct fs {
|
||||
u_int *fs_active; /* (u) used by snapshots to track fs */
|
||||
int32_t fs_old_cpc; /* cyl per cycle in postbl */
|
||||
int32_t fs_maxbsize; /* maximum blocking factor permitted */
|
||||
int64_t fs_sparecon64[17]; /* old rotation block list head */
|
||||
int64_t fs_unrefs; /* number of unreferenced inodes */
|
||||
int64_t fs_sparecon64[16]; /* old rotation block list head */
|
||||
int64_t fs_sblockloc; /* byte offset of standard superblock */
|
||||
struct csum_total fs_cstotal; /* (u) cylinder summary information */
|
||||
ufs_time_t fs_time; /* last time written */
|
||||
@ -406,6 +407,7 @@ CTASSERT(sizeof(struct fs) == 1376);
|
||||
#define FS_INDEXDIRS 0x08 /* kernel supports indexed directories */
|
||||
#define FS_ACLS 0x10 /* file system has ACLs enabled */
|
||||
#define FS_MULTILABEL 0x20 /* file system is MAC multi-label */
|
||||
#define FS_GJOURNAL 0x40 /* gjournaled file system */
|
||||
#define FS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */
|
||||
|
||||
/*
|
||||
@ -475,7 +477,8 @@ struct cg {
|
||||
int32_t cg_nclusterblks; /* number of clusters this cg */
|
||||
int32_t cg_niblk; /* number of inode blocks this cg */
|
||||
int32_t cg_initediblk; /* last initialized inode */
|
||||
int32_t cg_sparecon32[3]; /* reserved for future use */
|
||||
int32_t cg_unrefs; /* number of unreferenced inodes */
|
||||
int32_t cg_sparecon32[2]; /* reserved for future use */
|
||||
ufs_time_t cg_time; /* time last written */
|
||||
int64_t cg_sparecon64[3]; /* reserved for future use */
|
||||
u_int8_t cg_space[1]; /* space for cylinder group maps */
|
||||
|
37
sys/ufs/ufs/gjournal.h
Normal file
37
sys/ufs/ufs/gjournal.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*-
|
||||
* Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _UFS_UFS_GJOURNAL_H_
|
||||
#define _UFS_UFS_GJOURNAL_H_
|
||||
|
||||
/*
|
||||
* GEOM journal function prototypes.
|
||||
*/
|
||||
void ufs_gjournal_orphan(struct vnode *fvp);
|
||||
void ufs_gjournal_close(struct vnode *vp);
|
||||
#endif /* !_UFS_UFS_GJOURNAL_H_ */
|
150
sys/ufs/ufs/ufs_gjournal.c
Normal file
150
sys/ufs/ufs/ufs_gjournal.c
Normal file
@ -0,0 +1,150 @@
|
||||
/*-
|
||||
* Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_ufs.h"
|
||||
|
||||
#ifdef UFS_GJOURNAL
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mutex.h>
|
||||
|
||||
#include <ufs/ufs/extattr.h>
|
||||
#include <ufs/ufs/quota.h>
|
||||
#include <ufs/ufs/inode.h>
|
||||
#include <ufs/ufs/ufsmount.h>
|
||||
#include <ufs/ufs/gjournal.h>
|
||||
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <ufs/ffs/ffs_extern.h>
|
||||
|
||||
/*
|
||||
* Change the number of unreferenced inodes.
|
||||
*/
|
||||
static int
|
||||
ufs_gjournal_modref(struct vnode *vp, int count)
|
||||
{
|
||||
struct cg *cgp;
|
||||
struct buf *bp;
|
||||
ufs2_daddr_t cgbno;
|
||||
int error, cg;
|
||||
struct cdev *dev;
|
||||
struct inode *ip;
|
||||
struct ufsmount *ump;
|
||||
struct fs *fs;
|
||||
struct vnode *devvp;
|
||||
ino_t ino;
|
||||
|
||||
ip = VTOI(vp);
|
||||
ump = ip->i_ump;
|
||||
fs = ip->i_fs;
|
||||
devvp = ip->i_devvp;
|
||||
ino = ip->i_number;
|
||||
|
||||
cg = ino_to_cg(fs, ino);
|
||||
if (devvp->v_type != VCHR) {
|
||||
/* devvp is a snapshot */
|
||||
dev = VTOI(devvp)->i_devvp->v_rdev;
|
||||
cgbno = fragstoblks(fs, cgtod(fs, cg));
|
||||
} else {
|
||||
/* devvp is a normal disk device */
|
||||
dev = devvp->v_rdev;
|
||||
cgbno = fsbtodb(fs, cgtod(fs, cg));
|
||||
}
|
||||
if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg)
|
||||
panic("ffs_freefile: range: dev = %s, ino = %lu, fs = %s",
|
||||
devtoname(dev), (u_long)ino, fs->fs_fsmnt);
|
||||
if ((error = bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp))) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
cgp = (struct cg *)bp->b_data;
|
||||
if (!cg_chkmagic(cgp)) {
|
||||
brelse(bp);
|
||||
return (0);
|
||||
}
|
||||
bp->b_xflags |= BX_BKGRDWRITE;
|
||||
cgp->cg_unrefs += count;
|
||||
UFS_LOCK(ump);
|
||||
fs->fs_unrefs += count;
|
||||
fs->fs_fmod = 1;
|
||||
ACTIVECLEAR(fs, cg);
|
||||
UFS_UNLOCK(ump);
|
||||
bdwrite(bp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ufs_gjournal_orphan(struct vnode *fvp)
|
||||
{
|
||||
struct mount *mp;
|
||||
struct inode *ip;
|
||||
|
||||
mp = fvp->v_mount;
|
||||
if (mp->mnt_gjprovider == NULL)
|
||||
return;
|
||||
VI_LOCK(fvp);
|
||||
if (fvp->v_usecount < 2 || (fvp->v_vflag & VV_DELETED)) {
|
||||
VI_UNLOCK(fvp);
|
||||
return;
|
||||
}
|
||||
ip = VTOI(fvp);
|
||||
if ((fvp->v_type == VDIR && ip->i_nlink > 2) ||
|
||||
(fvp->v_type != VDIR && ip->i_nlink > 1)) {
|
||||
VI_UNLOCK(fvp);
|
||||
return;
|
||||
}
|
||||
fvp->v_vflag |= VV_DELETED;
|
||||
VI_UNLOCK(fvp);
|
||||
|
||||
ufs_gjournal_modref(fvp, 1);
|
||||
}
|
||||
|
||||
void
|
||||
ufs_gjournal_close(struct vnode *vp)
|
||||
{
|
||||
struct mount *mp;
|
||||
struct inode *ip;
|
||||
|
||||
mp = vp->v_mount;
|
||||
if (mp->mnt_gjprovider == NULL)
|
||||
return;
|
||||
if (!(vp->v_vflag & VV_DELETED))
|
||||
return;
|
||||
ip = VTOI(vp);
|
||||
if (ip->i_nlink > 0)
|
||||
return;
|
||||
ufs_gjournal_modref(vp, -1);
|
||||
}
|
||||
|
||||
#endif /* UFS_GJOURNAL */
|
@ -57,6 +57,9 @@ __FBSDID("$FreeBSD$");
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ufs/dirhash.h>
|
||||
#endif
|
||||
#ifdef UFS_GJOURNAL
|
||||
#include <ufs/ufs/gjournal.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Last reference to an inode. If necessary, write or delete it.
|
||||
@ -83,6 +86,9 @@ ufs_inactive(ap)
|
||||
*/
|
||||
if (ip->i_mode == 0)
|
||||
goto out;
|
||||
#ifdef UFS_GJOURNAL
|
||||
ufs_gjournal_close(vp);
|
||||
#endif
|
||||
if ((ip->i_effnlink == 0 && DOINGSOFTDEP(vp)) ||
|
||||
(ip->i_nlink <= 0 &&
|
||||
(vp->v_mount->mnt_flag & MNT_RDONLY) == 0)) {
|
||||
|
@ -83,6 +83,9 @@ __FBSDID("$FreeBSD$");
|
||||
#ifdef UFS_DIRHASH
|
||||
#include <ufs/ufs/dirhash.h>
|
||||
#endif
|
||||
#ifdef UFS_GJOURNAL
|
||||
#include <ufs/ufs/gjournal.h>
|
||||
#endif
|
||||
|
||||
#include <ufs/ffs/ffs_extern.h>
|
||||
|
||||
@ -803,6 +806,9 @@ ufs_remove(ap)
|
||||
error = EPERM;
|
||||
goto out;
|
||||
}
|
||||
#ifdef UFS_GJOURNAL
|
||||
ufs_gjournal_orphan(vp);
|
||||
#endif
|
||||
error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
|
||||
if (ip->i_nlink <= 0)
|
||||
vp->v_vflag |= VV_NOSYNC;
|
||||
@ -1709,6 +1715,9 @@ ufs_rmdir(ap)
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
#ifdef UFS_GJOURNAL
|
||||
ufs_gjournal_orphan(vp);
|
||||
#endif
|
||||
/*
|
||||
* Delete reference to directory before purging
|
||||
* inode. If we crash in between, the directory
|
||||
|
Loading…
Reference in New Issue
Block a user