Retire LFS.

If you want to play with it, you can find the final version of the
code in the repository the tag LFS_RETIREMENT.

If somebody makes LFS work again, adding it back is certainly
desireable, but as it is now nobody seems to care much about it,
and it has suffered considerable bitrot since its somewhat haphazard
integration.

R.I.P
This commit is contained in:
Poul-Henning Kamp 1998-01-30 11:34:06 +00:00
parent 0621c31aaf
commit c5b193bfba
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=32889
36 changed files with 47 additions and 5232 deletions

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91
* $Id: autoconf.c,v 1.83 1998/01/09 03:20:53 eivind Exp $
* $Id: autoconf.c,v 1.84 1998/01/24 02:54:12 eivind Exp $
*/
/*
@ -48,7 +48,6 @@
#include "opt_bootp.h"
#include "opt_ffs.h"
#include "opt_cd9660.h"
#include "opt_lfs.h"
#include "opt_mfs.h"
#include "opt_nfs.h"
@ -370,24 +369,6 @@ cpu_rootconf()
}
#endif
#if defined(LFS) || defined(LFS_ROOT)
if (!mountrootfsname) {
if (bootverbose)
printf("Considering LFS root f/s.\n");
mountrootfsname = "lfs";
/*
* Ignore the -a flag if this kernel isn't compiled
* with a generic root/swap configuration: if we skip
* setroot() and we aren't a generic kernel, chaos
* will ensue because setconf() will be a no-op.
* (rootdev is always initialized to NODEV in a
* generic configuration, so we test for that.)
*/
if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
setroot();
}
#endif
if (!mountrootfsname) {
panic("Nobody wants to mount my root for me");
}

View File

@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
# $Id: LINT,v 1.395 1998/01/25 03:55:47 eivind Exp $
# $Id: LINT,v 1.396 1998/01/26 06:33:48 julian Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@ -424,11 +424,11 @@ options TCPDEBUG
#
# Only the root, /usr, and /tmp filesystems need be statically
# compiled; everything else will be automatically loaded at mount
# time. (Exception: the UFS family---FFS, MFS, and LFS---cannot
# time. (Exception: the UFS family---FFS, and MFS --- cannot
# currently be demand-loaded.) Some people still prefer to statically
# compile other filesystems as well.
#
# NB: The LFS, PORTAL, and UNION filesystems are known to be buggy,
# NB: The PORTAL, and UNION filesystems are known to be buggy,
# and WILL panic your system if you attempt to do anything with them.
# They are included here as an incentive for some enterprising soul to
# sit down and fix them.
@ -443,7 +443,6 @@ options NFS #Network File System
options "CD9660" #ISO 9660 filesystem
options FDESC #File descriptor filesystem
options KERNFS #Kernel filesystem
#options LFS #Log filesystem
options MFS #Memory File System
options MSDOSFS #MS DOS File System
options NULLFS #NULL filesystem
@ -453,7 +452,6 @@ options UMAPFS #UID map filesystem
options UNION #Union filesystem
options "CD9660_ROOT" #CD-ROM usable as root device
options FFS_ROOT #FFS usable as root device
#options LFS_ROOT #LFS usable as root device
options NFS_ROOT #NFS usable as root device
# This DEVFS is experimental but seems to work
options DEVFS #devices filesystem

View File

@ -412,17 +412,6 @@ ufs/ffs/ffs_vfsops.c optional ffs
ufs/ffs/ffs_vfsops.c optional mfs
ufs/ffs/ffs_vnops.c optional ffs
ufs/ffs/ffs_vnops.c optional mfs
ufs/lfs/lfs_alloc.c optional lfs
ufs/lfs/lfs_balloc.c optional lfs
ufs/lfs/lfs_bio.c optional lfs
ufs/lfs/lfs_cksum.c optional lfs
ufs/lfs/lfs_debug.c optional lfs
ufs/lfs/lfs_inode.c optional lfs
ufs/lfs/lfs_segment.c optional lfs
ufs/lfs/lfs_subr.c optional lfs
ufs/lfs/lfs_syscalls.c optional lfs
ufs/lfs/lfs_vfsops.c optional lfs
ufs/lfs/lfs_vnops.c optional lfs
ufs/mfs/mfs_vfsops.c optional mfs
ufs/mfs/mfs_vnops.c optional mfs
ufs/ufs/ufs_bmap.c standard

View File

@ -1,4 +1,4 @@
# $Id: options,v 1.49 1998/01/25 04:23:29 eivind Exp $
# $Id: options,v 1.50 1998/01/26 18:31:18 julian Exp $
# Format:
# Option name filename
@ -48,7 +48,6 @@ UMAPFS opt_dontuse.h
# unavailable for the LKM-based versions.
CD9660
FFS
LFS
NFS
# The above static dependencies are planned removed, with a
@ -57,7 +56,6 @@ NFS
# they won't make any difference yet).
CD9660_ROOT opt_cd9660.h
FFS_ROOT opt_ffs.h
LFS_ROOT opt_lfs.h
NFS_ROOT opt_nfs.h
# Multi-session CD-Rs might require a huge amount of time in order to

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)ufsmount.h 8.6 (Berkeley) 3/30/95
* $Id: ufsmount.h,v 1.11 1997/10/16 10:50:27 phk Exp $
* $Id: ufsmount.h,v 1.12 1997/10/16 20:32:40 phk Exp $
*/
#ifndef _UFS_UFS_UFSMOUNT_H_
@ -77,12 +77,10 @@ struct ufsmount {
struct vnode *um_devvp; /* block device mounted vnode */
union { /* pointer to superblock */
struct lfs *lfs; /* LFS */
struct fs *fs; /* FFS */
struct ext2_sb_info *e2fs; /* EXT2FS */
} ufsmount_u;
#define um_fs ufsmount_u.fs
#define um_lfs ufsmount_u.lfs
#define um_e2fs ufsmount_u.e2fs
#define um_e2fsb ufsmount_u.e2fs->s_es

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)inode.h 8.9 (Berkeley) 5/14/95
* $Id: inode.h,v 1.18 1997/10/17 12:36:19 phk Exp $
* $Id: inode.h,v 1.19 1997/12/05 13:43:47 jkh Exp $
*/
#ifndef _UFS_UFS_INODE_H_
@ -70,11 +70,9 @@ struct inode {
union { /* Associated filesystem. */
struct fs *fs; /* FFS */
struct lfs *lfs; /* LFS */
struct ext2_sb_info *e2fs; /* EXT2FS */
} inode_u;
#define i_fs inode_u.fs
#define i_lfs inode_u.lfs
#define i_e2fs inode_u.e2fs
struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
u_quad_t i_modrev; /* Revision level for NFS lease. */

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)ufsmount.h 8.6 (Berkeley) 3/30/95
* $Id: ufsmount.h,v 1.11 1997/10/16 10:50:27 phk Exp $
* $Id: ufsmount.h,v 1.12 1997/10/16 20:32:40 phk Exp $
*/
#ifndef _UFS_UFS_UFSMOUNT_H_
@ -77,12 +77,10 @@ struct ufsmount {
struct vnode *um_devvp; /* block device mounted vnode */
union { /* pointer to superblock */
struct lfs *lfs; /* LFS */
struct fs *fs; /* FFS */
struct ext2_sb_info *e2fs; /* EXT2FS */
} ufsmount_u;
#define um_fs ufsmount_u.fs
#define um_lfs ufsmount_u.lfs
#define um_e2fs ufsmount_u.e2fs
#define um_e2fsb ufsmount_u.e2fs->s_es

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)inode.h 8.9 (Berkeley) 5/14/95
* $Id: inode.h,v 1.18 1997/10/17 12:36:19 phk Exp $
* $Id: inode.h,v 1.19 1997/12/05 13:43:47 jkh Exp $
*/
#ifndef _UFS_UFS_INODE_H_
@ -70,11 +70,9 @@ struct inode {
union { /* Associated filesystem. */
struct fs *fs; /* FFS */
struct lfs *lfs; /* LFS */
struct ext2_sb_info *e2fs; /* EXT2FS */
} inode_u;
#define i_fs inode_u.fs
#define i_lfs inode_u.lfs
#define i_e2fs inode_u.e2fs
struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
u_quad_t i_modrev; /* Revision level for NFS lease. */

View File

@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
# $Id: LINT,v 1.395 1998/01/25 03:55:47 eivind Exp $
# $Id: LINT,v 1.396 1998/01/26 06:33:48 julian Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@ -424,11 +424,11 @@ options TCPDEBUG
#
# Only the root, /usr, and /tmp filesystems need be statically
# compiled; everything else will be automatically loaded at mount
# time. (Exception: the UFS family---FFS, MFS, and LFS---cannot
# time. (Exception: the UFS family---FFS, and MFS --- cannot
# currently be demand-loaded.) Some people still prefer to statically
# compile other filesystems as well.
#
# NB: The LFS, PORTAL, and UNION filesystems are known to be buggy,
# NB: The PORTAL, and UNION filesystems are known to be buggy,
# and WILL panic your system if you attempt to do anything with them.
# They are included here as an incentive for some enterprising soul to
# sit down and fix them.
@ -443,7 +443,6 @@ options NFS #Network File System
options "CD9660" #ISO 9660 filesystem
options FDESC #File descriptor filesystem
options KERNFS #Kernel filesystem
#options LFS #Log filesystem
options MFS #Memory File System
options MSDOSFS #MS DOS File System
options NULLFS #NULL filesystem
@ -453,7 +452,6 @@ options UMAPFS #UID map filesystem
options UNION #Union filesystem
options "CD9660_ROOT" #CD-ROM usable as root device
options FFS_ROOT #FFS usable as root device
#options LFS_ROOT #LFS usable as root device
options NFS_ROOT #NFS usable as root device
# This DEVFS is experimental but seems to work
options DEVFS #devices filesystem

View File

@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
# $Id: LINT,v 1.395 1998/01/25 03:55:47 eivind Exp $
# $Id: LINT,v 1.396 1998/01/26 06:33:48 julian Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@ -424,11 +424,11 @@ options TCPDEBUG
#
# Only the root, /usr, and /tmp filesystems need be statically
# compiled; everything else will be automatically loaded at mount
# time. (Exception: the UFS family---FFS, MFS, and LFS---cannot
# time. (Exception: the UFS family---FFS, and MFS --- cannot
# currently be demand-loaded.) Some people still prefer to statically
# compile other filesystems as well.
#
# NB: The LFS, PORTAL, and UNION filesystems are known to be buggy,
# NB: The PORTAL, and UNION filesystems are known to be buggy,
# and WILL panic your system if you attempt to do anything with them.
# They are included here as an incentive for some enterprising soul to
# sit down and fix them.
@ -443,7 +443,6 @@ options NFS #Network File System
options "CD9660" #ISO 9660 filesystem
options FDESC #File descriptor filesystem
options KERNFS #Kernel filesystem
#options LFS #Log filesystem
options MFS #Memory File System
options MSDOSFS #MS DOS File System
options NULLFS #NULL filesystem
@ -453,7 +452,6 @@ options UMAPFS #UID map filesystem
options UNION #Union filesystem
options "CD9660_ROOT" #CD-ROM usable as root device
options FFS_ROOT #FFS usable as root device
#options LFS_ROOT #LFS usable as root device
options NFS_ROOT #NFS usable as root device
# This DEVFS is experimental but seems to work
options DEVFS #devices filesystem

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91
* $Id: autoconf.c,v 1.83 1998/01/09 03:20:53 eivind Exp $
* $Id: autoconf.c,v 1.84 1998/01/24 02:54:12 eivind Exp $
*/
/*
@ -48,7 +48,6 @@
#include "opt_bootp.h"
#include "opt_ffs.h"
#include "opt_cd9660.h"
#include "opt_lfs.h"
#include "opt_mfs.h"
#include "opt_nfs.h"
@ -370,24 +369,6 @@ cpu_rootconf()
}
#endif
#if defined(LFS) || defined(LFS_ROOT)
if (!mountrootfsname) {
if (bootverbose)
printf("Considering LFS root f/s.\n");
mountrootfsname = "lfs";
/*
* Ignore the -a flag if this kernel isn't compiled
* with a generic root/swap configuration: if we skip
* setroot() and we aren't a generic kernel, chaos
* will ensue because setconf() will be a no-op.
* (rootdev is always initialized to NODEV in a
* generic configuration, so we test for that.)
*/
if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
setroot();
}
#endif
if (!mountrootfsname) {
panic("Nobody wants to mount my root for me");
}

View File

