13ad81ce0Smckusick /*
22b768bd7Sbostic * Copyright (c) 1982, 1986, 1989, 1993
32b768bd7Sbostic * The Regents of the University of California. All rights reserved.
43ad81ce0Smckusick *
58eb14236Sbostic * %sccs.include.redist.c%
6065083aeSmckusick *
7*f8846554Smckusick * @(#)ffs_vnops.c 8.15 (Berkeley) 05/14/95
83ad81ce0Smckusick */
9ff129ffdSmckusic
105b516ec6Sbostic #include <sys/param.h>
115b516ec6Sbostic #include <sys/systm.h>
125b516ec6Sbostic #include <sys/resourcevar.h>
135b516ec6Sbostic #include <sys/kernel.h>
145b516ec6Sbostic #include <sys/file.h>
155b516ec6Sbostic #include <sys/stat.h>
165b516ec6Sbostic #include <sys/buf.h>
175b516ec6Sbostic #include <sys/proc.h>
185b516ec6Sbostic #include <sys/conf.h>
195b516ec6Sbostic #include <sys/mount.h>
205b516ec6Sbostic #include <sys/vnode.h>
215b516ec6Sbostic #include <sys/malloc.h>
2226a59bf8Skarels
23a0fa47aeSmckusick #include <vm/vm.h>
24a0fa47aeSmckusick
25b489f476Smckusick #include <miscfs/specfs/specdev.h>
26b489f476Smckusick #include <miscfs/fifofs/fifo.h>
27b489f476Smckusick
285b516ec6Sbostic #include <ufs/ufs/lockf.h>
295b516ec6Sbostic #include <ufs/ufs/quota.h>
305b516ec6Sbostic #include <ufs/ufs/inode.h>
315b516ec6Sbostic #include <ufs/ufs/dir.h>
32e08bd631Smckusick #include <ufs/ufs/ufsmount.h>
335b516ec6Sbostic #include <ufs/ufs/ufs_extern.h>
344476fdfbSroot
355b516ec6Sbostic #include <ufs/ffs/fs.h>
365b516ec6Sbostic #include <ufs/ffs/ffs_extern.h>
37065083aeSmckusick
385b516ec6Sbostic /* Global vfs data structures for ufs. */
394c2ecc49Sheideman int (**ffs_vnodeop_p)();
404c2ecc49Sheideman struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
414c2ecc49Sheideman { &vop_default_desc, vn_default_error },
424c2ecc49Sheideman { &vop_lookup_desc, ufs_lookup }, /* lookup */
434c2ecc49Sheideman { &vop_create_desc, ufs_create }, /* create */
444ba124f7Spendry { &vop_whiteout_desc, ufs_whiteout }, /* whiteout */
454c2ecc49Sheideman { &vop_mknod_desc, ufs_mknod }, /* mknod */
464c2ecc49Sheideman { &vop_open_desc, ufs_open }, /* open */
474c2ecc49Sheideman { &vop_close_desc, ufs_close }, /* close */
484c2ecc49Sheideman { &vop_access_desc, ufs_access }, /* access */
494c2ecc49Sheideman { &vop_getattr_desc, ufs_getattr }, /* getattr */
504c2ecc49Sheideman { &vop_setattr_desc, ufs_setattr }, /* setattr */
514c2ecc49Sheideman { &vop_read_desc, ffs_read }, /* read */
524c2ecc49Sheideman { &vop_write_desc, ffs_write }, /* write */
53e2e07ecbSmckusick { &vop_lease_desc, ufs_lease_check }, /* lease */
544c2ecc49Sheideman { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */
554c2ecc49Sheideman { &vop_select_desc, ufs_select }, /* select */
5635e970ecSmckusick { &vop_revoke_desc, ufs_revoke }, /* revoke */
574c2ecc49Sheideman { &vop_mmap_desc, ufs_mmap }, /* mmap */
584c2ecc49Sheideman { &vop_fsync_desc, ffs_fsync }, /* fsync */
594c2ecc49Sheideman { &vop_seek_desc, ufs_seek }, /* seek */
604c2ecc49Sheideman { &vop_remove_desc, ufs_remove }, /* remove */
614c2ecc49Sheideman { &vop_link_desc, ufs_link }, /* link */
624c2ecc49Sheideman { &vop_rename_desc, ufs_rename }, /* rename */
634c2ecc49Sheideman { &vop_mkdir_desc, ufs_mkdir }, /* mkdir */
644c2ecc49Sheideman { &vop_rmdir_desc, ufs_rmdir }, /* rmdir */
654c2ecc49Sheideman { &vop_symlink_desc, ufs_symlink }, /* symlink */
664c2ecc49Sheideman { &vop_readdir_desc, ufs_readdir }, /* readdir */
674c2ecc49Sheideman { &vop_readlink_desc, ufs_readlink }, /* readlink */
684c2ecc49Sheideman { &vop_abortop_desc, ufs_abortop }, /* abortop */
690b614b73Smckusick { &vop_inactive_desc, ufs_inactive }, /* inactive */
70abf9880aSmckusick { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */
714c2ecc49Sheideman { &vop_lock_desc, ufs_lock }, /* lock */
724c2ecc49Sheideman { &vop_unlock_desc, ufs_unlock }, /* unlock */
73cd3cfc28Smargo { &vop_bmap_desc, ufs_bmap }, /* bmap */
744c2ecc49Sheideman { &vop_strategy_desc, ufs_strategy }, /* strategy */
754c2ecc49Sheideman { &vop_print_desc, ufs_print }, /* print */
764c2ecc49Sheideman { &vop_islocked_desc, ufs_islocked }, /* islocked */
77f38482b1Smckusick { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */
784c2ecc49Sheideman { &vop_advlock_desc, ufs_advlock }, /* advlock */
794c2ecc49Sheideman { &vop_blkatoff_desc, ffs_blkatoff }, /* blkatoff */
804c2ecc49Sheideman { &vop_valloc_desc, ffs_valloc }, /* valloc */
819ba9fa2aSmckusick { &vop_reallocblks_desc, ffs_reallocblks }, /* reallocblks */
824c2ecc49Sheideman { &vop_vfree_desc, ffs_vfree }, /* vfree */
834c2ecc49Sheideman { &vop_truncate_desc, ffs_truncate }, /* truncate */
844c2ecc49Sheideman { &vop_update_desc, ffs_update }, /* update */
853abd5335Sheideman { &vop_bwrite_desc, vn_bwrite },
864c2ecc49Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL }
875b516ec6Sbostic };
884c2ecc49Sheideman struct vnodeopv_desc ffs_vnodeop_opv_desc =
894c2ecc49Sheideman { &ffs_vnodeop_p, ffs_vnodeop_entries };
904476fdfbSroot
914c2ecc49Sheideman int (**ffs_specop_p)();
924c2ecc49Sheideman struct vnodeopv_entry_desc ffs_specop_entries[] = {
934c2ecc49Sheideman { &vop_default_desc, vn_default_error },
944c2ecc49Sheideman { &vop_lookup_desc, spec_lookup }, /* lookup */
954c2ecc49Sheideman { &vop_create_desc, spec_create }, /* create */
964c2ecc49Sheideman { &vop_mknod_desc, spec_mknod }, /* mknod */
974c2ecc49Sheideman { &vop_open_desc, spec_open }, /* open */
984c2ecc49Sheideman { &vop_close_desc, ufsspec_close }, /* close */
994c2ecc49Sheideman { &vop_access_desc, ufs_access }, /* access */
1004c2ecc49Sheideman { &vop_getattr_desc, ufs_getattr }, /* getattr */
1014c2ecc49Sheideman { &vop_setattr_desc, ufs_setattr }, /* setattr */
1024c2ecc49Sheideman { &vop_read_desc, ufsspec_read }, /* read */
1034c2ecc49Sheideman { &vop_write_desc, ufsspec_write }, /* write */
104e2e07ecbSmckusick { &vop_lease_desc, spec_lease_check }, /* lease */
1054c2ecc49Sheideman { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
1064c2ecc49Sheideman { &vop_select_desc, spec_select }, /* select */
10735e970ecSmckusick { &vop_revoke_desc, spec_revoke }, /* revoke */
1084c2ecc49Sheideman { &vop_mmap_desc, spec_mmap }, /* mmap */
1099899e5a2Smckusick { &vop_fsync_desc, ffs_fsync }, /* fsync */
1104c2ecc49Sheideman { &vop_seek_desc, spec_seek }, /* seek */
1114c2ecc49Sheideman { &vop_remove_desc, spec_remove }, /* remove */
1124c2ecc49Sheideman { &vop_link_desc, spec_link }, /* link */
1134c2ecc49Sheideman { &vop_rename_desc, spec_rename }, /* rename */
1144c2ecc49Sheideman { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
1154c2ecc49Sheideman { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
1164c2ecc49Sheideman { &vop_symlink_desc, spec_symlink }, /* symlink */
1174c2ecc49Sheideman { &vop_readdir_desc, spec_readdir }, /* readdir */
1184c2ecc49Sheideman { &vop_readlink_desc, spec_readlink }, /* readlink */
1194c2ecc49Sheideman { &vop_abortop_desc, spec_abortop }, /* abortop */
1200b614b73Smckusick { &vop_inactive_desc, ufs_inactive }, /* inactive */
121abf9880aSmckusick { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */
1224c2ecc49Sheideman { &vop_lock_desc, ufs_lock }, /* lock */
1234c2ecc49Sheideman { &vop_unlock_desc, ufs_unlock }, /* unlock */
1244c2ecc49Sheideman { &vop_bmap_desc, spec_bmap }, /* bmap */
1254c2ecc49Sheideman { &vop_strategy_desc, spec_strategy }, /* strategy */
1264c2ecc49Sheideman { &vop_print_desc, ufs_print }, /* print */
1274c2ecc49Sheideman { &vop_islocked_desc, ufs_islocked }, /* islocked */
128f38482b1Smckusick { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
1294c2ecc49Sheideman { &vop_advlock_desc, spec_advlock }, /* advlock */
1304c2ecc49Sheideman { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */
1314c2ecc49Sheideman { &vop_valloc_desc, spec_valloc }, /* valloc */
1329ba9fa2aSmckusick { &vop_reallocblks_desc, spec_reallocblks }, /* reallocblks */
1334fc932a0Smckusick { &vop_vfree_desc, ffs_vfree }, /* vfree */
1344c2ecc49Sheideman { &vop_truncate_desc, spec_truncate }, /* truncate */
1354c2ecc49Sheideman { &vop_update_desc, ffs_update }, /* update */
1363abd5335Sheideman { &vop_bwrite_desc, vn_bwrite },
1374c2ecc49Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL }
138103644d0Smckusick };
1394c2ecc49Sheideman struct vnodeopv_desc ffs_specop_opv_desc =
1404c2ecc49Sheideman { &ffs_specop_p, ffs_specop_entries };
141103644d0Smckusick
142103644d0Smckusick #ifdef FIFO
1434c2ecc49Sheideman int (**ffs_fifoop_p)();
1444c2ecc49Sheideman struct vnodeopv_entry_desc ffs_fifoop_entries[] = {
1454c2ecc49Sheideman { &vop_default_desc, vn_default_error },
1464c2ecc49Sheideman { &vop_lookup_desc, fifo_lookup }, /* lookup */
1474c2ecc49Sheideman { &vop_create_desc, fifo_create }, /* create */
1484c2ecc49Sheideman { &vop_mknod_desc, fifo_mknod }, /* mknod */
1494c2ecc49Sheideman { &vop_open_desc, fifo_open }, /* open */
1504c2ecc49Sheideman { &vop_close_desc, ufsfifo_close }, /* close */
1514c2ecc49Sheideman { &vop_access_desc, ufs_access }, /* access */
1524c2ecc49Sheideman { &vop_getattr_desc, ufs_getattr }, /* getattr */
1534c2ecc49Sheideman { &vop_setattr_desc, ufs_setattr }, /* setattr */
1544c2ecc49Sheideman { &vop_read_desc, ufsfifo_read }, /* read */
1554c2ecc49Sheideman { &vop_write_desc, ufsfifo_write }, /* write */
156e2e07ecbSmckusick { &vop_lease_desc, fifo_lease_check }, /* lease */
1574c2ecc49Sheideman { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
1584c2ecc49Sheideman { &vop_select_desc, fifo_select }, /* select */
15935e970ecSmckusick { &vop_revoke_desc, fifo_revoke }, /* revoke */
1604c2ecc49Sheideman { &vop_mmap_desc, fifo_mmap }, /* mmap */
1619899e5a2Smckusick { &vop_fsync_desc, ffs_fsync }, /* fsync */
1624c2ecc49Sheideman { &vop_seek_desc, fifo_seek }, /* seek */
1634c2ecc49Sheideman { &vop_remove_desc, fifo_remove }, /* remove */
1644c2ecc49Sheideman { &vop_link_desc, fifo_link }, /* link */
1654c2ecc49Sheideman { &vop_rename_desc, fifo_rename }, /* rename */
1664c2ecc49Sheideman { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
1674c2ecc49Sheideman { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
1684c2ecc49Sheideman { &vop_symlink_desc, fifo_symlink }, /* symlink */
1694c2ecc49Sheideman { &vop_readdir_desc, fifo_readdir }, /* readdir */
1704c2ecc49Sheideman { &vop_readlink_desc, fifo_readlink }, /* readlink */
1714c2ecc49Sheideman { &vop_abortop_desc, fifo_abortop }, /* abortop */
1720b614b73Smckusick { &vop_inactive_desc, ufs_inactive }, /* inactive */
173abf9880aSmckusick { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */
1744c2ecc49Sheideman { &vop_lock_desc, ufs_lock }, /* lock */
1754c2ecc49Sheideman { &vop_unlock_desc, ufs_unlock }, /* unlock */
1764c2ecc49Sheideman { &vop_bmap_desc, fifo_bmap }, /* bmap */
1774c2ecc49Sheideman { &vop_strategy_desc, fifo_strategy }, /* strategy */
1784c2ecc49Sheideman { &vop_print_desc, ufs_print }, /* print */
1794c2ecc49Sheideman { &vop_islocked_desc, ufs_islocked }, /* islocked */
180f38482b1Smckusick { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
1814c2ecc49Sheideman { &vop_advlock_desc, fifo_advlock }, /* advlock */
1824c2ecc49Sheideman { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */
1834c2ecc49Sheideman { &vop_valloc_desc, fifo_valloc }, /* valloc */
1849ba9fa2aSmckusick { &vop_reallocblks_desc, fifo_reallocblks }, /* reallocblks */
1854fc932a0Smckusick { &vop_vfree_desc, ffs_vfree }, /* vfree */
1864c2ecc49Sheideman { &vop_truncate_desc, fifo_truncate }, /* truncate */
1874c2ecc49Sheideman { &vop_update_desc, ffs_update }, /* update */
1883abd5335Sheideman { &vop_bwrite_desc, vn_bwrite },
1894c2ecc49Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL }
190103644d0Smckusick };
1914c2ecc49Sheideman struct vnodeopv_desc ffs_fifoop_opv_desc =
1924c2ecc49Sheideman { &ffs_fifoop_p, ffs_fifoop_entries };
193103644d0Smckusick #endif /* FIFO */
194103644d0Smckusick
1959a45e376Smckusick /*
1969a45e376Smckusick * Enabling cluster read/write operations.
1979a45e376Smckusick */
198ed20614cSmckusick int doclusterread = 1;
199ed20614cSmckusick int doclusterwrite = 1;
2004476fdfbSroot
2010549e7feSmckusick #include <ufs/ufs/ufs_readwrite.c>
202d982b431Smckusick
2030c465d6dSsam /*
2040c465d6dSsam * Synch an open file.
2050c465d6dSsam */
206065083aeSmckusick /* ARGSUSED */
2075b516ec6Sbostic int
ffs_fsync(ap)2084c2ecc49Sheideman ffs_fsync(ap)
2099899e5a2Smckusick struct vop_fsync_args /* {
2109899e5a2Smckusick struct vnode *a_vp;
2119899e5a2Smckusick struct ucred *a_cred;
2129899e5a2Smckusick int a_waitfor;
2139899e5a2Smckusick struct proc *a_p;
2149899e5a2Smckusick } */ *ap;
2150c465d6dSsam {
2169899e5a2Smckusick register struct vnode *vp = ap->a_vp;
2179899e5a2Smckusick register struct buf *bp;
218100a94d5Smckusick struct timeval tv;
2199899e5a2Smckusick struct buf *nbp;
2209899e5a2Smckusick int s;
2210c465d6dSsam
2229899e5a2Smckusick /*
2239899e5a2Smckusick * Flush all dirty buffers associated with a vnode.
2249899e5a2Smckusick */
2259899e5a2Smckusick loop:
2269899e5a2Smckusick s = splbio();
2277d2dba8aSmckusick for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
2287d2dba8aSmckusick nbp = bp->b_vnbufs.le_next;
2299899e5a2Smckusick if ((bp->b_flags & B_BUSY))
2309899e5a2Smckusick continue;
2319899e5a2Smckusick if ((bp->b_flags & B_DELWRI) == 0)
2329899e5a2Smckusick panic("ffs_fsync: not dirty");
2339899e5a2Smckusick bremfree(bp);
2349899e5a2Smckusick bp->b_flags |= B_BUSY;
2359899e5a2Smckusick splx(s);
2369899e5a2Smckusick /*
2379899e5a2Smckusick * Wait for I/O associated with indirect blocks to complete,
2389899e5a2Smckusick * since there is no way to quickly wait for them below.
2399899e5a2Smckusick */
2409899e5a2Smckusick if (bp->b_vp == vp || ap->a_waitfor == MNT_NOWAIT)
2419899e5a2Smckusick (void) bawrite(bp);
2429899e5a2Smckusick else
2439899e5a2Smckusick (void) bwrite(bp);
2449899e5a2Smckusick goto loop;
2459899e5a2Smckusick }
2469899e5a2Smckusick if (ap->a_waitfor == MNT_WAIT) {
2479899e5a2Smckusick while (vp->v_numoutput) {
2489899e5a2Smckusick vp->v_flag |= VBWAIT;
2499899e5a2Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
2509899e5a2Smckusick }
2519899e5a2Smckusick #ifdef DIAGNOSTIC
2527d2dba8aSmckusick if (vp->v_dirtyblkhd.lh_first) {
2539899e5a2Smckusick vprint("ffs_fsync: dirty", vp);
2549899e5a2Smckusick goto loop;
2559899e5a2Smckusick }
2569899e5a2Smckusick #endif
2579899e5a2Smckusick }
2589899e5a2Smckusick splx(s);
259100a94d5Smckusick tv = time;
26073bac521Sbostic return (VOP_UPDATE(ap->a_vp, &tv, &tv, ap->a_waitfor == MNT_WAIT));
26173bac521Sbostic }
262abf9880aSmckusick
263abf9880aSmckusick /*
264abf9880aSmckusick * Reclaim an inode so that it can be used for other purposes.
265abf9880aSmckusick */
266abf9880aSmckusick int
ffs_reclaim(ap)267abf9880aSmckusick ffs_reclaim(ap)
268abf9880aSmckusick struct vop_reclaim_args /* {
269abf9880aSmckusick struct vnode *a_vp;
270*f8846554Smckusick struct proc *a_p;
271abf9880aSmckusick } */ *ap;
272abf9880aSmckusick {
273abf9880aSmckusick register struct vnode *vp = ap->a_vp;
274abf9880aSmckusick int error;
275abf9880aSmckusick
276*f8846554Smckusick if (error = ufs_reclaim(vp, ap->a_p))
277abf9880aSmckusick return (error);
2787624df1cSmckusick FREE(vp->v_data, VFSTOUFS(vp->v_mount)->um_devvp->v_tag == VT_MFS ?
2797624df1cSmckusick M_MFSNODE : M_FFSNODE);
280abf9880aSmckusick vp->v_data = NULL;
281abf9880aSmckusick return (0);
282abf9880aSmckusick }
283