1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61#include <sys/param.h>
62#include <sys/kernel.h>
63#include <sys/systm.h>
64#include <sys/malloc.h>
65#include <sys/file_internal.h>
66#include <sys/proc_internal.h>
67#include <sys/vnode_internal.h>
68#include <sys/mount_internal.h>
69#include <sys/quota.h>
70#include <sys/uio_internal.h>
71
72
73
74lck_grp_t * qf_lck_grp;
75lck_grp_attr_t * qf_lck_grp_attr;
76lck_attr_t * qf_lck_attr;
77
78
79lck_grp_t * quota_list_lck_grp;
80lck_grp_attr_t * quota_list_lck_grp_attr;
81lck_attr_t * quota_list_lck_attr;
82lck_mtx_t * quota_list_mtx_lock;
83
84
85static void dq_list_lock(void);
86static void dq_list_unlock(void);
87
88static void dq_lock_internal(struct dquot *dq);
89static void dq_unlock_internal(struct dquot *dq);
90
91static u_int32_t quotamagic[MAXQUOTAS] = INITQMAGICS;
92
93
94
95
96
97#define DQHASH(dqvp, id) \
98 (&dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash])
99LIST_HEAD(dqhash, dquot) *dqhashtbl;
100u_long dqhash;
101
102#define DQUOTINC 5
103long numdquot, desireddquot = DQUOTINC;
104
105
106
107
108TAILQ_HEAD(dqfreelist, dquot) dqfreelist;
109
110
111
112TAILQ_HEAD(dqdirtylist, dquot) dqdirtylist;
113
114
115static int dqlookup(struct quotafile *, u_long, struct dqblk *, u_int32_t *);
116static int dqsync_locked(struct dquot *dq);
117
118static void qf_lock(struct quotafile *);
119static void qf_unlock(struct quotafile *);
120static int qf_ref(struct quotafile *);
121static void qf_rele(struct quotafile *);
122
123
124
125
126
127void
128dqinit()
129{
130
131 dqhashtbl = hashinit(desiredvnodes, M_DQUOT, &dqhash);
132 TAILQ_INIT(&dqfreelist);
133 TAILQ_INIT(&dqdirtylist);
134
135
136
137
138 quota_list_lck_grp_attr= lck_grp_attr_alloc_init();
139 lck_grp_attr_setstat(quota_list_lck_grp_attr);
140 quota_list_lck_grp = lck_grp_alloc_init("quota list", quota_list_lck_grp_attr);
141
142
143
144
145 quota_list_lck_attr = lck_attr_alloc_init();
146
147
148
149
150
151 quota_list_mtx_lock = lck_mtx_alloc_init(quota_list_lck_grp, quota_list_lck_attr);
152
153
154
155
156
157 qf_lck_grp_attr= lck_grp_attr_alloc_init();
158 lck_grp_attr_setstat(qf_lck_grp_attr);
159 qf_lck_grp = lck_grp_alloc_init("quota file", qf_lck_grp_attr);
160
161
162
163
164 qf_lck_attr = lck_attr_alloc_init();
165
166}
167
168
169
170void
171dq_list_lock(void)
172{
173 lck_mtx_lock(quota_list_mtx_lock);
174}
175
176void
177dq_list_unlock(void)
178{
179 lck_mtx_unlock(quota_list_mtx_lock);
180}
181
182
183
184
185
186void
187dq_lock_internal(struct dquot *dq)
188{
189 while (dq->dq_lflags & DQ_LLOCK) {
190 dq->dq_lflags |= DQ_LWANT;
191 msleep(&dq->dq_lflags, quota_list_mtx_lock, PVFS, "dq_lock_internal", 0);
192 }
193 dq->dq_lflags |= DQ_LLOCK;
194}
195
196
197
198
199void
200dq_unlock_internal(struct dquot *dq)
201{
202 int wanted = dq->dq_lflags & DQ_LWANT;
203
204 dq->dq_lflags &= ~(DQ_LLOCK | DQ_LWANT);
205
206 if (wanted)
207 wakeup(&dq->dq_lflags);
208}
209
210void
211dqlock(struct dquot *dq) {
212
213 lck_mtx_lock(quota_list_mtx_lock);
214
215 dq_lock_internal(dq);
216
217 lck_mtx_unlock(quota_list_mtx_lock);
218}
219
220void
221dqunlock(struct dquot *dq) {
222
223 lck_mtx_lock(quota_list_mtx_lock);
224
225 dq_unlock_internal(dq);
226
227 lck_mtx_unlock(quota_list_mtx_lock);
228}
229
230
231
232int
233qf_get(struct quotafile *qfp, int type)
234{
235 int error = 0;
236
237 dq_list_lock();
238
239 switch (type) {
240
241 case QTF_OPENING:
242 while ( (qfp->qf_qflags & (QTF_OPENING | QTF_CLOSING)) ) {
243 if ( (qfp->qf_qflags & QTF_OPENING) ) {
244 error = EBUSY;
245 break;
246 }
247 if ( (qfp->qf_qflags & QTF_CLOSING) ) {
248 qfp->qf_qflags |= QTF_WANTED;
249 msleep(&qfp->qf_qflags, quota_list_mtx_lock, PVFS, "qf_get", 0);
250 }
251 }
252 if (qfp->qf_vp != NULLVP)
253 error = EBUSY;
254 if (error == 0)
255 qfp->qf_qflags |= QTF_OPENING;
256 break;
257
258 case QTF_CLOSING:
259 if ( (qfp->qf_qflags & QTF_CLOSING) ) {
260 error = EBUSY;
261 break;
262 }
263 qfp->qf_qflags |= QTF_CLOSING;
264
265 while ( (qfp->qf_qflags & QTF_OPENING) || qfp->qf_refcnt ) {
266 qfp->qf_qflags |= QTF_WANTED;
267 msleep(&qfp->qf_qflags, quota_list_mtx_lock, PVFS, "qf_get", 0);
268 }
269 if (qfp->qf_vp == NULLVP) {
270 qfp->qf_qflags &= ~QTF_CLOSING;
271 error = EBUSY;
272 }
273 break;
274 }
275 dq_list_unlock();
276
277 return (error);
278}
279
280void
281qf_put(struct quotafile *qfp, int type)
282{
283
284 dq_list_lock();
285
286 switch (type) {
287
288 case QTF_OPENING:
289 case QTF_CLOSING:
290 qfp->qf_qflags &= ~type;
291 break;
292 }
293 if ( (qfp->qf_qflags & QTF_WANTED) ) {
294 qfp->qf_qflags &= ~QTF_WANTED;
295 wakeup(&qfp->qf_qflags);
296 }
297 dq_list_unlock();
298}
299
300
301static void
302qf_lock(struct quotafile *qfp)
303{
304 lck_mtx_lock(&qfp->qf_lock);
305}
306
307static void
308qf_unlock(struct quotafile *qfp)
309{
310 lck_mtx_unlock(&qfp->qf_lock);
311}
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328static int
329qf_ref(struct quotafile *qfp)
330{
331 int error = 0;
332
333 if ( (qfp->qf_qflags & (QTF_OPENING | QTF_CLOSING)) || (qfp->qf_vp == NULLVP) )
334 error = EINVAL;
335 else
336 qfp->qf_refcnt++;
337
338 return (error);
339}
340
341
342
343
344
345
346
347static void
348qf_rele(struct quotafile *qfp)
349{
350 qfp->qf_refcnt--;
351
352 if ( (qfp->qf_qflags & QTF_WANTED) && qfp->qf_refcnt == 0) {
353 qfp->qf_qflags &= ~QTF_WANTED;
354 wakeup(&qfp->qf_qflags);
355 }
356}
357
358
359void
360dqfileinit(struct quotafile *qfp)
361{
362 qfp->qf_vp = NULLVP;
363 qfp->qf_qflags = 0;
364
365 lck_mtx_init(&qfp->qf_lock, qf_lck_grp, qf_lck_attr);
366}
367
368
369
370
371
372
373
374int
375dqfileopen(qfp, type)
376 struct quotafile *qfp;
377 int type;
378{
379 struct dqfilehdr header;
380 struct vfs_context context;
381 off_t file_size;
382 uio_t auio;
383 int error = 0;
384 char uio_buf[ UIO_SIZEOF(1) ];
385
386 context.vc_proc = current_proc();
387 context.vc_ucred = qfp->qf_cred;
388
389
390 if ((error = vnode_size(qfp->qf_vp, &file_size, &context)) != 0)
391 goto out;
392
393
394 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
395 &uio_buf[0], sizeof(uio_buf));
396 uio_addiov(auio, CAST_USER_ADDR_T(&header), sizeof (header));
397 error = VNOP_READ(qfp->qf_vp, auio, 0, &context);
398 if (error)
399 goto out;
400 else if (uio_resid(auio)) {
401 error = EINVAL;
402 goto out;
403 }
404
405 if ((header.dqh_magic != quotamagic[type]) ||
406 (header.dqh_version > QF_VERSION) ||
407 (!powerof2(header.dqh_maxentries)) ||
408 (header.dqh_maxentries > (file_size / sizeof(struct dqblk)))) {
409 error = EINVAL;
410 goto out;
411 }
412
413 if (header.dqh_btime > 0)
414 qfp->qf_btime = header.dqh_btime;
415 else
416 qfp->qf_btime = MAX_DQ_TIME;
417 if (header.dqh_itime > 0)
418 qfp->qf_itime = header.dqh_itime;
419 else
420 qfp->qf_itime = MAX_IQ_TIME;
421
422
423 qfp->qf_maxentries = header.dqh_maxentries;
424 qfp->qf_entrycnt = header.dqh_entrycnt;
425 qfp->qf_shift = dqhashshift(header.dqh_maxentries);
426out:
427 return (error);
428}
429
430
431
432
433void
434dqfileclose(struct quotafile *qfp, __unused int type)
435{
436 struct dqfilehdr header;
437 struct vfs_context context;
438 uio_t auio;
439 char uio_buf[ UIO_SIZEOF(1) ];
440
441 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
442 &uio_buf[0], sizeof(uio_buf));
443 uio_addiov(auio, CAST_USER_ADDR_T(&header), sizeof (header));
444
445 context.vc_proc = current_proc();
446 context.vc_ucred = qfp->qf_cred;
447
448 if (VNOP_READ(qfp->qf_vp, auio, 0, &context) == 0) {
449 header.dqh_entrycnt = qfp->qf_entrycnt;
450 uio_reset(auio, 0, UIO_SYSSPACE, UIO_WRITE);
451 uio_addiov(auio, CAST_USER_ADDR_T(&header), sizeof (header));
452 (void) VNOP_WRITE(qfp->qf_vp, auio, 0, &context);
453 }
454}
455
456
457
458
459
460
461int
462dqget(id, qfp, type, dqp)
463 u_long id;
464 struct quotafile *qfp;
465 register int type;
466 struct dquot **dqp;
467{
468 struct dquot *dq;
469 struct dquot *ndq = NULL;
470 struct dquot *fdq = NULL;
471 struct dqhash *dqh;
472 struct vnode *dqvp;
473 int error = 0;
474
475 if ( id == 0 || qfp->qf_vp == NULLVP ) {
476 *dqp = NODQUOT;
477 return (EINVAL);
478 }
479 dq_list_lock();
480
481 if ( (qf_ref(qfp)) ) {
482 dq_list_unlock();
483
484 *dqp = NODQUOT;
485 return (EINVAL);
486 }
487 if ( (dqvp = qfp->qf_vp) == NULLVP ) {
488 qf_rele(qfp);
489 dq_list_unlock();
490
491 *dqp = NODQUOT;
492 return (EINVAL);
493 }
494 dqh = DQHASH(dqvp, id);
495
496relookup:
497
498
499
500 for (dq = dqh->lh_first; dq; dq = dq->dq_hash.le_next) {
501 if (dq->dq_id != id ||
502 dq->dq_qfile->qf_vp != dqvp)
503 continue;
504
505 dq_lock_internal(dq);
506
507
508
509
510 if (dq->dq_id != id || dq->dq_qfile == NULL ||
511 dq->dq_qfile->qf_vp != dqvp) {
512 dq_unlock_internal(dq);
513 goto relookup;
514 }
515
516
517
518
519 if (dq->dq_cnt++ == 0) {
520 if (dq->dq_flags & DQ_MOD)
521 TAILQ_REMOVE(&dqdirtylist, dq, dq_freelist);
522 else
523 TAILQ_REMOVE(&dqfreelist, dq, dq_freelist);
524 }
525 dq_unlock_internal(dq);
526
527 if (fdq != NULL) {
528
529
530
531
532
533
534 TAILQ_INSERT_HEAD(&dqfreelist, fdq, dq_freelist);
535 }
536 qf_rele(qfp);
537 dq_list_unlock();
538
539 if (ndq != NULL) {
540
541
542
543
544
545 _FREE(ndq, M_DQUOT);
546 }
547 *dqp = dq;
548
549 return (0);
550 }
551
552
553
554 if (TAILQ_EMPTY(&dqfreelist) &&
555 numdquot < MAXQUOTAS * desiredvnodes)
556 desireddquot += DQUOTINC;
557
558 if (fdq != NULL) {
559
560
561
562
563
564 dq = fdq;
565 fdq = NULL;
566 } else if (numdquot < desireddquot) {
567 if (ndq == NULL) {
568
569
570
571 dq_list_unlock();
572
573 ndq = (struct dquot *)_MALLOC(sizeof *dq, M_DQUOT, M_WAITOK);
574 bzero((char *)ndq, sizeof *dq);
575
576 dq_list_lock();
577
578
579
580
581
582 goto relookup;
583 } else {
584
585
586
587
588
589 dq = ndq;
590 ndq = NULL;
591 numdquot++;
592 }
593 } else {
594 if (TAILQ_EMPTY(&dqfreelist)) {
595 qf_rele(qfp);
596 dq_list_unlock();
597
598 if (ndq) {
599
600
601
602
603
604 _FREE(ndq, M_DQUOT);
605 }
606 tablefull("dquot");
607 *dqp = NODQUOT;
608 return (EUSERS);
609 }
610 dq = TAILQ_FIRST(&dqfreelist);
611
612 dq_lock_internal(dq);
613
614 if (dq->dq_cnt || (dq->dq_flags & DQ_MOD)) {
615
616
617
618
619
620
621 dq_unlock_internal(dq);
622
623
624
625
626
627
628 goto relookup;
629 }
630 TAILQ_REMOVE(&dqfreelist, dq, dq_freelist);
631
632 if (dq->dq_qfile != NULL) {
633 LIST_REMOVE(dq, dq_hash);
634 dq->dq_qfile = NULL;
635 dq->dq_id = 0;
636 }
637 dq_unlock_internal(dq);
638
639
640
641
642
643
644
645
646 fdq = dq;
647 goto relookup;
648 }
649
650
651
652
653
654
655
656 dq_lock_internal(dq);
657
658
659
660
661 dq->dq_cnt = 1;
662 dq->dq_flags = 0;
663 dq->dq_id = id;
664 dq->dq_qfile = qfp;
665 dq->dq_type = type;
666
667
668
669
670
671
672
673
674 LIST_INSERT_HEAD(dqh, dq, dq_hash);
675 dq_list_unlock();
676
677 if (ndq) {
678
679
680
681
682
683 _FREE(ndq, M_DQUOT);
684 }
685
686 error = dqlookup(qfp, id, &dq->dq_dqb, &dq->dq_index);
687
688
689
690
691
692 if (error) {
693 dq_list_lock();
694
695 dq->dq_id = 0;
696 dq->dq_qfile = NULL;
697 LIST_REMOVE(dq, dq_hash);
698
699 dq_unlock_internal(dq);
700 qf_rele(qfp);
701 dq_list_unlock();
702
703 dqrele(dq);
704
705 *dqp = NODQUOT;
706 return (error);
707 }
708
709
710
711
712 if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
713 dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
714 dq->dq_flags |= DQ_FAKE;
715 if (dq->dq_id != 0) {
716 struct timeval tv;
717
718 microtime(&tv);
719 if (dq->dq_btime == 0)
720 dq->dq_btime = tv.tv_sec + qfp->qf_btime;
721 if (dq->dq_itime == 0)
722 dq->dq_itime = tv.tv_sec + qfp->qf_itime;
723 }
724 dq_list_lock();
725 dq_unlock_internal(dq);
726 qf_rele(qfp);
727 dq_list_unlock();
728
729 *dqp = dq;
730 return (0);
731}
732
733
734
735
736
737
738static int
739dqlookup(qfp, id, dqb, index)
740 struct quotafile *qfp;
741 u_long id;
742 struct dqblk *dqb;
743 u_int32_t *index;
744{
745 struct vnode *dqvp;
746 struct vfs_context context;
747 uio_t auio;
748 int i, skip, last;
749 u_long mask;
750 int error = 0;
751 char uio_buf[ UIO_SIZEOF(1) ];
752
753
754 qf_lock(qfp);
755
756 dqvp = qfp->qf_vp;
757
758 context.vc_proc = current_proc();
759 context.vc_ucred = qfp->qf_cred;
760
761 mask = qfp->qf_maxentries - 1;
762 i = dqhash1(id, qfp->qf_shift, mask);
763 skip = dqhash2(id, mask);
764
765 for (last = (i + (qfp->qf_maxentries-1) * skip) & mask;
766 i != last;
767 i = (i + skip) & mask) {
768 auio = uio_createwithbuffer(1, dqoffset(i), UIO_SYSSPACE, UIO_READ,
769 &uio_buf[0], sizeof(uio_buf));
770 uio_addiov(auio, CAST_USER_ADDR_T(dqb), sizeof (struct dqblk));
771 error = VNOP_READ(dqvp, auio, 0, &context);
772 if (error) {
773 printf("dqlookup: error %d looking up id %d at index %d\n", error, id, i);
774 break;
775 } else if (uio_resid(auio)) {
776 error = EIO;
777 printf("dqlookup: error looking up id %d at index %d\n", id, i);
778 break;
779 }
780
781
782
783
784
785 if (dqb->dqb_id == 0) {
786 bzero(dqb, sizeof(struct dqblk));
787 dqb->dqb_id = id;
788
789
790
791 uio_reset(auio, dqoffset(i), UIO_SYSSPACE, UIO_WRITE);
792 uio_addiov(auio, CAST_USER_ADDR_T(dqb), sizeof (struct dqblk));
793 error = VNOP_WRITE(dqvp, auio, 0, &context);
794 if (uio_resid(auio) && error == 0)
795 error = EIO;
796 if (error == 0)
797 ++qfp->qf_entrycnt;
798 break;
799 }
800
801 if (dqb->dqb_id == id)
802 break;
803 }
804 qf_unlock(qfp);
805
806 *index = i;
807
808 return (error);
809}
810
811
812
813
814
815void
816dqrele(struct dquot *dq)
817{
818
819 if (dq == NODQUOT)
820 return;
821 dqlock(dq);
822
823 if (dq->dq_cnt > 1) {
824 dq->dq_cnt--;
825
826 dqunlock(dq);
827 return;
828 }
829 if (dq->dq_flags & DQ_MOD)
830 (void) dqsync_locked(dq);
831 dq->dq_cnt--;
832
833 dq_list_lock();
834 TAILQ_INSERT_TAIL(&dqfreelist, dq, dq_freelist);
835 dq_unlock_internal(dq);
836 dq_list_unlock();
837}
838
839
840
841
842void
843dqreclaim(register struct dquot *dq)
844{
845
846 if (dq == NODQUOT)
847 return;
848
849 dq_list_lock();
850 dq_lock_internal(dq);
851
852 if (--dq->dq_cnt > 0) {
853 dq_unlock_internal(dq);
854 dq_list_unlock();
855 return;
856 }
857 if (dq->dq_flags & DQ_MOD)
858 TAILQ_INSERT_TAIL(&dqdirtylist, dq, dq_freelist);
859 else
860 TAILQ_INSERT_TAIL(&dqfreelist, dq, dq_freelist);
861
862 dq_unlock_internal(dq);
863 dq_list_unlock();
864}
865
866
867
868
869void
870dqsync_orphans(qfp)
871 struct quotafile *qfp;
872{
873 struct dquot *dq;
874
875 dq_list_lock();
876 loop:
877 TAILQ_FOREACH(dq, &dqdirtylist, dq_freelist) {
878 if (dq->dq_qfile != qfp)
879 continue;
880
881 dq_lock_internal(dq);
882
883 if (dq->dq_qfile != qfp) {
884
885
886
887
888
889 dq_unlock_internal(dq);
890 goto loop;
891 }
892 if ((dq->dq_flags & DQ_MOD) == 0) {
893
894
895
896
897
898 dq_unlock_internal(dq);
899 goto loop;
900 }
901 if (dq->dq_cnt != 0)
902 panic("dqsync_orphans: dquot in use");
903
904 TAILQ_REMOVE(&dqdirtylist, dq, dq_freelist);
905
906 dq_list_unlock();
907
908
909
910
911
912
913 (void) dqsync_locked(dq);
914
915 dq_list_lock();
916
917 TAILQ_INSERT_TAIL(&dqfreelist, dq, dq_freelist);
918
919 dq_unlock_internal(dq);
920 goto loop;
921 }
922 dq_list_unlock();
923}
924
925int
926dqsync(struct dquot *dq)
927{
928 int error = 0;
929
930 if (dq != NODQUOT) {
931 dqlock(dq);
932
933 if ( (dq->dq_flags & DQ_MOD) )
934 error = dqsync_locked(dq);
935
936 dqunlock(dq);
937 }
938 return (error);
939}
940
941
942
943
944
945int
946dqsync_locked(struct dquot *dq)
947{
948 struct proc *p = current_proc();
949 struct vfs_context context;
950 struct vnode *dqvp;
951 uio_t auio;
952 int error;
953 char uio_buf[ UIO_SIZEOF(1) ];
954
955 if (dq->dq_id == 0) {
956 dq->dq_flags &= ~DQ_MOD;
957 return (0);
958 }
959 if (dq->dq_qfile == NULL)
960 panic("dqsync: NULL dq_qfile");
961 if ((dqvp = dq->dq_qfile->qf_vp) == NULLVP)
962 panic("dqsync: NULL qf_vp");
963
964 auio = uio_createwithbuffer(1, dqoffset(dq->dq_index), UIO_SYSSPACE,
965 UIO_WRITE, &uio_buf[0], sizeof(uio_buf));
966 uio_addiov(auio, CAST_USER_ADDR_T(&dq->dq_dqb), sizeof (struct dqblk));
967
968 context.vc_proc = p;
969 context.vc_ucred = dq->dq_qfile->qf_cred;
970
971 error = VNOP_WRITE(dqvp, auio, 0, &context);
972 if (uio_resid(auio) && error == 0)
973 error = EIO;
974 dq->dq_flags &= ~DQ_MOD;
975
976 return (error);
977}
978
979
980
981
982void
983dqflush(vp)
984 register struct vnode *vp;
985{
986 register struct dquot *dq, *nextdq;
987 struct dqhash *dqh;
988
989
990
991
992
993
994 dq_list_lock();
995
996 for (dqh = &dqhashtbl[dqhash]; dqh >= dqhashtbl; dqh--) {
997 for (dq = dqh->lh_first; dq; dq = nextdq) {
998 nextdq = dq->dq_hash.le_next;
999 if (dq->dq_qfile->qf_vp != vp)
1000 continue;
1001 if (dq->dq_cnt)
1002 panic("dqflush: stray dquot");
1003 LIST_REMOVE(dq, dq_hash);
1004 dq->dq_qfile = NULL;
1005 }
1006 }
1007 dq_list_unlock();
1008}
1009
1010
1011
1012
1013
1014
1015__private_extern__ void
1016munge_dqblk(struct dqblk *dqblkp, struct user_dqblk *user_dqblkp, boolean_t to64)
1017{
1018 if (to64) {
1019
1020 bcopy((caddr_t)dqblkp, (caddr_t)user_dqblkp, offsetof(struct dqblk, dqb_btime));
1021 user_dqblkp->dqb_id = dqblkp->dqb_id;
1022 user_dqblkp->dqb_itime = dqblkp->dqb_itime;
1023 user_dqblkp->dqb_btime = dqblkp->dqb_btime;
1024 }
1025 else {
1026
1027 bcopy((caddr_t)user_dqblkp, (caddr_t)dqblkp, offsetof(struct dqblk, dqb_btime));
1028 dqblkp->dqb_id = user_dqblkp->dqb_id;
1029 dqblkp->dqb_itime = user_dqblkp->dqb_itime;
1030 dqblkp->dqb_btime = user_dqblkp->dqb_btime;
1031 }
1032}
1033