@ -39,7 +39,7 @@
* SUCH DAMAGE.
*
* @(#)init_main.c 8.9 (Berkeley) 1/21/94
* $Id: init_main.c,v 1.79 1997/12/14 02:10:12 dyson Exp $
* $Id: init_main.c,v 1.80 1998/01/22 17:29:44 dyson Exp $
*/
#include "opt_devfs.h"
@ -139,8 +139,7 @@ SYSINIT(placeholder, SI_SUB_DUMMY,SI_ORDER_ANY, NULL, NULL)
* This allows simple addition of new kernel subsystems that require
* boot time initialization. It also allows substitution of subsystem
* (for instance, a scheduler, kernel profiler, or VM system) by object
* module. Finally, it allows for optional "kernel threads", like an LFS
* cleaner.
* module. Finally, it allows for optional "kernel threads".
*/
void
main(framep)

View File

@ -2,7 +2,7 @@
* System call switch table.
*
* DO NOT EDIT-- this file is automatically generated.
* created from Id: syscalls.master,v 1.44 1997/10/26 20:27:51 phk Exp
* created from Id: syscalls.master,v 1.46 1998/01/24 02:54:35 eivind Exp
*/
#include "opt_compat.h"
@ -203,17 +203,10 @@ struct sysent sysent[] = {
{ 1, (sy_call_t *)setgid }, /* 181 = setgid */
{ 1, (sy_call_t *)setegid }, /* 182 = setegid */
{ 1, (sy_call_t *)seteuid }, /* 183 = seteuid */
#ifdef LFS
{ 3, (sy_call_t *)lfs_bmapv }, /* 184 = lfs_bmapv */
{ 3, (sy_call_t *)lfs_markv }, /* 185 = lfs_markv */
{ 2, (sy_call_t *)lfs_segclean }, /* 186 = lfs_segclean */
{ 2, (sy_call_t *)lfs_segwait }, /* 187 = lfs_segwait */
#else
{ 0, (sy_call_t *)nosys }, /* 184 = nosys */
{ 0, (sy_call_t *)nosys }, /* 185 = nosys */
{ 0, (sy_call_t *)nosys }, /* 186 = nosys */
{ 0, (sy_call_t *)nosys }, /* 187 = nosys */
#endif
{ 0, (sy_call_t *)nosys }, /* 184 = lfs_bmapv */
{ 0, (sy_call_t *)nosys }, /* 185 = lfs_markv */
{ 0, (sy_call_t *)nosys }, /* 186 = lfs_segclean */
{ 0, (sy_call_t *)nosys }, /* 187 = lfs_segwait */
{ 2, (sy_call_t *)stat }, /* 188 = stat */
{ 2, (sy_call_t *)fstat }, /* 189 = fstat */
{ 2, (sy_call_t *)lstat }, /* 190 = lstat */

View File

@ -2,7 +2,7 @@
* System call names.
*
* DO NOT EDIT-- this file is automatically generated.
* created from Id: syscalls.master,v 1.44 1997/10/26 20:27:51 phk Exp
* created from Id: syscalls.master,v 1.46 1998/01/24 02:54:35 eivind Exp
*/
char *syscallnames[] = {
@ -190,17 +190,10 @@ char *syscallnames[] = {
"setgid", /* 181 = setgid */
"setegid", /* 182 = setegid */
"seteuid", /* 183 = seteuid */
#ifdef LFS
"lfs_bmapv", /* 184 = lfs_bmapv */
"lfs_markv", /* 185 = lfs_markv */
"lfs_segclean", /* 186 = lfs_segclean */
"lfs_segwait", /* 187 = lfs_segwait */
#else
"#184", /* 184 = nosys */
"#185", /* 185 = nosys */
"#186", /* 186 = nosys */
"#187", /* 187 = nosys */
#endif
"#184", /* 184 = lfs_bmapv */
"#185", /* 185 = lfs_markv */
"#186", /* 186 = lfs_segclean */
"#187", /* 187 = lfs_segwait */
"stat", /* 188 = stat */
"fstat", /* 189 = fstat */
"lstat", /* 190 = lstat */

View File

@ -1,4 +1,4 @@
$Id: syscalls.master,v 1.45 1998/01/01 17:07:46 alex Exp $
$Id: syscalls.master,v 1.46 1998/01/24 02:54:35 eivind Exp $
; from: @(#)syscalls.master 8.2 (Berkeley) 1/13/94
;
; System call name/number master file.
@ -24,8 +24,6 @@
; #ifdef's, etc. may be included, and are copied to the output files.
#include "opt_lfs.h"
#include <sys/param.h>
#include <sys/sysent.h>
#include <sys/sysproto.h>
@ -280,21 +278,10 @@
181 STD POSIX { int setgid(gid_t gid); }
182 STD BSD { int setegid(gid_t egid); }
183 STD BSD { int seteuid(uid_t euid); }
#ifdef LFS
184 STD BSD { int lfs_bmapv(struct fsid **fsidp, \
struct block_info *blkiov, int blkcnt); }
185 STD BSD { int lfs_markv(struct fsid **fsidp, \
struct block_info *blkiov, int blkcnt); }
186 STD BSD { int lfs_segclean(struct fsid **fsidp, \
u_long segment); }
187 STD BSD { int lfs_segwait(struct fsid **fsidp, \
struct timeval *tv); }
#else
184 UNIMPL BSD nosys
185 UNIMPL BSD nosys
186 UNIMPL BSD nosys
187 UNIMPL BSD nosys
#endif
184 UNIMPL BSD lfs_bmapv
185 UNIMPL BSD lfs_markv
186 UNIMPL BSD lfs_segclean
187 UNIMPL BSD lfs_segwait
188 STD POSIX { int stat(char *path, struct stat *ub); }
189 STD POSIX { int fstat(int fd, struct stat *sb); }
190 STD POSIX { int lstat(char *path, struct stat *ub); }

View File

@ -2,7 +2,7 @@
* System call hiders.
*
* DO NOT EDIT-- this file is automatically generated.
* created from Id: syscalls.master,v 1.44 1997/10/26 20:27:51 phk Exp
* created from Id: syscalls.master,v 1.46 1998/01/24 02:54:35 eivind Exp
*/
HIDE_POSIX(fork)
@ -162,17 +162,10 @@ HIDE_BSD(ntp_adjtime)
HIDE_POSIX(setgid)
HIDE_BSD(setegid)
HIDE_BSD(seteuid)
#ifdef LFS
HIDE_BSD(lfs_bmapv)
HIDE_BSD(lfs_markv)
HIDE_BSD(lfs_segclean)
HIDE_BSD(lfs_segwait)
#else
HIDE_BSD(nosys)
HIDE_BSD(nosys)
HIDE_BSD(nosys)
HIDE_BSD(nosys)
#endif
HIDE_POSIX(stat)
HIDE_POSIX(fstat)
HIDE_POSIX(lstat)

View File

@ -2,7 +2,7 @@
* System call numbers.
*
* DO NOT EDIT-- this file is automatically generated.
* created from Id: syscalls.master,v 1.44 1997/10/26 20:27:51 phk Exp
* created from Id: syscalls.master,v 1.46 1998/01/24 02:54:35 eivind Exp
*/
#define SYS_syscall 0
@ -170,10 +170,6 @@
#define SYS_setgid 181
#define SYS_setegid 182
#define SYS_seteuid 183
#define SYS_lfs_bmapv 184
#define SYS_lfs_markv 185
#define SYS_lfs_segclean 186
#define SYS_lfs_segwait 187
#define SYS_stat 188
#define SYS_fstat 189
#define SYS_lstat 190

View File

@ -2,7 +2,7 @@
* System call prototypes.
*
* DO NOT EDIT-- this file is automatically generated.
* created from Id: syscalls.master,v 1.44 1997/10/26 20:27:51 phk Exp
* created from Id: syscalls.master,v 1.46 1998/01/24 02:54:35 eivind Exp
*/
#ifndef _SYS_SYSPROTO_H_
@ -246,7 +246,7 @@ struct getpagesize_args {
int dummy;
};
struct msync_args {
caddr_t addr;
void * addr;
size_t len;
int flags;
};
@ -263,16 +263,16 @@ struct ovadvise_args {
int anom;
};
struct munmap_args {
caddr_t addr;
void * addr;
size_t len;
};
struct mprotect_args {
caddr_t addr;
const void * addr;
size_t len;
int prot;
};
struct madvise_args {
caddr_t addr;
void * addr;
size_t len;
int behav;
};
@ -549,27 +549,6 @@ struct setegid_args {
struct seteuid_args {
uid_t euid;
};
#ifdef LFS
struct lfs_bmapv_args {
struct fsid ** fsidp;
struct block_info * blkiov;
int blkcnt;
};
struct lfs_markv_args {
struct fsid ** fsidp;
struct block_info * blkiov;
int blkcnt;
};
struct lfs_segclean_args {
struct fsid ** fsidp;
u_long segment;
};
struct lfs_segwait_args {
struct fsid ** fsidp;
struct timeval * tv;
};
#else
#endif
struct stat_args {
char * path;
struct stat * ub;
@ -638,11 +617,11 @@ struct sysctl_args {
size_t newlen;
};
struct mlock_args {
caddr_t addr;
const void * addr;
size_t len;
};
struct munlock_args {
caddr_t addr;
const void * addr;
size_t len;
};
struct utrace_args {
@ -736,7 +715,7 @@ struct nanosleep_args {
struct timespec * rmtp;
};
struct minherit_args {
caddr_t addr;
void * addr;
size_t len;
int inherit;
};
@ -967,13 +946,6 @@ int ntp_adjtime __P((struct proc *, struct ntp_adjtime_args *));
int setgid __P((struct proc *, struct setgid_args *));
int setegid __P((struct proc *, struct setegid_args *));
int seteuid __P((struct proc *, struct seteuid_args *));
#ifdef LFS
int lfs_bmapv __P((struct proc *, struct lfs_bmapv_args *));
int lfs_markv __P((struct proc *, struct lfs_markv_args *));
int lfs_segclean __P((struct proc *, struct lfs_segclean_args *));
int lfs_segwait __P((struct proc *, struct lfs_segwait_args *));
#else
#endif
int stat __P((struct proc *, struct stat_args *));
int fstat __P((struct proc *, struct fstat_args *));
int lstat __P((struct proc *, struct lstat_args *));
@ -1071,7 +1043,7 @@ struct getkerninfo_args {
int arg;
};
struct ommap_args {
caddr_t addr;
void * addr;
int len;
int prot;
int flags;
@ -1157,9 +1129,6 @@ struct ogetdirentries_args {
u_int count;
long * basep;
};
#ifdef LFS
#else
#endif
int ocreat __P((struct proc *, struct ocreat_args *));
int olseek __P((struct proc *, struct olseek_args *));
int ostat __P((struct proc *, struct ostat_args *));

View File

@ -1,139 +0,0 @@
# @(#)README 8.1 (Berkeley) 6/11/93
The file system is reasonably stable, but incomplete. There are
places where cleaning performance can be improved dramatically (see
comments in lfs_syscalls.c). For details on the implementation,
performance and why garbage collection always wins, see Dr. Margo
Seltzer's thesis available for anonymous ftp from toe.cs.berkeley.edu,
in the directory pub/personal/margo/thesis.ps.Z, or the January 1993
USENIX paper.
Missing Functionality:
Multiple block sizes and/or fragments are not yet implemented.
----------
The disk is laid out in segments. The first segment starts 8K into the
disk (the first 8K is used for boot information). Each segment is composed
of the following:
An optional super block
One or more groups of:
segment summary
0 or more data blocks
0 or more inode blocks
The segment summary and inode/data blocks start after the super block (if
present), and grow toward the end of the segment.
_______________________________________________
| | | | |
| summary | data/inode | summary | data/inode |
| block | blocks | block | blocks | ...
|_________|____________|_________|____________|
The data/inode blocks following a summary block are described by the
summary block. In order to permit the segment to be written in any order
and in a forward direction only, a checksum is calculated across the
blocks described by the summary. Additionally, the summary is checksummed
and timestamped. Both of these are intended for recovery; the former is
to make it easy to determine that it *is* a summary block and the latter
is to make it easy to determine when recovery is finished for partially
written segments. These checksums are also used by the cleaner.
Summary block (detail)
________________
| sum cksum |
| data cksum |
| next segment |
| timestamp |
| FINFO count |
| inode count |
| flags |
|______________|
| FINFO-1 | 0 or more file info structures, identifying the
| . | blocks in the segment.
| . |
| . |
| FINFO-N |
| inode-N |
| . |
| . |
| . | 0 or more inode daddr_t's, identifying the inode
| inode-1 | blocks in the segment.
|______________|
Inode blocks are blocks of on-disk inodes in the same format as those in
the FFS. However, spare[0] contains the inode number of the inode so we
can find a particular inode on a page. They are packed page_size /
sizeof(inode) to a block. Data blocks are exactly as in the FFS. Both
inodes and data blocks move around the file system at will.
The file system is described by a super-block which is replicated and
occurs as the first block of the first and other segments. (The maximum
number of super-blocks is MAXNUMSB). Each super-block maintains a list
of the disk addresses of all the super-blocks. The super-block maintains
a small amount of checkpoint information, essentially just enough to find
the inode for the IFILE (fs->lfs_idaddr).
The IFILE is visible in the file system, as inode number IFILE_INUM. It
contains information shared between the kernel and various user processes.
Ifile (detail)
________________
| cleaner info | Cleaner information per file system. (Page
| | granularity.)
|______________|
| segment | Space available and last modified times per
| usage table | segment. (Page granularity.)
|______________|
| IFILE-1 | Per inode status information: current version #,
| . | if currently allocated, last access time and
| . | current disk address of containing inode block.
| . | If current disk address is LFS_UNUSED_DADDR, the
| IFILE-N | inode is not in use, and it's on the free list.
|______________|
First Segment at Creation Time:
_____________________________________________________________
| | | | | | | |
| 8K pad | Super | summary | inode | ifile | root | l + f |
| | block | | block | | dir | dir |
|________|_______|_________|_______|_______|_______|_______|
^
Segment starts here.
Some differences from the Sprite LFS implementation.
1. The LFS implementation placed the ifile metadata and the super block
at fixed locations. This implementation replicates the super block
and puts each at a fixed location. The checkpoint data is divided into
two parts -- just enough information to find the IFILE is stored in
two of the super blocks, although it is not toggled between them as in
the Sprite implementation. (This was deliberate, to avoid a single
point of failure.) The remaining checkpoint information is treated as
a regular file, which means that the cleaner info, the segment usage
table and the ifile meta-data are stored in normal log segments.
(Tastes great, less filling...)
2. The segment layout is radically different in Sprite; this implementation
uses something a lot like network framing, where data/inode blocks are
written asynchronously, and a checksum is used to validate any set of
summary and data/inode blocks. Sprite writes summary blocks synchronously
after the data/inode blocks have been written and the existence of the
summary block validates the data/inode blocks. This permits us to write
everything contiguously, even partial segments and their summaries, whereas
Sprite is forced to seek (from the end of the data inode to the summary
which lives at the end of the segment). Additionally, writing the summary
synchronously should cost about 1/2 a rotation per summary.
3. Sprite LFS distinguishes between different types of blocks in the segment.
Other than inode blocks and data blocks, we don't.
4. Sprite LFS traverses the IFILE looking for free blocks. We maintain a
free list threaded through the IFILE entries.
5. The cleaner runs in user space, as opposed to kernel space. It shares
information with the kernel by reading/writing the IFILE and through
cleaner specific system calls.

View File

@ -1,116 +0,0 @@
# @(#)TODO 8.1 (Berkeley) 6/11/93
NOTE: Changed the lookup on a page of inodes to search from the back
in case the same inode gets written twice on the same page.
Make sure that if you are writing a file, but not all the blocks
make it into a single segment, that you do not write the inode in
that segment.
Keith:
Why not delete the lfs_bmapv call, just mark everything dirty
that isn't deleted/truncated? Get some numbers about
what percentage of the stuff that the cleaner thinks
might be live is live. If it's high, get rid of lfs_bmapv.
There is a nasty problem in that it may take *more* room to write
the data to clean a segment than is returned by the new segment
because of indirect blocks in segment 2 being dirtied by the data
being copied into the log from segment 1. The suggested solution
at this point is to detect it when we have no space left on the
filesystem, write the extra data into the last segment (leaving
no clean ones), make it a checkpoint and shut down the file system
for fixing by a utility reading the raw partition. Argument is
that this should never happen and is practically impossible to fix
since the cleaner would have to theoretically build a model of the
entire filesystem in memory to detect the condition occurring.
A file coalescing cleaner will help avoid the problem, and one
that reads/writes from the raw disk could fix it.
DONE Currently, inodes are being flushed to disk synchronously upon
creation -- see ufs_makeinode. However, only the inode
is flushed, the directory "name" is written using VOP_BWRITE,
so it's not synchronous. Possible solutions: 1: get some
ordering in the writes so that inode/directory entries get
stuffed into the same segment. 2: do both synchronously
3: add Mendel's information into the stream so we log
creation/deletion of inodes. 4: do some form of partial
segment when changing the inode (creation/deletion/rename).
DONE Fix i_block increment for indirect blocks.
If the file system is tar'd, extracted on top of another LFS, the
IFILE ain't worth diddly. Is the cleaner writing the IFILE?
If not, let's make it read-only.
DONE Delete unnecessary source from utils in main-line source tree.
DONE Make sure that we're counting meta blocks in the inode i_block count.
Overlap the version and nextfree fields in the IFILE
DONE Vinvalbuf (Kirk):
Why writing blocks that are no longer useful?
Are the semantics of close such that blocks have to be flushed?
How specify in the buf chain the blocks that don't need
to be written? (Different numbering of indirect blocks.)
Margo:
Change so that only search one sector of inode block file for the
inode by using sector addresses in the ifile instead of
logical disk addresses.
Fix the use of the ifile version field to use the generation
number instead.
DONE Unmount; not doing a bgetvp (VHOLD) in lfs_newbuf call.
DONE Document in the README file where the checkpoint information is
on disk.
Variable block sizes (Margo/Keith).
Switch the byte accounting to sector accounting.
DONE Check lfs.h and make sure that the #defines/structures are all
actually needed.
DONE Add a check in lfs_segment.c so that if the segment is empty,
we don't write it.
Need to keep vnode v_numoutput up to date for pending writes?
DONE USENIX paper (Carl/Margo).
Evelyn:
lfsck: If delete a file that's being executed, the version number
isn't updated, and lfsck has to figure this out; case is the same as if have an inode that no directory references,
so the file should be reattached into lost+found.
Recovery/fsck.
Carl:
Investigate: clustering of reads (if blocks in the segment are ordered,
should read them all) and writes (McVoy paper).
Investigate: should the access time be part of the IFILE:
pro: theoretically, saves disk writes
con: cacheing inodes should obviate this advantage
the IFILE is already humongous
Cleaner.
Port to OSF/1 (Carl/Keith).
Currently there's no notion of write error checking.
+ Failed data/inode writes should be rescheduled (kernel level
bad blocking).
+ Failed superblock writes should cause selection of new
superblock for checkpointing.
FUTURE FANTASIES: ============
+ unrm, versioning
+ transactions
+ extended cleaner policies (hot/cold data, data placement)
==============================
Problem with the concept of multiple buffer headers referencing the segment:
Positives:
Don't lock down 1 segment per file system of physical memory.
Don't copy from buffers to segment memory.
Don't tie down the bus to transfer 1M.
Works on controllers supporting less than large transfers.
Disk can start writing immediately instead of waiting 1/2 rotation
and the full transfer.
Negatives:
Have to do segment write then segment summary write, since the latter
is what verifies that the segment is okay. (Is there another way
to do this?)
==============================
The algorithm for selecting the disk addresses of the super-blocks
has to be available to the user program which checks the file system.
(Currently in newfs, becomes a common subroutine.)

View File

@ -1,397 +0,0 @@
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)lfs.h 8.9 (Berkeley) 5/8/95
* $Id: lfs.h,v 1.9 1997/02/22 09:47:15 peter Exp $
*/
#ifndef _UFS_LFS_LFS_H_
#define _UFS_LFS_LFS_H_
#define LFS_LABELPAD 8192 /* LFS label size */
#define LFS_SBPAD 8192 /* LFS superblock size */
/*
* XXX
* This is a kluge and NEEDS to go away.
*
* Right now, ufs code handles most of the calls for directory operations
* such as create, mkdir, link, etc. As a result VOP_UPDATE is being
* called with waitfor set (since ffs does these things synchronously).
* Since LFS does not want to do these synchronously, we treat the last
* argument to lfs_update as a set of flags. If LFS_SYNC is set, then
* the update should be synchronous, if not, do it asynchronously.
* Unfortunately, this means that LFS won't work with NFS yet because
* NFS goes through paths that will make normal calls to ufs which will
* call lfs with a last argument of 1.
*/
#define LFS_SYNC 0x02
/* On-disk and in-memory checkpoint segment usage structure. */
typedef struct segusage SEGUSE;
struct segusage {
u_int32_t su_nbytes; /* number of live bytes */
u_int32_t su_lastmod; /* SEGUSE last modified timestamp */
u_int16_t su_nsums; /* number of summaries in segment */
u_int16_t su_ninos; /* number of inode blocks in seg */
#define SEGUSE_ACTIVE 0x01 /* segment is currently being written */
#define SEGUSE_DIRTY 0x02 /* segment has data in it */
#define SEGUSE_SUPERBLOCK 0x04 /* segment contains a superblock */
u_int32_t su_flags;
};
#define SEGUPB(fs) (1 << (fs)->lfs_sushift)
#define SEGTABSIZE_SU(fs) \
(((fs)->lfs_nseg + SEGUPB(fs) - 1) >> (fs)->lfs_sushift)
/* On-disk file information. One per file with data blocks in the segment. */
typedef struct finfo FINFO;
struct finfo {
u_int32_t fi_nblocks; /* number of blocks */
u_int32_t fi_version; /* version number */
u_int32_t fi_ino; /* inode number */
u_int32_t fi_lastlength; /* length of last block in array */
ufs_daddr_t fi_blocks[1]; /* array of logical block numbers */
};
/* On-disk and in-memory super block. */
struct lfs {
#define LFS_MAGIC 0x070162
u_int32_t lfs_magic; /* magic number */
#define LFS_VERSION 1
u_int32_t lfs_version; /* version number */
u_int32_t lfs_size; /* number of blocks in fs */
u_int32_t lfs_ssize; /* number of blocks per segment */
u_int32_t lfs_dsize; /* number of disk blocks in fs */
u_int32_t lfs_bsize; /* file system block size */
u_int32_t lfs_fsize; /* size of frag blocks in fs */
u_int32_t lfs_frag; /* number of frags in a block in fs */
/* Checkpoint region. */
ino_t lfs_free; /* start of the free list */
u_int32_t lfs_bfree; /* number of free disk blocks */
u_int32_t lfs_nfiles; /* number of allocated inodes */
int32_t lfs_avail; /* blocks available for writing */
u_int32_t lfs_uinodes; /* inodes in cache not yet on disk */
ufs_daddr_t lfs_idaddr; /* inode file disk address */
ino_t lfs_ifile; /* inode file inode number */
ufs_daddr_t lfs_lastseg; /* address of last segment written */
ufs_daddr_t lfs_nextseg; /* address of next segment to write */
ufs_daddr_t lfs_curseg; /* current segment being written */
ufs_daddr_t lfs_offset; /* offset in curseg for next partial */
ufs_daddr_t lfs_lastpseg; /* address of last partial written */
u_int32_t lfs_tstamp; /* time stamp */
/* These are configuration parameters. */
u_int32_t lfs_minfree; /* minimum percentage of free blocks */
/* These fields can be computed from the others. */
u_int64_t lfs_maxfilesize; /* maximum representable file size */
u_int32_t lfs_dbpseg; /* disk blocks per segment */
u_int32_t lfs_inopb; /* inodes per block */
u_int32_t lfs_ifpb; /* IFILE entries per block */
u_int32_t lfs_sepb; /* SEGUSE entries per block */
u_int32_t lfs_nindir; /* indirect pointers per block */
u_int32_t lfs_nseg; /* number of segments */
u_int32_t lfs_nspf; /* number of sectors per fragment */
u_int32_t lfs_cleansz; /* cleaner info size in blocks */
u_int32_t lfs_segtabsz; /* segment table size in blocks */
u_int32_t lfs_segmask; /* calculate offset within a segment */
u_int32_t lfs_segshift; /* fast mult/div for segments */
u_int64_t lfs_bmask; /* calc block offset from file offset */
u_int32_t lfs_bshift; /* calc block number from file offset */
u_int64_t lfs_ffmask; /* calc frag offset from file offset */
u_int32_t lfs_ffshift; /* fast mult/div for frag from file */
u_int64_t lfs_fbmask; /* calc frag offset from block offset */
u_int32_t lfs_fbshift; /* fast mult/div for frag from block */
u_int32_t lfs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
u_int32_t lfs_sushift; /* fast mult/div for segusage table */
int32_t lfs_maxsymlinklen; /* max length of an internal symlink */
#define LFS_MIN_SBINTERVAL 5 /* minimum superblock segment spacing */
#define LFS_MAXNUMSB 10 /* superblock disk offsets */
ufs_daddr_t lfs_sboffs[LFS_MAXNUMSB];
/* Checksum -- last valid disk field. */
u_int32_t lfs_cksum; /* checksum for superblock checking */
/* These fields are set at mount time and are meaningless on disk. */
struct segment *lfs_sp; /* current segment being written */
struct vnode *lfs_ivnode; /* vnode for the ifile */
u_long lfs_seglock; /* single-thread the segment writer */
pid_t lfs_lockpid; /* pid of lock holder */
u_long lfs_iocount; /* number of ios pending */
u_long lfs_writer; /* don't allow any dirops to start */
u_long lfs_dirops; /* count of active directory ops */
u_long lfs_doifile; /* Write ifile blocks on next write */
u_long lfs_nactive; /* Number of segments since last ckp */
int8_t lfs_fmod; /* super block modified flag */
int8_t lfs_clean; /* file system is clean flag */
int8_t lfs_ronly; /* mounted read-only flag */
int8_t lfs_flags; /* currently unused flag */
u_char lfs_fsmnt[MNAMELEN]; /* name mounted on */
int32_t lfs_pad[40]; /* round to 512 bytes */
};
/*
* Inode 0: out-of-band inode number
* Inode 1: IFILE inode number
* Inode 2: root inode
* Inode 3: lost+found inode number
*/
#define LFS_UNUSED_INUM 0 /* out of band inode number */
#define LFS_IFILE_INUM 1 /* IFILE inode number */
#define LOSTFOUNDINO 3 /* lost+found inode number */
#define LFS_FIRST_INUM 4 /* first free inode number */
/* Address calculations for metadata located in the inode */
#define S_INDIR(fs) -NDADDR
#define D_INDIR(fs) (S_INDIR(fs) - NINDIR(fs) - 1)
#define T_INDIR(fs) (D_INDIR(fs) - NINDIR(fs) * NINDIR(fs) - 1)
/* Unassigned disk address. */
#define UNASSIGNED -1
/* Unused logical block number */
#define LFS_UNUSED_LBN -1
typedef struct ifile IFILE;
struct ifile {
u_int32_t if_version; /* inode version number */
#define LFS_UNUSED_DADDR 0 /* out-of-band daddr */
ufs_daddr_t if_daddr; /* inode disk address */
ino_t if_nextfree; /* next-unallocated inode */
};
/*
* Cleaner information structure. This resides in the ifile and is used
* to pass information between the cleaner and the kernel.
*/
typedef struct _cleanerinfo {
u_int32_t clean; /* K: number of clean segments */
u_int32_t dirty; /* K: number of dirty segments */
} CLEANERINFO;
#define CLEANSIZE_SU(fs) \
((sizeof(CLEANERINFO) + (fs)->lfs_bsize - 1) >> (fs)->lfs_bshift)
/*
* All summary blocks are the same size, so we can always read a summary
* block easily from a segment.
*/
#define LFS_SUMMARY_SIZE 512
/* On-disk segment summary information */
typedef struct segsum SEGSUM;
struct segsum {
u_int32_t ss_sumsum; /* check sum of summary block */
u_int32_t ss_datasum; /* check sum of data */
u_int32_t ss_magic; /* segment summary magic number */
#define SS_MAGIC 0x061561
ufs_daddr_t ss_next; /* next segment */
u_int32_t ss_create; /* creation time stamp */
u_int16_t ss_nfinfo; /* number of file info structures */
u_int16_t ss_ninos; /* number of inodes in summary */
#define SS_DIROP 0x01 /* segment begins a dirop */
#define SS_CONT 0x02 /* more partials to finish this write*/
u_int16_t ss_flags; /* used for directory operations */
u_int16_t ss_pad; /* extra space */
/* FINFO's and inode daddr's... */
};
/* NINDIR is the number of indirects in a file system block. */
#define NINDIR(fs) ((fs)->lfs_nindir)
/* INOPB is the number of inodes in a secondary storage block. */
#define INOPB(fs) ((fs)->lfs_inopb)
#define blksize(fs, ip, lbn) \
(((lbn) >= NDADDR || (ip)->i_size >= ((lbn) + 1) << (fs)->lfs_bshift) \
? (fs)->lfs_bsize \
: (fragroundup(fs, blkoff(fs, (ip)->i_size))))
#define blkoff(fs, loc) ((int)((loc) & (fs)->lfs_bmask))
#define fragoff(fs, loc) /* calculates (loc % fs->lfs_fsize) */ \
((int)((loc) & (fs)->lfs_ffmask))
#define fsbtodb(fs, b) ((b) << (fs)->lfs_fsbtodb)
#define dbtofsb(fs, b) ((b) >> (fs)->lfs_fsbtodb)
#define fragstodb(fs, b) ((b) << (fs)->lfs_fsbtodb - (fs)->lfs_fbshift)
#define dbtofrags(fs, b) ((b) >> (fs)->lfs_fsbtodb - (fs)->lfs_fbshift)
#define lblkno(fs, loc) ((loc) >> (fs)->lfs_bshift)
#define lblktosize(fs, blk) ((blk) << (fs)->lfs_bshift)
#define numfrags(fs, loc) /* calculates (loc / fs->lfs_fsize) */ \
((loc) >> (fs)->lfs_ffshift)
#define blkroundup(fs, size) /* calculates roundup(size, fs->lfs_bsize) */ \
((int)(((size) + (fs)->lfs_bmask) & (~(fs)->lfs_bmask)))
#define fragroundup(fs, size) /* calculates roundup(size, fs->lfs_fsize) */ \
((int)(((size) + (fs)->lfs_ffmask) & (~(fs)->lfs_ffmask)))
#define fragstoblks(fs, frags) /* calculates (frags / fs->lfs_frag) */ \
((frags) >> (fs)->lfs_fbshift)
#define blkstofrags(fs, blks) /* calculates (blks * fs->lfs_frag) */ \
((blks) << (fs)->lfs_fbshift)
#define fragnum(fs, fsb) /* calculates (fsb % fs->lfs_frag) */ \
((fsb) & ((fs)->lfs_frag - 1))
#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->lfs_frag) */ \
((fsb) &~ ((fs)->lfs_frag - 1))
#define dblksize(fs, dip, lbn) \
(((lbn) >= NDADDR || (dip)->di_size >= ((lbn) + 1) << (fs)->lfs_bshift)\
? (fs)->lfs_bsize \
: (fragroundup(fs, blkoff(fs, (dip)->di_size))))
#define datosn(fs, daddr) /* disk address to segment number */ \
(((daddr) - (fs)->lfs_sboffs[0]) / fsbtodb((fs), (fs)->lfs_ssize))
#define sntoda(fs, sn) /* segment number to disk address */ \
((ufs_daddr_t)((sn) * ((fs)->lfs_ssize << (fs)->lfs_fsbtodb) + \
(fs)->lfs_sboffs[0]))
/* Read in the block with the cleaner info from the ifile. */
#define LFS_CLEANERINFO(CP, F, BP) { \
VTOI((F)->lfs_ivnode)->i_flag |= IN_ACCESS; \
if (bread((F)->lfs_ivnode, \
(ufs_daddr_t)0, (F)->lfs_bsize, NOCRED, &(BP))) \
panic("lfs: ifile read"); \
(CP) = (CLEANERINFO *)(BP)->b_data; \
}
/* Read in the block with a specific inode from the ifile. */
#define LFS_IENTRY(IP, F, IN, BP) { \
int _e; \
VTOI((F)->lfs_ivnode)->i_flag |= IN_ACCESS; \
if (_e = bread((F)->lfs_ivnode, \
(IN) / (F)->lfs_ifpb + (F)->lfs_cleansz + (F)->lfs_segtabsz,\
(F)->lfs_bsize, NOCRED, &(BP))) \
panic("lfs: ifile read %d", _e); \
(IP) = (IFILE *)(BP)->b_data + (IN) % (F)->lfs_ifpb; \
}
/* Read in the block with a specific segment usage entry from the ifile. */
#define LFS_SEGENTRY(SP, F, IN, BP) { \
int _e; \
VTOI((F)->lfs_ivnode)->i_flag |= IN_ACCESS; \
_e = bread((F)->lfs_ivnode, \
((IN) >> (F)->lfs_sushift) + (F)->lfs_cleansz, \
(F)->lfs_bsize, NOCRED, &(BP)); \
if (_e) \
panic("lfs: ifile read: %d", _e); \
(SP) = (SEGUSE *)(BP)->b_data + ((IN) & (F)->lfs_sepb - 1); \
}
#ifdef CC_WALL
/* The above ^^^^^^^^^^^^^^^^^^^^^^^^^^^
* looks like a potential bug to me.
*/
#endif
/*
* Determine if there is enough room currently available to write db
* disk blocks. We need enough blocks for the new blocks, the current,
* inode blocks, a summary block, plus potentially the ifile inode and
* the segment usage table, plus an ifile page.
*/
#define LFS_FITS(fs, db) \
((int32_t)((db + ((fs)->lfs_uinodes + INOPB((fs))) / \
INOPB((fs)) + fsbtodb(fs, 1) + LFS_SUMMARY_SIZE / DEV_BSIZE + \
(fs)->lfs_segtabsz)) < (fs)->lfs_avail)
/* Determine if a buffer belongs to the ifile */
#define IS_IFILE(bp) (VTOI(bp->b_vp)->i_number == LFS_IFILE_INUM)
/*
* Structures used by lfs_bmapv and lfs_markv to communicate information
* about inodes and data blocks.
*/
typedef struct block_info {
ino_t bi_inode; /* inode # */
ufs_daddr_t bi_lbn; /* logical block w/in file */
ufs_daddr_t bi_daddr; /* disk address of block */
time_t bi_segcreate; /* origin segment create time */
int bi_version; /* file version number */
void *bi_bp; /* data buffer */
int bi_size; /* size of the block (if fragment) */
} BLOCK_INFO;
/* In-memory description of a segment about to be written. */
struct segment {
struct lfs *fs; /* file system pointer */
struct buf **bpp; /* pointer to buffer array */
struct buf **cbpp; /* pointer to next available bp */
struct buf **start_bpp; /* pointer to first bp in this set */
struct buf *ibp; /* buffer pointer to inode page */
struct finfo *fip; /* current fileinfo pointer */
struct vnode *vp; /* vnode being gathered */
void *segsum; /* segment summary info */
u_int32_t ninodes; /* number of inodes in this segment */
u_int32_t seg_bytes_left; /* bytes left in segment */
u_int32_t sum_bytes_left; /* bytes left in summary block */
u_int32_t seg_number; /* number of this segment */
ufs_daddr_t *start_lbp; /* beginning lbn for this set */
#define SEGM_CKP 0x01 /* doing a checkpoint */
#define SEGM_CLEAN 0x02 /* cleaner call; don't sort */
#define SEGM_SYNC 0x04 /* wait for segment */
u_int16_t seg_flags; /* run-time flags for this segment */
};
#define ISSPACE(F, BB, C) \
(((C)->cr_uid == 0 && (F)->lfs_bfree >= (BB)) || \
((C)->cr_uid != 0 && IS_FREESPACE(F, BB)))
#define IS_FREESPACE(F, BB) \
((F)->lfs_bfree > ((F)->lfs_dsize * (F)->lfs_minfree / 100 + (BB)))
#define ISSPACE_XXX(F, BB) \
((F)->lfs_bfree >= (BB))
#define DOSTATS
#ifdef DOSTATS
/* Statistics Counters */
struct lfs_stats {
u_int segsused;
u_int psegwrites;
u_int psyncwrites;
u_int pcleanwrites;
u_int blocktot;
u_int cleanblocks;
u_int ncheckpoints;
u_int nwrites;
u_int nsync_writes;
u_int wait_exceeded;
u_int write_exceeded;
u_int flush_invoked;
};
extern struct lfs_stats lfs_stats;
#endif
#endif

View File

@ -1,252 +0,0 @@
/*
* Copyright (c) 1991, 1993, 1995
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)lfs_alloc.c 8.7 (Berkeley) 5/14/95
* $Id: lfs_alloc.c,v 1.19 1997/10/16 11:58:30 phk Exp $
*/
#include "opt_quota.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/malloc.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
/* Allocate a new inode. */
/* ARGSUSED */
int
lfs_valloc(pvp, mode, cred, vpp)
struct vnode *pvp;
int mode;
struct ucred *cred;
struct vnode **vpp;
{
struct lfs *fs;
struct buf *bp;
struct ifile *ifp;
struct inode *ip;
struct vnode *vp;
ufs_daddr_t blkno;
ino_t new_ino;
u_long i, max;
int error;
/* Get the head of the freelist. */
fs = VTOI(pvp)->i_lfs;
new_ino = fs->lfs_free;
#ifdef ALLOCPRINT
printf("lfs_ialloc: allocate inode %d\n", new_ino);
#endif
/*
* Remove the inode from the free list and write the new start
* of the free list into the superblock.
*/
LFS_IENTRY(ifp, fs, new_ino, bp);
if (ifp->if_daddr != LFS_UNUSED_DADDR)
panic("lfs_ialloc: inuse inode on the free list");
fs->lfs_free = ifp->if_nextfree;
brelse(bp);
/* Extend IFILE so that the next lfs_valloc will succeed. */
if (fs->lfs_free == LFS_UNUSED_INUM) {
vp = fs->lfs_ivnode;
ip = VTOI(vp);
blkno = lblkno(fs, ip->i_size);
lfs_balloc(vp, 0, fs->lfs_bsize, blkno, &bp);
ip->i_size += fs->lfs_bsize;
vnode_pager_setsize(vp, (u_long)ip->i_size);
i = (blkno - fs->lfs_segtabsz - fs->lfs_cleansz) *
fs->lfs_ifpb;
fs->lfs_free = i;
max = i + fs->lfs_ifpb;
for (ifp = (struct ifile *)bp->b_data; i < max; ++ifp) {
ifp->if_version = 1;
ifp->if_daddr = LFS_UNUSED_DADDR;
ifp->if_nextfree = ++i;
}
ifp--;
ifp->if_nextfree = LFS_UNUSED_INUM;
if (error = VOP_BWRITE(bp))
return (error);
}
/* Create a vnode to associate with the inode. */
if (error = lfs_vcreate(pvp->v_mount, new_ino, &vp))
return (error);
ip = VTOI(vp);
/* Zero out the direct and indirect block addresses. */
bzero(&ip->i_din, sizeof(struct dinode));
ip->i_din.di_inumber = new_ino;
/* Set a new generation number for this inode. */
if (ip->i_gen == 0 || ++ip->i_gen == 0)
ip->i_gen = random() / 2 + 1;
/* Insert into the inode hash table. */
ufs_ihashins(ip);
if (error = ufs_vinit(vp->v_mount, lfs_specop_p, LFS_FIFOOPS, &vp)) {
vput(vp);
*vpp = NULL;
return (error);
}
*vpp = vp;
vp->v_flag |= VDIROP;
VREF(ip->i_devvp);
/* Set superblock modified bit and increment file count. */
fs->lfs_fmod = 1;
++fs->lfs_nfiles;
return (0);
}
/* Create a new vnode/inode pair and initialize what fields we can. */
int
lfs_vcreate(mp, ino, vpp)
struct mount *mp;
ino_t ino;
struct vnode **vpp;
{
struct inode *ip;
struct ufsmount *ump;
int error, i;
/*
* Do the MALLOC before the getnewvnode since doing so afterward
* might cause a bogus v_data pointer to get dereferenced
* elsewhere if MALLOC should block.
*/
MALLOC(ip, struct inode *, sizeof(struct inode), M_LFSNODE, M_WAITOK);
/* Create the vnode. */
if (error = getnewvnode(VT_LFS, mp, lfs_vnodeop_p, vpp)) {
*vpp = NULL;
FREE(ip, M_LFSNODE);
return (error);
}
/* Get a pointer to the private mount structure. */
ump = VFSTOUFS(mp);
/* Initialize the inode. */
lockinit(&ip->i_lock, PINOD, "lfsinode", 0, 0);
(*vpp)->v_data = ip;
ip->i_vnode = *vpp;
ip->i_devvp = ump->um_devvp;
ip->i_flag = IN_MODIFIED;
ip->i_dev = ump->um_dev;
ip->i_number = ip->i_din.di_inumber = ino;
ip->i_lfs = ump->um_lfs;
#ifdef QUOTA
for (i = 0; i < MAXQUOTAS; i++)
ip->i_dquot[i] = NODQUOT;
#endif
ip->i_lockf = 0;
ip->i_diroff = 0;
ip->i_mode = 0;
ip->i_size = 0;
ip->i_blocks = 0;
++ump->um_lfs->lfs_uinodes;
return (0);
}
/* Free an inode. */
/* ARGUSED */
int
lfs_vfree(pvp, ino, mode)
struct vnode *pvp;
ino_t ino;
int mode;
{
SEGUSE *sup;
struct buf *bp;
struct ifile *ifp;
struct inode *ip;
struct lfs *fs;
ufs_daddr_t old_iaddr;
/* Get the inode number and file system. */
ip = VTOI(pvp);
fs = ip->i_lfs;
ino = ip->i_number;
if (ip->i_flag & IN_MODIFIED) {
--fs->lfs_uinodes;
ip->i_flag &=
~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
}
/*
* Set the ifile's inode entry to unused, increment its version number
* and link it into the free chain.
*/
LFS_IENTRY(ifp, fs, ino, bp);
old_iaddr = ifp->if_daddr;
ifp->if_daddr = LFS_UNUSED_DADDR;
++ifp->if_version;
ifp->if_nextfree = fs->lfs_free;
fs->lfs_free = ino;
(void) VOP_BWRITE(bp);
if (old_iaddr != LFS_UNUSED_DADDR) {
LFS_SEGENTRY(sup, fs, datosn(fs, old_iaddr), bp);
#ifdef DIAGNOSTIC
if (sup->su_nbytes < sizeof(struct dinode))
panic("lfs_vfree: negative byte count (segment %d)",
datosn(fs, old_iaddr));
#endif
sup->su_nbytes -= sizeof(struct dinode);
(void) VOP_BWRITE(bp);
}
/* Set superblock modified bit and decrement file count. */
fs->lfs_fmod = 1;
--fs->lfs_nfiles;
return (0);
}

View File

@ -1,245 +0,0 @@
/*
* Copyright (c) 1989, 1991, 1993
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)lfs_balloc.c 8.4 (Berkeley) 5/8/95
* $Id: lfs_balloc.c,v 1.12 1997/05/25 04:57:11 peter Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
static int lfs_fragextend(struct vnode *vp, int osize, int nsize, daddr_t lbn,
struct buf **bpp);
int
lfs_balloc(vp, offset, iosize, lbn, bpp)
struct vnode *vp;
int offset;
u_long iosize;
ufs_daddr_t lbn;
struct buf **bpp;
{
struct buf *ibp, *bp;
struct inode *ip;
struct lfs *fs;
struct indir indirs[NIADDR+2];
ufs_daddr_t daddr, lastblock;
int bb; /* number of disk blocks in a block disk blocks */
int error, frags, i, nsize, osize, num;
ip = VTOI(vp);
fs = ip->i_lfs;
/*
* Three cases: it's a block beyond the end of file, it's a block in
* the file that may or may not have been assigned a disk address or
* we're writing an entire block. Note, if the daddr is unassigned,
* the block might still have existed in the cache (if it was read
* or written earlier). If it did, make sure we don't count it as a
* new block or zero out its contents. If it did not, make sure
* we allocate any necessary indirect blocks.
* If we are writing a block beyond the end of the file, we need to
* check if the old last block was a fragment. If it was, we need
* to rewrite it.
*/
*bpp = NULL;
if (error = ufs_bmaparray(vp, lbn, &daddr, &indirs[0], &num, NULL, NULL ))
return (error);
/* Check for block beyond end of file and fragment extension needed. */
lastblock = lblkno(fs, ip->i_size);
if (lastblock < NDADDR && lastblock < lbn) {
osize = blksize(fs, ip, lastblock);
if (osize < fs->lfs_bsize && osize > 0) {
if (error = lfs_fragextend(vp, osize, fs->lfs_bsize,
lastblock, &bp))
return(error);
ip->i_size = (lastblock + 1) * fs->lfs_bsize;
vnode_pager_setsize(vp, (u_long)ip->i_size);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
VOP_BWRITE(bp);
}
}
bb = VFSTOUFS(vp->v_mount)->um_seqinc;
if (daddr == UNASSIGNED)
/* May need to allocate indirect blocks */
for (i = 1; i < num; ++i)
if (!indirs[i].in_exists) {
ibp = getblk(vp, indirs[i].in_lbn, fs->lfs_bsize,
0, 0);
if (!(ibp->b_flags & (B_DONE | B_DELWRI))) {
if (!ISSPACE(fs, bb, curproc->p_ucred)){
ibp->b_flags |= B_INVAL;
brelse(ibp);
error = ENOSPC;
} else {
ip->i_blocks += bb;
ip->i_lfs->lfs_bfree -= bb;
vfs_bio_clrbuf(ibp);
error = VOP_BWRITE(ibp);
}
} else
panic ("Indirect block should not exist");
if (!ISSPACE(fs, bb, curproc->p_ucred)){
ibp->b_flags |= B_INVAL;
brelse(ibp);
return(ENOSPC);
} else {
ip->i_blocks += bb;
ip->i_lfs->lfs_bfree -= bb;
clrbuf(ibp);
if(error = VOP_BWRITE(ibp))
return(error);
}
}
/*
* If the block we are writing is a direct block, it's the last
* block in the file, and offset + iosize is less than a full
* block, we can write one or more fragments. There are two cases:
* the block is brand new and we should allocate it the correct
* size or it already exists and contains some fragments and
* may need to extend it.
*/
if (lbn < NDADDR && lblkno(fs, ip->i_size) == lbn) {
nsize = fragroundup(fs, offset + iosize);
frags = numfrags(fs, nsize);
bb = fragstodb(fs, frags);
if (lblktosize(fs, lbn) == ip->i_size)
/* Brand new block or fragment */
*bpp = bp = getblk(vp, lbn, nsize, 0, 0);
else {
/* Extend existing block */
if (error = lfs_fragextend(vp, (int)blksize(fs, ip, lbn),
nsize, lbn, &bp))
return(error);
*bpp = bp;
}
} else {
/*
* Get the existing block from the cache either because the
* block is 1) not a direct block or because it's not the last
* block in the file.
*/
frags = dbtofrags(fs, bb);
*bpp = bp = getblk(vp, lbn, blksize(fs, ip, lbn), 0, 0);
}
/*
* The block we are writing may be a brand new block
* in which case we need to do accounting (i.e. check
* for free space and update the inode number of blocks.
*/
if (!(bp->b_flags & (B_CACHE | B_DONE | B_DELWRI))) {
if (daddr == UNASSIGNED)
if (!ISSPACE(fs, bb, curproc->p_ucred)) {
bp->b_flags |= B_INVAL;
brelse(bp);
return(ENOSPC);
} else {
ip->i_blocks += bb;
ip->i_lfs->lfs_bfree -= bb;
if (iosize != fs->lfs_bsize)
vfs_bio_clrbuf(bp);
}
else if (iosize == fs->lfs_bsize)
/* Optimization: I/O is unnecessary. */
bp->b_blkno = daddr;
else {
/*
* We need to read the block to preserve the
* existing bytes.
*/
bp->b_blkno = daddr;
bp->b_flags |= B_READ;
vfs_busy_pages(bp, 0);
VOP_STRATEGY(bp);
return(biowait(bp));
}
}
return (0);
}
static int
lfs_fragextend(vp, osize, nsize, lbn, bpp)
struct vnode *vp;
int osize;
int nsize;
daddr_t lbn;
struct buf **bpp;
{
struct inode *ip;
struct lfs *fs;
long bb;
int error;
ip = VTOI(vp);
fs = ip->i_lfs;
bb = (long)fragstodb(fs, numfrags(fs, nsize - osize));
if (!ISSPACE(fs, bb, curproc->p_ucred)) {
return(ENOSPC);
}
if (error = bread(vp, lbn, osize, NOCRED, bpp)) {
brelse(*bpp);
return(error);
}
#ifdef QUOTA
if (error = chkdq(ip, bb, curproc->p_ucred, 0)) {
brelse(*bpp);
return (error);
}
#endif
ip->i_blocks += bb;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
fs->lfs_bfree -= fragstodb(fs, numfrags(fs, (nsize - osize)));
allocbuf(*bpp, nsize);
bzero((char *)((*bpp)->b_data) + osize, (u_int)(nsize - osize));
return(0);
}

View File

@ -1,202 +0,0 @@
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)lfs_bio.c 8.10 (Berkeley) 6/10/95
* $Id: lfs_bio.c,v 1.13 1997/06/15 17:56:46 dyson Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/kernel.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
static void lfs_flush __P((void));
/*
* LFS block write function.
*
* XXX
* No write cost accounting is done.
* This is almost certainly wrong for synchronous operations and NFS.
*/
int lfs_allclean_wakeup; /* Cleaner wakeup address. */
int locked_queue_count; /* XXX Count of locked-down buffers. */
static int lfs_writing; /* Set if already kicked off a writer
because of buffer space */
/*
#define WRITE_THRESHHOLD ((nbuf >> 2) - 10)
#define WAIT_THRESHHOLD ((nbuf >> 1) - 10)
*/
#define WAIT_THRESHHOLD (nbuf - (nbuf >> 2) - 10)
#define WRITE_THRESHHOLD ((nbuf >> 1) - 10)
#define LFS_BUFWAIT 2
int
lfs_bwrite(ap)
struct vop_bwrite_args /* {
struct buf *a_bp;
} */ *ap;
{
register struct buf *bp = ap->a_bp;
struct lfs *fs;
struct inode *ip;
int db, error, s;
/*
* Set the delayed write flag and use reassignbuf to move the buffer
* from the clean list to the dirty one.
*
* Set the B_LOCKED flag and unlock the buffer, causing brelse to move
* the buffer onto the LOCKED free list. This is necessary, otherwise
* getnewbuf() would try to reclaim the buffers using bawrite, which
* isn't going to work.
*
* XXX we don't let meta-data writes run out of space because they can
* come from the segment writer. We need to make sure that there is
* enough space reserved so that there's room to write meta-data
* blocks.
*/
if (!(bp->b_flags & B_LOCKED)) {
fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs;
db = fragstodb(fs, numfrags(fs, bp->b_bcount));
while (!LFS_FITS(fs, db) && !IS_IFILE(bp) &&
bp->b_lblkno > 0) {
/* Out of space, need cleaner to run */
wakeup(&lfs_allclean_wakeup);
wakeup(&fs->lfs_nextseg);
error = tsleep(&fs->lfs_avail, PCATCH | PUSER,
"cleaner", 0);
if (error) {
brelse(bp);
return (error);
}
}
ip = VTOI((bp)->b_vp);
if (!(ip->i_flag & IN_MODIFIED))
++fs->lfs_uinodes;
ip->i_flag |= IN_CHANGE | IN_MODIFIED | IN_UPDATE;
fs->lfs_avail -= db;
++locked_queue_count;
++numdirtybuffers;
bp->b_flags |= B_DELWRI | B_LOCKED;
bp->b_flags &= ~(B_READ | B_ERROR);
s = splbio();
reassignbuf(bp, bp->b_vp);
splx(s);
}
brelse(bp);
return (0);
}
/*
* XXX
* This routine flushes buffers out of the B_LOCKED queue when LFS has too
* many locked down. Eventually the pageout daemon will simply call LFS
* when pages need to be reclaimed. Note, we have one static count of locked
* buffers, so we can't have more than a single file system. To make this
* work for multiple file systems, put the count into the mount structure.
*/
static void
lfs_flush()
{
register struct mount *mp, *nmp;
struct proc *p = curproc; /* XXX */
#ifdef DOSTATS
++lfs_stats.write_exceeded;
#endif
if (lfs_writing)
return;
lfs_writing = 1;
simple_lock(&mountlist_slock);
for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
nmp = mp->mnt_list.cqe_next;
continue;
}
if (mp->mnt_stat.f_type == lfs_mount_type &&
(mp->mnt_flag & MNT_RDONLY) == 0 &&
!((((struct ufsmount *)mp->mnt_data))->ufsmount_u.lfs)->lfs_dirops ) {
/*
* We set the queue to 0 here because we are about to
* write all the dirty buffers we have. If more come
* in while we're writing the segment, they may not
* get written, so we want the count to reflect these
* new writes after the segwrite completes.
*/
#ifdef DOSTATS
++lfs_stats.flush_invoked;
#endif
lfs_segwrite(mp, 0);
}
simple_lock(&mountlist_slock);
nmp = mp->mnt_list.cqe_next;
vfs_unbusy(mp, p);
}
simple_unlock(&mountlist_slock);
lfs_writing = 0;
}
int
lfs_check(vp, blkno)
struct vnode *vp;
ufs_daddr_t blkno;
{
int error;
error = 0;
if (incore(vp, blkno))
return (0);
if (locked_queue_count > WRITE_THRESHHOLD)
lfs_flush();
/* If out of buffers, wait on writer */
while (locked_queue_count > WAIT_THRESHHOLD) {
#ifdef DOSTATS
++lfs_stats.wait_exceeded;
#endif
error = tsleep(&locked_queue_count, PCATCH | PUSER, "buffers",
hz * LFS_BUFWAIT);
}
return (error);
}

View File

@ -1,69 +0,0 @@
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)lfs_cksum.c 8.2 (Berkeley) 10/9/94
* $Id: lfs_cksum.c,v 1.7 1997/02/22 09:47:18 peter Exp $
*/
#ifdef KERNEL
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <ufs/lfs/lfs.h>
#else
#include <sys/types.h>
#endif
#include <ufs/lfs/lfs_extern.h>
/*
* Simple, general purpose, fast checksum. Data must be short-aligned.
* Returns a u_long in case we ever want to do something more rigorous.
*
* XXX
* Use the TCP/IP checksum instead.
*/
u_long
cksum(str, len)
register void *str;
register size_t len;
{
register u_long sum;
len &= ~(sizeof(u_short) - 1);
for (sum = 0; len; len -= sizeof(u_short)) {
sum ^= *(u_short *)str;
str = (void *)((u_short *)str + 1);
}
return (sum);
}

