aboutsummaryrefslogtreecommitdiff
path: root/ufs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'ufs/inode.c')
-rw-r--r--ufs/inode.c335
1 files changed, 156 insertions, 179 deletions
diff --git a/ufs/inode.c b/ufs/inode.c
index 640e6b6f..77a45edb 100644
--- a/ufs/inode.c
+++ b/ufs/inode.c
@@ -1,5 +1,7 @@
/* Inode management routines
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+
+ 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
@@ -20,6 +22,8 @@
#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)
@@ -42,10 +46,10 @@ inode_init ()
nodehash[n] = 0;
}
-/* Fetch inode INUM, set *NPP to the node structure;
+/* Fetch inode INUM, set *NPP to the node structure;
gain one user reference and lock the node. */
-error_t
-diskfs_cached_lookup (int inum, struct node **npp)
+error_t
+diskfs_cached_lookup (ino_t inum, struct node **npp)
{
struct disknode *dn;
struct node *np;
@@ -68,6 +72,7 @@ diskfs_cached_lookup (int inum, struct node **npp)
dn->number = inum;
dn->dirents = 0;
+ dn->dir_idx = 0;
rwlock_init (&dn->allocptrlock);
dn->dirty = 0;
@@ -85,7 +90,7 @@ diskfs_cached_lookup (int inum, struct node **npp)
spin_unlock (&diskfs_node_refcnt_lock);
err = read_disknode (np);
-
+
if (!diskfs_check_readonly () && !np->dn_stat.st_gen)
{
spin_lock (&gennumberlock);
@@ -95,7 +100,7 @@ diskfs_cached_lookup (int inum, struct node **npp)
spin_unlock (&gennumberlock);
np->dn_set_ctime = 1;
}
-
+
if (err)
return err;
else
@@ -111,13 +116,13 @@ struct node *
ifind (ino_t inum)
{
struct node *np;
-
+
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);
spin_unlock (&diskfs_node_refcnt_lock);
return np;
@@ -127,7 +132,7 @@ ifind (ino_t inum)
/* The last reference to a node has gone away; drop
it from the hash table and clean all state in the dn structure. */
-void
+void
diskfs_node_norefs (struct node *np)
{
*np->dn->hprevp = np->dn->hnext;
@@ -155,7 +160,7 @@ 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
@@ -167,17 +172,17 @@ diskfs_lost_hardrefs (struct node *np)
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. */
spin_unlock (&_libports_portrefcntlock);
-
+
/* Right now the node is locked with no hard refs;
- this is an anomolous situation. Before messing with
- the reference count on the file pager, we have to
+ 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. */
@@ -209,53 +214,41 @@ diskfs_new_hardrefs (struct node *np)
static error_t
read_disknode (struct node *np)
{
- static int fsid, fsidset;
struct stat *st = &np->dn_stat;
struct dinode *di = dino (np->dn->number);
error_t err;
-
+
err = diskfs_catch_exception ();
if (err)
return err;
- np->istranslated = !! di->di_trans;
-
- if (!fsidset)
- {
- fsid = getpid ();
- fsidset = 1;
- }
-
st->st_fstype = FSTYPE_UFS;
- st->st_fsid = fsid;
+ 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));
+ 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);
-#ifdef notyet
- st->st_atimespec = di->di_atime;
- st->st_mtimespec = di->di_mtime;
- st->st_ctimespec = di->di_ctime;
-#else
- st->st_atime = read_disk_entry (di->di_atime.tv_sec);
- st->st_atime_usec = read_disk_entry (di->di_atime.tv_nsec) / 1000;
- st->st_mtime = read_disk_entry (di->di_mtime.tv_sec);
- st->st_mtime_usec = read_disk_entry (di->di_mtime.tv_nsec) / 1000;
- st->st_ctime = read_disk_entry (di->di_ctime.tv_sec);
- st->st_ctime_usec = read_disk_entry (di->di_ctime.tv_nsec) / 1000;
-#endif
+ 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 = 0;
+ st->st_author = st->st_uid;
+ np->author_tracks_uid = 1;
}
else
{
@@ -270,8 +263,8 @@ read_disknode (struct node *np)
if (!S_ISBLK (st->st_mode) && !S_ISCHR (st->st_mode))
st->st_rdev = 0;
- if (S_ISLNK (st->st_mode)
- && direct_symlink_extension
+ if (S_ISLNK (st->st_mode)
+ && direct_symlink_extension
&& st->st_size < sblock->fs_maxsymlinklen)
np->allocsize = 0;
else
@@ -297,14 +290,25 @@ error_t diskfs_node_reload (struct node *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;
-
- assert (!np->dn_set_ctime && !np->dn_set_atime && !np->dn_set_mtime);
+
if (np->dn_stat_dirty)
{
assert (!diskfs_readonly);
@@ -312,9 +316,9 @@ write_node (struct node *np)
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);
@@ -323,12 +327,13 @@ write_node (struct node *np)
if (compat_mode == COMPAT_GNU)
{
- write_disk_entry (di->di_model, st->st_mode & 0xffff);
- write_disk_entry (di->di_modeh, (st->st_mode >> 16) & 0xffff);
+ 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
+ else
{
- write_disk_entry (di->di_model, st->st_mode & 0xffff);
+ write_disk_entry (di->di_model, st->st_mode & 0xffff & ~S_ITRANS);
di->di_modeh = 0;
}
@@ -337,7 +342,7 @@ write_node (struct node *np)
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);
@@ -348,49 +353,43 @@ write_node (struct node *np)
write_disk_entry (di->di_nlink, st->st_nlink);
write_disk_entry (di->di_size, st->st_size);
-#ifdef notyet
- di->di_atime = st->st_atimespec;
- di->di_mtime = st->st_mtimespec;
- di->di_ctime = st->st_ctimespec;
-#else
- write_disk_entry (di->di_atime.tv_sec, st->st_atime);
- write_disk_entry (di->di_atime.tv_nsec, st->st_atime_usec * 1000);
- write_disk_entry (di->di_mtime.tv_sec, st->st_mtime);
- write_disk_entry (di->di_mtime.tv_nsec, st->st_mtime_usec * 1000);
- write_disk_entry (di->di_ctime.tv_sec, st->st_ctime);
- write_disk_entry (di->di_ctime.tv_nsec, st->st_ctime_usec * 1000);
-#endif
+ 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, char *target)
+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;
@@ -401,29 +400,28 @@ create_symlink_hook (struct node *np, char *target)
diskfs_end_catch_exception ();
return 0;
}
-error_t (*diskfs_create_symlink_hook)(struct node *, char *)
+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
+static error_t
read_symlink_hook (struct node *np,
char *buf)
{
error_t err;
-
- if (!direct_symlink_extension
+
+ 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);
- if (! diskfs_check_readonly ())
- np->dn_set_atime = 1;
+ diskfs_set_node_atime (np);
diskfs_end_catch_exception ();
return 0;
@@ -439,7 +437,7 @@ diskfs_node_iterate (error_t (*fun)(struct node *))
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. */
spin_lock (&diskfs_node_refcnt_lock);
@@ -479,10 +477,10 @@ write_all_disknodes ()
write_node (np);
return 0;
}
-
+
diskfs_node_iterate (helper);
}
-
+
void
diskfs_write_disknode (struct node *np, int wait)
{
@@ -497,23 +495,27 @@ error_t
diskfs_set_statfs (struct statfs *st)
{
st->f_type = FSTYPE_UFS;
- st->f_bsize = sblock->fs_bsize;
- st->f_blocks = sblock->fs_dsize * sblock->fs_frag;
+ 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, char *name, u_int namelen,
+diskfs_set_translator (struct node *np, const char *name, u_int namelen,
struct protid *cred)
{
daddr_t blkno;
@@ -530,10 +532,10 @@ diskfs_set_translator (struct node *np, char *name, u_int namelen,
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 */
@@ -554,10 +556,10 @@ diskfs_set_translator (struct node *np, char *name, u_int namelen,
di->di_trans = 0;
record_poke (di, sizeof (struct dinode));
np->dn_stat.st_blocks -= btodb (sblock->fs_bsize);
- np->istranslated = 0;
+ np->dn_stat.st_mode &= ~S_IPTRANS;
np->dn_set_ctime = 1;
}
-
+
if (namelen)
{
bcopy (&namelen, buf, sizeof (u_int));
@@ -566,10 +568,10 @@ diskfs_set_translator (struct node *np, char *name, u_int namelen,
bcopy (buf, disk_image + fsaddr (sblock, blkno), sblock->fs_bsize);
sync_disk_blocks (blkno, sblock->fs_bsize, 1);
- np->istranslated = 1;
+ np->dn_stat.st_mode |= S_IPTRANS;
np->dn_set_ctime = 1;
}
-
+
diskfs_end_catch_exception ();
return err;
}
@@ -582,7 +584,7 @@ diskfs_get_translator (struct node *np, char **namep, u_int *namelen)
error_t err;
daddr_t blkno;
u_int datalen;
- void *transloc;
+ const void *transloc;
err = diskfs_catch_exception ();
if (err)
@@ -591,10 +593,17 @@ diskfs_get_translator (struct node *np, char **namep, u_int *namelen)
blkno = read_disk_entry ((dino (np->dn->number))->di_trans);
assert (blkno);
transloc = disk_image + fsaddr (sblock, blkno);
-
+
datalen = *(u_int *)transloc;
- *namep = malloc (datalen);
- bcopy (transloc + sizeof (u_int), *namep, datalen);
+ 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 ();
@@ -619,108 +628,76 @@ diskfs_shutdown_soft_ports ()
offset into inode block holding inode (4 bytes) */
error_t
diskfs_S_file_get_storage_info (struct protid *cred,
- int *class,
- off_t **addresses,
- u_int *naddresses,
- size_t *block_size,
- char *storage_name,
- mach_port_t *storage_port,
- mach_msg_type_name_t *storage_port_type,
- char **storage_data,
- u_int *storage_data_len,
- int *flags)
+ 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;
- int i;
- struct dinode *di;
- void *cp;
-
+ struct store *file_store;
+ struct store_run runs[NDADDR];
+ size_t num_runs = 0;
+
+ if (! cred)
+ return EOPNOTSUPP;
+
np = cred->po->np;
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)
{
mutex_unlock (&np->lock);
return EINVAL;
}
-
- if (*naddresses < NDADDR * 2)
- vm_allocate (mach_task_self (), (vm_address_t *) addresses,
- sizeof (int) * NDADDR * 2, 1);
- else
- bzero (addresses, *naddresses * 2 * sizeof (int));
- *naddresses = NDADDR * 2;
-
- if (*storage_data_len < 4 * sizeof (int))
- vm_allocate (mach_task_self (), (vm_address_t *) storage_data,
- sizeof (int) * 4, 1);
- *storage_data_len = 4 * sizeof (int);
- di = dino (np->dn->number);
-
err = diskfs_catch_exception ();
- if (err)
- {
- mutex_unlock (&np->lock);
- return err;
- }
-
- /* Copy the block pointers */
+ 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 ();
- if (!direct_symlink_extension
- || np->dn_stat.st_size >= sblock->fs_maxsymlinklen
- || !S_ISLNK (np->dn_stat.st_mode))
+ mutex_unlock (&np->lock);
+
+ if (! err)
+ err = store_clone (store, &file_store);
+ if (! err)
{
- for (i = 0; i < NDADDR; i++)
- {
- (*addresses)[2 * i] = fsbtodb (sblock,
- read_disk_entry (di->di_db[i]));
- if ((i + 1) * sblock->fs_bsize > np->allocsize)
- (*addresses)[2 * i + 1] = np->allocsize - i * sblock->fs_bsize;
- else
- (*addresses)[2 * i + 1] = sblock->fs_bsize;
- }
+ 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;
- /* Fill in the aux data */
- cp = *storage_data;
-
- *(int *)cp = htonl (np->dn->number);
- cp += sizeof (int);
-
- *(int *)cp = htonl (di->di_trans);
- cp += sizeof (int);
-
- *(int *)cp = htonl (fsbtodb (sblock, ino_to_fsba (sblock, np->dn->number)));
- cp += sizeof (int);
-
- *(int *)cp = htonl (ino_to_fsbo (sblock, np->dn->number)
- * sizeof (struct dinode));
-
-
- diskfs_end_catch_exception ();
-
- *class = STORAGE_DEVICE;
- *flags = 0;
- *block_size = DEV_BSIZE;
-
- if (diskfs_device_name)
- strcpy (storage_name, diskfs_device_name);
-
- if (diskfs_isuid (0, cred))
- *storage_port = diskfs_device;
- else
- *storage_port = MACH_PORT_NULL;
- *storage_port_type = MACH_MSG_TYPE_COPY_SEND;
-
- mutex_unlock (&np->lock);
-
- return 0;
+ return err;
}
-
-