summaryrefslogtreecommitdiff
path: root/ufs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'ufs/inode.c')
-rw-r--r--ufs/inode.c705
1 files changed, 0 insertions, 705 deletions
diff --git a/ufs/inode.c b/ufs/inode.c
deleted file mode 100644
index 066eb1e5..00000000
--- a/ufs/inode.c
+++ /dev/null
@@ -1,705 +0,0 @@
-/* Inode management routines
-
- Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2007
- Free Software Foundation, Inc.
-
- 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 "ufs.h"
-#include <string.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <netinet/in.h>
-#include <fcntl.h>
-#include <hurd/store.h>
-
-#define INOHSZ 512
-#if ((INOHSZ&(INOHSZ-1)) == 0)
-#define INOHASH(ino) ((ino)&(INOHSZ-1))
-#else
-#define INOHASH(ino) (((unsigned)(ino))%INOHSZ)
-#endif
-
-static struct node *nodehash[INOHSZ];
-static error_t read_disknode (struct node *np);
-
-pthread_spinlock_t gennumberlock = PTHREAD_SPINLOCK_INITIALIZER;
-
-/* Initialize the inode hash table. */
-void
-inode_init ()
-{
- int n;
- for (n = 0; n < INOHSZ; n++)
- nodehash[n] = 0;
-}
-
-/* Fetch inode INUM, set *NPP to the node structure;
- gain one user reference and lock the node. */
-error_t
-diskfs_cached_lookup (ino_t inum, struct node **npp)
-{
- struct disknode *dn;
- struct node *np;
- error_t err;
-
- pthread_spin_lock (&diskfs_node_refcnt_lock);
- for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
- {
- if (np->dn->number != inum)
- continue;
-
- np->references++;
- pthread_spin_unlock (&diskfs_node_refcnt_lock);
- pthread_mutex_lock (&np->lock);
- *npp = np;
- return 0;
- }
-
- dn = malloc (sizeof (struct disknode));
-
- dn->number = inum;
- dn->dirents = 0;
- dn->dir_idx = 0;
-
- pthread_rwlock_init (&dn->allocptrlock, NULL);
- pthread_mutex_init (&dn->waitlock, NULL);
- pthread_cond_init (&dn->waitcond, NULL);
- dn->dirty = 0;
- dn->fileinfo = 0;
-
- np = diskfs_make_node (dn);
- np->cache_id = inum;
-
- pthread_mutex_lock (&np->lock);
- dn->hnext = nodehash[INOHASH(inum)];
- if (dn->hnext)
- dn->hnext->dn->hprevp = &dn->hnext;
- dn->hprevp = &nodehash[INOHASH(inum)];
- nodehash[INOHASH(inum)] = np;
- pthread_spin_unlock (&diskfs_node_refcnt_lock);
-
- err = read_disknode (np);
-
- if (!diskfs_check_readonly () && !np->dn_stat.st_gen)
- {
- pthread_spin_lock (&gennumberlock);
- if (++nextgennumber < diskfs_mtime->seconds)
- nextgennumber = diskfs_mtime->seconds;
- np->dn_stat.st_gen = nextgennumber;
- pthread_spin_unlock (&gennumberlock);
- np->dn_set_ctime = 1;
- }
-
- if (err)
- return err;
- else
- {
- *npp = np;
- return 0;
- }
-}
-
-/* Lookup node INUM (which must have a reference already) and return it
- without allocating any new references. */
-struct node *
-ifind (ino_t inum)
-{
- struct node *np;
-
- pthread_spin_lock (&diskfs_node_refcnt_lock);
- for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
- {
- if (np->dn->number != inum)
- continue;
-
- assert (np->references);
- pthread_spin_unlock (&diskfs_node_refcnt_lock);
- return np;
- }
- assert (0);
-}
-
-/* The last reference to a node has gone away; drop
- it from the hash table and clean all state in the dn structure. */
-void
-diskfs_node_norefs (struct node *np)
-{
- *np->dn->hprevp = np->dn->hnext;
- if (np->dn->hnext)
- np->dn->hnext->dn->hprevp = np->dn->hprevp;
- if (np->dn->dirents)
- free (np->dn->dirents);
- assert (!np->dn->fileinfo);
- free (np->dn);
- free (np);
-}
-
-/* The last hard reference to a node has gone away; arrange to have
- all the weak references dropped that can be. */
-void
-diskfs_try_dropping_softrefs (struct node *np)
-{
- drop_pager_softrefs (np);
-}
-
-/* The last hard reference to a node has gone away. */
-void
-diskfs_lost_hardrefs (struct node *np)
-{
-#ifdef notanymore
- struct port_info *pi;
- struct pager *p;
-
- /* Check and see if there is a pager which has only
- one reference (ours). If so, then drop that reference,
- breaking the cycle. The complexity in this routine
- is all due to this cycle. */
-
- if (np->dn->fileinfo)
- {
- pthread_spin_lock (&_libports_portrefcntlock);
- pi = (struct port_info *) np->dn->fileinfo->p;
- if (pi->refcnt == 1)
- {
-
- /* The only way to get a new reference to the pager
- in this state is to call diskfs_get_filemap; this
- can't happen as long as we hold NP locked. So
- we can safely unlock _libports_portrefcntlock for
- the following call. */
- pthread_spin_unlock (&_libports_portrefcntlock);
-
- /* Right now the node is locked with no hard refs;
- this is an anomalous situation. Before messing with
- the reference count on the file pager, we have to
- give ourselves a reference back so that we are really
- allowed to hold the lock. Then we can do the
- unreference. */
- p = np->dn->fileinfo->p;
- np->dn->fileinfo = 0;
- diskfs_nref (np);
- pager_unreference (p);
-
- assert (np->references == 1 && np->light_references == 0);
-
- /* This will do the real deallocate. Whew. */
- diskfs_nput (np);
- }
- else
- pthread_spin_unlock (&_libports_portrefcntlock);
- }
-#endif
-}
-
-/* A new hard reference to a node has been created; it's now OK to
- have unused weak references. */
-void
-diskfs_new_hardrefs (struct node *np)
-{
- allow_pager_softrefs (np);
-}
-
-/* Read stat information out of the dinode. */
-static error_t
-read_disknode (struct node *np)
-{
- struct stat *st = &np->dn_stat;
- struct dinode *di = dino (np->dn->number);
- error_t err;
-
- err = diskfs_catch_exception ();
- if (err)
- return err;
-
- st->st_fstype = FSTYPE_UFS;
- st->st_fsid = getpid (); /* This call is very cheap. */
- st->st_ino = np->dn->number;
- st->st_gen = read_disk_entry (di->di_gen);
- st->st_rdev = read_disk_entry(di->di_rdev);
- st->st_mode = (((read_disk_entry (di->di_model)
- | (read_disk_entry (di->di_modeh) << 16))
- & ~S_ITRANS)
- | (di->di_trans ? S_IPTRANS : 0));
- st->st_nlink = read_disk_entry (di->di_nlink);
- st->st_size = read_disk_entry (di->di_size);
- st->st_atim.tv_sec = read_disk_entry (di->di_atime.tv_sec);
- st->st_atim.tv_nsec = read_disk_entry (di->di_atime.tv_nsec);
- st->st_mtim.tv_sec = read_disk_entry (di->di_mtime.tv_sec);
- st->st_mtim.tv_nsec = read_disk_entry (di->di_mtime.tv_nsec);
- st->st_ctim.tv_sec = read_disk_entry (di->di_ctime.tv_sec);
- st->st_ctim.tv_nsec = read_disk_entry (di->di_ctime.tv_nsec);
- st->st_blksize = sblock->fs_bsize;
- st->st_blocks = read_disk_entry (di->di_blocks);
- st->st_flags = read_disk_entry (di->di_flags);
-
- if (sblock->fs_inodefmt < FS_44INODEFMT)
- {
- st->st_uid = read_disk_entry (di->di_ouid);
- st->st_gid = read_disk_entry (di->di_ogid);
- st->st_author = st->st_uid;
- np->author_tracks_uid = 1;
- }
- else
- {
- st->st_uid = read_disk_entry (di->di_uid);
- st->st_gid = read_disk_entry (di->di_gid);
- st->st_author = read_disk_entry (di->di_author);
- if (st->st_author == -1)
- st->st_author = st->st_uid;
- }
-
- diskfs_end_catch_exception ();
- if (!S_ISBLK (st->st_mode) && !S_ISCHR (st->st_mode))
- st->st_rdev = 0;
-
- if (S_ISLNK (st->st_mode)
- && direct_symlink_extension
- && st->st_size < sblock->fs_maxsymlinklen)
- np->allocsize = 0;
- else
- {
- if (lblkno (sblock, np->dn_stat.st_size) < NDADDR)
- np->allocsize = fragroundup (sblock, st->st_size);
- else
- np->allocsize = blkroundup (sblock, st->st_size);
- }
-
- return 0;
-}
-
-error_t diskfs_node_reload (struct node *node)
-{
- if (node->dn->dirents)
- {
- free (node->dn->dirents);
- node->dn->dirents = 0;
- }
- flush_node_pager (node);
- read_disknode (node);
- return 0;
-}
-
-/* Return 0 if NP's author can be changed to AUTHOR; otherwise return an
- error code. */
-error_t
-diskfs_validate_author_change (struct node *np, uid_t author)
-{
- if (compat_mode == COMPAT_GNU)
- return 0;
- else
- /* For non-hurd filesystems, the author & owner are the same. */
- return (author == np->dn_stat.st_uid) ? 0 : EINVAL;
-}
-
-static void
-write_node (struct node *np)
-{
- struct stat *st = &np->dn_stat;
- struct dinode *di = dino (np->dn->number);
- error_t err;
-
- if (np->dn_stat_dirty)
- {
- assert (!diskfs_readonly);
-
- err = diskfs_catch_exception ();
- if (err)
- return;
-
- write_disk_entry (di->di_gen, st->st_gen);
-
- if (S_ISBLK (st->st_mode) || S_ISCHR (st->st_mode))
- write_disk_entry (di->di_rdev, st->st_rdev);
-
- /* We happen to know that the stat mode bits are the same
- as the ufs mode bits. */
-
- if (compat_mode == COMPAT_GNU)
- {
- mode_t mode = st->st_mode & ~S_ITRANS;
- write_disk_entry (di->di_model, mode & 0xffff);
- write_disk_entry (di->di_modeh, (mode >> 16) & 0xffff);
- }
- else
- {
- write_disk_entry (di->di_model, st->st_mode & 0xffff & ~S_ITRANS);
- di->di_modeh = 0;
- }
-
- if (compat_mode != COMPAT_BSD42)
- {
- write_disk_entry (di->di_uid, st->st_uid);
- write_disk_entry (di->di_gid, st->st_gid);
- }
-
- if (sblock->fs_inodefmt < FS_44INODEFMT)
- {
- write_disk_entry (di->di_ouid, st->st_uid & 0xffff);
- write_disk_entry (di->di_ogid, st->st_gid & 0xffff);
- }
- else if (compat_mode == COMPAT_GNU)
- write_disk_entry (di->di_author, st->st_author);
-
- write_disk_entry (di->di_nlink, st->st_nlink);
- write_disk_entry (di->di_size, st->st_size);
- write_disk_entry (di->di_atime.tv_sec, st->st_atim.tv_sec);
- write_disk_entry (di->di_atime.tv_nsec, st->st_atim.tv_nsec);
- write_disk_entry (di->di_mtime.tv_sec, st->st_mtim.tv_sec);
- write_disk_entry (di->di_mtime.tv_nsec, st->st_mtim.tv_nsec);
- write_disk_entry (di->di_ctime.tv_sec, st->st_ctim.tv_sec);
- write_disk_entry (di->di_ctime.tv_nsec, st->st_ctim.tv_nsec);
- write_disk_entry (di->di_blocks, st->st_blocks);
- write_disk_entry (di->di_flags, st->st_flags);
-
- diskfs_end_catch_exception ();
- np->dn_stat_dirty = 0;
- record_poke (di, sizeof (struct dinode));
- }
-}
-
-/* See if we should create a symlink by writing it directly into
- the block pointer array. Returning EINVAL tells diskfs to do it
- the usual way. */
-static error_t
-create_symlink_hook (struct node *np, const char *target)
-{
- int len = strlen (target);
- error_t err;
- struct dinode *di;
-
- if (!direct_symlink_extension)
- return EINVAL;
-
- assert (compat_mode != COMPAT_BSD42);
-
- if (len >= sblock->fs_maxsymlinklen)
- return EINVAL;
-
- err = diskfs_catch_exception ();
- if (err)
- return err;
-
- di = dino (np->dn->number);
- bcopy (target, di->di_shortlink, len);
- np->dn_stat.st_size = len;
- np->dn_set_ctime = 1;
- np->dn_set_mtime = 1;
- record_poke (di, sizeof (struct dinode));
-
- diskfs_end_catch_exception ();
- return 0;
-}
-error_t (*diskfs_create_symlink_hook)(struct node *, const char *)
- = create_symlink_hook;
-
-/* Check if this symlink is stored directly in the block pointer array.
- Returning EINVAL tells diskfs to do it the usual way. */
-static error_t
-read_symlink_hook (struct node *np,
- char *buf)
-{
- error_t err;
-
- if (!direct_symlink_extension
- || np->dn_stat.st_size >= sblock->fs_maxsymlinklen)
- return EINVAL;
-
- err = diskfs_catch_exception ();
- if (err)
- return err;
-
- bcopy ((dino (np->dn->number))->di_shortlink, buf, np->dn_stat.st_size);
-
- diskfs_set_node_atime (np);
-
- diskfs_end_catch_exception ();
- return 0;
-}
-error_t (*diskfs_read_symlink_hook)(struct node *, char *)
- = read_symlink_hook;
-
-error_t
-diskfs_node_iterate (error_t (*fun)(struct node *))
-{
- struct node *np;
- struct item {struct item *next; struct node *np;} *list = 0;
- struct item *i;
- error_t err;
- int n;
-
- /* Acquire a reference on all the nodes in the hash table
- and enter them into a list on the stack. */
- pthread_spin_lock (&diskfs_node_refcnt_lock);
- for (n = 0; n < INOHSZ; n++)
- for (np = nodehash[n]; np; np = np->dn->hnext)
- {
- np->references++;
- i = alloca (sizeof (struct item));
- i->next = list;
- i->np = np;
- list = i;
- }
- pthread_spin_unlock (&diskfs_node_refcnt_lock);
-
- err = 0;
- for (i = list; i; i = i->next)
- {
- if (!err)
- {
- pthread_mutex_lock (&i->np->lock);
- err = (*fun)(i->np);
- pthread_mutex_unlock (&i->np->lock);
- }
- diskfs_nrele (i->np);
- }
- return err;
-}
-
-/* Write all active disknodes into the dinode pager. */
-void
-write_all_disknodes ()
-{
- error_t
- helper (struct node *np)
- {
- diskfs_set_node_times (np);
- write_node (np);
- return 0;
- }
-
- diskfs_node_iterate (helper);
-}
-
-void
-diskfs_write_disknode (struct node *np, int wait)
-{
- write_node (np);
- if (wait)
- sync_dinode (np->dn->number, 1);
-}
-
-/* Implement the diskfs_set_statfs callback from the diskfs library;
- see <hurd/diskfs.h> for the interface description. */
-error_t
-diskfs_set_statfs (struct statfs *st)
-{
- st->f_type = FSTYPE_UFS;
- st->f_bsize = sblock->fs_fsize;
- st->f_blocks = sblock->fs_dsize;
- st->f_bfree = (sblock->fs_cstotal.cs_nbfree * sblock->fs_frag
- + sblock->fs_cstotal.cs_nffree);
- st->f_bavail = ((sblock->fs_dsize * (100 - sblock->fs_minfree) / 100)
- - (sblock->fs_dsize - st->f_bfree));
- if (st->f_bfree < ((sblock->fs_dsize * (100 - sblock->fs_minfree) / 100)))
- st->f_bavail = 0;
- st->f_files = sblock->fs_ncg * sblock->fs_ipg - 2; /* not 0 or 1 */
- st->f_ffree = sblock->fs_cstotal.cs_nifree;
- st->f_fsid = getpid ();
- st->f_namelen = 0;
- st->f_favail = st->f_ffree;
- st->f_frsize = sblock->fs_fsize;
- return 0;
-}
-
-/* Implement the diskfs_set_translator callback from the diskfs
- library; see <hurd/diskfs.h> for the interface description. */
-error_t
-diskfs_set_translator (struct node *np, const char *name, u_int namelen,
- struct protid *cred)
-{
- daddr_t blkno;
- error_t err;
- char buf[sblock->fs_bsize];
- struct dinode *di;
-
- if (compat_mode != COMPAT_GNU)
- return EOPNOTSUPP;
-
- if (namelen + sizeof (u_int) > sblock->fs_bsize)
- return ENAMETOOLONG;
-
- err = diskfs_catch_exception ();
- if (err)
- return err;
-
- di = dino (np->dn->number);
- blkno = read_disk_entry (di->di_trans);
-
- if (namelen && !blkno)
- {
- /* Allocate block for translator */
- err = ffs_alloc (np, 0, 0, sblock->fs_bsize, &blkno, cred);
- if (err)
- {
- diskfs_end_catch_exception ();
- return err;
- }
- write_disk_entry (di->di_trans, blkno);
- record_poke (di, sizeof (struct dinode));
- np->dn_set_ctime = 1;
- }
- else if (!namelen && blkno)
- {
- /* Clear block for translator going away. */
- ffs_blkfree (np, blkno, sblock->fs_bsize);
- di->di_trans = 0;
- record_poke (di, sizeof (struct dinode));
- np->dn_stat.st_blocks -= btodb (sblock->fs_bsize);
- np->dn_stat.st_mode &= ~S_IPTRANS;
- np->dn_set_ctime = 1;
- }
-
- if (namelen)
- {
- bcopy (&namelen, buf, sizeof (u_int));
- bcopy (name, buf + sizeof (u_int), namelen);
-
- bcopy (buf, disk_image + fsaddr (sblock, blkno), sblock->fs_bsize);
- sync_disk_blocks (blkno, sblock->fs_bsize, 1);
-
- np->dn_stat.st_mode |= S_IPTRANS;
- np->dn_set_ctime = 1;
- }
-
- diskfs_end_catch_exception ();
- return err;
-}
-
-/* Implement the diskfs_get_translator callback from the diskfs library.
- See <hurd/diskfs.h> for the interface description. */
-error_t
-diskfs_get_translator (struct node *np, char **namep, u_int *namelen)
-{
- error_t err;
- daddr_t blkno;
- u_int datalen;
- const void *transloc;
-
- err = diskfs_catch_exception ();
- if (err)
- return err;
-
- blkno = read_disk_entry ((dino (np->dn->number))->di_trans);
- assert (blkno);
- transloc = disk_image + fsaddr (sblock, blkno);
-
- datalen = *(u_int *)transloc;
- if (datalen > sblock->fs_bsize - sizeof (u_int))
- err = EFTYPE;
- else
- {
- *namep = malloc (datalen);
- if (*namep == NULL)
- err = ENOMEM;
- memcpy (*namep, transloc + sizeof (u_int), datalen);
- }
-
- diskfs_end_catch_exception ();
-
- *namelen = datalen;
- return 0;
-}
-
-/* Called when all hard ports have gone away. */
-void
-diskfs_shutdown_soft_ports ()
-{
- /* Should initiate termination of internally held pager ports
- (the only things that should be soft) XXX */
-}
-
-/* Return a description of the storage of the file. */
-/* In STORAGE_DATA are the following, in network byte order:
-
- Inode number (4 bytes)
- disk address of transator spec (4 bytes)
- disk address of inode structure (4 bytes)
- offset into inode block holding inode (4 bytes) */
-error_t
-diskfs_S_file_get_storage_info (struct protid *cred,
- mach_port_t **ports,
- mach_msg_type_name_t *ports_type,
- mach_msg_type_number_t *num_ports,
- int **ints, mach_msg_type_number_t *num_ints,
- off_t **offsets,
- mach_msg_type_number_t *num_offsets,
- char **data, mach_msg_type_number_t *data_len)
-{
- error_t err;
- struct node *np;
- struct store *file_store;
- struct store_run runs[NDADDR];
- size_t num_runs = 0;
-
- if (! cred)
- return EOPNOTSUPP;
-
- np = cred->po->np;
- pthread_mutex_lock (&np->lock);
-
- /* See if this file fits in the direct block pointers. If not, punt
- for now. (Reading indir blocks is a pain, and I'm postponing
- pain.) XXX */
- if (np->allocsize > NDADDR * sblock->fs_bsize)
- {
- pthread_mutex_unlock (&np->lock);
- return EINVAL;
- }
-
- err = diskfs_catch_exception ();
- if (! err)
- if (!direct_symlink_extension
- || np->dn_stat.st_size >= sblock->fs_maxsymlinklen
- || !S_ISLNK (np->dn_stat.st_mode))
- /* Copy the block pointers */
- {
- int i;
- struct store_run *run = runs;
- struct dinode *di = dino (np->dn->number);
-
- for (i = 0; i < NDADDR; i++)
- {
- store_offset_t start = fsbtodb (sblock, read_disk_entry (di->di_db[i]));
- store_offset_t length =
- (((i + 1) * sblock->fs_bsize > np->allocsize)
- ? np->allocsize - i * sblock->fs_bsize
- : sblock->fs_bsize);
- start <<= log2_dev_blocks_per_dev_bsize;
- length <<= log2_dev_blocks_per_dev_bsize;
- if (num_runs == 0 || run->start + run->length != start)
- *run++ = (struct store_run){ start, length };
- else
- run->length += length;
- }
- }
- diskfs_end_catch_exception ();
-
- pthread_mutex_unlock (&np->lock);
-
- if (! err)
- err = store_clone (store, &file_store);
- if (! err)
- {
- err = store_remap (file_store, runs, num_runs, &file_store);
- if (! err)
- err = store_return (file_store, ports, num_ports, ints, num_ints,
- offsets, num_offsets, data, data_len);
- store_free (file_store);
- }
- *ports_type = MACH_MSG_TYPE_COPY_SEND;
-
- return err;
-}