View File

@ -1,139 +0,0 @@
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)lfs_debug.c 8.1 (Berkeley) 6/11/93
* $Id: lfs_debug.c,v 1.6 1997/02/22 09:47:19 peter Exp $
*/
#ifdef DEBUG
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mount.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/lfs/lfs.h>
static void lfs_dump_dinode __P((struct dinode *dip));
static void lfs_dump_super __P((struct lfs *lfsp));
static void
lfs_dump_super(lfsp)
struct lfs *lfsp;
{
int i;
(void)printf("%s%lx\t%s%lx\t%s%d\t%s%d\n",
"magic ", lfsp->lfs_magic,
"version ", lfsp->lfs_version,
"size ", lfsp->lfs_size,
"ssize ", lfsp->lfs_ssize);
(void)printf("%s%d\t%s%d\t%s%d\t%s%d\n",
"dsize ", lfsp->lfs_dsize,
"bsize ", lfsp->lfs_bsize,
"fsize ", lfsp->lfs_fsize,
"frag ", lfsp->lfs_frag);
(void)printf("%s%d\t%s%d\t%s%d\t%s%d\n",
"minfree ", lfsp->lfs_minfree,
"inopb ", lfsp->lfs_inopb,
"ifpb ", lfsp->lfs_ifpb,
"nindir ", lfsp->lfs_nindir);
(void)printf("%s%d\t%s%d\t%s%d\t%s%d\n",
"nseg ", lfsp->lfs_nseg,
"nspf ", lfsp->lfs_nspf,
"cleansz ", lfsp->lfs_cleansz,
"segtabsz ", lfsp->lfs_segtabsz);
(void)printf("%s%lx\t%s%d\t%s%lx\t%s%d\n",
"segmask ", lfsp->lfs_segmask,
"segshift ", lfsp->lfs_segshift,
"bmask ", lfsp->lfs_bmask,
"bshift ", lfsp->lfs_bshift);
(void)printf("%s%lx\t%s%d\t%s%lx\t%s%d\n",
"ffmask ", lfsp->lfs_ffmask,
"ffshift ", lfsp->lfs_ffshift,
"fbmask ", lfsp->lfs_fbmask,
"fbshift ", lfsp->lfs_fbshift);
(void)printf("%s%d\t%s%d\t%s%lx\t%s%qx\n",
"sushift ", lfsp->lfs_sushift,
"fsbtodb ", lfsp->lfs_fsbtodb,
"cksum ", lfsp->lfs_cksum,
"maxfilesize ", lfsp->lfs_maxfilesize);
(void)printf("Superblock disk addresses:");
for (i = 0; i < LFS_MAXNUMSB; i++)
(void)printf(" %lx", lfsp->lfs_sboffs[i]);
(void)printf("\n");
(void)printf("Checkpoint Info\n");
(void)printf("%s%d\t%s%lx\t%s%d\n",
"free ", lfsp->lfs_free,
"idaddr ", lfsp->lfs_idaddr,
"ifile ", lfsp->lfs_ifile);
(void)printf("%s%lx\t%s%d\t%s%lx\t%s%lx\t%s%lx\t%s%lx\n",
"bfree ", lfsp->lfs_bfree,
"nfiles ", lfsp->lfs_nfiles,
"lastseg ", lfsp->lfs_lastseg,
"nextseg ", lfsp->lfs_nextseg,
"curseg ", lfsp->lfs_curseg,
"offset ", lfsp->lfs_offset);
(void)printf("tstamp %lx\n", lfsp->lfs_tstamp);
}
static void
lfs_dump_dinode(dip)
struct dinode *dip;
{
int i;
(void)printf("%s%u\t%s%d\t%s%u\t%s%u\t%s%lu\n",
"mode ", dip->di_mode,
"nlink ", dip->di_nlink,
"uid ", dip->di_uid,
"gid ", dip->di_gid,
"size ", dip->di_size);
(void)printf("inum %ld\n", dip->di_inumber);
(void)printf("Direct Addresses\n");
for (i = 0; i < NDADDR; i++) {
(void)printf("\t%lx", dip->di_db[i]);
if ((i % 6) == 5)
(void)printf("\n");
}
for (i = 0; i < NIADDR; i++)
(void)printf("\t%lx", dip->di_ib[i]);
(void)printf("\n");
}
#endif /* DEBUG */

