/* Copyright (C) 1994, 1995, 1996 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include "fs.h" #include "dinode.h" /* Define this if memory objects should not be cached by the kernel. Normally, don't define it, but defining it causes a much greater rate of paging requests, which may be helpful in catching bugs. */ /* #undef DONT_CACHE_MEMORY_OBJECTS */ struct disknode { ino_t number; /* For a directory, this array holds the number of directory entries in each DIRBLKSIZE piece of the directory. */ int *dirents; /* Links on hash list. */ struct node *hnext, **hprevp; struct rwlock allocptrlock; struct dirty_indir *dirty; struct user_pager_info *fileinfo; }; /* Identifies a particular block and where it's found when interpreting indirect block structure. */ struct iblock_spec { /* Disk address of block */ daddr_t bno; /* Offset in next block up; -1 if it's in the inode itself. */ int offset; }; /* Identifies an indirect block owned by this file which might be dirty. */ struct dirty_indir { daddr_t bno; /* Disk address of block. */ struct dirty_indir *next; }; struct user_pager_info { struct node *np; enum pager_type { DISK, FILE_DATA, } type; struct pager *p; vm_prot_t max_prot; }; #include extern vm_address_t zeroblock; extern struct fs *sblock; extern struct csum *csum; int sblock_dirty; int csum_dirty; spin_lock_t node2pagelock; spin_lock_t alloclock; spin_lock_t gennumberlock; u_long nextgennumber; /* The compat_mode specifies whether or not we write extensions onto the disk. */ enum compat_mode { COMPAT_GNU = 0, COMPAT_BSD42 = 1, COMPAT_BSD44 = 2, } compat_mode; /* If this is set, then this filesystem has two extensions: 1) directory entries include the type field. 2) symlink targets might be written directly in the di_db field of the dinode. */ int direct_symlink_extension; /* If this is set, then the disk is byteswapped from native order. */ int swab_disk; /* Handy macros */ #define DEV_BSIZE 512 #define NBBY 8 #define btodb(n) ((n) / DEV_BSIZE) #define howmany(x,y) (((x)+((y)-1))/(y)) #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) #define isclr(a, i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) #define isset(a, i) ((a)[(i)/NBBY] & (1<<((i)%NBBY))) #define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY)) #define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<(i)%NBBY)) #define fsaddr(fs,n) (fsbtodb(fs,n)*DEV_BSIZE) /* Functions for looking inside disk_image */ /* Convert an inode number to the dinode on disk. */ extern inline struct dinode * dino (ino_t inum) { return (struct dinode *) (disk_image + fsaddr (sblock, ino_to_fsba (sblock, inum)) + ino_to_fsbo (sblock, inum) * sizeof (struct dinode)); } /* Convert a indirect block number to a daddr_t table. */ extern inline daddr_t * indir_block (daddr_t bno) { return (daddr_t *) (disk_image + fsaddr (sblock, bno)); } /* Convert a cg number to the cylinder group. */ extern inline struct cg * cg_locate (int ncg) { return (struct cg *) (disk_image + fsaddr (sblock, cgtod (sblock, ncg))); } /* Sync part of the disk */ extern inline void sync_disk_blocks (daddr_t blkno, size_t nbytes, int wait) { pager_sync_some (disk_pager, fsaddr (sblock, blkno), nbytes, wait); } /* Sync an disk inode */ extern inline void sync_dinode (int inum, int wait) { sync_disk_blocks (ino_to_fsba (sblock, inum), sblock->fs_fsize, wait); } /* Functions for byte swapping */ extern inline short swab_short (short arg) { return (((arg & 0xff) << 8) | ((arg & 0xff00) >> 8)); } extern inline long swab_long (long arg) { return (((arg & 0xff) << 24) | ((arg & 0xff00) << 8) | ((arg & 0xff0000) >> 8) | ((arg & 0xff000000) >> 24)); } /* Return ENTRY, after byteswapping it if necessary */ #define read_disk_entry(entry) \ ({ \ if (!swab_disk || sizeof (entry) == 1) \ (entry); \ else if (sizeof (entry) == 2) \ swab_short (entry); \ else if (sizeof (entry) == 4) \ swab_long (entry); \ else \ abort (); \ }) /* Execute A = B, but byteswap it along the way if necessary */ #define write_disk_entry(a,b) \ ({ \ if (!swab_disk || sizeof (a) == 1) \ ((a) = (b)); \ else if (sizeof (a) == 2) \ ((a) = (swab_short (b))); \ else if (sizeof (a) == 4) \ ((a) = (swab_long (b))); \ else \ abort (); \ }) /* From alloc.c: */ error_t ffs_alloc (struct node *, daddr_t, daddr_t, int, daddr_t *, struct protid *); void ffs_blkfree(struct node *, daddr_t bno, long size); daddr_t ffs_blkpref (struct node *, daddr_t, int, daddr_t *); error_t ffs_realloccg(struct node *, daddr_t, daddr_t, int, int, daddr_t *, struct protid *); /* From bmap.c */ error_t fetch_indir_spec (struct node *, daddr_t, struct iblock_spec *); void mark_indir_dirty (struct node *, daddr_t); /* From hyper.c: */ void get_hypermetadata (void); void copy_sblock (void); /* From inode.c: */ struct node *ifind (ino_t ino); void inode_init (void); void write_all_disknodes (void); /* From pager.c: */ void create_disk_pager (void); void din_map (struct node *); void sin_map (struct node *); void sin_remap (struct node *, int); void sin_unmap (struct node *); void din_unmap (struct node *); void drop_pager_softrefs (struct node *); void allow_pager_softrefs (struct node *); void flush_node_pager (struct node *); /* From subr.c: */ void ffs_fragacct (struct fs *, int, long [], int); int ffs_isblock(struct fs *, u_char *, daddr_t); void ffs_clrblock(struct fs *, u_char *, daddr_t); void ffs_setblock (struct fs *, u_char *, daddr_t); int skpc (int, int, char *); int scanc (u_int, u_char *, u_char [], int); /* From pokeloc.c: */ void record_poke (void *, vm_size_t); void sync_disk (int); void flush_pokes ();