ufsops.c revision 4a634bb80136cc001d14ab96addd9915105e5223
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <sys/bootdebug.h>
int print_cache_stats = 0;
/*
* This fd is used when talking to the device file itself.
*/
/*
* hooks into ufs logging support
*/
extern void lufs_boot_init(fileid_t *);
extern void lufs_closeall(void);
extern void lufs_merge_deltas(fileid_t *);
/* Only got one of these...ergo, only 1 fs open at once */
/* static */
struct dirinfo {
int loc;
};
/*
* Function prototypes
*/
static int boot_ufs_mountroot(char *str);
static int boot_ufs_unmountroot(void);
static int boot_ufs_close(int fd);
static void boot_ufs_closeall(int flag);
struct boot_fs_ops boot_ufs_ops = {
"ufs",
};
/* These are the pools of buffers, etc. */
/* Compilers like to play with alignment, so force the issue here */
static union {
} b;
/*
* There is only 1 open (mounted) device at any given time.
* So we can keep a single, global devp file descriptor to
* use to index into the di[] array. This is not true for the
* fi[] array. We can have more than one file open at once,
* so there is no global fd for the fi[].
* The user program must save the fd passed back from open()
* and use it to do subsequent read()'s.
*/
static int
{
int retval;
/* Try the inode cache first */
return (0);
/* Nope, not there so lets read it off the disk. */
/* never more than 1 disk block */
/* Maybe the block is in the disk block cache */
/* Not in the block cache so read it from disk */
return (retval);
}
bkmem_alloc(sizeof (struct inode));
sizeof (struct inode)))
return (0);
}
static fileid_t *
{
if (fd >= 0) {
}
return (0);
}
static ino_t
{
char *q;
char c;
char lpath[MAXPATHLEN];
int len, r;
printf("null path\n");
return ((ino_t)0);
}
while (*lpathp) {
/* if at the beginning of pathname get root inode */
return ((ino_t)0);
while (*lpathp == '/')
lpathp++; /* skip leading slashes */
q = lpathp;
while (*q != '/' && *q != '\0')
q++; /* find end of component */
c = *q;
*q = '\0'; /* terminate component */
/* Bail out early if opening root */
if (r && (*lpathp == '\0'))
return ((ino_t)UFSROOTINO);
return ((ino_t)0);
filep->fi_blocknum =
/* check the block cache */
if (set_bcache(filep))
return ((ino_t)0);
}
/* absolute link */
/* copy rest of unprocessed path up */
/* point to unprocessed path */
/* prepend link in before unprocessed path */
continue;
} else
*q = c;
if (c == '\0')
break;
lpathp = q;
continue;
} else {
return ((ino_t)0);
}
}
return (inode);
}
/*
* Map <file, file logical block> into a file system block number.
* Reads indirect blocks as needed to find the block. Returns zero when
* block isn't there; returns negative fsbn when block is uninitialized.
*/
static daddr32_t
{
int i, j, sh;
/*
* blocks 0..NDADDR are direct blocks
*/
return (nb);
}
/*
* addresses NIADDR have single and double indirect blocks.
* the first step is to determine how many levels of indirection.
*/
sh = 1;
for (j = NIADDR; j > 0; j--) {
break;
}
if (j == 0) {
return ((daddr32_t)0);
}
/*
* fetch the first indirect block address from the inode
*/
if (nb == 0) {
return ((daddr32_t)0);
}
/*
* fetch through the indirect blocks
*/
for (; j <= NIADDR; j++) {
/* First look through the disk block cache */
return (0);
}
}
if (nb == 0) {
return ((daddr32_t)0);
}
}
return (nb);
}
static ino_t
{
int len;
#ifdef DEBUG
static int warned = 0;
#endif
return (0);
return (0);
return (0);
/*
* First look through the directory entry cache
*/
return (in);
/*
* If the entire directory is cached, return failure
*/
return (0);
/*
* Otherwise, read the entire directory into the cache
*/
in = 0;
continue;
/*
*/
continue;
/*
* Put this entry into the cache. If the entry has been
* partially cached, check before inserting. This should be
* rare if sized correctly
*/
continue;
#ifdef DEBUG
if (!warned) {
printf("ufsboot: directory cache too small\n");
warned++;
}
#endif
}
}
return (in);
}
/*
* get next entry in a directory.
*/
struct direct *
{
int off;
for (;;) {
return (NULL);
}
if (off == 0) {
if (d <= 0)
return (NULL);
/* check the block cache */
if (set_bcache(filep))
return (NULL);
}
}
continue;
return (dp);
}
}
/*
* Get the next block of data from the file. If possible, dma right into
* user's buffer
*/
static int
{
caddr_t p;
static int pos;
static int blks_read;
/* find the amt left to be read in the file */
if (diff <= 0) {
printf("Short read\n");
return (-1);
}
/* which block (or frag) in the file do we read? */
/* which physical block on the device do we read? */
/*
* zero fsbn -> unallocated hole.
* negative fsbn -> allocated but uninitialized.
* since we only read from the fs, treat both the same.
*/
/* either blksize or fragsize */
/*
* optimization if we are reading large blocks of data then
* we can go directly to user's buffer
*/
*rcount = 0;
if (zeroize) {
return (-1);
}
read_opt++;
if ((blks_read++ & 0x3) == 0)
return (0);
} else {
if (zeroize) {
return (-1);
}
/*
* round and round she goes (though not on every block..
* - OBP's take a fair bit of time to actually print stuff)
* On x86, the screen oriented bootconf program doesn't
* want this noise...
*/
if ((blks_read++ & 0x3) == 0)
}
return (0);
}
/*
* This is the high-level read function. It works like this.
* We assume that our IO device buffers up some amount of
* data and that we can get a ptr to it. Thus we need
* and this greatly increases our IO speed. When we already
* have data in the buffer, we just return that data (with bcopy() ).
*/
static ssize_t
{
size_t i, j;
caddr_t n;
int rcount;
return (-1);
}
/* that was easy */
if ((i = count) == 0)
return (0);
n = buf;
while (i > 0) {
/* If we need to reload the buffer, do so */
i -= rcount;
} else {
/* else just bcopy from our buffer */
j = MIN(i, j);
buf += j;
i -= j;
}
}
return (buf - n);
}
/*
* This routine will open a device as it is known by the V2 OBP.
* Interface Defn:
* err = boot_ufs_mountroot(string);
* err = 0 on success
* err = -1 on failure
* string: char string describing the properties of the device.
* We must not dork with any fi[]'s here. Save that for later.
*/
static int
boot_ufs_mountroot(char *str)
{
int h;
/*
* Open the device and setup the read of the ufs superblock
* only the first time mountroot is called. Subsequent calls
* to mountroot succeed immediatly
*/
/*
* Encode the knowledge that we normally boot from the 'a'
* slice of the leaf device on the OBP path; we also permit
* a 'nolabel' device, i.e. the entire device. Since v2path
* points to 'str' as well, changing str should have the
* desired result.
*/
}
if (h == 0) {
return (-1);
}
ufs_devp->di_dcookie = h;
head->fi_filedes = 0;
/* Setup read of the superblock */
return (-1);
}
}
return (0);
}
/*
* Unmount the currently mounted root fs. In practice, this means
* closing all open files and releasing resources. All of this
* is done by boot_ufs_closeall().
*/
int
boot_ufs_unmountroot(void)
{
return (-1);
return (0);
}
/*
* We allocate an fd here for use when talking
* to the file itself.
*/
/*ARGSUSED*/
static int
{
static int filedes = 1;
/* build and link a new file descriptor */
return (-1);
}
return (-1);
}
return (filep->fi_filedes);
}
/*
* We don't do any IO here.
* We just play games with the device pointers.
*/
static off_t
{
/* Make sure user knows what file he is talking to */
return (-1);
switch (whence) {
case SEEK_CUR:
break;
case SEEK_SET:
break;
default:
case SEEK_END:
break;
}
return (0);
}
/*
* ufs_fstat() only supports size, mode, and times at present time.
*/
static int
{
return (-1);
return (0);
case IFDIR:
break;
case IFLNK:
break;
case IFREG:
break;
default:
break;
}
return (0);
}
static int
boot_ufs_close(int fd)
{
/* Make sure user knows what file he is talking to */
return (-1);
/* Clear the ranks */
/* unlink and deallocate node */
return (0);
} else {
/* Big problem */
return (-1);
}
}
/* closeall is now idempotent */
/*ARGSUSED*/
static void
boot_ufs_closeall(int flag)
{
if (head)
prom_panic("boot_ufs_closeall: head != NULL.\n");
return;
}
prom_panic("Filesystem may be inconsistent.\n");
if (verbosemode & print_cache_stats)
}
static int
{
/*
* Read directory entries from the file open on "fd" into the
* "size"-byte buffer at "dep" until the buffer is exhausted
* or we reach EOF on the directory. Returns the number of
* entries read.
*/
int n;
/*
* File is open, check type to make sure it's a directory.
*/
/*
* If file is a symbolic link, we'll follow
* it JIC it points to a directory!
*/
char pn[MAXPATHLEN];
/*
* Return failure if:
* (a) we get an I/O error reading the path name.
* (b) the path name points to a non-existant file,
* (c) we get an I/O error reading the target inode.
*/
if (set_bcache(fp))
return (-1);
}
return (-1);
}
}
/*
* If target file is a directory, go ahead
* and read it. This consists of making
* repeated calls to readdir() until we reach
* end-of-file or run out of buffer space.
*/
int cnt = 0;
/*
* Read all directory entries in the file ...
*/
/*
* Next entry is valid.
* Compute name length and
* break loop if there's not
* enough space in the output
* buffer for the next entry.
*
* NOTE: "SLOP" is the number
* of bytes inserted into the
* dirent struct's "d_name"
* field by the compiler to
* preserve alignment.
*/
((n > SLOP) ? n : 0)),
sizeof (off_t));
if (n > size)
break; /* user buffer is full */
size -= n;
cnt += 1;
((char *)dep + n);
}
}
/*
* Remember where we left off for next time
*/
return (cnt);
}
}
return (-1);
}