View File

@ -1,97 +0,0 @@
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)lfs_extern.h 8.6 (Berkeley) 5/8/95
* $Id: lfs_extern.h,v 1.18 1997/10/16 10:49:44 phk Exp $
*/
#ifndef _UFS_LFS_LFS_EXTERN_H_
#define _UFS_LFS_LFS_EXTERN_H_
#ifdef KERNEL
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_LFSNODE);
MALLOC_DECLARE(M_SEGMENT); /* XXX should be M_LFSSEGMENT ?? */
#endif
struct inode;
struct mount;
struct nameidata;
int lfs_balloc __P((struct vnode *, int, u_long, ufs_daddr_t, struct buf **));
int lfs_blkatoff __P((struct vnode *, off_t, char **, struct buf **));
int lfs_bwrite __P((struct vop_bwrite_args *));
int lfs_check __P((struct vnode *, ufs_daddr_t));
void lfs_free_buffer __P((caddr_t, int));
int lfs_gatherblock __P((struct segment *, struct buf *, int *));
struct dinode *
lfs_ifind __P((struct lfs *, ino_t, struct dinode *));
int lfs_init __P((struct vfsconf *));
int lfs_initseg __P((struct lfs *));
int lfs_makeinode __P((int, struct nameidata *, struct inode **));
int lfs_mountroot __P((void));
struct buf *
lfs_newbuf __P((struct vnode *, ufs_daddr_t, size_t));
void lfs_seglock __P((struct lfs *, unsigned long flags));
void lfs_segunlock __P((struct lfs *));
int lfs_segwrite __P((struct mount *, int));
#define lfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
size_t, struct proc *)))eopnotsupp)
int lfs_truncate __P((struct vnode *, off_t, int, struct ucred *, struct proc *));
int lfs_update __P((struct vnode *, struct timeval *, struct timeval *, int));
void lfs_updatemeta __P((struct segment *));
int lfs_valloc __P((struct vnode *, int, struct ucred *, struct vnode **));
int lfs_vcreate __P((struct mount *, ino_t, struct vnode **));
int lfs_vfree __P((struct vnode *, ino_t, int));
int lfs_vflush __P((struct vnode *));
int lfs_vref __P((struct vnode *));
void lfs_vunref __P((struct vnode *));
int lfs_writeinode __P((struct lfs *, struct segment *, struct inode *));
int lfs_writeseg __P((struct lfs *, struct segment *));
void lfs_writesuper __P((struct lfs *));
extern int lfs_allclean_wakeup;
extern int lfs_mount_type;
extern int locked_queue_count;
extern vop_t **lfs_vnodeop_p;
extern vop_t **lfs_specop_p;
extern vop_t **lfs_fifoop_p;
#define LFS_FIFOOPS lfs_fifoop_p
#endif /* KERNEL */
__BEGIN_DECLS
u_long cksum __P((void *, size_t)); /* XXX */
__END_DECLS
#endif /* !_UFS_LFS_LFS_EXTERN_H_ */

