root/kern/vfs/device.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dev_open
  2. dev_close
  3. dev_reclaim
  4. dev_read
  5. null_io
  6. dev_write
  7. dev_ioctl
  8. dev_stat
  9. dev_gettype
  10. dev_tryseek
  11. null_fsync
  12. dev_mmap
  13. dev_truncate
  14. dev_namefile
  15. null_creat
  16. null_mkdir
  17. null_symlink
  18. null_nameop
  19. null_link
  20. null_rename
  21. dev_lookup
  22. dev_lookparent
  23. dev_create_vnode

   1 /*
   2  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
   3  *      The President and Fellows of Harvard College.
   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  * 3. Neither the name of the University nor the names of its contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /*
  31  * Vnode operations for VFS devices.
  32  *
  33  * These hand off to the functions in the VFS device structure (see dev.h)
  34  * but take care of a bunch of common tasks in a uniform fashion.
  35  */
  36 #include <types.h>
  37 #include <kern/errno.h>
  38 #include <kern/fcntl.h>
  39 #include <stat.h>
  40 #include <lib.h>
  41 #include <uio.h>
  42 #include <synch.h>
  43 #include <vnode.h>
  44 #include <device.h>
  45 
  46 /*
  47  * Called for each open().
  48  *
  49  * We reject O_APPEND.
  50  */
  51 static
  52 int
  53 dev_open(struct vnode *v, int flags)
  54 {
  55         struct device *d = v->vn_data;
  56 
  57         if (flags & (O_CREAT | O_TRUNC | O_EXCL | O_APPEND)) {
  58                 return EINVAL;
  59         }
  60 
  61         return d->d_open(d, flags);
  62 }
  63 
  64 /*
  65  * Called on the last close().
  66  * Just pass through.
  67  */
  68 static
  69 int
  70 dev_close(struct vnode *v)
  71 {
  72         struct device *d = v->vn_data;
  73         return d->d_close(d);
  74 }
  75 
  76 /*
  77  * Called when the vnode refcount reaches zero.
  78  * Do nothing; devices are permanent.
  79  */
  80 static
  81 int
  82 dev_reclaim(struct vnode *v)
  83 {
  84         (void)v;
  85         /* nothing - device continues to exist even when not in use */
  86         return 0;
  87 }
  88 
  89 /*
  90  * Called for read. Hand off to d_io.
  91  */
  92 static
  93 int
  94 dev_read(struct vnode *v, struct uio *uio)
  95 {
  96         struct device *d = v->vn_data;
  97         KASSERT(uio->uio_rw == UIO_READ);
  98         return d->d_io(d, uio);
  99 }
 100 
 101 /*
 102  * Used for several functions with the same type signature that are
 103  * not meaningful on devices.
 104  */
 105 static
 106 int
 107 null_io(struct vnode *v, struct uio *uio)
 108 {
 109         (void)v;
 110         (void)uio;
 111         return EINVAL;
 112 }
 113 
 114 /*
 115  * Called for write. Hand off to d_io.
 116  */
 117 static
 118 int
 119 dev_write(struct vnode *v, struct uio *uio)
 120 {
 121         struct device *d = v->vn_data;
 122         KASSERT(uio->uio_rw == UIO_WRITE);
 123         return d->d_io(d, uio);
 124 }
 125 
 126 /*
 127  * Called for ioctl(). Just pass through.
 128  */
 129 static
 130 int
 131 dev_ioctl(struct vnode *v, int op, userptr_t data)
 132 {
 133         struct device *d = v->vn_data;
 134         return d->d_ioctl(d, op, data);
 135 }
 136 
 137 /*
 138  * Called for stat().
 139  * Set the type and the size (block devices only).
 140  * The link count for a device is always 1.
 141  */
 142 static
 143 int
 144 dev_stat(struct vnode *v, struct stat *statbuf)
 145 {
 146         struct device *d = v->vn_data;
 147         int result;
 148 
 149         bzero(statbuf, sizeof(struct stat));
 150 
 151         if (d->d_blocks > 0) {
 152                 statbuf->st_size = d->d_blocks * d->d_blocksize;
 153                 statbuf->st_blksize = d->d_blocksize;
 154         }
 155         else {
 156                 statbuf->st_size = 0;
 157         }
 158 
 159         result = VOP_GETTYPE(v, &statbuf->st_mode);
 160         if (result) {
 161                 return result;
 162         }
 163         /* Make up some plausible default permissions. */
 164         statbuf->st_mode |= 0600;
 165 
 166         statbuf->st_nlink = 1;
 167         statbuf->st_blocks = d->d_blocks;
 168 
 169         /* The device number this device sits on (in OS/161, it doesn't) */
 170         statbuf->st_dev = 0;
 171 
 172         /* The device number this device *is* */
 173         statbuf->st_rdev = d->d_devnumber;
 174 
 175         return 0;
 176 }
 177 
 178 /*
 179  * Return the type. A device is a "block device" if it has a known
 180  * length. A device that generates data in a stream is a "character
 181  * device".
 182  */
 183 static
 184 int
 185 dev_gettype(struct vnode *v, mode_t *ret)
 186 {
 187         struct device *d = v->vn_data;
 188         if (d->d_blocks > 0) {
 189                 *ret = S_IFBLK;
 190         }
 191         else {
 192                 *ret = S_IFCHR;
 193         }
 194         return 0;
 195 }
 196 
 197 /*
 198  * Attempt a seek.
 199  * For block devices, require block alignment.
 200  * For character devices, prohibit seeking entirely.
 201  */
 202 static
 203 int
 204 dev_tryseek(struct vnode *v, off_t pos)
 205 {
 206         struct device *d = v->vn_data;
 207         if (d->d_blocks > 0) {
 208                 if ((pos % d->d_blocksize)!=0) {
 209                         /* not block-aligned */
 210                         return EINVAL;
 211                 }
 212                 if (pos < 0) {
 213                         /* 
 214                          * Nonsensical.
 215                          * (note: off_t must be signed for SEEK_CUR or
 216                          * SEEK_END seeks to work, so this case must
 217                          * be checked.)
 218                          */
 219                         return EINVAL;
 220                 }
 221                 if (pos / d->d_blocksize >= d->d_blocks) {
 222                         /* off the end */
 223                         return EINVAL;
 224                 }
 225         }
 226         else {
 227                 return ESPIPE;
 228         }
 229         return 0;
 230 }
 231 
 232 /*
 233  * For fsync() - meaningless, do nothing.
 234  */
 235 static
 236 int
 237 null_fsync(struct vnode *v)
 238 {
 239         (void)v;
 240         return 0;
 241 }
 242 
 243 /*
 244  * For mmap. If you want this to do anything, you have to write it
 245  * yourself. Some devices may not make sense to map. Others do.
 246  */
 247 static
 248 int
 249 dev_mmap(struct vnode *v  /* add stuff as needed */)
 250 {
 251         (void)v;
 252         return EUNIMP;
 253 }
 254 
 255 /*
 256  * For ftruncate(). 
 257  */
 258 static
 259 int
 260 dev_truncate(struct vnode *v, off_t len)
 261 {
 262         struct device *d = v->vn_data;
 263 
 264         /*
 265          * Allow truncating to the object's own size, if it has one.
 266          */
 267         if (d->d_blocks > 0 && (off_t)(d->d_blocks*d->d_blocksize) == len) {
 268                 return 0;
 269         }
 270 
 271         return EINVAL;
 272 }
 273 
 274 /*
 275  * For namefile (which implements "pwd")
 276  *
 277  * This should never be reached, as it's not possible to chdir to a
 278  * device vnode.
 279  */
 280 static
 281 int
 282 dev_namefile(struct vnode *v, struct uio *uio)
 283 {
 284         /*
 285          * The name of a device is always just "device:". The VFS
 286          * layer puts in the device name for us, so we don't need to
 287          * do anything further.
 288          */
 289 
 290         (void)v;
 291         (void)uio;
 292 
 293         return 0;
 294 }
 295 
 296 /*
 297  * Operations that are completely meaningless on devices.
 298  */
 299 
 300 static
 301 int
 302 null_creat(struct vnode *v, const char *name, bool excl, mode_t mode,
 303            struct vnode **result)
 304 {
 305         (void)v;
 306         (void)name;
 307         (void)excl;
 308         (void)mode;
 309         (void)result;
 310         return ENOTDIR;
 311 }
 312 
 313 static
 314 int
 315 null_mkdir(struct vnode *v, const char *name, mode_t mode)
 316 {
 317         (void)v;
 318         (void)name;
 319         (void)mode;
 320         return ENOTDIR;
 321 }
 322 
 323 static
 324 int
 325 null_symlink(struct vnode *v, const char *contents, const char *name)
 326 {
 327         (void)v;
 328         (void)contents;
 329         (void)name;
 330         return ENOTDIR;
 331 }
 332 
 333 static
 334 int
 335 null_nameop(struct vnode *v, const char *name)
 336 {
 337         (void)v;
 338         (void)name;
 339         return ENOTDIR;
 340 }
 341 
 342 static
 343 int
 344 null_link(struct vnode *v, const char *name, struct vnode *file)
 345 {
 346         (void)v;
 347         (void)name;
 348         (void)file;
 349         return ENOTDIR;
 350 }
 351 
 352 static
 353 int
 354 null_rename(struct vnode *v, const char *n1, struct vnode *v2, const char *n2)
 355 {
 356         (void)v;
 357         (void)n1;
 358         (void)v2;
 359         (void)n2;
 360         return ENOTDIR;
 361 }
 362 
 363 
 364 /*
 365  * Name lookup.
 366  *
 367  * One interesting feature of device:name pathname syntax is that you
 368  * can implement pathnames on arbitrary devices. For instance, if you
 369  * had a graphics device that supported multiple resolutions (which we
 370  * don't), you might arrange things so that you could open it with
 371  * pathnames like "video:800x600/24bpp" in order to select the operating
 372  * mode.
 373  *
 374  * However, we have no support for this in the base system.
 375  */
 376 static
 377 int
 378 dev_lookup(struct vnode *dir, 
 379            char *pathname, struct vnode **result)
 380 {
 381         /*
 382          * If the path was "device:", we get "". For that, return self.
 383          * Anything else is an error.
 384          * Increment the ref count of the vnode before returning it.
 385          */
 386         if (strlen(pathname)>0) {
 387                 return ENOENT;
 388         }
 389         VOP_INCREF(dir);
 390         *result = dir;
 391         return 0;
 392 }
 393 
 394 static
 395 int
 396 dev_lookparent(struct vnode *dir, 
 397                char *pathname, struct vnode **result,
 398                char *namebuf, size_t buflen)
 399 {
 400         /*
 401          * This is always an error.
 402          */
 403         (void)dir;
 404         (void)pathname;
 405         (void)result;
 406         (void)namebuf;
 407         (void)buflen;
 408 
 409         return ENOTDIR;
 410 }
 411 
 412 /*
 413  * Function table for device vnodes.
 414  */
 415 static const struct vnode_ops dev_vnode_ops = {
 416         VOP_MAGIC,
 417 
 418         dev_open,
 419         dev_close,
 420         dev_reclaim,
 421         dev_read,
 422         null_io,      /* readlink */
 423         null_io,      /* getdirentry */
 424         dev_write,
 425         dev_ioctl,
 426         dev_stat,
 427         dev_gettype,
 428         dev_tryseek,
 429         null_fsync,
 430         dev_mmap,
 431         dev_truncate,
 432         dev_namefile,
 433         null_creat,
 434         null_symlink,
 435         null_mkdir,
 436         null_link,
 437         null_nameop,  /* remove */
 438         null_nameop,  /* rmdir */
 439         null_rename,
 440         dev_lookup,
 441         dev_lookparent,
 442 };
 443 
 444 /*
 445  * Function to create a vnode for a VFS device.
 446  */
 447 struct vnode *
 448 dev_create_vnode(struct device *dev)
 449 {
 450         int result;
 451         struct vnode *v;
 452 
 453         v = kmalloc(sizeof(struct vnode));
 454         if (v==NULL) {
 455                 return NULL;
 456         }
 457 
 458         result = VOP_INIT(v, &dev_vnode_ops, NULL, dev);
 459         if (result != 0) {
 460                 panic("While creating vnode for device: VOP_INIT: %s\n",
 461                       strerror(result));
 462         }
 463 
 464         return v;
 465 }

/* [<][>][^][v][top][bottom][index][help] */