/* Copyright (C) 1994 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 /* 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 */ /* Simple reader/writer lock. */ struct rwlock { int readers; int writers_waiting; int readers_waiting; }; 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 mutex rwlock_master; struct condition rwlock_wakeup; struct rwlock dinlock; /* locks INDIR_DOUBLE pointer */ /* sinlock locks INDIR_SINGLE pointer and all the pointers in the double indir block. */ struct rwlock sinlock; /* datalock locks all the direct block pointers and all the pointers in all the single indir blocks */ struct rwlock datalock; /* These pointers are locked by sinmaplock and dinmaplock for all nodes. */ daddr_t *dinloc; daddr_t *sinloc; size_t dinloclen; size_t sinloclen; /* These two pointers are locked by pagernplock for all nodes. */ struct user_pager_info *sininfo; struct user_pager_info *fileinfo; }; /* Get a reader lock on reader-writer lock LOCK for disknode DN */ extern inline void rwlock_reader_lock (struct rwlock *lock, struct disknode *dn) { mutex_lock (&dn->rwlock_master); if (lock->readers == -1 || lock->writers_waiting) { lock->readers_waiting++; do condition_wait (&dn->rwlock_wakeup, &dn->rwlock_master); while (lock->readers == -1 || lock->writers_waiting); lock->readers_waiting--; } lock->readers++; mutex_unlock (&dn->rwlock_master); } /* Get a writer lock on reader-writer lock LOCK for disknode DN */ extern inline void rwlock_writer_lock (struct rwlock *lock, struct disknode *dn) { mutex_lock (&dn->rwlock_master); if (lock->readers) { lock->writers_waiting++; do condition_wait (&dn->rwlock_wakeup, &dn->rwlock_master); while (lock->readers); lock->writers_waiting--; } lock->readers = -1; mutex_unlock (&dn->rwlock_master); } /* Release a reader lock on reader-writer lock LOCK for disknode DN */ extern inline void rwlock_reader_unlock (struct rwlock *lock, struct disknode *dn) { mutex_lock (&dn->rwlock_master); assert (lock->readers); lock->readers--; if (lock->readers_waiting || lock->writers_waiting) condition_broadcast (&dn->rwlock_wakeup); mutex_unlock (&dn->rwlock_master); } /* Release a writer lock on reader-writer lock LOCK for disknode DN */ extern inline void rwlock_writer_unlock (struct rwlock *lock, struct disknode *dn) { mutex_lock (&dn->rwlock_master); assert (lock->readers == -1); lock->readers = 0; if (lock->readers_waiting || lock->writers_waiting) condition_broadcast (&dn->rwlock_wakeup); mutex_unlock (&dn->rwlock_master); } /* Initialize reader-writer lock LOCK */ extern inline void rwlock_init (struct rwlock *lock) { lock->readers = 0; lock->readers_waiting = 0; lock->writers_waiting = 0; } struct user_pager_info { struct node *np; enum pager_type { DINODE, CG, SINDIR, DINDIR, FILE_DATA, } type; struct pager *p; struct user_pager_info *next, **prevp; }; struct user_pager_info *dinpager, *dinodepager, *cgpager; vm_address_t zeroblock; struct fs *sblock; struct dinode *dinodes; vm_address_t cgs; struct csum *csum; int sblock_dirty; int csum_dirty; spin_lock_t alloclock; struct mutex dinmaplock; struct mutex sinmaplock; struct mutex pagernplock; spin_lock_t gennumberlock; u_long nextgennumber; mach_port_t ufs_device; /* 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; #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)) /* 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 devio.c: */ error_t dev_write_sync (daddr_t addr, vm_address_t data, long len); error_t dev_write (daddr_t addr, vm_address_t data, long len); error_t dev_read_sync (daddr_t addr, vm_address_t *data, long len); /* From hyper.c: */ void get_hypermetadata (void); /* From inode.c: */ error_t iget (ino_t ino, struct node **NP); struct node *ifind (ino_t ino); void inode_init (void); void write_all_disknodes (void); /* From pager.c: */ void sync_dinode (struct node *, int); void pager_init (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 *); /* 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);