View File

@ -1,378 +0,0 @@
/*
* Copyright (c) 1986, 1989, 1991, 1993
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)lfs_inode.c 8.9 (Berkeley) 5/8/95
* $Id: lfs_inode.c,v 1.19 1997/10/16 10:49:47 phk Exp $
*/
#include "opt_quota.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/kernel.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
/* Search a block for a specific dinode. */
struct dinode *
lfs_ifind(fs, ino, dip)
struct lfs *fs;
ino_t ino;
register struct dinode *dip;
{
register int cnt;
register struct dinode *ldip;
for (cnt = INOPB(fs), ldip = dip + (cnt - 1); cnt--; --ldip)
if (ldip->di_inumber == ino)
return (ldip);
panic("lfs_ifind: dinode %u not found", ino);
/* NOTREACHED */
}
int
lfs_update(vp, access, modify, waitfor)
struct vnode *vp;
struct timeval *access;
struct timeval *modify;
int waitfor;
{
struct inode *ip;
int error;
if (vp->v_mount->mnt_flag & MNT_RDONLY){
return (0);
}
ip = VTOI(vp);
/* XXX
* We used to just return here. Now we make sure to check if
* we were called by lfs_fsync, since in this case, the inode
* may have been written to disk without all buffers connected
* with the vnode being flushed. It seems really suspicious
* that this could happen since from what I understand of the
* intended semantics, one of these flags should be set if there
* are still dirty buffers. Compare to how ffs_fsync/ffs_update
* work together and you'll see what I mean.
*/
if (((ip->i_flag & (IN_ACCESS|IN_CHANGE|IN_MODIFIED|IN_UPDATE)) == 0)
&& (vp->v_dirtyblkhd.lh_first == NULL))
return(0);
if (ip->i_flag & IN_ACCESS)
ip->i_atime = access->tv_sec;
if (ip->i_flag & IN_UPDATE) {
ip->i_mtime = modify->tv_sec;
(ip)->i_modrev++;
}
if (ip->i_flag & IN_CHANGE)
ip->i_ctime = time.tv_sec;
ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);
if (!(ip->i_flag & IN_MODIFIED))
++(VFSTOUFS(vp->v_mount)->um_lfs->lfs_uinodes);
ip->i_flag |= IN_MODIFIED;
/* If sync, push back the vnode and any dirty blocks it may have. */
error = (waitfor & LFS_SYNC ? lfs_vflush(vp) : 0);
if(waitfor & LFS_SYNC && vp->v_dirtyblkhd.lh_first != NULL)
panic("lfs_update: dirty bufs");
return( error );
}
/* Update segment usage information when removing a block. */
#define UPDATE_SEGUSE \
if (lastseg != -1) { \
LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \
if (num > sup->su_nbytes) \
panic("lfs_truncate: negative bytes in segment %d", \
lastseg); \
sup->su_nbytes -= num; \
e1 = VOP_BWRITE(sup_bp); \
fragsreleased += numfrags(fs, num); \
}
#define SEGDEC(S) { \
if (daddr != 0) { \
if (lastseg != (seg = datosn(fs, daddr))) { \
UPDATE_SEGUSE; \
num = (S); \
lastseg = seg; \
} else \
num += (S); \
} \
}
/*
* Truncate the inode ip to at most length size. Update segment usage
* table information.
*/
/* ARGSUSED */
int
lfs_truncate(vp, length, flags, cred, p)
struct vnode *vp;
off_t length;
int flags;
struct ucred *cred;
struct proc *p;
{
register struct indir *inp;
register int i;
register ufs_daddr_t *daddrp;
struct buf *bp, *sup_bp;
struct timeval tv;
struct ifile *ifp;
struct inode *ip;
struct lfs *fs;
struct indir a[NIADDR + 2], a_end[NIADDR + 2];
SEGUSE *sup;
ufs_daddr_t daddr, lastblock, lbn, olastblock;
ufs_daddr_t oldsize_lastblock, oldsize_newlast, newsize;
long off, a_released, fragsreleased, i_released;
int e1, e2, depth, lastseg, num, offset, seg, freesize;
ip = VTOI(vp);
gettime(&tv);
if (vp->v_type == VLNK && vp->v_mount->mnt_maxsymlinklen > 0) {
#ifdef DIAGNOSTIC
if (length != 0)
panic("lfs_truncate: partial truncate of symlink");
#endif
bzero((char *)&ip->i_shortlink, (u_int)ip->i_size);
ip->i_size = 0;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
return (UFS_UPDATE(vp, &tv, &tv, 0));
}
vnode_pager_setsize(vp, (u_long)length);
fs = ip->i_lfs;
/* If length is larger than the file, just update the times. */
if (ip->i_size <= length) {
ip->i_flag |= IN_CHANGE | IN_UPDATE;
return (UFS_UPDATE(vp, &tv, &tv, 0));
}
/*
* Calculate index into inode's block list of last direct and indirect
* blocks (if any) which we want to keep. Lastblock is 0 when the
* file is truncated to 0.
*/
lastblock = lblkno(fs, length + fs->lfs_bsize - 1);
olastblock = lblkno(fs, ip->i_size + fs->lfs_bsize - 1) - 1;
/*
* Update the size of the file. If the file is not being truncated to
* a block boundry, the contents of the partial block following the end
* of the file must be zero'ed in case it ever become accessable again
* because of subsequent file growth. For this part of the code,
* oldsize_newlast refers to the old size of the new last block in the file.
*/
offset = blkoff(fs, length);
lbn = lblkno(fs, length);
oldsize_newlast = blksize(fs, ip, lbn);
/* Now set oldsize to the current size of the current last block */
oldsize_lastblock = blksize(fs, ip, olastblock);
if (offset == 0)
ip->i_size = length;
else {
#ifdef QUOTA
if (e1 = getinoquota(ip))
return (e1);
#endif
if (e1 = bread(vp, lbn, oldsize_newlast, NOCRED, &bp))
return (e1);
ip->i_size = length;
newsize = blksize(fs, ip, lbn);
bzero((char *)bp->b_data + offset, (u_int)(newsize - offset));
allocbuf(bp, newsize);
if (e1 = VOP_BWRITE(bp))
return (e1);
}
/*
* Modify sup->su_nbyte counters for each deleted block; keep track
* of number of blocks removed for ip->i_blocks.
*/
fragsreleased = 0;
num = 0;
lastseg = -1;
for (lbn = olastblock; lbn >= lastblock;) {
/* XXX use run length from bmap array to make this faster */
ufs_bmaparray(vp, lbn, &daddr, a, &depth, NULL, NULL);
if (lbn == olastblock) {
for (i = NIADDR + 2; i--;)
a_end[i] = a[i];
freesize = oldsize_lastblock;
} else
freesize = fs->lfs_bsize;
switch (depth) {
case 0: /* Direct block. */
daddr = ip->i_db[lbn];
SEGDEC(freesize);
ip->i_db[lbn] = 0;
--lbn;
break;
#ifdef DIAGNOSTIC
case 1: /* An indirect block. */
panic("lfs_truncate: ufs_bmaparray returned depth 1");
/* NOTREACHED */
#endif
default: /* Chain of indirect blocks. */
inp = a + --depth;
if (inp->in_off > 0 && lbn != lastblock) {
lbn -= inp->in_off < lbn - lastblock ?
inp->in_off : lbn - lastblock;
break;
}
for (; depth && (inp->in_off == 0 || lbn == lastblock);
--inp, --depth) {
if (bread(vp,
inp->in_lbn, fs->lfs_bsize, NOCRED, &bp))
panic("lfs_truncate: bread bno %d",
inp->in_lbn);
daddrp = (ufs_daddr_t *)bp->b_data +
inp->in_off;
for (i = inp->in_off;
i++ <= a_end[depth].in_off;) {
daddr = *daddrp++;
SEGDEC(freesize);
}
a_end[depth].in_off = NINDIR(fs) - 1;
if (inp->in_off == 0)
brelse (bp);
else {
bzero((ufs_daddr_t *)bp->b_data +
inp->in_off, fs->lfs_bsize -
inp->in_off * sizeof(ufs_daddr_t));
if (e1 = VOP_BWRITE(bp))
return (e1);
}
}
if (depth == 0 && a[1].in_off == 0) {
off = a[0].in_off;
daddr = ip->i_ib[off];
SEGDEC(freesize);
ip->i_ib[off] = 0;
}
if (lbn == lastblock || lbn <= NDADDR)
--lbn;
else {
lbn -= NINDIR(fs);
if (lbn < lastblock)
lbn = lastblock;
}
}
}
UPDATE_SEGUSE;
/* If truncating the file to 0, update the version number. */
if (length == 0) {
LFS_IENTRY(ifp, fs, ip->i_number, bp);
++ifp->if_version;
(void) VOP_BWRITE(bp);
}
#ifdef DIAGNOSTIC
if (ip->i_blocks < fragstodb(fs, fragsreleased)) {
printf("lfs_truncate: frag count < 0\n");
fragsreleased = dbtofrags(fs, ip->i_blocks);
panic("lfs_truncate: frag count < 0\n");
}
#endif
ip->i_blocks -= fragstodb(fs, fragsreleased);
fs->lfs_bfree += fragstodb(fs, fragsreleased);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
/*
* Traverse dirty block list counting number of dirty buffers
* that are being deleted out of the cache, so that the lfs_avail
* field can be updated.
*/
a_released = 0;
i_released = 0;
for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = bp->b_vnbufs.le_next)
if (bp->b_flags & B_LOCKED) {
a_released += numfrags(fs, bp->b_bcount);
/*
* XXX
* When buffers are created in the cache, their block
* number is set equal to their logical block number.
* If that is still true, we are assuming that the
* blocks are new (not yet on disk) and weren't
* counted above. However, there is a slight chance
* that a block's disk address is equal to its logical
* block number in which case, we'll get an overcounting
* here.
*/
if (bp->b_blkno == bp->b_lblkno)
i_released += numfrags(fs, bp->b_bcount);
}
fragsreleased = i_released;
#ifdef DIAGNOSTIC
if (fragsreleased > dbtofrags(fs, ip->i_blocks)) {
printf("lfs_inode: Warning! %s\n",
"more frags released from inode than are in inode");
fragsreleased = dbtofrags(fs, ip->i_blocks);
panic("lfs_inode: Warning. More frags released\n");
}
#endif
fs->lfs_bfree += fragstodb(fs, fragsreleased);
ip->i_blocks -= fragstodb(fs, fragsreleased);
#ifdef DIAGNOSTIC
if (length == 0 && ip->i_blocks != 0) {
printf("lfs_inode: Warning! %s%ld%s\n",
"Truncation to zero, but ", ip->i_blocks,
" blocks left on inode");
panic("lfs_inode");
}
#endif
fs->lfs_avail += fragstodb(fs, a_released);
e1 = vinvalbuf(vp, (length > 0) ? V_SAVE : 0, cred, p,
0, 0);
e2 = UFS_UPDATE(vp, &tv, &tv, 0);
return (e1 ? e1 : e2 ? e2 : 0);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,184 +0,0 @@
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)lfs_subr.c 8.4 (Berkeley) 5/8/95
* $Id: lfs_subr.c,v 1.11 1997/08/02 14:33:21 bde Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/vnode.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
/*
* Return buffer with the contents of block "offset" from the beginning of
* directory "ip". If "res" is non-zero, fill it in with a pointer to the
* remaining space in the directory.
*/
int
lfs_blkatoff(vp, offset, res, bpp)
struct vnode *vp;
off_t offset;
char **res;
struct buf **bpp;
{
register struct lfs *fs;
struct inode *ip;
struct buf *bp;
ufs_daddr_t lbn;
int bsize, error;
ip = VTOI(vp);
fs = ip->i_lfs;
lbn = lblkno(fs, offset);
bsize = blksize(fs, ip, lbn);
*bpp = NULL;
if (error = bread(vp, lbn, bsize, NOCRED, &bp)) {
brelse(bp);
return (error);
}
if (res)
*res = (char *)bp->b_data + blkoff(fs, offset);
*bpp = bp;
return (0);
}
/*
* lfs_seglock --
* Single thread the segment writer.
*/
void
lfs_seglock(fs, flags)
struct lfs *fs;
unsigned long flags;
{
struct segment *sp;
int s;
if (fs->lfs_seglock)
if (fs->lfs_lockpid == curproc->p_pid) {
++fs->lfs_seglock;
fs->lfs_sp->seg_flags |= flags;
return;
} else while (fs->lfs_seglock)
(void)tsleep(&fs->lfs_seglock, PRIBIO + 1,
"lfs seglock", 0);
/* XXX RACE CONDITION????? */
fs->lfs_seglock = 1;
fs->lfs_lockpid = curproc->p_pid;
sp = fs->lfs_sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK);
sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) /
sizeof(ufs_daddr_t) + 1) * sizeof(struct buf *),
M_SEGMENT, M_WAITOK);
sp->seg_flags = flags;
sp->vp = NULL;
(void) lfs_initseg(fs);
/*
* Keep a cumulative count of the outstanding I/O operations. If the
* disk drive catches up with us it could go to zero before we finish,
* so we artificially increment it by one until we've scheduled all of
* the writes we intend to do.
*/
s = splbio();
++fs->lfs_iocount;
splx(s);
}
/*
* lfs_segunlock --
* Single thread the segment writer.
*/
void
lfs_segunlock(fs)
struct lfs *fs;
{
struct segment *sp;
unsigned long sync, ckp;
int s;
if (fs->lfs_seglock == 1) {
sp = fs->lfs_sp;
sync = sp->seg_flags & SEGM_SYNC;
ckp = sp->seg_flags & SEGM_CKP;
if (sp->bpp != sp->cbpp) {
/* Free allocated segment summary */
fs->lfs_offset -= LFS_SUMMARY_SIZE / DEV_BSIZE;
lfs_free_buffer((*sp->bpp)->b_data, roundup((*sp->bpp)->b_bufsize, DEV_BSIZE));
relpbuf(*sp->bpp);
} else
printf ("unlock to 0 with no summary");
free(sp->bpp, M_SEGMENT);
free(sp, M_SEGMENT);
/*
* If the I/O count is non-zero, sleep until it reaches zero.
* At the moment, the user's process hangs around so we can
* sleep.
*/
s = splbio();
--fs->lfs_iocount;
/*
* We let checkpoints happen asynchronously. That means
* that during recovery, we have to roll forward between
* the two segments described by the first and second
* superblocks to make sure that the checkpoint described
* by a superblock completed.
*/
if (sync && fs->lfs_iocount)
(void)tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs vflush", 0);
splx(s);
if (ckp) {
fs->lfs_nactive = 0;
lfs_writesuper(fs);
}
--fs->lfs_seglock;
fs->lfs_lockpid = 0;
wakeup(&fs->lfs_seglock);
} else if (fs->lfs_seglock == 0) {
panic ("Seglock not held");
} else {
--fs->lfs_seglock;
}
}

