|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /* $NetBSD: lfs_syscalls.c,v 1.8 1995/03/21 13:34:08 mycroft Exp $ */
23:
24: /*-
25: * Copyright (c) 1991, 1993, 1994
26: * The Regents of the University of California. All rights reserved.
27: *
28: * Redistribution and use in source and binary forms, with or without
29: * modification, are permitted provided that the following conditions
30: * are met:
31: * 1. Redistributions of source code must retain the above copyright
32: * notice, this list of conditions and the following disclaimer.
33: * 2. Redistributions in binary form must reproduce the above copyright
34: * notice, this list of conditions and the following disclaimer in the
35: * documentation and/or other materials provided with the distribution.
36: * 3. All advertising materials mentioning features or use of this software
37: * must display the following acknowledgement:
38: * This product includes software developed by the University of
39: * California, Berkeley and its contributors.
40: * 4. Neither the name of the University nor the names of its contributors
41: * may be used to endorse or promote products derived from this software
42: * without specific prior written permission.
43: *
44: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54: * SUCH DAMAGE.
55: *
56: * @(#)lfs_syscalls.c 8.6 (Berkeley) 6/16/94
57: */
58:
59: #include <sys/param.h>
60: #include <sys/systm.h>
61: #include <sys/proc.h>
62: #include <sys/buf.h>
63: #include <sys/mount.h>
64: #include <sys/vnode.h>
65: #include <sys/malloc.h>
66: #include <sys/kernel.h>
67:
68: #include <sys/syscallargs.h>
69:
70: #include <ufs/ufs/quota.h>
71: #include <ufs/ufs/inode.h>
72: #include <ufs/ufs/ufsmount.h>
73: #include <ufs/ufs/ufs_extern.h>
74:
75: #include <ufs/lfs/lfs.h>
76: #include <ufs/lfs/lfs_extern.h>
77: #define BUMP_FIP(SP) \
78: (SP)->fip = (FINFO *) (&(SP)->fip->fi_blocks[(SP)->fip->fi_nblocks])
79:
80: #define INC_FINFO(SP) ++((SEGSUM *)((SP)->segsum))->ss_nfinfo
81: #define DEC_FINFO(SP) --((SEGSUM *)((SP)->segsum))->ss_nfinfo
82:
83: /*
84: * Before committing to add something to a segment summary, make sure there
85: * is enough room. S is the bytes added to the summary.
86: */
87: #define CHECK_SEG(s) \
88: if (sp->sum_bytes_left < (s)) { \
89: (void) lfs_writeseg(fs, sp); \
90: }
91: struct buf *lfs_fakebuf __P((struct vnode *, int, size_t, caddr_t));
92:
93: /*
94: * lfs_markv:
95: *
96: * This will mark inodes and blocks dirty, so they are written into the log.
97: * It will block until all the blocks have been written. The segment create
98: * time passed in the block_info and inode_info structures is used to decide
99: * if the data is valid for each block (in case some process dirtied a block
100: * or inode that is being cleaned between the determination that a block is
101: * live and the lfs_markv call).
102: *
103: * 0 on success
104: * -1/errno is return on error.
105: */
106: int
107: lfs_markv(p, uap, retval)
108: struct proc *p;
109: struct lfs_markv_args /* {
110: syscallarg(fsid_t *) fsidp;
111: syscallarg(struct block_info *) blkiov;
112: syscallarg(int) blkcnt;
113: } */ *uap;
114: register_t *retval;
115: {
116: struct segment *sp;
117: BLOCK_INFO *blkp;
118: IFILE *ifp;
119: struct buf *bp, **bpp;
120: struct inode *ip;
121: struct lfs *fs;
122: struct mount *mntp;
123: struct vnode *vp;
124: fsid_t fsid;
125: void *start;
126: ino_t lastino;
127: daddr_t b_daddr, v_daddr;
128: u_long bsize;
129: int cnt, error;
130:
131: if (error = suser(p->p_ucred, &p->p_acflag))
132: return (error);
133:
134: if (error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t)))
135: return (error);
136: if ((mntp = getvfs(&fsid)) == NULL)
137: return (EINVAL);
138:
139: cnt = SCARG(uap, blkcnt);
140: // start = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK);
141: MALLOC(start, void *, cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK);
142: if (error = copyin(SCARG(uap, blkiov), start, cnt * sizeof(BLOCK_INFO)))
143: goto err1;
144:
145: /* Mark blocks/inodes dirty. */
146: fs = VFSTOUFS(mntp)->um_lfs;
147: bsize = fs->lfs_bsize;
148: error = 0;
149:
150: lfs_seglock(fs, SEGM_SYNC | SEGM_CLEAN);
151: sp = fs->lfs_sp;
152: for (v_daddr = LFS_UNUSED_DADDR, lastino = LFS_UNUSED_INUM,
153: blkp = start; cnt--; ++blkp) {
154: /*
155: * Get the IFILE entry (only once) and see if the file still
156: * exists.
157: */
158: if (lastino != blkp->bi_inode) {
159: if (lastino != LFS_UNUSED_INUM) {
160: /* Finish up last file */
161: if (sp->fip->fi_nblocks == 0) {
162: DEC_FINFO(sp);
163: sp->sum_bytes_left +=
164: sizeof(FINFO) - sizeof(daddr_t);
165: } else {
166: lfs_updatemeta(sp);
167: BUMP_FIP(sp);
168: }
169:
170: lfs_writeinode(fs, sp, ip);
171: lfs_vunref(vp);
172: }
173:
174: /* Start a new file */
175: CHECK_SEG(sizeof(FINFO));
176: sp->sum_bytes_left -= sizeof(FINFO) - sizeof(daddr_t);
177: INC_FINFO(sp);
178: sp->start_lbp = &sp->fip->fi_blocks[0];
179: sp->vp = NULL;
180: sp->fip->fi_version = blkp->bi_version;
181: sp->fip->fi_nblocks = 0;
182: sp->fip->fi_ino = blkp->bi_inode;
183: lastino = blkp->bi_inode;
184: if (blkp->bi_inode == LFS_IFILE_INUM)
185: v_daddr = fs->lfs_idaddr;
186: else {
187: LFS_IENTRY(ifp, fs, blkp->bi_inode, bp);
188: v_daddr = ifp->if_daddr;
189: brelse(bp);
190: }
191: if (v_daddr == LFS_UNUSED_DADDR)
192: continue;
193:
194: /* Get the vnode/inode. */
195: if (lfs_fastvget(mntp, blkp->bi_inode, v_daddr, &vp,
196: blkp->bi_lbn == LFS_UNUSED_LBN ?
197: blkp->bi_bp : NULL)) {
198: #if DIAGNOSTIC
199: printf("lfs_markv: VFS_VGET failed (%d)\n",
200: blkp->bi_inode);
201: #endif
202: lastino = LFS_UNUSED_INUM;
203: v_daddr = LFS_UNUSED_DADDR;
204: continue;
205: }
206: sp->vp = vp;
207: ip = VTOI(vp);
208: } else if (v_daddr == LFS_UNUSED_DADDR)
209: continue;
210:
211: /* If this BLOCK_INFO didn't contain a block, keep going. */
212: if (blkp->bi_lbn == LFS_UNUSED_LBN)
213: continue;
214: if (VOP_BMAP(vp, blkp->bi_lbn, NULL, &b_daddr, NULL) ||
215: b_daddr != blkp->bi_daddr)
216: continue;
217: /*
218: * If we got to here, then we are keeping the block. If it
219: * is an indirect block, we want to actually put it in the
220: * buffer cache so that it can be updated in the finish_meta
221: * section. If it's not, we need to allocate a fake buffer
222: * so that writeseg can perform the copyin and write the buffer.
223: */
224: if (blkp->bi_lbn >= 0) /* Data Block */
225: bp = lfs_fakebuf(vp, blkp->bi_lbn, bsize,
226: blkp->bi_bp);
227: else {
228: bp = getblk(vp, blkp->bi_lbn, bsize, 0, 0);
229: if (!(bp->b_flags & (B_DELWRI | B_DONE | B_CACHE)) &&
230: (error = copyin(blkp->bi_bp, bp->b_data,
231: bsize)))
232: goto err2;
233: if (error = VOP_BWRITE(bp))
234: goto err2;
235: }
236: while (lfs_gatherblock(sp, bp, NULL));
237: }
238: if (sp->vp) {
239: if (sp->fip->fi_nblocks == 0) {
240: DEC_FINFO(sp);
241: sp->sum_bytes_left +=
242: sizeof(FINFO) - sizeof(daddr_t);
243: } else
244: lfs_updatemeta(sp);
245:
246: lfs_writeinode(fs, sp, ip);
247: lfs_vunref(vp);
248: }
249: (void) lfs_writeseg(fs, sp);
250: lfs_segunlock(fs);
251: free(start, M_SEGMENT);
252: return (error);
253:
254: /*
255: * XXX
256: * If we come in to error 2, we might have indirect blocks that were
257: * updated and now have bad block pointers. I don't know what to do
258: * about this.
259: */
260:
261: err2: lfs_vunref(vp);
262: /* Free up fakebuffers */
263: for (bpp = --sp->cbpp; bpp >= sp->bpp; --bpp)
264: if ((*bpp)->b_flags & B_CALL) {
265: brelvp(*bpp);
266: free(*bpp, M_SEGMENT);
267: } else
268: brelse(*bpp);
269: lfs_segunlock(fs);
270: err1:
271: free(start, M_SEGMENT);
272: return (error);
273: }
274:
275: /*
276: * lfs_bmapv:
277: *
278: * This will fill in the current disk address for arrays of blocks.
279: *
280: * 0 on success
281: * -1/errno is return on error.
282: */
283: int
284: lfs_bmapv(p, uap, retval)
285: struct proc *p;
286: struct lfs_bmapv_args /* {
287: syscallarg(fsid_t *) fsidp;
288: syscallarg(struct block_info *) blkiov;
289: syscallarg(int) blkcnt;
290: } */ *uap;
291: register_t *retval;
292: {
293: BLOCK_INFO *blkp;
294: struct mount *mntp;
295: struct vnode *vp;
296: fsid_t fsid;
297: void *start;
298: daddr_t daddr;
299: int cnt, error, step;
300:
301: if (error = suser(p->p_ucred, &p->p_acflag))
302: return (error);
303:
304: if (error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t)))
305: return (error);
306: if ((mntp = getvfs(&fsid)) == NULL)
307: return (EINVAL);
308:
309: cnt = SCARG(uap, blkcnt);
310: // start = blkp = malloc(cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK);
311: MALLOC(blkp, BLOCK_INFO *, cnt * sizeof(BLOCK_INFO), M_SEGMENT, M_WAITOK);
312: start = blkp;
313: if (error = copyin(SCARG(uap, blkiov), blkp,
314: cnt * sizeof(BLOCK_INFO))) {
315: free(blkp, M_SEGMENT);
316: return (error);
317: }
318:
319: for (step = cnt; step--; ++blkp) {
320: if (blkp->bi_lbn == LFS_UNUSED_LBN)
321: continue;
322: /* Could be a deadlock ? */
323: if (VFS_VGET(mntp, blkp->bi_inode, &vp))
324: daddr = LFS_UNUSED_DADDR;
325: else {
326: if (VOP_BMAP(vp, blkp->bi_lbn, NULL, &daddr, NULL))
327: daddr = LFS_UNUSED_DADDR;
328: vput(vp);
329: }
330: blkp->bi_daddr = daddr;
331: }
332: copyout(start, SCARG(uap, blkiov), cnt * sizeof(BLOCK_INFO));
333: free(start, M_SEGMENT);
334: return (0);
335: }
336:
337: /*
338: * lfs_segclean:
339: *
340: * Mark the segment clean.
341: *
342: * 0 on success
343: * -1/errno is return on error.
344: */
345: int
346: lfs_segclean(p, uap, retval)
347: struct proc *p;
348: struct lfs_segclean_args /* {
349: syscallarg(fsid_t *) fsidp;
350: syscallarg(u_long) segment;
351: } */ *uap;
352: register_t *retval;
353: {
354: CLEANERINFO *cip;
355: SEGUSE *sup;
356: struct buf *bp;
357: struct mount *mntp;
358: struct lfs *fs;
359: fsid_t fsid;
360: int error;
361:
362: if (error = suser(p->p_ucred, &p->p_acflag))
363: return (error);
364:
365: if (error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t)))
366: return (error);
367: if ((mntp = getvfs(&fsid)) == NULL)
368: return (EINVAL);
369:
370: fs = VFSTOUFS(mntp)->um_lfs;
371:
372: if (datosn(fs, fs->lfs_curseg) == SCARG(uap, segment))
373: return (EBUSY);
374:
375: LFS_SEGENTRY(sup, fs, SCARG(uap, segment), bp);
376: if (sup->su_flags & SEGUSE_ACTIVE) {
377: brelse(bp);
378: return (EBUSY);
379: }
380: fs->lfs_avail += fsbtodb(fs, fs->lfs_ssize) - 1;
381: fs->lfs_bfree += (sup->su_nsums * LFS_SUMMARY_SIZE / DEV_BSIZE) +
382: sup->su_ninos * btodb(fs->lfs_bsize);
383: sup->su_flags &= ~SEGUSE_DIRTY;
384: (void) VOP_BWRITE(bp);
385:
386: LFS_CLEANERINFO(cip, fs, bp);
387: ++cip->clean;
388: --cip->dirty;
389: (void) VOP_BWRITE(bp);
390: wakeup(&fs->lfs_avail);
391: return (0);
392: }
393:
394: /*
395: * lfs_segwait:
396: *
397: * This will block until a segment in file system fsid is written. A timeout
398: * in milliseconds may be specified which will awake the cleaner automatically.
399: * An fsid of -1 means any file system, and a timeout of 0 means forever.
400: *
401: * 0 on success
402: * 1 on timeout
403: * -1/errno is return on error.
404: */
405: int
406: lfs_segwait(p, uap, retval)
407: struct proc *p;
408: struct lfs_segwait_args /* {
409: syscallarg(fsid_t *) fsidp;
410: syscallarg(struct timeval *) tv;
411: } */ *uap;
412: register_t *retval;
413: {
414: extern int lfs_allclean_wakeup;
415: struct mount *mntp;
416: struct timeval atv;
417: fsid_t fsid;
418: void *addr;
419: u_long timeout;
420: int error, s;
421:
422: if (error = suser(p->p_ucred, &p->p_acflag)) {
423: return (error);
424: }
425: #ifdef WHEN_QUADS_WORK
426: if (error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t)))
427: return (error);
428: if (fsid == (fsid_t)-1)
429: addr = &lfs_allclean_wakeup;
430: else {
431: if ((mntp = getvfs(&fsid)) == NULL)
432: return (EINVAL);
433: addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg;
434: }
435: #else
436: if (error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t)))
437: return (error);
438: if ((mntp = getvfs(&fsid)) == NULL)
439: addr = &lfs_allclean_wakeup;
440: else
441: addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg;
442: #endif
443:
444: if (SCARG(uap, tv)) {
445: if (error =
446: copyin(SCARG(uap, tv), &atv, sizeof(struct timeval)))
447: return (error);
448: if (itimerfix(&atv))
449: return (EINVAL);
450: s = splclock();
451: timeradd(&atv, &time, &atv);
452: timeout = hzto(&atv);
453: splx(s);
454: } else
455: timeout = 0;
456:
457: error = tsleep(addr, PCATCH | PUSER, "segment", timeout);
458: return (error == ERESTART ? EINTR : 0);
459: }
460:
461: /*
462: * VFS_VGET call specialized for the cleaner. The cleaner already knows the
463: * daddr from the ifile, so don't look it up again. If the cleaner is
464: * processing IINFO structures, it may have the ondisk inode already, so
465: * don't go retrieving it again.
466: */
467: int
468: lfs_fastvget(mp, ino, daddr, vpp, dinp)
469: struct mount *mp;
470: ino_t ino;
471: daddr_t daddr;
472: struct vnode **vpp;
473: struct dinode *dinp;
474: {
475: register struct inode *ip;
476: struct vnode *vp;
477: struct ufsmount *ump;
478: struct buf *bp;
479: dev_t dev;
480: int error;
481:
482: ump = VFSTOUFS(mp);
483: dev = ump->um_dev;
484: /*
485: * This is playing fast and loose. Someone may have the inode
486: * locked, in which case they are going to be distinctly unhappy
487: * if we trash something.
488: */
489: if ((*vpp = ufs_ihashlookup(dev, ino)) != NULL) {
490: lfs_vref(*vpp);
491: if ((*vpp)->v_flag & VXLOCK)
492: printf ("Cleaned vnode VXLOCKED\n");
493: ip = VTOI(*vpp);
494: if (ip->i_flag & IN_LOCKED)
495: printf("cleaned vnode locked\n");
496: if (!(ip->i_flag & IN_MODIFIED)) {
497: ++ump->um_lfs->lfs_uinodes;
498: ip->i_flag |= IN_MODIFIED;
499: }
500: ip->i_flag |= IN_MODIFIED;
501: return (0);
502: }
503:
504: /* Allocate new vnode/inode. */
505: if (error = lfs_vcreate(mp, ino, &vp)) {
506: *vpp = NULL;
507: return (error);
508: }
509:
510: /*
511: * Put it onto its hash chain and lock it so that other requests for
512: * this inode will block if they arrive while we are sleeping waiting
513: * for old data structures to be purged or for the contents of the
514: * disk portion of this inode to be read.
515: */
516: ip = VTOI(vp);
517: ufs_ihashins(ip);
518:
519: /*
520: * XXX
521: * This may not need to be here, logically it should go down with
522: * the i_devvp initialization.
523: * Ask Kirk.
524: */
525: ip->i_lfs = ump->um_lfs;
526:
527: /* Read in the disk contents for the inode, copy into the inode. */
528: if (dinp)
529: if (error = copyin(dinp, &ip->i_din, sizeof(struct dinode)))
530: return (error);
531: else {
532: if (error = bread(ump->um_devvp, daddr,
533: (int)ump->um_lfs->lfs_bsize, NOCRED, &bp)) {
534: /*
535: * The inode does not contain anything useful, so it
536: * would be misleading to leave it on its hash chain.
537: * Iput() will return it to the free list.
538: */
539: ufs_ihashrem(ip);
540:
541: /* Unlock and discard unneeded inode. */
542: lfs_vunref(vp);
543: brelse(bp);
544: *vpp = NULL;
545: return (error);
546: }
547: ip->i_din =
548: *lfs_ifind(ump->um_lfs, ino, (struct dinode *)bp->b_data);
549: brelse(bp);
550: }
551:
552: /* Inode was just read from user space or disk, make sure it's locked */
553: ip->i_flag |= IN_LOCKED;
554:
555: /*
556: * Initialize the vnode from the inode, check for aliases. In all
557: * cases re-init ip, the underlying vnode/inode may have changed.
558: */
559: if (error = ufs_vinit(mp, lfs_specop_p, LFS_FIFOOPS, &vp)) {
560: lfs_vunref(vp);
561: *vpp = NULL;
562: return (error);
563: }
564: /*
565: * Finish inode initialization now that aliasing has been resolved.
566: */
567: ip->i_devvp = ump->um_devvp;
568: ip->i_flag |= IN_MODIFIED;
569: ++ump->um_lfs->lfs_uinodes;
570: VREF(ip->i_devvp);
571: *vpp = vp;
572: return (0);
573: }
574: struct buf *
575: lfs_fakebuf(vp, lbn, size, uaddr)
576: struct vnode *vp;
577: int lbn;
578: size_t size;
579: caddr_t uaddr;
580: {
581: struct buf *bp;
582:
583: bp = lfs_newbuf(vp, lbn, 0);
584: bp->b_saveaddr = uaddr;
585: bp->b_bufsize = size;
586: bp->b_bcount = size;
587: bp->b_flags |= B_INVAL;
588: return (bp);
589: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.