]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
MFC r209962, r211970-r211972, r212050, r212605, r212611
[FreeBSD/stable/8.git] / sys / cddl / contrib / opensolaris / uts / common / fs / zfs / zvol.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
23  * All rights reserved.
24  */
25 /*
26  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29
30 /*
31  * ZFS volume emulation driver.
32  *
33  * Makes a DMU object look like a volume of arbitrary size, up to 2^64 bytes.
34  * Volumes are accessed through the symbolic links named:
35  *
36  * /dev/zvol/dsk/<pool_name>/<dataset_name>
37  * /dev/zvol/rdsk/<pool_name>/<dataset_name>
38  *
39  * These links are created by the ZFS-specific devfsadm link generator.
40  * Volumes are persistent through reboot.  No user command needs to be
41  * run before opening and using a device.
42  */
43
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/kernel.h>
47 #include <sys/errno.h>
48 #include <sys/uio.h>
49 #include <sys/bio.h>
50 #include <sys/buf.h>
51 #include <sys/kmem.h>
52 #include <sys/conf.h>
53 #include <sys/cmn_err.h>
54 #include <sys/stat.h>
55 #include <sys/zap.h>
56 #include <sys/spa.h>
57 #include <sys/zio.h>
58 #include <sys/dmu_traverse.h>
59 #include <sys/dnode.h>
60 #include <sys/dsl_dataset.h>
61 #include <sys/dsl_prop.h>
62 #include <sys/dkio.h>
63 #include <sys/byteorder.h>
64 #include <sys/sunddi.h>
65 #include <sys/dirent.h>
66 #include <sys/policy.h>
67 #include <sys/fs/zfs.h>
68 #include <sys/zfs_ioctl.h>
69 #include <sys/zil.h>
70 #include <sys/refcount.h>
71 #include <sys/zfs_znode.h>
72 #include <sys/zfs_rlock.h>
73 #include <sys/vdev_impl.h>
74 #include <sys/zvol.h>
75 #include <sys/zil_impl.h>
76 #include <geom/geom.h>
77
78 #include "zfs_namecheck.h"
79
80 #define ZVOL_DUMPSIZE   "dumpsize"
81
82 struct g_class zfs_zvol_class = {
83         .name = "ZFS::ZVOL",
84         .version = G_VERSION,
85 };
86
87 DECLARE_GEOM_CLASS(zfs_zvol_class, zfs_zvol);
88
89 /*
90  * This lock protects the zvol_state structure from being modified
91  * while it's being used, e.g. an open that comes in before a create
92  * finishes.  It also protects temporary opens of the dataset so that,
93  * e.g., an open doesn't get a spurious EBUSY.
94  */
95 static kmutex_t zvol_state_lock;
96 static uint32_t zvol_minors;
97
98 typedef struct zvol_extent {
99         list_node_t     ze_node;
100         dva_t           ze_dva;         /* dva associated with this extent */
101         uint64_t        ze_nblks;       /* number of blocks in extent */
102 } zvol_extent_t;
103
104 /*
105  * The in-core state of each volume.
106  */
107 typedef struct zvol_state {
108         char            zv_name[MAXPATHLEN]; /* pool/dd name */
109         uint64_t        zv_volsize;     /* amount of space we advertise */
110         uint64_t        zv_volblocksize; /* volume block size */
111         struct g_provider *zv_provider; /* GEOM provider */
112         uint8_t         zv_min_bs;      /* minimum addressable block shift */
113         uint8_t         zv_flags;       /* readonly; dumpified */
114         objset_t        *zv_objset;     /* objset handle */
115         uint32_t        zv_mode;        /* DS_MODE_* flags at open time */
116         uint32_t        zv_total_opens; /* total open count */
117         zilog_t         *zv_zilog;      /* ZIL handle */
118         list_t          zv_extents;     /* List of extents for dump */
119         znode_t         zv_znode;       /* for range locking */
120         int             zv_state;
121         struct bio_queue_head zv_queue;
122         struct mtx      zv_queue_mtx;   /* zv_queue mutex */
123 } zvol_state_t;
124
125 /*
126  * zvol specific flags
127  */
128 #define ZVOL_RDONLY     0x1
129 #define ZVOL_DUMPIFIED  0x2
130 #define ZVOL_EXCL       0x4
131
132 /*
133  * zvol maximum transfer in one DMU tx.
134  */
135 int zvol_maxphys = DMU_MAX_ACCESS/2;
136
137 extern int zfs_set_prop_nvlist(const char *, nvlist_t *);
138 static int zvol_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio);
139 static int zvol_dumpify(zvol_state_t *zv);
140 static int zvol_dump_fini(zvol_state_t *zv);
141 static int zvol_dump_init(zvol_state_t *zv, boolean_t resize);
142
143 static void
144 zvol_size_changed(zvol_state_t *zv, major_t maj)
145 {
146         struct g_provider *pp;
147
148         g_topology_assert();
149
150         pp = zv->zv_provider;
151         if (pp == NULL)
152                 return;
153         if (zv->zv_volsize == pp->mediasize)
154                 return;
155         /*
156          * Changing provider size is not really supported by GEOM, but it
157          * should be safe when provider is closed.
158          */
159         if (zv->zv_total_opens > 0)
160                 return;
161         pp->mediasize = zv->zv_volsize;
162 }
163
164 int
165 zvol_check_volsize(uint64_t volsize, uint64_t blocksize)
166 {
167         if (volsize == 0)
168                 return (EINVAL);
169
170         if (volsize % blocksize != 0)
171                 return (EINVAL);
172
173 #ifdef _ILP32
174         if (volsize - 1 > SPEC_MAXOFFSET_T)
175                 return (EOVERFLOW);
176 #endif
177         return (0);
178 }
179
180 int
181 zvol_check_volblocksize(uint64_t volblocksize)
182 {
183         if (volblocksize < SPA_MINBLOCKSIZE ||
184             volblocksize > SPA_MAXBLOCKSIZE ||
185             !ISP2(volblocksize))
186                 return (EDOM);
187
188         return (0);
189 }
190
191 static void
192 zvol_readonly_changed_cb(void *arg, uint64_t newval)
193 {
194         zvol_state_t *zv = arg;
195
196         if (newval)
197                 zv->zv_flags |= ZVOL_RDONLY;
198         else
199                 zv->zv_flags &= ~ZVOL_RDONLY;
200 }
201
202 int
203 zvol_get_stats(objset_t *os, nvlist_t *nv)
204 {
205         int error;
206         dmu_object_info_t doi;
207         uint64_t val;
208
209
210         error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &val);
211         if (error)
212                 return (error);
213
214         dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_VOLSIZE, val);
215
216         error = dmu_object_info(os, ZVOL_OBJ, &doi);
217
218         if (error == 0) {
219                 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_VOLBLOCKSIZE,
220                     doi.doi_data_block_size);
221         }
222
223         return (error);
224 }
225
226 static zvol_state_t *
227 zvol_minor_lookup(const char *name)
228 {
229         struct g_provider *pp;
230         struct g_geom *gp;
231
232         g_topology_assert();
233         ASSERT(MUTEX_HELD(&zvol_state_lock));
234
235         LIST_FOREACH(gp, &zfs_zvol_class.geom, geom) {
236                 LIST_FOREACH(pp, &gp->provider, provider) {
237                         if (strcmp(pp->name + sizeof(ZVOL_DEV_DIR), name) == 0)
238                                 return (pp->private);
239                 }
240         }
241
242         return (NULL);
243 }
244
245 static int
246 zvol_access(struct g_provider *pp, int acr, int acw, int ace)
247 {
248         zvol_state_t *zv;
249
250         g_topology_assert();
251         mutex_enter(&zvol_state_lock);
252
253         zv = pp->private;
254         if (zv == NULL) {
255                 if (acr <= 0 && acw <= 0 && ace <= 0)
256                         return (0);
257                 mutex_exit(&zvol_state_lock);
258                 return (pp->error);
259         }
260
261         ASSERT(zv->zv_objset != NULL);
262
263         if (acw > 0 &&
264             ((zv->zv_flags & ZVOL_RDONLY) ||
265              (zv->zv_mode & DS_MODE_READONLY))) {
266                 mutex_exit(&zvol_state_lock);
267                 return (EROFS);
268         }
269
270         zv->zv_total_opens += acr + acw + ace;
271         zvol_size_changed(zv, 0);
272
273         mutex_exit(&zvol_state_lock);
274
275         return (0);
276 }
277
278 /*
279  * zvol_log_write() handles synchronous writes using TX_WRITE ZIL transactions.
280  *
281  * We store data in the log buffers if it's small enough.
282  * Otherwise we will later flush the data out via dmu_sync().
283  */
284 ssize_t zvol_immediate_write_sz = 32768;
285
286 static void
287 zvol_log_write(zvol_state_t *zv, dmu_tx_t *tx, offset_t off, ssize_t len)
288 {
289         uint32_t blocksize = zv->zv_volblocksize;
290         zilog_t *zilog = zv->zv_zilog;
291         lr_write_t *lr;
292
293         if (zilog->zl_replay) {
294                 dsl_dataset_dirty(dmu_objset_ds(zilog->zl_os), tx);
295                 zilog->zl_replayed_seq[dmu_tx_get_txg(tx) & TXG_MASK] =
296                     zilog->zl_replaying_seq;
297                 return;
298         }
299
300         while (len) {
301                 ssize_t nbytes = MIN(len, blocksize - P2PHASE(off, blocksize));
302                 itx_t *itx = zil_itx_create(TX_WRITE, sizeof (*lr));
303
304                 itx->itx_wr_state =
305                     len > zvol_immediate_write_sz ?  WR_INDIRECT : WR_NEED_COPY;
306                 itx->itx_private = zv;
307                 lr = (lr_write_t *)&itx->itx_lr;
308                 lr->lr_foid = ZVOL_OBJ;
309                 lr->lr_offset = off;
310                 lr->lr_length = nbytes;
311                 lr->lr_blkoff = off - P2ALIGN_TYPED(off, blocksize, uint64_t);
312                 BP_ZERO(&lr->lr_blkptr);
313
314                 (void) zil_itx_assign(zilog, itx, tx);
315                 len -= nbytes;
316                 off += nbytes;
317         }
318 }
319
320 static void
321 zvol_start(struct bio *bp)
322 {
323         zvol_state_t *zv;
324
325         switch (bp->bio_cmd) {
326         case BIO_READ:
327         case BIO_WRITE:
328         case BIO_FLUSH:
329                 zv = bp->bio_to->private;
330                 ASSERT(zv != NULL);
331                 mtx_lock(&zv->zv_queue_mtx);
332                 bioq_insert_tail(&zv->zv_queue, bp);
333                 wakeup_one(&zv->zv_queue);
334                 mtx_unlock(&zv->zv_queue_mtx);
335                 break;
336         case BIO_GETATTR:
337                 if (g_handleattr_int(bp, "ZFS::iszvol", 1))
338                         break;
339                 /* FALLTHROUGH */
340         case BIO_DELETE:
341         default:
342                 g_io_deliver(bp, EOPNOTSUPP);
343                 break;
344         }
345 }
346
347 static void
348 zvol_serve_one(zvol_state_t *zv, struct bio *bp)
349 {
350         uint64_t off, volsize;
351         size_t resid;
352         char *addr;
353         objset_t *os;
354         rl_t *rl;
355         int error = 0;
356         boolean_t doread = (bp->bio_cmd == BIO_READ);
357
358         off = bp->bio_offset;
359         volsize = zv->zv_volsize;
360
361         os = zv->zv_objset;
362         ASSERT(os != NULL);
363
364         addr = bp->bio_data;
365         resid = bp->bio_length;
366
367         error = 0;
368
369         /*
370          * There must be no buffer changes when doing a dmu_sync() because
371          * we can't change the data whilst calculating the checksum.
372          * A better approach than a per zvol rwlock would be to lock ranges.
373          */
374         rl = zfs_range_lock(&zv->zv_znode, off, resid,
375             doread ? RL_READER : RL_WRITER);
376
377         while (resid != 0 && off < volsize) {
378                 size_t size = MIN(resid, zvol_maxphys); /* zvol_maxphys per tx */
379
380                 if (size > volsize - off)       /* don't write past the end */
381                         size = volsize - off;
382
383                 if (doread) {
384                         error = dmu_read(os, ZVOL_OBJ, off, size, addr,
385                             DMU_READ_PREFETCH);
386                 } else {
387                         dmu_tx_t *tx = dmu_tx_create(os);
388                         dmu_tx_hold_write(tx, ZVOL_OBJ, off, size);
389                         error = dmu_tx_assign(tx, TXG_WAIT);
390                         if (error) {
391                                 dmu_tx_abort(tx);
392                         } else {
393                                 dmu_write(os, ZVOL_OBJ, off, size, addr, tx);
394                                 zvol_log_write(zv, tx, off, size);
395                                 dmu_tx_commit(tx);
396                         }
397                 }
398                 if (error) {
399                         /* convert checksum errors into IO errors */
400                         if (error == ECKSUM)
401                                 error = EIO;
402                         break;
403                 }
404                 off += size;
405                 addr += size;
406                 resid -= size;
407         }
408         zfs_range_unlock(rl);
409
410         bp->bio_completed = bp->bio_length - resid;
411         if (bp->bio_completed < bp->bio_length)
412                 bp->bio_error = (off > volsize ? EINVAL : error);
413 }
414
415 static void
416 zvol_worker(void *arg)
417 {
418         zvol_state_t *zv;
419         struct bio *bp;
420
421         thread_lock(curthread);
422         sched_prio(curthread, PRIBIO);
423         thread_unlock(curthread);
424
425         zv = arg;
426         for (;;) {
427                 mtx_lock(&zv->zv_queue_mtx);
428                 bp = bioq_takefirst(&zv->zv_queue);
429                 if (bp == NULL) {
430                         if (zv->zv_state == 1) {
431                                 zv->zv_state = 2;
432                                 wakeup(&zv->zv_state);
433                                 mtx_unlock(&zv->zv_queue_mtx);
434                                 kthread_exit();
435                         }
436                         msleep(&zv->zv_queue, &zv->zv_queue_mtx, PRIBIO | PDROP,
437                             "zvol:io", 0);
438                         continue;
439                 }
440                 mtx_unlock(&zv->zv_queue_mtx);
441                 switch (bp->bio_cmd) {
442                 case BIO_FLUSH:
443                         break;
444                 case BIO_READ:
445                 case BIO_WRITE:
446                         zvol_serve_one(zv, bp);
447                         break;
448                 }
449
450                 if (bp->bio_cmd == BIO_FLUSH && !zil_disable)
451                         zil_commit(zv->zv_zilog, UINT64_MAX, ZVOL_OBJ);
452
453                 g_io_deliver(bp, bp->bio_error);
454         }
455 }
456
457 /* extent mapping arg */
458 struct maparg {
459         zvol_state_t    *ma_zv;
460         uint64_t        ma_blks;
461 };
462
463 /*ARGSUSED*/
464 static int
465 zvol_map_block(spa_t *spa, blkptr_t *bp, const zbookmark_t *zb,
466     const dnode_phys_t *dnp, void *arg)
467 {
468         struct maparg *ma = arg;
469         zvol_extent_t *ze;
470         int bs = ma->ma_zv->zv_volblocksize;
471
472         if (bp == NULL || zb->zb_object != ZVOL_OBJ || zb->zb_level != 0)
473                 return (0);
474
475         VERIFY3U(ma->ma_blks, ==, zb->zb_blkid);
476         ma->ma_blks++;
477
478         /* Abort immediately if we have encountered gang blocks */
479         if (BP_IS_GANG(bp))
480                 return (EFRAGS);
481
482         /*
483          * See if the block is at the end of the previous extent.
484          */
485         ze = list_tail(&ma->ma_zv->zv_extents);
486         if (ze &&
487             DVA_GET_VDEV(BP_IDENTITY(bp)) == DVA_GET_VDEV(&ze->ze_dva) &&
488             DVA_GET_OFFSET(BP_IDENTITY(bp)) ==
489             DVA_GET_OFFSET(&ze->ze_dva) + ze->ze_nblks * bs) {
490                 ze->ze_nblks++;
491                 return (0);
492         }
493
494         dprintf_bp(bp, "%s", "next blkptr:");
495
496         /* start a new extent */
497         ze = kmem_zalloc(sizeof (zvol_extent_t), KM_SLEEP);
498         ze->ze_dva = bp->blk_dva[0];    /* structure assignment */
499         ze->ze_nblks = 1;
500         list_insert_tail(&ma->ma_zv->zv_extents, ze);
501         return (0);
502 }
503
504 static void
505 zvol_free_extents(zvol_state_t *zv)
506 {
507         zvol_extent_t *ze;
508
509         while (ze = list_head(&zv->zv_extents)) {
510                 list_remove(&zv->zv_extents, ze);
511                 kmem_free(ze, sizeof (zvol_extent_t));
512         }
513 }
514
515 static int
516 zvol_get_lbas(zvol_state_t *zv)
517 {
518         struct maparg   ma;
519         int             err;
520
521         ma.ma_zv = zv;
522         ma.ma_blks = 0;
523         zvol_free_extents(zv);
524
525         err = traverse_dataset(dmu_objset_ds(zv->zv_objset), 0,
526             TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA, zvol_map_block, &ma);
527         if (err || ma.ma_blks != (zv->zv_volsize / zv->zv_volblocksize)) {
528                 zvol_free_extents(zv);
529                 return (err ? err : EIO);
530         }
531
532         return (0);
533 }
534
535 /* ARGSUSED */
536 void
537 zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
538 {
539         zfs_creat_t *zct = arg;
540         nvlist_t *nvprops = zct->zct_props;
541         int error;
542         uint64_t volblocksize, volsize;
543
544         VERIFY(nvlist_lookup_uint64(nvprops,
545             zfs_prop_to_name(ZFS_PROP_VOLSIZE), &volsize) == 0);
546         if (nvlist_lookup_uint64(nvprops,
547             zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &volblocksize) != 0)
548                 volblocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
549
550         /*
551          * These properties must be removed from the list so the generic
552          * property setting step won't apply to them.
553          */
554         VERIFY(nvlist_remove_all(nvprops,
555             zfs_prop_to_name(ZFS_PROP_VOLSIZE)) == 0);
556         (void) nvlist_remove_all(nvprops,
557             zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE));
558
559         error = dmu_object_claim(os, ZVOL_OBJ, DMU_OT_ZVOL, volblocksize,
560             DMU_OT_NONE, 0, tx);
561         ASSERT(error == 0);
562
563         error = zap_create_claim(os, ZVOL_ZAP_OBJ, DMU_OT_ZVOL_PROP,
564             DMU_OT_NONE, 0, tx);
565         ASSERT(error == 0);
566
567         error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize, tx);
568         ASSERT(error == 0);
569 }
570
571 /*
572  * Replay a TX_WRITE ZIL transaction that didn't get committed
573  * after a system failure
574  */
575 static int
576 zvol_replay_write(zvol_state_t *zv, lr_write_t *lr, boolean_t byteswap)
577 {
578         objset_t *os = zv->zv_objset;
579         char *data = (char *)(lr + 1);  /* data follows lr_write_t */
580         uint64_t off = lr->lr_offset;
581         uint64_t len = lr->lr_length;
582         dmu_tx_t *tx;
583         int error;
584
585         if (byteswap)
586                 byteswap_uint64_array(lr, sizeof (*lr));
587
588         /* If it's a dmu_sync() block get the data and write the whole block */
589         if (lr->lr_common.lrc_reclen == sizeof (lr_write_t))
590                 zil_get_replay_data(dmu_objset_zil(os), lr);
591
592         tx = dmu_tx_create(os);
593         dmu_tx_hold_write(tx, ZVOL_OBJ, off, len);
594         error = dmu_tx_assign(tx, TXG_WAIT);
595         if (error) {
596                 dmu_tx_abort(tx);
597         } else {
598                 dmu_write(os, ZVOL_OBJ, off, len, data, tx);
599                 dmu_tx_commit(tx);
600         }
601
602         return (error);
603 }
604
605 /* ARGSUSED */
606 static int
607 zvol_replay_err(zvol_state_t *zv, lr_t *lr, boolean_t byteswap)
608 {
609         return (ENOTSUP);
610 }
611
612 /*
613  * Callback vectors for replaying records.
614  * Only TX_WRITE is needed for zvol.
615  */
616 zil_replay_func_t *zvol_replay_vector[TX_MAX_TYPE] = {
617         zvol_replay_err,        /* 0 no such transaction type */
618         zvol_replay_err,        /* TX_CREATE */
619         zvol_replay_err,        /* TX_MKDIR */
620         zvol_replay_err,        /* TX_MKXATTR */
621         zvol_replay_err,        /* TX_SYMLINK */
622         zvol_replay_err,        /* TX_REMOVE */
623         zvol_replay_err,        /* TX_RMDIR */
624         zvol_replay_err,        /* TX_LINK */
625         zvol_replay_err,        /* TX_RENAME */
626         zvol_replay_write,      /* TX_WRITE */
627         zvol_replay_err,        /* TX_TRUNCATE */
628         zvol_replay_err,        /* TX_SETATTR */
629         zvol_replay_err,        /* TX_ACL */
630         zvol_replay_err,        /* TX_CREATE_ACL */
631         zvol_replay_err,        /* TX_CREATE_ATTR */
632         zvol_replay_err,        /* TX_CREATE_ACL_ATTR */
633         zvol_replay_err,        /* TX_MKDIR_ACL */
634         zvol_replay_err,        /* TX_MKDIR_ATTR */
635         zvol_replay_err,        /* TX_MKDIR_ACL_ATTR */
636         zvol_replay_err,        /* TX_WRITE2 */
637 };
638
639 /*
640  * Create a minor node (plus a whole lot more) for the specified volume.
641  */
642 int
643 zvol_create_minor(const char *name, major_t maj)
644 {
645         struct g_provider *pp;
646         struct g_geom *gp;
647         zvol_state_t *zv;
648         objset_t *os;
649         dmu_object_info_t doi;
650         uint64_t volsize;
651         int ds_mode = DS_MODE_OWNER;
652         int error;
653
654         DROP_GIANT();
655         g_topology_lock();
656         mutex_enter(&zvol_state_lock);
657
658         if ((zv = zvol_minor_lookup(name)) != NULL) {
659                 error = EEXIST;
660                 goto end;
661         }
662
663         if (strchr(name, '@') != 0)
664                 ds_mode |= DS_MODE_READONLY;
665
666         error = dmu_objset_open(name, DMU_OST_ZVOL, ds_mode, &os);
667         if (error)
668                 goto end;
669
670         error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize);
671         if (error) {
672                 dmu_objset_close(os);
673                 goto end;
674         }
675
676         gp = g_new_geomf(&zfs_zvol_class, "zfs::zvol::%s", name);
677         gp->start = zvol_start;
678         gp->access = zvol_access;
679         pp = g_new_providerf(gp, "%s/%s", ZVOL_DEV_DIR, name);
680         pp->mediasize = volsize;
681         pp->sectorsize = DEV_BSIZE;
682
683         zv = kmem_zalloc(sizeof(*zv), KM_SLEEP);
684         (void) strcpy(zv->zv_name, name);
685         zv->zv_min_bs = DEV_BSHIFT;
686         zv->zv_provider = pp;
687         zv->zv_volsize = pp->mediasize;
688         zv->zv_objset = os;
689         zv->zv_mode = ds_mode;
690         zv->zv_zilog = zil_open(os, zvol_get_data);
691         mutex_init(&zv->zv_znode.z_range_lock, NULL, MUTEX_DEFAULT, NULL);
692         avl_create(&zv->zv_znode.z_range_avl, zfs_range_compare,
693             sizeof (rl_t), offsetof(rl_t, r_node));
694         list_create(&zv->zv_extents, sizeof (zvol_extent_t),
695             offsetof(zvol_extent_t, ze_node));
696         /* get and cache the blocksize */
697         error = dmu_object_info(os, ZVOL_OBJ, &doi);
698         ASSERT(error == 0);
699         zv->zv_volblocksize = doi.doi_data_block_size;
700
701         zil_replay(os, zv, zvol_replay_vector);
702
703         /* XXX this should handle the possible i/o error */
704         VERIFY(dsl_prop_register(dmu_objset_ds(zv->zv_objset),
705             "readonly", zvol_readonly_changed_cb, zv) == 0);
706
707         pp->private = zv;
708         g_error_provider(pp, 0);
709
710         bioq_init(&zv->zv_queue);
711         mtx_init(&zv->zv_queue_mtx, "zvol", NULL, MTX_DEF);
712         zv->zv_state = 0;
713         kproc_kthread_add(zvol_worker, zv, &zfsproc, NULL, 0, 0, "zfskern",
714             "zvol %s", pp->name + strlen(ZVOL_DEV_DIR) + 1);
715
716         zvol_minors++;
717 end:
718         mutex_exit(&zvol_state_lock);
719         g_topology_unlock();
720         PICKUP_GIANT();
721
722         return (error);
723 }
724
725 /*
726  * Remove minor node for the specified volume.
727  */
728 int
729 zvol_remove_minor(const char *name)
730 {
731         struct g_provider *pp;
732         zvol_state_t *zv;
733         int error = 0;
734
735         DROP_GIANT();
736         g_topology_lock();
737         mutex_enter(&zvol_state_lock);
738
739         if ((zv = zvol_minor_lookup(name)) == NULL) {
740                 error = ENXIO;
741                 goto end;
742         }
743
744         if (zv->zv_total_opens != 0) {
745                 error = EBUSY;
746                 goto end;
747         }
748
749         VERIFY(dsl_prop_unregister(dmu_objset_ds(zv->zv_objset),
750             "readonly", zvol_readonly_changed_cb, zv) == 0);
751
752         mtx_lock(&zv->zv_queue_mtx);
753         zv->zv_state = 1;
754         wakeup_one(&zv->zv_queue);
755         while (zv->zv_state != 2)
756                 msleep(&zv->zv_state, &zv->zv_queue_mtx, 0, "zvol:w", 0);
757         mtx_unlock(&zv->zv_queue_mtx);
758         mtx_destroy(&zv->zv_queue_mtx);
759
760         pp = zv->zv_provider;
761         pp->private = NULL;
762         g_wither_geom(pp->geom, ENXIO);
763
764         zil_close(zv->zv_zilog);
765         zv->zv_zilog = NULL;
766         dmu_objset_close(zv->zv_objset);
767         zv->zv_objset = NULL;
768         avl_destroy(&zv->zv_znode.z_range_avl);
769         mutex_destroy(&zv->zv_znode.z_range_lock);
770
771         kmem_free(zv, sizeof(*zv));
772
773         zvol_minors--;
774 end:
775         mutex_exit(&zvol_state_lock);
776         g_topology_unlock();
777         PICKUP_GIANT();
778
779         return (error);
780 }
781
782 int
783 zvol_prealloc(zvol_state_t *zv)
784 {
785         objset_t *os = zv->zv_objset;
786         dmu_tx_t *tx;
787         void *data;
788         uint64_t refd, avail, usedobjs, availobjs;
789         uint64_t resid = zv->zv_volsize;
790         uint64_t off = 0;
791
792         /* Check the space usage before attempting to allocate the space */
793         dmu_objset_space(os, &refd, &avail, &usedobjs, &availobjs);
794         if (avail < zv->zv_volsize)
795                 return (ENOSPC);
796
797         /* Free old extents if they exist */
798         zvol_free_extents(zv);
799
800         /* allocate the blocks by writing each one */
801         data = kmem_zalloc(SPA_MAXBLOCKSIZE, KM_SLEEP);
802
803         while (resid != 0) {
804                 int error;
805                 uint64_t bytes = MIN(resid, SPA_MAXBLOCKSIZE);
806
807                 tx = dmu_tx_create(os);
808                 dmu_tx_hold_write(tx, ZVOL_OBJ, off, bytes);
809                 error = dmu_tx_assign(tx, TXG_WAIT);
810                 if (error) {
811                         dmu_tx_abort(tx);
812                         kmem_free(data, SPA_MAXBLOCKSIZE);
813                         (void) dmu_free_long_range(os, ZVOL_OBJ, 0, off);
814                         return (error);
815                 }
816                 dmu_write(os, ZVOL_OBJ, off, bytes, data, tx);
817                 dmu_tx_commit(tx);
818                 off += bytes;
819                 resid -= bytes;
820         }
821         kmem_free(data, SPA_MAXBLOCKSIZE);
822         txg_wait_synced(dmu_objset_pool(os), 0);
823
824         return (0);
825 }
826
827 int
828 zvol_update_volsize(zvol_state_t *zv, major_t maj, uint64_t volsize)
829 {
830         dmu_tx_t *tx;
831         int error;
832
833         ASSERT(MUTEX_HELD(&zvol_state_lock));
834
835         tx = dmu_tx_create(zv->zv_objset);
836         dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL);
837         error = dmu_tx_assign(tx, TXG_WAIT);
838         if (error) {
839                 dmu_tx_abort(tx);
840                 return (error);
841         }
842
843         error = zap_update(zv->zv_objset, ZVOL_ZAP_OBJ, "size", 8, 1,
844             &volsize, tx);
845         dmu_tx_commit(tx);
846
847         if (error == 0)
848                 error = dmu_free_long_range(zv->zv_objset,
849                     ZVOL_OBJ, volsize, DMU_OBJECT_END);
850
851         /*
852          * If we are using a faked-up state (zv_provider == NULL) then don't
853          * try to update the in-core zvol state.
854          */
855         if (error == 0 && zv->zv_provider) {
856                 zv->zv_volsize = volsize;
857                 zvol_size_changed(zv, maj);
858         }
859         return (error);
860 }
861
862 int
863 zvol_set_volsize(const char *name, major_t maj, uint64_t volsize)
864 {
865         zvol_state_t *zv;
866         int error;
867         dmu_object_info_t doi;
868         uint64_t old_volsize = 0ULL;
869         zvol_state_t state = { 0 };
870
871         DROP_GIANT();
872         g_topology_lock();
873         mutex_enter(&zvol_state_lock);
874
875         if ((zv = zvol_minor_lookup(name)) == NULL) {
876                 /*
877                  * If we are doing a "zfs clone -o volsize=", then the
878                  * minor node won't exist yet.
879                  */
880                 error = dmu_objset_open(name, DMU_OST_ZVOL, DS_MODE_OWNER,
881                     &state.zv_objset);
882                 if (error != 0)
883                         goto out;
884                 zv = &state;
885         }
886         old_volsize = zv->zv_volsize;
887
888         if ((error = dmu_object_info(zv->zv_objset, ZVOL_OBJ, &doi)) != 0 ||
889             (error = zvol_check_volsize(volsize,
890             doi.doi_data_block_size)) != 0)
891                 goto out;
892
893         if (zv->zv_flags & ZVOL_RDONLY || (zv->zv_mode & DS_MODE_READONLY)) {
894                 error = EROFS;
895                 goto out;
896         }
897
898         error = zvol_update_volsize(zv, maj, volsize);
899
900 #if 0
901         /*
902          * Reinitialize the dump area to the new size. If we
903          * failed to resize the dump area then restore the it back to
904          * it's original size.
905          */
906         if (error == 0 && zv->zv_flags & ZVOL_DUMPIFIED) {
907                 if ((error = zvol_dumpify(zv)) != 0 ||
908                     (error = dumpvp_resize()) != 0) {
909                         (void) zvol_update_volsize(zv, maj, old_volsize);
910                         error = zvol_dumpify(zv);
911                 }
912         }
913 #endif
914
915 out:
916         if (state.zv_objset)
917                 dmu_objset_close(state.zv_objset);
918
919         mutex_exit(&zvol_state_lock);
920         g_topology_unlock();
921         PICKUP_GIANT();
922
923         return (error);
924 }
925
926 int
927 zvol_set_volblocksize(const char *name, uint64_t volblocksize)
928 {
929         zvol_state_t *zv;
930         dmu_tx_t *tx;
931         int error;
932
933         DROP_GIANT();
934         g_topology_lock();
935         mutex_enter(&zvol_state_lock);
936
937         if ((zv = zvol_minor_lookup(name)) == NULL) {
938                 error = ENXIO;
939                 goto end;
940         }
941         if (zv->zv_flags & ZVOL_RDONLY || (zv->zv_mode & DS_MODE_READONLY)) {
942                 error = EROFS;
943                 goto end;
944         }
945
946         tx = dmu_tx_create(zv->zv_objset);
947         dmu_tx_hold_bonus(tx, ZVOL_OBJ);
948         error = dmu_tx_assign(tx, TXG_WAIT);
949         if (error) {
950                 dmu_tx_abort(tx);
951         } else {
952                 error = dmu_object_set_blocksize(zv->zv_objset, ZVOL_OBJ,
953                     volblocksize, 0, tx);
954                 if (error == ENOTSUP)
955                         error = EBUSY;
956                 dmu_tx_commit(tx);
957                 if (error == 0)
958                         zv->zv_volblocksize = volblocksize;
959         }
960 end:
961         mutex_exit(&zvol_state_lock);
962         g_topology_unlock();
963         PICKUP_GIANT();
964
965         return (error);
966 }
967
968 void
969 zvol_get_done(dmu_buf_t *db, void *vzgd)
970 {
971         zgd_t *zgd = (zgd_t *)vzgd;
972         rl_t *rl = zgd->zgd_rl;
973
974         dmu_buf_rele(db, vzgd);
975         zfs_range_unlock(rl);
976         zil_add_block(zgd->zgd_zilog, zgd->zgd_bp);
977         kmem_free(zgd, sizeof (zgd_t));
978 }
979
980 /*
981  * Get data to generate a TX_WRITE intent log record.
982  */
983 static int
984 zvol_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
985 {
986         zvol_state_t *zv = arg;
987         objset_t *os = zv->zv_objset;
988         dmu_buf_t *db;
989         rl_t *rl;
990         zgd_t *zgd;
991         uint64_t boff;                  /* block starting offset */
992         int dlen = lr->lr_length;       /* length of user data */
993         int error;
994
995         ASSERT(zio);
996         ASSERT(dlen != 0);
997
998         /*
999          * Write records come in two flavors: immediate and indirect.
1000          * For small writes it's cheaper to store the data with the
1001          * log record (immediate); for large writes it's cheaper to
1002          * sync the data and get a pointer to it (indirect) so that
1003          * we don't have to write the data twice.
1004          */
1005         if (buf != NULL) /* immediate write */
1006                 return (dmu_read(os, ZVOL_OBJ, lr->lr_offset, dlen, buf,
1007                     DMU_READ_NO_PREFETCH));
1008
1009         zgd = (zgd_t *)kmem_alloc(sizeof (zgd_t), KM_SLEEP);
1010         zgd->zgd_zilog = zv->zv_zilog;
1011         zgd->zgd_bp = &lr->lr_blkptr;
1012
1013         /*
1014          * Lock the range of the block to ensure that when the data is
1015          * written out and its checksum is being calculated that no other
1016          * thread can change the block.
1017          */
1018         boff = P2ALIGN_TYPED(lr->lr_offset, zv->zv_volblocksize, uint64_t);
1019         rl = zfs_range_lock(&zv->zv_znode, boff, zv->zv_volblocksize,
1020             RL_READER);
1021         zgd->zgd_rl = rl;
1022
1023         VERIFY(0 == dmu_buf_hold(os, ZVOL_OBJ, lr->lr_offset, zgd, &db));
1024
1025         error = dmu_sync(zio, db, &lr->lr_blkptr,
1026             lr->lr_common.lrc_txg, zvol_get_done, zgd);
1027         if (error == 0) {
1028                 /*
1029                  * dmu_sync() can compress a block of zeros to a null blkptr
1030                  * but the block size still needs to be passed through to
1031                  * replay.
1032                  */
1033                 BP_SET_LSIZE(&lr->lr_blkptr, db->db_size);
1034                 zil_add_block(zv->zv_zilog, &lr->lr_blkptr);
1035         }
1036
1037         /*
1038          * If we get EINPROGRESS, then we need to wait for a
1039          * write IO initiated by dmu_sync() to complete before
1040          * we can release this dbuf.  We will finish everything
1041          * up in the zvol_get_done() callback.
1042          */
1043         if (error == EINPROGRESS)
1044                 return (0);
1045         dmu_buf_rele(db, zgd);
1046         zfs_range_unlock(rl);
1047         kmem_free(zgd, sizeof (zgd_t));
1048         return (error);
1049 }
1050
1051 int
1052 zvol_busy(void)
1053 {
1054         return (zvol_minors != 0);
1055 }
1056
1057 void
1058 zvol_init(void)
1059 {
1060         mutex_init(&zvol_state_lock, NULL, MUTEX_DEFAULT, NULL);
1061         ZFS_LOG(1, "ZVOL Initialized.");
1062 }
1063
1064 void
1065 zvol_fini(void)
1066 {
1067         mutex_destroy(&zvol_state_lock);
1068         ZFS_LOG(1, "ZVOL Deinitialized.");
1069 }
1070
1071 static boolean_t
1072 zvol_is_swap(zvol_state_t *zv)
1073 {
1074         vnode_t *vp;
1075         boolean_t ret = B_FALSE;
1076         char *devpath;
1077         size_t devpathlen;
1078         int error;
1079
1080 #if 0
1081         devpathlen = strlen(ZVOL_FULL_DEV_DIR) + strlen(zv->zv_name) + 1;
1082         devpath = kmem_alloc(devpathlen, KM_SLEEP);
1083         (void) sprintf(devpath, "%s%s", ZVOL_FULL_DEV_DIR, zv->zv_name);
1084         error = lookupname(devpath, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp);
1085         kmem_free(devpath, devpathlen);
1086
1087         ret = !error && IS_SWAPVP(common_specvp(vp));
1088
1089         if (vp != NULL)
1090                 VN_RELE(vp);
1091 #endif
1092
1093         return (ret);
1094 }
1095
1096 static int
1097 zvol_dump_init(zvol_state_t *zv, boolean_t resize)
1098 {
1099         dmu_tx_t *tx;
1100         int error = 0;
1101         objset_t *os = zv->zv_objset;
1102         nvlist_t *nv = NULL;
1103
1104         ASSERT(MUTEX_HELD(&zvol_state_lock));
1105
1106         tx = dmu_tx_create(os);
1107         dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL);
1108         error = dmu_tx_assign(tx, TXG_WAIT);
1109         if (error) {
1110                 dmu_tx_abort(tx);
1111                 return (error);
1112         }
1113
1114         /*
1115          * If we are resizing the dump device then we only need to
1116          * update the refreservation to match the newly updated
1117          * zvolsize. Otherwise, we save off the original state of the
1118          * zvol so that we can restore them if the zvol is ever undumpified.
1119          */
1120         if (resize) {
1121                 error = zap_update(os, ZVOL_ZAP_OBJ,
1122                     zfs_prop_to_name(ZFS_PROP_REFRESERVATION), 8, 1,
1123                     &zv->zv_volsize, tx);
1124         } else {
1125                 uint64_t checksum, compress, refresrv, vbs;
1126
1127                 error = dsl_prop_get_integer(zv->zv_name,
1128                     zfs_prop_to_name(ZFS_PROP_COMPRESSION), &compress, NULL);
1129                 error = error ? error : dsl_prop_get_integer(zv->zv_name,
1130                     zfs_prop_to_name(ZFS_PROP_CHECKSUM), &checksum, NULL);
1131                 error = error ? error : dsl_prop_get_integer(zv->zv_name,
1132                     zfs_prop_to_name(ZFS_PROP_REFRESERVATION), &refresrv, NULL);
1133                 error = error ? error : dsl_prop_get_integer(zv->zv_name,
1134                     zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &vbs, NULL);
1135
1136                 error = error ? error : zap_update(os, ZVOL_ZAP_OBJ,
1137                     zfs_prop_to_name(ZFS_PROP_COMPRESSION), 8, 1,
1138                     &compress, tx);
1139                 error = error ? error : zap_update(os, ZVOL_ZAP_OBJ,
1140                     zfs_prop_to_name(ZFS_PROP_CHECKSUM), 8, 1, &checksum, tx);
1141                 error = error ? error : zap_update(os, ZVOL_ZAP_OBJ,
1142                     zfs_prop_to_name(ZFS_PROP_REFRESERVATION), 8, 1,
1143                     &refresrv, tx);
1144                 error = error ? error : zap_update(os, ZVOL_ZAP_OBJ,
1145                     zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 8, 1,
1146                     &vbs, tx);
1147         }
1148         dmu_tx_commit(tx);
1149
1150         /* Truncate the file */
1151         if (!error)
1152                 error = dmu_free_long_range(zv->zv_objset,
1153                     ZVOL_OBJ, 0, DMU_OBJECT_END);
1154
1155         if (error)
1156                 return (error);
1157
1158         /*
1159          * We only need update the zvol's property if we are initializing
1160          * the dump area for the first time.
1161          */
1162         if (!resize) {
1163                 VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1164                 VERIFY(nvlist_add_uint64(nv,
1165                     zfs_prop_to_name(ZFS_PROP_REFRESERVATION), 0) == 0);
1166                 VERIFY(nvlist_add_uint64(nv,
1167                     zfs_prop_to_name(ZFS_PROP_COMPRESSION),
1168                     ZIO_COMPRESS_OFF) == 0);
1169                 VERIFY(nvlist_add_uint64(nv,
1170                     zfs_prop_to_name(ZFS_PROP_CHECKSUM),
1171                     ZIO_CHECKSUM_OFF) == 0);
1172                 VERIFY(nvlist_add_uint64(nv,
1173                     zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
1174                     SPA_MAXBLOCKSIZE) == 0);
1175
1176                 error = zfs_set_prop_nvlist(zv->zv_name, nv);
1177                 nvlist_free(nv);
1178
1179                 if (error)
1180                         return (error);
1181         }
1182
1183         /* Allocate the space for the dump */
1184         error = zvol_prealloc(zv);
1185         return (error);
1186 }
1187
1188 static int
1189 zvol_dumpify(zvol_state_t *zv)
1190 {
1191         int error = 0;
1192         uint64_t dumpsize = 0;
1193         dmu_tx_t *tx;
1194         objset_t *os = zv->zv_objset;
1195
1196         if (zv->zv_flags & ZVOL_RDONLY || (zv->zv_mode & DS_MODE_READONLY))
1197                 return (EROFS);
1198
1199         /*
1200          * We do not support swap devices acting as dump devices.
1201          */
1202         if (zvol_is_swap(zv))
1203                 return (ENOTSUP);
1204
1205         if (zap_lookup(zv->zv_objset, ZVOL_ZAP_OBJ, ZVOL_DUMPSIZE,
1206             8, 1, &dumpsize) != 0 || dumpsize != zv->zv_volsize) {
1207                 boolean_t resize = (dumpsize > 0) ? B_TRUE : B_FALSE;
1208
1209                 if ((error = zvol_dump_init(zv, resize)) != 0) {
1210                         (void) zvol_dump_fini(zv);
1211                         return (error);
1212                 }
1213         }
1214
1215         /*
1216          * Build up our lba mapping.
1217          */
1218         error = zvol_get_lbas(zv);
1219         if (error) {
1220                 (void) zvol_dump_fini(zv);
1221                 return (error);
1222         }
1223
1224         tx = dmu_tx_create(os);
1225         dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL);
1226         error = dmu_tx_assign(tx, TXG_WAIT);
1227         if (error) {
1228                 dmu_tx_abort(tx);
1229                 (void) zvol_dump_fini(zv);
1230                 return (error);
1231         }
1232
1233         zv->zv_flags |= ZVOL_DUMPIFIED;
1234         error = zap_update(os, ZVOL_ZAP_OBJ, ZVOL_DUMPSIZE, 8, 1,
1235             &zv->zv_volsize, tx);
1236         dmu_tx_commit(tx);
1237
1238         if (error) {
1239                 (void) zvol_dump_fini(zv);
1240                 return (error);
1241         }
1242
1243         txg_wait_synced(dmu_objset_pool(os), 0);
1244         return (0);
1245 }
1246
1247 static int
1248 zvol_dump_fini(zvol_state_t *zv)
1249 {
1250         dmu_tx_t *tx;
1251         objset_t *os = zv->zv_objset;
1252         nvlist_t *nv;
1253         int error = 0;
1254         uint64_t checksum, compress, refresrv, vbs;
1255
1256         /*
1257          * Attempt to restore the zvol back to its pre-dumpified state.
1258          * This is a best-effort attempt as it's possible that not all
1259          * of these properties were initialized during the dumpify process
1260          * (i.e. error during zvol_dump_init).
1261          */
1262
1263         tx = dmu_tx_create(os);
1264         dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL);
1265         error = dmu_tx_assign(tx, TXG_WAIT);
1266         if (error) {
1267                 dmu_tx_abort(tx);
1268                 return (error);
1269         }
1270         (void) zap_remove(os, ZVOL_ZAP_OBJ, ZVOL_DUMPSIZE, tx);
1271         dmu_tx_commit(tx);
1272
1273         (void) zap_lookup(zv->zv_objset, ZVOL_ZAP_OBJ,
1274             zfs_prop_to_name(ZFS_PROP_CHECKSUM), 8, 1, &checksum);
1275         (void) zap_lookup(zv->zv_objset, ZVOL_ZAP_OBJ,
1276             zfs_prop_to_name(ZFS_PROP_COMPRESSION), 8, 1, &compress);
1277         (void) zap_lookup(zv->zv_objset, ZVOL_ZAP_OBJ,
1278             zfs_prop_to_name(ZFS_PROP_REFRESERVATION), 8, 1, &refresrv);
1279         (void) zap_lookup(zv->zv_objset, ZVOL_ZAP_OBJ,
1280             zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 8, 1, &vbs);
1281
1282         VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1283         (void) nvlist_add_uint64(nv,
1284             zfs_prop_to_name(ZFS_PROP_CHECKSUM), checksum);
1285         (void) nvlist_add_uint64(nv,
1286             zfs_prop_to_name(ZFS_PROP_COMPRESSION), compress);
1287         (void) nvlist_add_uint64(nv,
1288             zfs_prop_to_name(ZFS_PROP_REFRESERVATION), refresrv);
1289         (void) nvlist_add_uint64(nv,
1290             zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), vbs);
1291         (void) zfs_set_prop_nvlist(zv->zv_name, nv);
1292         nvlist_free(nv);
1293
1294         zvol_free_extents(zv);
1295         zv->zv_flags &= ~ZVOL_DUMPIFIED;
1296         (void) dmu_free_long_range(os, ZVOL_OBJ, 0, DMU_OBJECT_END);
1297
1298         return (0);
1299 }