View File

@ -1,582 +0,0 @@
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)lfs_syscalls.c 8.10 (Berkeley) 5/14/95
* $Id: lfs_syscalls.c,v 1.20 1997/11/06 19:29:51 phk Exp $
*/
#include "opt_lfs.h" /* XXX: Indicate bogus header dependency */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
#define BUMP_FIP(SP) \
(SP)->fip = (FINFO *) (&(SP)->fip->fi_blocks[(SP)->fip->fi_nblocks])
#define INC_FINFO(SP) ++((SEGSUM *)((SP)->segsum))->ss_nfinfo
#define DEC_FINFO(SP) --((SEGSUM *)((SP)->segsum))->ss_nfinfo
/*
* Before committing to add something to a segment summary, make sure there
* is enough room. S is the bytes added to the summary.
*/
#define CHECK_SEG(s) \
if (sp->sum_bytes_left < (s)) { \
(void) lfs_writeseg(fs, sp); \
}
static struct buf *lfs_fakebuf __P((struct vnode *, int, size_t, caddr_t));
static int lfs_fastvget __P((struct mount *, ino_t, daddr_t, struct vnode **,
struct dinode *));
int debug_cleaner = 0;
int clean_vnlocked = 0;
int clean_inlocked = 0;
/*
* lfs_markv:
*
* This will mark inodes and blocks dirty, so they are written into the log.
* It will block until all the blocks have been written. The segment create
* time passed in the block_info and inode_info structures is used to decide
* if the data is valid for each block (in case some process dirtied a block
* or inode that is being cleaned between the determination that a block is
* live and the lfs_markv call).
*
* 0 on success
* -1/errno is return on error.
*/
#ifndef _SYS_SYSPROTO_H_
struct lfs_markv_args {
fsid_t *fsidp; /* file system */
BLOCK_INFO *blkiov; /* block array */
int blkcnt; /* count of block array entries */
};
#endif
int
lfs_markv(p, uap)
struct proc *p;
struct lfs_markv_args *uap;
{
struct segment *sp;
BLOCK_INFO *blkp;
IFILE *ifp;
struct buf *bp, **bpp;
struct inode *ip = 0;
struct lfs *fs;
struct mount *mntp;
struct vnode *vp;
fsid_t fsid;
void *start;
ino_t lastino;
ufs_daddr_t b_daddr, v_daddr;
u_long bsize;
int cnt, error;
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
if (error = copyin(uap->fsidp, &fsid, sizeof(fsid_t)))
return (error);
if ((mntp = vfs_getvfs(&fsid)) == NULL)
return (EINVAL);
cnt = uap->blkcnt;
start = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK);
if (error = copyin(uap->blkiov, start, cnt * sizeof(BLOCK_INFO)))
goto err1;
/* Mark blocks/inodes dirty. */
fs = VFSTOUFS(mntp)->um_lfs;
bsize = fs->lfs_bsize;
error = 0;
lfs_seglock(fs, SEGM_SYNC | SEGM_CLEAN);
sp = fs->lfs_sp;
for (v_daddr = LFS_UNUSED_DADDR, lastino = LFS_UNUSED_INUM,
blkp = start; cnt--; ++blkp) {
/*
* Get the IFILE entry (only once) and see if the file still
* exists.
*/
if (lastino != blkp->bi_inode) {
if (lastino != LFS_UNUSED_INUM) {
/* Finish up last file */
if (sp->fip->fi_nblocks == 0) {
DEC_FINFO(sp);
sp->sum_bytes_left +=
sizeof(FINFO) - sizeof(ufs_daddr_t);
} else {
lfs_updatemeta(sp);
BUMP_FIP(sp);
}
lfs_writeinode(fs, sp, ip);
lfs_vunref(vp);
}
/* Start a new file */
CHECK_SEG(sizeof(FINFO));
sp->sum_bytes_left -= sizeof(FINFO) - sizeof(ufs_daddr_t);
INC_FINFO(sp);
sp->start_lbp = &sp->fip->fi_blocks[0];
sp->vp = NULL;
sp->fip->fi_version = blkp->bi_version;
sp->fip->fi_nblocks = 0;
sp->fip->fi_ino = blkp->bi_inode;
lastino = blkp->bi_inode;
if (blkp->bi_inode == LFS_IFILE_INUM)
v_daddr = fs->lfs_idaddr;
else {
LFS_IENTRY(ifp, fs, blkp->bi_inode, bp);
v_daddr = ifp->if_daddr;
brelse(bp);
}
if (v_daddr == LFS_UNUSED_DADDR)
continue;
/* Get the vnode/inode. */
if (lfs_fastvget(mntp, blkp->bi_inode, v_daddr, &vp,
blkp->bi_lbn == LFS_UNUSED_LBN ?
blkp->bi_bp : NULL)) {
#ifdef DIAGNOSTIC
printf("lfs_markv: VFS_VGET failed (%ld)\n",
blkp->bi_inode);
panic("lfs_markv VFS_VGET FAILED");
#endif
lastino = LFS_UNUSED_INUM;
v_daddr = LFS_UNUSED_DADDR;
continue;
}
sp->vp = vp;
ip = VTOI(vp);
} else if (v_daddr == LFS_UNUSED_DADDR)
continue;
/* If this BLOCK_INFO didn't contain a block, keep going. */
if (blkp->bi_lbn == LFS_UNUSED_LBN)
continue;
if (VOP_BMAP(vp, blkp->bi_lbn, NULL, &b_daddr, NULL, NULL) ||
b_daddr != blkp->bi_daddr)
continue;
/*
* If we got to here, then we are keeping the block. If it
* is an indirect block, we want to actually put it in the
* buffer cache so that it can be updated in the finish_meta
* section. If it's not, we need to allocate a fake buffer
* so that writeseg can perform the copyin and write the buffer.
*/
if (blkp->bi_lbn >= 0) /* Data Block */
bp = lfs_fakebuf(vp, blkp->bi_lbn, bsize,
blkp->bi_bp);
else {
bp = getblk(vp, blkp->bi_lbn, bsize, 0, 0);
if (!(bp->b_flags & (B_DELWRI | B_DONE | B_CACHE)) &&
(error = copyin(blkp->bi_bp, bp->b_data,
blkp->bi_size)))
goto err2;
if (error = VOP_BWRITE(bp))
goto err2;
}
while (lfs_gatherblock(sp, bp, NULL));
}
if (sp->vp) {
if (sp->fip->fi_nblocks == 0) {
DEC_FINFO(sp);
sp->sum_bytes_left +=
sizeof(FINFO) - sizeof(ufs_daddr_t);
} else
lfs_updatemeta(sp);
lfs_writeinode(fs, sp, ip);
lfs_vunref(vp);
}
(void) lfs_writeseg(fs, sp);
lfs_segunlock(fs);
free(start, M_SEGMENT);
return (error);
/*
* XXX
* If we come in to error 2, we might have indirect blocks that were
* updated and now have bad block pointers. I don't know what to do
* about this.
*/
err2: lfs_vunref(vp);
/* Free up fakebuffers */
for (bpp = --sp->cbpp; bpp >= sp->bpp; --bpp)
if ((*bpp)->b_flags & B_CALL) {
relpbuf(*bpp);
} else
brelse(*bpp);
lfs_segunlock(fs);
err1:
free(start, M_SEGMENT);
return (error);
}
/*
* lfs_bmapv:
*
* This will fill in the current disk address for arrays of blocks.
*
* 0 on success
* -1/errno is return on error.
*/
#ifndef _SYS_SYSPROTO_H_
struct lfs_bmapv_args {
fsid_t *fsidp; /* file system */
BLOCK_INFO *blkiov; /* block array */
int blkcnt; /* count of block array entries */
};
#endif
int
lfs_bmapv(p, uap)
struct proc *p;
struct lfs_bmapv_args *uap;
{
BLOCK_INFO *blkp;
struct mount *mntp;
struct ufsmount *ump;
struct vnode *vp;
fsid_t fsid;
void *start;
ufs_daddr_t daddr;
int cnt, error, step;
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
if (error = copyin(uap->fsidp, &fsid, sizeof(fsid_t)))
return (error);
if ((mntp = vfs_getvfs(&fsid)) == NULL)
return (EINVAL);
cnt = uap->blkcnt;
start = blkp = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK);
if (error = copyin(uap->blkiov, blkp, cnt * sizeof(BLOCK_INFO))) {
free(blkp, M_SEGMENT);
return (error);
}
for (step = cnt; step--; ++blkp) {
if (blkp->bi_lbn == LFS_UNUSED_LBN)
continue;
/*
* A regular call to VFS_VGET could deadlock
* here. Instead, we try an unlocked access.
*/
ump = VFSTOUFS(mntp);
if ((vp =
ufs_ihashlookup(ump->um_dev, blkp->bi_inode)) != NULL) {
if (VOP_BMAP(vp, blkp->bi_lbn, NULL, &daddr, NULL, NULL))
daddr = LFS_UNUSED_DADDR;
} else if (VFS_VGET(mntp, blkp->bi_inode, &vp))
daddr = LFS_UNUSED_DADDR;
else {
if (VOP_BMAP(vp, blkp->bi_lbn, NULL, &daddr, NULL, NULL))
daddr = LFS_UNUSED_DADDR;
vput(vp);
}
blkp->bi_daddr = daddr;
}
copyout(start, uap->blkiov, cnt * sizeof(BLOCK_INFO));
free(start, M_SEGMENT);
return (0);
}
/*
* lfs_segclean:
*
* Mark the segment clean.
*
* 0 on success
* -1/errno is return on error.
*/
#ifndef _SYS_SYSPROTO_H_
struct lfs_segclean_args {
fsid_t *fsidp; /* file system */
u_long segment; /* segment number */
};
#endif
int
lfs_segclean(p, uap)
struct proc *p;
struct lfs_segclean_args *uap;
{
CLEANERINFO *cip;
SEGUSE *sup;
struct buf *bp;
struct mount *mntp;
struct lfs *fs;
fsid_t fsid;
int error;
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
if (error = copyin(uap->fsidp, &fsid, sizeof(fsid_t)))
return (error);
if ((mntp = vfs_getvfs(&fsid)) == NULL)
return (EINVAL);
fs = VFSTOUFS(mntp)->um_lfs;
if (datosn(fs, fs->lfs_curseg) == uap->segment)
return (EBUSY);
LFS_SEGENTRY(sup, fs, uap->segment, bp);
if (sup->su_flags & SEGUSE_ACTIVE) {
brelse(bp);
return (EBUSY);
}
fs->lfs_avail += fsbtodb(fs, fs->lfs_ssize) - 1;
fs->lfs_bfree += (sup->su_nsums * LFS_SUMMARY_SIZE / DEV_BSIZE) +
sup->su_ninos * btodb(fs->lfs_bsize);
sup->su_flags &= ~SEGUSE_DIRTY;
(void) VOP_BWRITE(bp);
LFS_CLEANERINFO(cip, fs, bp);
++cip->clean;
--cip->dirty;
(void) VOP_BWRITE(bp);
wakeup(&fs->lfs_avail);
return (0);
}
/*
* lfs_segwait:
*
* This will block until a segment in file system fsid is written. A timeout
* in milliseconds may be specified which will awake the cleaner automatically.
* An fsid of -1 means any file system, and a timeout of 0 means forever.
*
* 0 on success
* 1 on timeout
* -1/errno is return on error.
*/
#ifndef _SYS_SYSPROTO_H_
struct lfs_segwait_args {
fsid_t *fsidp; /* file system */
struct timeval *tv; /* timeout */
};
#endif
int
lfs_segwait(p, uap)
struct proc *p;
struct lfs_segwait_args *uap;
{
struct mount *mntp;
struct timeval atv;
fsid_t fsid;
void *addr;
u_long timeout;
int error, s;
if (error = suser(p->p_ucred, &p->p_acflag)) {
return (error);
}
#ifdef WHEN_QUADS_WORK
if (error = copyin(uap->fsidp, &fsid, sizeof(fsid_t)))
return (error);
if (fsid == (fsid_t)-1)
addr = &lfs_allclean_wakeup;
else {
if ((mntp = vfs_getvfs(&fsid)) == NULL)
return (EINVAL);
addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg;
}
#else
if (error = copyin(uap->fsidp, &fsid, sizeof(fsid_t)))
return (error);
if ((mntp = vfs_getvfs(&fsid)) == NULL)
addr = &lfs_allclean_wakeup;
else
addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg;
#endif
if (uap->tv) {
if (error = copyin(uap->tv, &atv, sizeof(struct timeval)))
return (error);
if (itimerfix(&atv))
return (EINVAL);
s = splclock();
timevaladd(&atv, &time);
timeout = hzto(&atv);
splx(s);
} else
timeout = 0;
error = tsleep(addr, PCATCH | PUSER, "segment", timeout);
return (error == ERESTART ? EINTR : 0);
}
/*
* VFS_VGET call specialized for the cleaner. The cleaner already knows the
* daddr from the ifile, so don't look it up again. If the cleaner is
* processing IINFO structures, it may have the ondisk inode already, so
* don't go retrieving it again.
*/
static int
lfs_fastvget(mp, ino, daddr, vpp, dinp)
struct mount *mp;
ino_t ino;
ufs_daddr_t daddr;
struct vnode **vpp;
struct dinode *dinp;
{
register struct inode *ip;
struct vnode *vp;
struct ufsmount *ump;
struct buf *bp;
dev_t dev;
int error;
ump = VFSTOUFS(mp);
dev = ump->um_dev;
/*
* This is playing fast and loose. Someone may have the inode
* locked, in which case they are going to be distinctly unhappy
* if we trash something.
*/
if ((*vpp = ufs_ihashlookup(dev, ino)) != NULL) {
lfs_vref(*vpp);
if ((*vpp)->v_flag & VXLOCK)
clean_vnlocked++;
ip = VTOI(*vpp);
if (lockstatus(&ip->i_lock))
clean_inlocked++;
if (!(ip->i_flag & IN_MODIFIED))
++ump->um_lfs->lfs_uinodes;
ip->i_flag |= IN_MODIFIED;
return (0);
}
/* Allocate new vnode/inode. */
if (error = lfs_vcreate(mp, ino, &vp)) {
*vpp = NULL;
return (error);
}
/*
* Put it onto its hash chain and lock it so that other requests for
* this inode will block if they arrive while we are sleeping waiting
* for old data structures to be purged or for the contents of the
* disk portion of this inode to be read.
*/
ip = VTOI(vp);
ufs_ihashins(ip);
/*
* XXX
* This may not need to be here, logically it should go down with
* the i_devvp initialization.
* Ask Kirk.
*/
ip->i_lfs = ump->um_lfs;
/* Read in the disk contents for the inode, copy into the inode. */
if (dinp)
if (error = copyin(dinp, &ip->i_din, sizeof(struct dinode)))
return (error);
else {
if (error = bread(ump->um_devvp, daddr,
(int)ump->um_lfs->lfs_bsize, NOCRED, &bp)) {
/*
* The inode does not contain anything useful, so it
* would be misleading to leave it on its hash chain.
* Iput() will return it to the free list.
*/
ufs_ihashrem(ip);
/* Unlock and discard unneeded inode. */
lfs_vunref(vp);
brelse(bp);
*vpp = NULL;
return (error);
}
ip->i_din =
*lfs_ifind(ump->um_lfs, ino, (struct dinode *)bp->b_data);
brelse(bp);
}
/*
* Initialize the vnode from the inode, check for aliases. In all
* cases re-init ip, the underlying vnode/inode may have changed.
*/
if (error = ufs_vinit(mp, lfs_specop_p, LFS_FIFOOPS, &vp)) {
lfs_vunref(vp);
*vpp = NULL;
return (error);
}
/*
* Finish inode initialization now that aliasing has been resolved.
*/
ip->i_devvp = ump->um_devvp;
ip->i_flag |= IN_MODIFIED;
++ump->um_lfs->lfs_uinodes;
VREF(ip->i_devvp);
*vpp = vp;
return (0);
}
static struct buf *
lfs_fakebuf(vp, lbn, size, uaddr)
struct vnode *vp;
int lbn;
size_t size;
caddr_t uaddr;
{
struct buf *bp;
bp = lfs_newbuf(vp, lbn, 0);
bp->b_saveaddr = uaddr;
bp->b_bufsize = size;
bp->b_bcount = size;
bp->b_flags |= B_INVAL;
return (bp);
}

