os161-1.99
 All Data Structures
device.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * Vnode operations for VFS devices.
00032  *
00033  * These hand off to the functions in the VFS device structure (see dev.h)
00034  * but take care of a bunch of common tasks in a uniform fashion.
00035  */
00036 #include <types.h>
00037 #include <kern/errno.h>
00038 #include <kern/fcntl.h>
00039 #include <stat.h>
00040 #include <lib.h>
00041 #include <uio.h>
00042 #include <synch.h>
00043 #include <vnode.h>
00044 #include <device.h>
00045 
00046 /*
00047  * Called for each open().
00048  *
00049  * We reject O_APPEND.
00050  */
00051 static
00052 int
00053 dev_open(struct vnode *v, int flags)
00054 {
00055         struct device *d = v->vn_data;
00056 
00057         if (flags & (O_CREAT | O_TRUNC | O_EXCL | O_APPEND)) {
00058                 return EINVAL;
00059         }
00060 
00061         return d->d_open(d, flags);
00062 }
00063 
00064 /*
00065  * Called on the last close().
00066  * Just pass through.
00067  */
00068 static
00069 int
00070 dev_close(struct vnode *v)
00071 {
00072         struct device *d = v->vn_data;
00073         return d->d_close(d);
00074 }
00075 
00076 /*
00077  * Called when the vnode refcount reaches zero.
00078  * Do nothing; devices are permanent.
00079  */
00080 static
00081 int
00082 dev_reclaim(struct vnode *v)
00083 {
00084         (void)v;
00085         /* nothing - device continues to exist even when not in use */
00086         return 0;
00087 }
00088 
00089 /*
00090  * Called for read. Hand off to d_io.
00091  */
00092 static
00093 int
00094 dev_read(struct vnode *v, struct uio *uio)
00095 {
00096         struct device *d = v->vn_data;
00097         KASSERT(uio->uio_rw == UIO_READ);
00098         return d->d_io(d, uio);
00099 }
00100 
00101 /*
00102  * Used for several functions with the same type signature that are
00103  * not meaningful on devices.
00104  */
00105 static
00106 int
00107 null_io(struct vnode *v, struct uio *uio)
00108 {
00109         (void)v;
00110         (void)uio;
00111         return EINVAL;
00112 }
00113 
00114 /*
00115  * Called for write. Hand off to d_io.
00116  */
00117 static
00118 int
00119 dev_write(struct vnode *v, struct uio *uio)
00120 {
00121         struct device *d = v->vn_data;
00122         KASSERT(uio->uio_rw == UIO_WRITE);
00123         return d->d_io(d, uio);
00124 }
00125 
00126 /*
00127  * Called for ioctl(). Just pass through.
00128  */
00129 static
00130 int
00131 dev_ioctl(struct vnode *v, int op, userptr_t data)
00132 {
00133         struct device *d = v->vn_data;
00134         return d->d_ioctl(d, op, data);
00135 }
00136 
00137 /*
00138  * Called for stat().
00139  * Set the type and the size (block devices only).
00140  * The link count for a device is always 1.
00141  */
00142 static
00143 int
00144 dev_stat(struct vnode *v, struct stat *statbuf)
00145 {
00146         struct device *d = v->vn_data;
00147         int result;
00148 
00149         bzero(statbuf, sizeof(struct stat));
00150 
00151         if (d->d_blocks > 0) {
00152                 statbuf->st_size = d->d_blocks * d->d_blocksize;
00153                 statbuf->st_blksize = d->d_blocksize;
00154         }
00155         else {
00156                 statbuf->st_size = 0;
00157         }
00158 
00159         result = VOP_GETTYPE(v, &statbuf->st_mode);
00160         if (result) {
00161                 return result;
00162         }
00163         /* Make up some plausible default permissions. */
00164         statbuf->st_mode |= 0600;
00165 
00166         statbuf->st_nlink = 1;
00167         statbuf->st_blocks = d->d_blocks;
00168 
00169         /* The device number this device sits on (in OS/161, it doesn't) */
00170         statbuf->st_dev = 0;
00171 
00172         /* The device number this device *is* */
00173         statbuf->st_rdev = d->d_devnumber;
00174 
00175         return 0;
00176 }
00177 
00178 /*
00179  * Return the type. A device is a "block device" if it has a known
00180  * length. A device that generates data in a stream is a "character
00181  * device".
00182  */
00183 static
00184 int
00185 dev_gettype(struct vnode *v, mode_t *ret)
00186 {
00187         struct device *d = v->vn_data;
00188         if (d->d_blocks > 0) {
00189                 *ret = S_IFBLK;
00190         }
00191         else {
00192                 *ret = S_IFCHR;
00193         }
00194         return 0;
00195 }
00196 
00197 /*
00198  * Attempt a seek.
00199  * For block devices, require block alignment.
00200  * For character devices, prohibit seeking entirely.
00201  */
00202 static
00203 int
00204 dev_tryseek(struct vnode *v, off_t pos)
00205 {
00206         struct device *d = v->vn_data;
00207         if (d->d_blocks > 0) {
00208                 if ((pos % d->d_blocksize)!=0) {
00209                         /* not block-aligned */
00210                         return EINVAL;
00211                 }
00212                 if (pos < 0) {
00213                         /* 
00214                          * Nonsensical.
00215                          * (note: off_t must be signed for SEEK_CUR or
00216                          * SEEK_END seeks to work, so this case must
00217                          * be checked.)
00218                          */
00219                         return EINVAL;
00220                 }
00221                 if (pos / d->d_blocksize >= d->d_blocks) {
00222                         /* off the end */
00223                         return EINVAL;
00224                 }
00225         }
00226         else {
00227                 return ESPIPE;
00228         }
00229         return 0;
00230 }
00231 
00232 /*
00233  * For fsync() - meaningless, do nothing.
00234  */
00235 static
00236 int
00237 null_fsync(struct vnode *v)
00238 {
00239         (void)v;
00240         return 0;
00241 }
00242 
00243 /*
00244  * For mmap. If you want this to do anything, you have to write it
00245  * yourself. Some devices may not make sense to map. Others do.
00246  */
00247 static
00248 int
00249 dev_mmap(struct vnode *v  /* add stuff as needed */)
00250 {
00251         (void)v;
00252         return EUNIMP;
00253 }
00254 
00255 /*
00256  * For ftruncate(). 
00257  */
00258 static
00259 int
00260 dev_truncate(struct vnode *v, off_t len)
00261 {
00262         struct device *d = v->vn_data;
00263 
00264         /*
00265          * Allow truncating to the object's own size, if it has one.
00266          */
00267         if (d->d_blocks > 0 && (off_t)(d->d_blocks*d->d_blocksize) == len) {
00268                 return 0;
00269         }
00270 
00271         return EINVAL;
00272 }
00273 
00274 /*
00275  * For namefile (which implements "pwd")
00276  *
00277  * This should never be reached, as it's not possible to chdir to a
00278  * device vnode.
00279  */
00280 static
00281 int
00282 dev_namefile(struct vnode *v, struct uio *uio)
00283 {
00284         /*
00285          * The name of a device is always just "device:". The VFS
00286          * layer puts in the device name for us, so we don't need to
00287          * do anything further.
00288          */
00289 
00290         (void)v;
00291         (void)uio;
00292 
00293         return 0;
00294 }
00295 
00296 /*
00297  * Operations that are completely meaningless on devices.
00298  */
00299 
00300 static
00301 int
00302 null_creat(struct vnode *v, const char *name, bool excl, mode_t mode,
00303            struct vnode **result)
00304 {
00305         (void)v;
00306         (void)name;
00307         (void)excl;
00308         (void)mode;
00309         (void)result;
00310         return ENOTDIR;
00311 }
00312 
00313 static
00314 int
00315 null_mkdir(struct vnode *v, const char *name, mode_t mode)
00316 {
00317         (void)v;
00318         (void)name;
00319         (void)mode;
00320         return ENOTDIR;
00321 }
00322 
00323 static
00324 int
00325 null_symlink(struct vnode *v, const char *contents, const char *name)
00326 {
00327         (void)v;
00328         (void)contents;
00329         (void)name;
00330         return ENOTDIR;
00331 }
00332 
00333 static
00334 int
00335 null_nameop(struct vnode *v, const char *name)
00336 {
00337         (void)v;
00338         (void)name;
00339         return ENOTDIR;
00340 }
00341 
00342 static
00343 int
00344 null_link(struct vnode *v, const char *name, struct vnode *file)
00345 {
00346         (void)v;
00347         (void)name;
00348         (void)file;
00349         return ENOTDIR;
00350 }
00351 
00352 static
00353 int
00354 null_rename(struct vnode *v, const char *n1, struct vnode *v2, const char *n2)
00355 {
00356         (void)v;
00357         (void)n1;
00358         (void)v2;
00359         (void)n2;
00360         return ENOTDIR;
00361 }
00362 
00363 
00364 /*
00365  * Name lookup.
00366  *
00367  * One interesting feature of device:name pathname syntax is that you
00368  * can implement pathnames on arbitrary devices. For instance, if you
00369  * had a graphics device that supported multiple resolutions (which we
00370  * don't), you might arrange things so that you could open it with
00371  * pathnames like "video:800x600/24bpp" in order to select the operating
00372  * mode.
00373  *
00374  * However, we have no support for this in the base system.
00375  */
00376 static
00377 int
00378 dev_lookup(struct vnode *dir, 
00379            char *pathname, struct vnode **result)
00380 {
00381         /*
00382          * If the path was "device:", we get "". For that, return self.
00383          * Anything else is an error.
00384          * Increment the ref count of the vnode before returning it.
00385          */
00386         if (strlen(pathname)>0) {
00387                 return ENOENT;
00388         }
00389         VOP_INCREF(dir);
00390         *result = dir;
00391         return 0;
00392 }
00393 
00394 static
00395 int
00396 dev_lookparent(struct vnode *dir, 
00397                char *pathname, struct vnode **result,
00398                char *namebuf, size_t buflen)
00399 {
00400         /*
00401          * This is always an error.
00402          */
00403         (void)dir;
00404         (void)pathname;
00405         (void)result;
00406         (void)namebuf;
00407         (void)buflen;
00408 
00409         return ENOTDIR;
00410 }
00411 
00412 /*
00413  * Function table for device vnodes.
00414  */
00415 static const struct vnode_ops dev_vnode_ops = {
00416         VOP_MAGIC,
00417 
00418         dev_open,
00419         dev_close,
00420         dev_reclaim,
00421         dev_read,
00422         null_io,      /* readlink */
00423         null_io,      /* getdirentry */
00424         dev_write,
00425         dev_ioctl,
00426         dev_stat,
00427         dev_gettype,
00428         dev_tryseek,
00429         null_fsync,
00430         dev_mmap,
00431         dev_truncate,
00432         dev_namefile,
00433         null_creat,
00434         null_symlink,
00435         null_mkdir,
00436         null_link,
00437         null_nameop,  /* remove */
00438         null_nameop,  /* rmdir */
00439         null_rename,
00440         dev_lookup,
00441         dev_lookparent,
00442 };
00443 
00444 /*
00445  * Function to create a vnode for a VFS device.
00446  */
00447 struct vnode *
00448 dev_create_vnode(struct device *dev)
00449 {
00450         int result;
00451         struct vnode *v;
00452 
00453         v = kmalloc(sizeof(struct vnode));
00454         if (v==NULL) {
00455                 return NULL;
00456         }
00457 
00458         result = VOP_INIT(v, &dev_vnode_ops, NULL, dev);
00459         if (result != 0) {
00460                 panic("While creating vnode for device: VOP_INIT: %s\n",
00461                       strerror(result));
00462         }
00463 
00464         return v;
00465 }
 All Data Structures