The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/boot/zfs/zfs.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2007 Doug Rabson
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  *      $FreeBSD: releng/8.1/sys/boot/zfs/zfs.c 206815 2010-04-18 21:36:34Z pjd $
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/8.1/sys/boot/zfs/zfs.c 206815 2010-04-18 21:36:34Z pjd $");
   31 
   32 /*
   33  *      Stand-alone file reading package.
   34  */
   35 
   36 #include <sys/param.h>
   37 #include <sys/disklabel.h>
   38 #include <sys/time.h>
   39 #include <sys/queue.h>
   40 #include <stddef.h>
   41 #include <stdarg.h>
   42 #include <string.h>
   43 #include <stand.h>
   44 #include <bootstrap.h>
   45 
   46 #include "zfsimpl.c"
   47 
   48 static int      zfs_open(const char *path, struct open_file *f);
   49 static int      zfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
   50 static int      zfs_close(struct open_file *f);
   51 static int      zfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
   52 static off_t    zfs_seek(struct open_file *f, off_t offset, int where);
   53 static int      zfs_stat(struct open_file *f, struct stat *sb);
   54 static int      zfs_readdir(struct open_file *f, struct dirent *d);
   55 
   56 struct devsw zfs_dev;
   57 
   58 struct fs_ops zfs_fsops = {
   59         "zfs",
   60         zfs_open,
   61         zfs_close,
   62         zfs_read,
   63         zfs_write,
   64         zfs_seek,
   65         zfs_stat,
   66         zfs_readdir
   67 };
   68 
   69 /*
   70  * In-core open file.
   71  */
   72 struct file {
   73         off_t           f_seekp;        /* seek pointer */
   74         dnode_phys_t    f_dnode;
   75         uint64_t        f_zap_type;     /* zap type for readdir */
   76         uint64_t        f_num_leafs;    /* number of fzap leaf blocks */
   77         zap_leaf_phys_t *f_zap_leaf;    /* zap leaf buffer */
   78 };
   79 
   80 /*
   81  * Open a file.
   82  */
   83 static int
   84 zfs_open(const char *upath, struct open_file *f)
   85 {
   86         spa_t *spa = (spa_t *) f->f_devdata;
   87         struct file *fp;
   88         int rc;
   89 
   90         if (f->f_dev != &zfs_dev)
   91                 return (EINVAL);
   92 
   93         rc = zfs_mount_pool(spa);
   94         if (rc)
   95                 return (rc);
   96 
   97         /* allocate file system specific data structure */
   98         fp = malloc(sizeof(struct file));
   99         bzero(fp, sizeof(struct file));
  100         f->f_fsdata = (void *)fp;
  101 
  102         if (spa->spa_root_objset.os_type != DMU_OST_ZFS) {
  103                 printf("Unexpected object set type %llu\n",
  104                     spa->spa_root_objset.os_type);
  105                 rc = EIO;
  106                 goto out;
  107         }
  108 
  109         rc = zfs_lookup(spa, upath, &fp->f_dnode);
  110         if (rc)
  111                 goto out;
  112 
  113         fp->f_seekp = 0;
  114 out:
  115         if (rc) {
  116                 f->f_fsdata = NULL;
  117                 free(fp);
  118         }
  119         return (rc);
  120 }
  121 
  122 static int
  123 zfs_close(struct open_file *f)
  124 {
  125         struct file *fp = (struct file *)f->f_fsdata;
  126 
  127         dnode_cache_obj = 0;
  128         f->f_fsdata = (void *)0;
  129         if (fp == (struct file *)0)
  130                 return (0);
  131 
  132         free(fp);
  133         return (0);
  134 }
  135 
  136 /*
  137  * Copy a portion of a file into kernel memory.
  138  * Cross block boundaries when necessary.
  139  */
  140 static int
  141 zfs_read(struct open_file *f, void *start, size_t size, size_t *resid   /* out */)
  142 {
  143         spa_t *spa = (spa_t *) f->f_devdata;
  144         struct file *fp = (struct file *)f->f_fsdata;
  145         const znode_phys_t *zp = (const znode_phys_t *) fp->f_dnode.dn_bonus;
  146         size_t n;
  147         int rc;
  148 
  149         n = size;
  150         if (fp->f_seekp + n > zp->zp_size)
  151                 n = zp->zp_size - fp->f_seekp;
  152         
  153         rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n);
  154         if (rc)
  155                 return (rc);
  156 
  157         if (0) {
  158             int i;
  159             for (i = 0; i < n; i++)
  160                 putchar(((char*) start)[i]);
  161         }
  162         fp->f_seekp += n;
  163         if (resid)
  164                 *resid = size - n;
  165 
  166         return (0);
  167 }
  168 
  169 /*
  170  * Don't be silly - the bootstrap has no business writing anything.
  171  */
  172 static int
  173 zfs_write(struct open_file *f, void *start, size_t size, size_t *resid  /* out */)
  174 {
  175 
  176         return (EROFS);
  177 }
  178 
  179 static off_t
  180 zfs_seek(struct open_file *f, off_t offset, int where)
  181 {
  182         struct file *fp = (struct file *)f->f_fsdata;
  183         znode_phys_t *zp = (znode_phys_t *) fp->f_dnode.dn_bonus;
  184 
  185         switch (where) {
  186         case SEEK_SET:
  187                 fp->f_seekp = offset;
  188                 break;
  189         case SEEK_CUR:
  190                 fp->f_seekp += offset;
  191                 break;
  192         case SEEK_END:
  193                 fp->f_seekp = zp->zp_size - offset;
  194                 break;
  195         default:
  196                 errno = EINVAL;
  197                 return (-1);
  198         }
  199         return (fp->f_seekp);
  200 }
  201 
  202 static int
  203 zfs_stat(struct open_file *f, struct stat *sb)
  204 {
  205         struct file *fp = (struct file *)f->f_fsdata;
  206         znode_phys_t *zp = (znode_phys_t *) fp->f_dnode.dn_bonus;
  207 
  208         /* only important stuff */
  209         sb->st_mode = zp->zp_mode;
  210         sb->st_uid = zp->zp_uid;
  211         sb->st_gid = zp->zp_gid;
  212         sb->st_size = zp->zp_size;
  213 
  214         return (0);
  215 }
  216 
  217 static int
  218 zfs_readdir(struct open_file *f, struct dirent *d)
  219 {
  220         spa_t *spa = (spa_t *) f->f_devdata;
  221         struct file *fp = (struct file *)f->f_fsdata;
  222         znode_phys_t *zp = (znode_phys_t *) fp->f_dnode.dn_bonus;
  223         mzap_ent_phys_t mze;
  224         size_t bsize = fp->f_dnode.dn_datablkszsec << SPA_MINBLOCKSHIFT;
  225         int rc;
  226 
  227         if ((zp->zp_mode >> 12) != 0x4) {
  228                 return (ENOTDIR);
  229         }
  230 
  231         /*
  232          * If this is the first read, get the zap type.
  233          */
  234         if (fp->f_seekp == 0) {
  235                 rc = dnode_read(spa, &fp->f_dnode,
  236                                 0, &fp->f_zap_type, sizeof(fp->f_zap_type));
  237                 if (rc)
  238                         return (rc);
  239 
  240                 if (fp->f_zap_type == ZBT_MICRO) {
  241                         fp->f_seekp = offsetof(mzap_phys_t, mz_chunk);
  242                 } else {
  243                         rc = dnode_read(spa, &fp->f_dnode,
  244                                         offsetof(zap_phys_t, zap_num_leafs),
  245                                         &fp->f_num_leafs,
  246                                         sizeof(fp->f_num_leafs));
  247                         if (rc)
  248                                 return (rc);
  249 
  250                         fp->f_seekp = bsize;
  251                         fp->f_zap_leaf = (zap_leaf_phys_t *)malloc(bsize);
  252                         rc = dnode_read(spa, &fp->f_dnode,
  253                                         fp->f_seekp,
  254                                         fp->f_zap_leaf,
  255                                         bsize);
  256                         if (rc)
  257                                 return (rc);
  258                 }
  259         }
  260 
  261         if (fp->f_zap_type == ZBT_MICRO) {
  262         mzap_next:
  263                 if (fp->f_seekp >= bsize)
  264                         return (ENOENT);
  265 
  266                 rc = dnode_read(spa, &fp->f_dnode,
  267                                 fp->f_seekp, &mze, sizeof(mze));
  268                 fp->f_seekp += sizeof(mze);
  269 
  270                 if (!mze.mze_name[0])
  271                         goto mzap_next;
  272 
  273                 d->d_fileno = ZFS_DIRENT_OBJ(mze.mze_value);
  274                 d->d_type = ZFS_DIRENT_TYPE(mze.mze_value);
  275                 strcpy(d->d_name, mze.mze_name);
  276                 d->d_namlen = strlen(d->d_name);
  277                 return (0);
  278         } else {
  279                 zap_leaf_t zl;
  280                 zap_leaf_chunk_t *zc, *nc;
  281                 int chunk;
  282                 size_t namelen;
  283                 char *p;
  284                 uint64_t value;
  285 
  286                 /*
  287                  * Initialise this so we can use the ZAP size
  288                  * calculating macros.
  289                  */
  290                 zl.l_bs = ilog2(bsize);
  291                 zl.l_phys = fp->f_zap_leaf;
  292 
  293                 /*
  294                  * Figure out which chunk we are currently looking at
  295                  * and consider seeking to the next leaf. We use the
  296                  * low bits of f_seekp as a simple chunk index.
  297                  */
  298         fzap_next:
  299                 chunk = fp->f_seekp & (bsize - 1);
  300                 if (chunk == ZAP_LEAF_NUMCHUNKS(&zl)) {
  301                         fp->f_seekp = (fp->f_seekp & ~(bsize - 1)) + bsize;
  302                         chunk = 0;
  303 
  304                         /*
  305                          * Check for EOF and read the new leaf.
  306                          */
  307                         if (fp->f_seekp >= bsize * fp->f_num_leafs)
  308                                 return (ENOENT);
  309 
  310                         rc = dnode_read(spa, &fp->f_dnode,
  311                                         fp->f_seekp,
  312                                         fp->f_zap_leaf,
  313                                         bsize);
  314                         if (rc)
  315                                 return (rc);
  316                 }
  317 
  318                 zc = &ZAP_LEAF_CHUNK(&zl, chunk);
  319                 fp->f_seekp++;
  320                 if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY)
  321                         goto fzap_next;
  322 
  323                 namelen = zc->l_entry.le_name_length;
  324                 if (namelen > sizeof(d->d_name))
  325                         namelen = sizeof(d->d_name);
  326 
  327                 /*
  328                  * Paste the name back together.
  329                  */
  330                 nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk);
  331                 p = d->d_name;
  332                 while (namelen > 0) {
  333                         int len;
  334                         len = namelen;
  335                         if (len > ZAP_LEAF_ARRAY_BYTES)
  336                                 len = ZAP_LEAF_ARRAY_BYTES;
  337                         memcpy(p, nc->l_array.la_array, len);
  338                         p += len;
  339                         namelen -= len;
  340                         nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next);
  341                 }
  342                 d->d_name[sizeof(d->d_name) - 1] = 0;
  343 
  344                 /*
  345                  * Assume the first eight bytes of the value are
  346                  * a uint64_t.
  347                  */
  348                 value = fzap_leaf_value(&zl, zc);
  349 
  350                 d->d_fileno = ZFS_DIRENT_OBJ(value);
  351                 d->d_type = ZFS_DIRENT_TYPE(value);
  352                 d->d_namlen = strlen(d->d_name);
  353 
  354                 return (0);
  355         }
  356 }
  357 
  358 static int
  359 vdev_read(vdev_t *vdev, void *priv, off_t offset, void *buf, size_t size)
  360 {
  361         int fd;
  362 
  363         fd = (uintptr_t) priv;
  364         lseek(fd, offset, SEEK_SET);
  365         if (read(fd, buf, size) == size) {
  366                 return 0;
  367         } else {
  368                 return (EIO);
  369         }
  370 }
  371 
  372 /*
  373  * Convert a pool guid to a 'unit number' suitable for use with zfs_dev_open.
  374  */
  375 int
  376 zfs_guid_to_unit(uint64_t guid)
  377 {
  378         spa_t *spa;
  379         int unit;
  380 
  381         unit = 0;
  382         STAILQ_FOREACH(spa, &zfs_pools, spa_link) {
  383                 if (spa->spa_guid == guid)
  384                         return unit;
  385                 unit++;
  386         }
  387         return (-1);
  388 }
  389 
  390 static int
  391 zfs_dev_init(void) 
  392 {
  393         char devname[512];
  394         int unit, slice;
  395         int fd;
  396 
  397         /*
  398          * Open all the disks we can find and see if we can reconstruct
  399          * ZFS pools from them. Bogusly assumes that the disks are named
  400          * diskN, diskNpM or diskNsM.
  401          */
  402         zfs_init();
  403         for (unit = 0; unit < 32 /* XXX */; unit++) {
  404                 sprintf(devname, "disk%d:", unit);
  405                 fd = open(devname, O_RDONLY);
  406                 if (fd == -1)
  407                         continue;
  408 
  409                 /*
  410                  * If we find a vdev, the zfs code will eat the fd, otherwise
  411                  * we close it.
  412                  */
  413                 if (vdev_probe(vdev_read, (void*) (uintptr_t) fd, 0))
  414                         close(fd);
  415 
  416                 for (slice = 1; slice <= 128; slice++) {
  417                         sprintf(devname, "disk%dp%d:", unit, slice);
  418                         fd = open(devname, O_RDONLY);
  419                         if (fd == -1) {
  420                                 sprintf(devname, "disk%ds%d:", unit, slice);
  421                                 fd = open(devname, O_RDONLY);
  422                                 if (fd == -1)
  423                                         continue;
  424                         }
  425                         if (vdev_probe(vdev_read, (void*) (uintptr_t) fd, 0))
  426                                 close(fd);
  427                 }
  428         }
  429 
  430         return (0);
  431 }
  432 
  433 /*
  434  * Print information about ZFS pools
  435  */
  436 static void
  437 zfs_dev_print(int verbose)
  438 {
  439         spa_t *spa;
  440         char line[80];
  441         int unit;
  442 
  443         if (verbose) {
  444                 spa_all_status();
  445                 return;
  446         }
  447         unit = 0;
  448         STAILQ_FOREACH(spa, &zfs_pools, spa_link) {
  449                 sprintf(line, "    zfs%d:   %s\n", unit, spa->spa_name);
  450                 pager_output(line);
  451                 unit++;
  452         }
  453 }
  454 
  455 /*
  456  * Attempt to open the pool described by (dev) for use by (f).
  457  */
  458 static int 
  459 zfs_dev_open(struct open_file *f, ...)
  460 {
  461         va_list         args;
  462         struct devdesc  *dev;
  463         int             unit, i;
  464         spa_t           *spa;
  465 
  466         va_start(args, f);
  467         dev = va_arg(args, struct devdesc*);
  468         va_end(args);
  469 
  470         /*
  471          * We mostly ignore the stuff that devopen sends us. For now,
  472          * use the unit to find a pool - later we will override the
  473          * devname parsing so that we can name a pool and a fs within
  474          * the pool.
  475          */
  476         unit = dev->d_unit;
  477         
  478         i = 0;
  479         STAILQ_FOREACH(spa, &zfs_pools, spa_link) {
  480                 if (i == unit)
  481                         break;
  482                 i++;
  483         }
  484         if (!spa) {
  485                 return (ENXIO);
  486         }
  487 
  488         f->f_devdata = spa;
  489         free(dev);
  490         return (0);
  491 }
  492 
  493 static int 
  494 zfs_dev_close(struct open_file *f)
  495 {
  496 
  497         f->f_devdata = NULL;
  498         return (0);
  499 }
  500 
  501 static int 
  502 zfs_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize)
  503 {
  504 
  505         return (ENOSYS);
  506 }
  507 
  508 struct devsw zfs_dev = {
  509         .dv_name = "zfs", 
  510         .dv_type = DEVT_ZFS, 
  511         .dv_init = zfs_dev_init,
  512         .dv_strategy = zfs_dev_strategy, 
  513         .dv_open = zfs_dev_open, 
  514         .dv_close = zfs_dev_close, 
  515         .dv_ioctl = noioctl,
  516         .dv_print = zfs_dev_print,
  517         .dv_cleanup = NULL
  518 };

Cache object: a2f2af88f72d3e7dd59252d2578b4323


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.