View File

@ -1,737 +0,0 @@
/*
* Copyright (c) 1989, 1991, 1993, 1994
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)lfs_vfsops.c 8.20 (Berkeley) 6/10/95
* $Id: lfs_vfsops.c,v 1.26 1997/10/16 20:32:37 phk Exp $
*/
#include "opt_quota.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/fcntl.h>
#include <sys/disklabel.h>
#include <miscfs/specfs/specdev.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
MALLOC_DEFINE(M_LFSNODE, "LFS node", "LFS vnode private part");
MALLOC_DEFINE(M_SEGMENT, "LFS segment", "Segment for LFS");
static int lfs_fhtovp __P((struct mount *, struct fid *, struct sockaddr *,
struct vnode **, int *, struct ucred **));
static int lfs_mount __P((struct mount *, char *, caddr_t,
struct nameidata *, struct proc *));
static int lfs_mountfs __P((struct vnode *, struct mount *, struct proc *));
static int lfs_statfs __P((struct mount *, struct statfs *, struct proc *));
static int lfs_sync __P((struct mount *, int, struct ucred *, struct proc *));
static int lfs_unmount __P((struct mount *, int, struct proc *));
static int lfs_vget __P((struct mount *, ino_t, struct vnode **));
static int lfs_vptofh __P((struct vnode *, struct fid *));
struct vfsops lfs_vfsops = {
lfs_mount,
ufs_start,
lfs_unmount,
ufs_root,
ufs_quotactl,
lfs_statfs,
lfs_sync,
lfs_vget,
lfs_fhtovp,
lfs_vptofh,
lfs_init,
#ifdef notyet
lfs_sysctl,
#endif
};
VFS_SET(lfs_vfsops, lfs, MOUNT_LFS, 0);
/*
* Called by main() when ufs is going to be mounted as root.
*/
int
lfs_mountroot()
{
struct fs *fs;
struct mount *mp;
struct proc *p = curproc; /* XXX */
int error;
if ((error = bdevvp(rootdev, &rootvp))) {
printf("lfs_mountroot: can't find rootvp");
return (error);
}
if (error = vfs_rootmountalloc("lfs", "root_device", &mp))
return (error);
if (error = lfs_mountfs(rootvp, mp, p)) {
mp->mnt_vfc->vfc_refcount--;
vfs_unbusy(mp, p);
free(mp, M_MOUNT);
return (error);
}
simple_lock(&mountlist_slock);
CIRCLEQ_INSERT_HEAD(&mountlist, mp, mnt_list);
simple_unlock(&mountlist_slock);
(void)lfs_statfs(mp, &mp->mnt_stat, p);
vfs_unbusy(mp, p);
return (0);
}
/*
* lfs_mount
*
* Called when mounting local physical media
*
* PARAMETERS:
* mountroot
* mp mount point structure
* path NULL (flag for root mount!!!)
* data <unused>
* ndp <unused>
* p process (user credentials check [statfs])
*
* mount
* mp mount point structure
* path path to mount point
* data pointer to argument struct in user space
* ndp mount point namei() return (used for
* credentials on reload), reused to look
* up block device.
* p process (user credentials check)
*
* RETURNS: 0 Success
* !0 error number (errno.h)
*
* LOCK STATE:
*
* ENTRY
* mount point is locked
* EXIT
* mount point is locked
*
* NOTES:
* A NULL path can be used for a flag since the mount
* system call will fail with EFAULT in copyinstr in
* namei() if it is a genuine NULL from the user.
*
* Root mounts are not currently supported.
*/
static int
lfs_mount(mp, path, data, ndp, p)
register struct mount *mp;
char *path;
caddr_t data;
struct nameidata *ndp;
struct proc *p;
{
struct vnode *devvp;
struct ufs_args args;
struct ufsmount *ump = 0;
register struct lfs *fs; /* LFS */
u_int size;
int err;
mode_t accessmode;
/*
* Use NULL path to flag a root mount
*/
if( path == NULL) {
/*
***
* Mounting root file system
***
*/
/* XXX -- implement*/
panic("lfs_mount: NULL path not implemented");
}
/*
***
* Mounting non-root file system or updating a file system
***
*/
/* copy in user arguments*/
if (err = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
goto error_1;
/* Until LFS can do NFS right. XXX */
if (args.export.ex_flags & MNT_EXPORTED) {
err = EINVAL;
goto error_1;
}
/*
* If updating, check whether changing from read-only to
* read/write; if there is no device name, that's all we do.
*/
if (mp->mnt_flag & MNT_UPDATE) {
ump = VFSTOUFS(mp);
if (fs->lfs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
/*
* If upgrade to read-write by non-root, then verify
* that user has necessary permissions on the device.
*/
if (p->p_ucred->cr_uid != 0) {
vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY,
p);
if (err = VOP_ACCESS(ump->um_devvp,
VREAD | VWRITE, p->p_ucred, p)) {
VOP_UNLOCK(ump->um_devvp, 0, p);
return (err);
}
VOP_UNLOCK(ump->um_devvp, 0, p);
}
fs->lfs_ronly = 0;
}
if (args.fspec == 0) {
/*
* Process export requests. Jumping to "success"
* will return the vfs_export() error code.
*/
err = vfs_export(mp, &ump->um_export, &args.export);
goto success;
}
}
/*
* Not an update, or updating the name: look up the name
* and verify that it refers to a sensible block device.
*/
NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
if (err = namei(ndp))
goto error_1;
devvp = ndp->ni_vp;
if (devvp->v_type != VBLK) {
err = ENOTBLK;
goto error_2;
}
if (major(devvp->v_rdev) >= nblkdev) {
err = ENXIO;
goto error_2;
}
/*
* If mount by non-root, then verify that user has necessary
* permissions on the device.
*/
if (p->p_ucred->cr_uid != 0) {
accessmode = VREAD;
if ((mp->mnt_flag & MNT_RDONLY) == 0)
accessmode |= VWRITE;
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
if (err = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) {
vput(devvp);
return (err);
}
VOP_UNLOCK(devvp, 0, p);
}
if ((mp->mnt_flag & MNT_UPDATE) == 0)
err = lfs_mountfs(devvp, mp, p); /* LFS */
else {
if (devvp != ump->um_devvp)
err = EINVAL; /* needs translation */
else
vrele(devvp);
}
if (err) {
goto error_2;
}
ump = VFSTOUFS(mp);
fs = ump->um_lfs; /* LFS */
#ifdef NOTLFS /* LFS */
(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
MNAMELEN);
(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
&size);
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
(void) ufs_statfs(mp, &mp->mnt_stat, p);
#else
(void)copyinstr(path, fs->lfs_fsmnt, sizeof(fs->lfs_fsmnt) - 1, &size);
bzero(fs->lfs_fsmnt + size, sizeof(fs->lfs_fsmnt) - size);
bcopy((caddr_t)fs->lfs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
MNAMELEN);
(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
&size);
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
(void) lfs_statfs(mp, &mp->mnt_stat, p);
#endif
error_2: /* error with devvp held*/
/* release devvp before failing*/
vrele(devvp);
error_1: /* no state to back out*/
success:
return( err);
}
/*
* Common code for mount and mountroot
* LFS specific
*/
static int
lfs_mountfs(devvp, mp, p)
register struct vnode *devvp;
struct mount *mp;
struct proc *p;
{
register struct lfs *fs;
register struct ufsmount *ump;
struct vnode *vp;
struct buf *bp;
struct partinfo dpart;
dev_t dev;
int error, i, ronly, size;
struct ucred *cred;
cred = p ? p->p_ucred : NOCRED;
/*
* Disallow multiple mounts of the same device.
* Disallow mounting of a device that is currently in use
* (except for root, which might share swap device for miniroot).
* Flush out any old buffers remaining from a previous use.
*/
if (error = vfs_mountedon(devvp))
return (error);
if (vcount(devvp) > 1 && devvp != rootvp)
return (EBUSY);
if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0))
return (error);
ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))
return (error);
if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
size = DEV_BSIZE;
else {
size = dpart.disklab->d_secsize;
#ifdef NEVER_USED
dpart.part->p_fstype = FS_LFS;
dpart.part->p_fsize = fs->lfs_fsize; /* frag size */
dpart.part->p_frag = fs->lfs_frag; /* frags per block */
dpart.part->p_cpg = fs->lfs_segshift; /* segment shift */
#endif
}
/* Don't free random space on error. */
bp = NULL;
ump = NULL;
/* Read in the superblock. */
if (error = bread(devvp, LFS_LABELPAD / size, LFS_SBPAD, cred, &bp))
goto out;
fs = (struct lfs *)bp->b_data;
/* Check the basics. */
if (fs->lfs_magic != LFS_MAGIC || fs->lfs_bsize > MAXBSIZE ||
fs->lfs_bsize < sizeof(struct lfs)) {
error = EINVAL; /* XXX needs translation */
goto out;
}
/* Allocate the mount structure, copy the superblock into it. */
ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
bzero(ump, sizeof *ump);
ump->um_malloctype = M_LFSNODE;
ump->um_blkatoff = lfs_blkatoff;
ump->um_truncate = lfs_truncate;
ump->um_update = lfs_update;
ump->um_valloc = lfs_valloc;
ump->um_vfree = lfs_vfree;
fs = ump->um_lfs = malloc(sizeof(struct lfs), M_UFSMNT, M_WAITOK);
bcopy(bp->b_data, fs, sizeof(struct lfs));
if (sizeof(struct lfs) < LFS_SBPAD) /* XXX why? */
bp->b_flags |= B_INVAL;
brelse(bp);
bp = NULL;
/* Set up the I/O information */
fs->lfs_iocount = 0;
/* Set up the ifile and lock aflags */
fs->lfs_doifile = 0;
fs->lfs_writer = 0;
fs->lfs_dirops = 0;
fs->lfs_seglock = 0;
/* Set the file system readonly/modify bits. */
fs->lfs_ronly = ronly;
if (ronly == 0)
fs->lfs_fmod = 1;
/* Initialize the mount structure. */
dev = devvp->v_rdev;
mp->mnt_data = (qaddr_t)ump;
mp->mnt_stat.f_fsid.val[0] = (long)dev;
mp->mnt_stat.f_fsid.val[1] = lfs_mount_type;
mp->mnt_maxsymlinklen = fs->lfs_maxsymlinklen;
mp->mnt_flag |= MNT_LOCAL;
ump->um_mountp = mp;
ump->um_dev = dev;
ump->um_devvp = devvp;
ump->um_bptrtodb = 0;
ump->um_seqinc = 1 << fs->lfs_fsbtodb;
ump->um_nindir = fs->lfs_nindir;
for (i = 0; i < MAXQUOTAS; i++)
ump->um_quotas[i] = NULLVP;
devvp->v_specflags |= SI_MOUNTEDON;
/*
* We use the ifile vnode for almost every operation. Instead of
* retrieving it from the hash table each time we retrieve it here,
* artificially increment the reference count and keep a pointer
* to it in the incore copy of the superblock.
*/
if (error = VFS_VGET(mp, LFS_IFILE_INUM, &vp))
goto out;
fs->lfs_ivnode = vp;
VREF(vp);
vput(vp);
return (0);
out:
if (bp)
brelse(bp);
(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
if (ump) {
free(ump->um_lfs, M_UFSMNT);
free(ump, M_UFSMNT);
mp->mnt_data = (qaddr_t)0;
}
return (error);
}
/*
* unmount system call
*/
static int
lfs_unmount(mp, mntflags, p)
struct mount *mp;
int mntflags;
struct proc *p;
{
register struct ufsmount *ump;
register struct lfs *fs;
int i, error, flags, ronly;
flags = 0;
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
ump = VFSTOUFS(mp);
fs = ump->um_lfs;
#ifdef QUOTA
if (mp->mnt_flag & MNT_QUOTA) {
if (error = vflush(mp, fs->lfs_ivnode, SKIPSYSTEM|flags))
return (error);
for (i = 0; i < MAXQUOTAS; i++) {
if (ump->um_quotas[i] == NULLVP)
continue;
quotaoff(p, mp, i);
}
/*
* Here we fall through to vflush again to ensure
* that we have gotten rid of all the system vnodes.
*/
}
#endif
if (error = vflush(mp, fs->lfs_ivnode, flags))
return (error);
fs->lfs_clean = 1;
if (error = VFS_SYNC(mp, 1, p->p_ucred, p))
return (error);
if (fs->lfs_ivnode->v_dirtyblkhd.lh_first)
panic("lfs_unmount: still dirty blocks on ifile vnode");
vrele(fs->lfs_ivnode);
vgone(fs->lfs_ivnode);
ronly = fs->lfs_ronly;
ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
error = VOP_CLOSE(ump->um_devvp,
ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
vrele(ump->um_devvp);
free(fs, M_UFSMNT);
free(ump, M_UFSMNT);
mp->mnt_data = (qaddr_t)0;
mp->mnt_flag &= ~MNT_LOCAL;
return (error);
}
/*
* Get file system statistics.
*/
static int
lfs_statfs(mp, sbp, p)
struct mount *mp;
register struct statfs *sbp;
struct proc *p;
{
register struct lfs *fs;
register struct ufsmount *ump;
ump = VFSTOUFS(mp);
fs = ump->um_lfs;
if (fs->lfs_magic != LFS_MAGIC)
panic("lfs_statfs: magic");
sbp->f_bsize = fs->lfs_fsize;
sbp->f_iosize = fs->lfs_bsize;
sbp->f_blocks = dbtofrags(fs,fs->lfs_dsize);
sbp->f_bfree = dbtofrags(fs, fs->lfs_bfree);
/*
* To compute the available space. Subtract the minimum free
* from the total number of blocks in the file system. Set avail
* to the smaller of this number and fs->lfs_bfree.
*/
sbp->f_bavail = fs->lfs_dsize * (100 - fs->lfs_minfree) / 100;
sbp->f_bavail =
sbp->f_bavail > fs->lfs_bfree ? fs->lfs_bfree : sbp->f_bavail;
sbp->f_bavail = dbtofrags(fs, sbp->f_bavail);
sbp->f_files = fs->lfs_nfiles;
sbp->f_ffree = sbp->f_bfree * INOPB(fs);
if (sbp != &mp->mnt_stat) {
sbp->f_type = mp->mnt_vfc->vfc_typenum;
bcopy((caddr_t)mp->mnt_stat.f_mntonname,
(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
}
return (0);
}
/*
* Go through the disk queues to initiate sandbagged IO;
* go through the inodes to write those that have been modified;
* initiate the writing of the super block if it has been modified.
*
* Note: we are always called with the filesystem marked `MPBUSY'.
*/
static int
lfs_sync(mp, waitfor, cred, p)
struct mount *mp;
int waitfor;
struct ucred *cred;
struct proc *p;
{
int error;
/* All syncs must be checkpoints until roll-forward is implemented. */
error = lfs_segwrite(mp, SEGM_CKP | (waitfor ? SEGM_SYNC : 0));
#ifdef QUOTA
qsync(mp);
#endif
return (error);
}
/*
* Look up an LFS dinode number to find its incore vnode. If not already
* in core, read it in from the specified device. Return the inode locked.
* Detection and handling of mount points must be done by the calling routine.
*/
static int
lfs_vget(mp, ino, vpp)
struct mount *mp;
ino_t ino;
struct vnode **vpp;
{
register struct lfs *fs;
register struct inode *ip;
struct buf *bp;
struct ifile *ifp;
struct vnode *vp;
struct ufsmount *ump;
ufs_daddr_t daddr;
dev_t dev;
int error;
ump = VFSTOUFS(mp);
dev = ump->um_dev;
if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
return (0);
/* Translate the inode number to a disk address. */
fs = ump->um_lfs;
if (ino == LFS_IFILE_INUM)
daddr = fs->lfs_idaddr;
else {
LFS_IENTRY(ifp, fs, ino, bp);
daddr = ifp->if_daddr;
brelse(bp);
if (daddr == LFS_UNUSED_DADDR)
return (ENOENT);
}
/* Allocate new vnode/inode. */
if (error = lfs_vcreate(mp, ino, &vp)) {
*vpp = NULL;
return (error);
}
/*
* Put it onto its hash chain and lock it so that other requests for
* this inode will block if they arrive while we are sleeping waiting
* for old data structures to be purged or for the contents of the
* disk portion of this inode to be read.
*/
ip = VTOI(vp);
ufs_ihashins(ip);
/*
* XXX
* This may not need to be here, logically it should go down with
* the i_devvp initialization.
* Ask Kirk.
*/
ip->i_lfs = ump->um_lfs;
/* Read in the disk contents for the inode, copy into the inode. */
if (error =
bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp)) {
/*
* The inode does not contain anything useful, so it would
* be misleading to leave it on its hash chain. With mode
* still zero, it will be unlinked and returned to the free
* list by vput().
*/
vput(vp);
brelse(bp);
*vpp = NULL;
return (error);
}
ip->i_din = *lfs_ifind(fs, ino, (struct dinode *)bp->b_data);
brelse(bp);
/*
* Initialize the vnode from the inode, check for aliases. In all
* cases re-init ip, the underlying vnode/inode may have changed.
*/
if (error = ufs_vinit(mp, lfs_specop_p, LFS_FIFOOPS, &vp)) {
vput(vp);
*vpp = NULL;
return (error);
}
/*
* Finish inode initialization now that aliasing has been resolved.
*/
ip->i_devvp = ump->um_devvp;
VREF(ip->i_devvp);
*vpp = vp;
return (0);
}
/*
* File handle to vnode
*
* Have to be really careful about stale file handles:
* - check that the inode number is valid
* - call lfs_vget() to get the locked inode
* - check for an unallocated inode (i_mode == 0)
* - check that the given client host has export rights and return
* those rights via. exflagsp and credanonp
*
* XXX
* use ifile to see if inode is allocated instead of reading off disk
* what is the relationship between my generational number and the NFS
* generational number.
*/
static int
lfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
register struct mount *mp;
struct fid *fhp;
struct sockaddr *nam;
struct vnode **vpp;
int *exflagsp;
struct ucred **credanonp;
{
register struct ufid *ufhp;
ufhp = (struct ufid *)fhp;
if (ufhp->ufid_ino < ROOTINO)
return (ESTALE);
return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
}
/*
* Vnode pointer to File handle
*/
/* ARGSUSED */
static int
lfs_vptofh(vp, fhp)
struct vnode *vp;
struct fid *fhp;
{
register struct inode *ip;
register struct ufid *ufhp;
ip = VTOI(vp);
ufhp = (struct ufid *)fhp;
ufhp->ufid_len = sizeof(struct ufid);
ufhp->ufid_ino = ip->i_number;
ufhp->ufid_gen = ip->i_gen;
return (0);
}
/*
* Initialize the filesystem, most work done by ufs_init.
*/
int lfs_mount_type;
int
lfs_init(vfsp)
struct vfsconf *vfsp;
{
lfs_mount_type = vfsp->vfc_typenum;
return (ufs_init(vfsp));
}

View File

@ -1,232 +0,0 @@
/*
* Copyright (c) 1986, 1989, 1991, 1993, 1995
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)lfs_vnops.c 8.13 (Berkeley) 6/10/95
* $Id: lfs_vnops.c,v 1.29 1997/10/16 20:32:37 phk Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/resourcevar.h>
#include <sys/signalvar.h>
#include <sys/kernel.h>
#include <sys/stat.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <vm/vm.h>
#include <vm/vm_prot.h>
#include <vm/vm_page.h>
#include <vm/vm_extern.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
static int lfs_close __P((struct vop_close_args *));
static int lfs_fsync __P((struct vop_fsync_args *));
static int lfs_getattr __P((struct vop_getattr_args *));
static int lfs_inactive __P((struct vop_inactive_args *));
static int lfs_read __P((struct vop_read_args *));
static int lfs_write __P((struct vop_write_args *));
/* Global vfs data structures for lfs. */
vop_t **lfs_vnodeop_p;
static struct vnodeopv_entry_desc lfs_vnodeop_entries[] = {
{ &vop_default_desc, (vop_t *) ufs_vnoperate },
{ &vop_bwrite_desc, (vop_t *) lfs_bwrite },
{ &vop_close_desc, (vop_t *) lfs_close },
{ &vop_fsync_desc, (vop_t *) lfs_fsync },
{ &vop_getattr_desc, (vop_t *) lfs_getattr },
{ &vop_read_desc, (vop_t *) lfs_read },
{ &vop_write_desc, (vop_t *) lfs_write },
{ &vop_lookup_desc, (vop_t *) ufs_lookup },
{ NULL, NULL }
};
static struct vnodeopv_desc lfs_vnodeop_opv_desc =
{ &lfs_vnodeop_p, lfs_vnodeop_entries };
vop_t **lfs_specop_p;
static struct vnodeopv_entry_desc lfs_specop_entries[] = {
{ &vop_default_desc, (vop_t *) ufs_vnoperatespec },
{ &vop_bwrite_desc, (vop_t *) lfs_bwrite },
{ &vop_getattr_desc, (vop_t *) lfs_getattr },
{ NULL, NULL }
};
static struct vnodeopv_desc lfs_specop_opv_desc =
{ &lfs_specop_p, lfs_specop_entries };
vop_t **lfs_fifoop_p;
static struct vnodeopv_entry_desc lfs_fifoop_entries[] = {
{ &vop_default_desc, (vop_t *) ufs_vnoperatefifo },
{ &vop_bwrite_desc, (vop_t *) lfs_bwrite },
{ &vop_getattr_desc, (vop_t *) lfs_getattr },
{ NULL, NULL }
};
static struct vnodeopv_desc lfs_fifoop_opv_desc =
{ &lfs_fifoop_p, lfs_fifoop_entries };
VNODEOP_SET(lfs_vnodeop_opv_desc);
VNODEOP_SET(lfs_specop_opv_desc);
VNODEOP_SET(lfs_fifoop_opv_desc);
#define LFS_READWRITE
#include <ufs/ufs/ufs_readwrite.c>
#undef LFS_READWRITE
/*
* Synch an open file.
*/
/* ARGSUSED */
static int
lfs_fsync(ap)
struct vop_fsync_args /* {
struct vnode *a_vp;
struct ucred *a_cred;
int a_waitfor;
struct proc *a_p;
} */ *ap;
{
struct timeval tv;
int error;
gettime(&tv);
error = (UFS_UPDATE(ap->a_vp, &tv, &tv,
ap->a_waitfor == MNT_WAIT ? LFS_SYNC : 0));
if(ap->a_waitfor == MNT_WAIT && ap->a_vp->v_dirtyblkhd.lh_first != NULL)
panic("lfs_fsync: dirty bufs");
return( error );
}
/*
* These macros are used to bracket UFS directory ops, so that we can
* identify all the pages touched during directory ops which need to
* be ordered and flushed atomically, so that they may be recovered.
*/
#define SET_DIROP(fs) { \
if ((fs)->lfs_writer) \
tsleep(&(fs)->lfs_dirops, PRIBIO + 1, "lfs_dirop", 0); \
++(fs)->lfs_dirops; \
(fs)->lfs_doifile = 1; \
}
#define SET_ENDOP(fs) { \
--(fs)->lfs_dirops; \
if (!(fs)->lfs_dirops) \
wakeup(&(fs)->lfs_writer); \
}
#define MARK_VNODE(dvp) (dvp)->v_flag |= VDIROP
/* XXX hack to avoid calling ITIMES in getattr */
static int
lfs_getattr(ap)
struct vop_getattr_args /* {
struct vnode *a_vp;
struct vattr *a_vap;
struct ucred *a_cred;
struct proc *a_p;
} */ *ap;
{
register struct vnode *vp = ap->a_vp;
register struct inode *ip = VTOI(vp);
register struct vattr *vap = ap->a_vap;
/*
* Copy from inode table
*/
vap->va_fsid = ip->i_dev;
vap->va_fileid = ip->i_number;
vap->va_mode = ip->i_mode & ~IFMT;
vap->va_nlink = ip->i_nlink;
vap->va_uid = ip->i_uid;
vap->va_gid = ip->i_gid;
vap->va_rdev = (dev_t)ip->i_rdev;
vap->va_size = ip->i_din.di_size;
vap->va_atime.tv_sec = ip->i_atime;
vap->va_atime.tv_nsec = ip->i_atimensec;
vap->va_mtime.tv_sec = ip->i_mtime;
vap->va_mtime.tv_nsec = ip->i_mtimensec;
vap->va_ctime.tv_sec = ip->i_ctime;
vap->va_ctime.tv_nsec = ip->i_ctimensec;
vap->va_flags = ip->i_flags;
vap->va_gen = ip->i_gen;
/* this doesn't belong here */
if (vp->v_type == VBLK)
vap->va_blocksize = BLKDEV_IOSIZE;
else if (vp->v_type == VCHR)
vap->va_blocksize = MAXBSIZE;
else
vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
vap->va_bytes = dbtob(ip->i_blocks);
vap->va_type = vp->v_type;
vap->va_filerev = ip->i_modrev;
return (0);
}
/*
* Close called
*
* XXX -- we were using ufs_close, but since it updates the
* times on the inode, we might need to bump the uinodes
* count.
*/
/* ARGSUSED */
static int
lfs_close(ap)
struct vop_close_args /* {
struct vnode *a_vp;
int a_fflag;
struct ucred *a_cred;
struct proc *a_p;
} */ *ap;
{
register struct vnode *vp = ap->a_vp;
register struct inode *ip = VTOI(vp);
int mod;
simple_lock(&vp->v_interlock);
if (vp->v_usecount > 1) {
mod = ip->i_flag & IN_MODIFIED;
ITIMES(ip, &time, &time);
if (!mod && ip->i_flag & IN_MODIFIED)
ip->i_lfs->lfs_uinodes++;
}
simple_unlock(&vp->v_interlock);
return (0);
}

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)inode.h 8.9 (Berkeley) 5/14/95
* $Id: inode.h,v 1.18 1997/10/17 12:36:19 phk Exp $
* $Id: inode.h,v 1.19 1997/12/05 13:43:47 jkh Exp $
*/
#ifndef _UFS_UFS_INODE_H_
@ -70,11 +70,9 @@ struct inode {
union { /* Associated filesystem. */
struct fs *fs; /* FFS */
struct lfs *lfs; /* LFS */
struct ext2_sb_info *e2fs; /* EXT2FS */
} inode_u;
#define i_fs inode_u.fs
#define i_lfs inode_u.lfs
#define i_e2fs inode_u.e2fs
struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
u_quad_t i_modrev; /* Revision level for NFS lease. */

View File

@ -31,20 +31,9 @@
* SUCH DAMAGE.
*
* @(#)ufs_readwrite.c 8.11 (Berkeley) 5/8/95
* $Id: ufs_readwrite.c,v 1.39 1998/01/06 05:24:04 dyson Exp $
* $Id: ufs_readwrite.c,v 1.40 1998/01/22 17:30:22 dyson Exp $
*/
#ifdef LFS_READWRITE
#define BLKSIZE(a, b, c) blksize(a, b, c)
#define FS struct lfs
#define I_FS i_lfs
#define READ lfs_read
#define READ_S "lfs_read"
#define WRITE lfs_write
#define WRITE_S "lfs_write"
#define fs_bsize lfs_bsize
#define fs_maxfilesize lfs_maxfilesize
#else
#define BLKSIZE(a, b, c) blksize(a, b, c)
#define FS struct fs
#define I_FS i_fs
@ -52,7 +41,6 @@
#define READ_S "ffs_read"
#define WRITE ffs_write
#define WRITE_S "ffs_write"
#endif
#include <vm/vm.h>
#include <vm/vm_object.h>
@ -147,11 +135,6 @@ READ(ap)
if (bytesinfile < xfersize)
xfersize = bytesinfile;
#ifdef LFS_READWRITE
(void)lfs_check(vp, lbn);
error = cluster_read(vp, ip->i_size, lbn,
size, NOCRED, uio->uio_resid, seqcount, &bp);
#else
if (lblktosize(fs, nextlbn) >= ip->i_size)
error = bread(vp, lbn, size, NOCRED, &bp);
else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0)
@ -163,7 +146,6 @@ READ(ap)
size, &nextlbn, &nextsize, 1, NOCRED, &bp);
} else
error = bread(vp, lbn, size, NOCRED, &bp);
#endif
if (error) {
brelse(bp);
bp = NULL;
@ -291,10 +273,6 @@ WRITE(ap)
if (uio->uio_offset + xfersize > ip->i_size)
vnode_pager_setsize(vp, uio->uio_offset + xfersize);
#ifdef LFS_READWRITE
(void)lfs_check(vp, lbn);
error = lfs_balloc(vp, blkoffset, xfersize, lbn, &bp);
#else
if (fs->fs_bsize > xfersize)
flags |= B_CLRBUF;
else
@ -302,7 +280,6 @@ WRITE(ap)
error = ffs_balloc(ip,
lbn, blkoffset + xfersize, ap->a_cred, &bp, flags);
#endif
if (error)
break;
@ -325,9 +302,6 @@ WRITE(ap)
error =
uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
#ifdef LFS_READWRITE
(void)VOP_BWRITE(bp);
#else
if (ioflag & IO_VMIO)
bp->b_flags |= B_RELBUF;
@ -344,7 +318,6 @@ WRITE(ap)
bp->b_flags |= B_CLUSTEROK;
bdwrite(bp);
}
#endif
if (error || xfersize == 0)
break;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
@ -373,7 +346,6 @@ WRITE(ap)
return (error);
}
#ifndef LFS_READWRITE
/*
* get page routine
@ -526,4 +498,3 @@ ffs_getpages(ap)
return (rtval);
}
#endif

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)ufsmount.h 8.6 (Berkeley) 3/30/95
* $Id: ufsmount.h,v 1.11 1997/10/16 10:50:27 phk Exp $
* $Id: ufsmount.h,v 1.12 1997/10/16 20:32:40 phk Exp $
*/
#ifndef _UFS_UFS_UFSMOUNT_H_
@ -77,12 +77,10 @@ struct ufsmount {
struct vnode *um_devvp; /* block device mounted vnode */
union { /* pointer to superblock */
struct lfs *lfs; /* LFS */
struct fs *fs; /* FFS */
struct ext2_sb_info *e2fs; /* EXT2FS */
} ufsmount_u;
#define um_fs ufsmount_u.fs
#define um_lfs ufsmount_u.lfs
#define um_e2fs ufsmount_u.e2fs
#define um_e2fsb ufsmount_u.e2fs->s_es