]> git.saurik.com Git - apple/xnu.git/blame - bsd/miscfs/synthfs/synthfs_vnops.c
xnu-1228.tar.gz
[apple/xnu.git] / bsd / miscfs / synthfs / synthfs_vnops.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * Copyright (c) 1998-1999 Apple Computer, Inc. All Rights Reserved.
30 *
31 * Modification History:
32 *
33 * 02-Feb-2000 Clark Warner Added copyfile to table
34 * 17-Aug-1999 Pat Dirks New today.
35 */
36
37#include <mach/mach_types.h>
38#include <mach/machine/boolean.h>
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/file.h>
43#include <sys/stat.h>
1c79356b 44#include <sys/proc.h>
91447636 45#include <sys/kauth.h>
1c79356b 46#include <sys/conf.h>
91447636
A
47#include <sys/mount_internal.h>
48#include <sys/vnode_internal.h>
1c79356b
A
49#include <sys/malloc.h>
50#include <sys/dirent.h>
51#include <sys/namei.h>
52#include <sys/attr.h>
91447636 53#include <sys/uio_internal.h>
1c79356b
A
54
55#include <sys/vm.h>
56#include <sys/errno.h>
57#include <vfs/vfs_support.h>
58
59#include "synthfs.h"
60
61#define RWSUPPORT 0
62
63#if RWSUPPORT
64#error NOT PORTED FOR UBC
1c79356b
A
65#include <sys/ubc.h>
66#endif
67
91447636
A
68static int synthfs_remove_internal(struct vnode *dvp, struct vnode *vp,
69 struct componentname *cnp, vfs_context_t context);
70
1c79356b
A
71
72#define VOPFUNC int (*)(void *)
73
74/* Global vfs data structures for synthfs. */
75int (**synthfs_vnodeop_p) (void *);
76struct vnodeopv_entry_desc synthfs_vnodeop_entries[] = {
91447636
A
77 {&vnop_default_desc, (VOPFUNC)vn_default_error},
78 {&vnop_strategy_desc, (VOPFUNC)err_strategy}, /* strategy - not supported */
79 {&vnop_bwrite_desc, (VOPFUNC)err_bwrite}, /* bwrite - not supported */
80 {&vnop_lookup_desc, (VOPFUNC)synthfs_cached_lookup}, /* cached lookup */
81 {&vnop_create_desc, (VOPFUNC)synthfs_create}, /* create - DEBUGGER */
82 {&vnop_whiteout_desc, (VOPFUNC)err_whiteout}, /* whiteout - not supported */
83 {&vnop_mknod_desc, (VOPFUNC)err_mknod}, /* mknod - not supported */
84 {&vnop_open_desc, (VOPFUNC)synthfs_open}, /* open - DEBUGGER */
85 {&vnop_close_desc, (VOPFUNC)nop_close}, /* close - NOP */
86 {&vnop_getattr_desc, (VOPFUNC)synthfs_getattr}, /* getattr */
87 {&vnop_setattr_desc, (VOPFUNC)synthfs_setattr}, /* setattr */
88 {&vnop_getattrlist_desc, (VOPFUNC)err_getattrlist}, /* getattrlist - not supported */
89 {&vnop_setattrlist_desc, (VOPFUNC)err_setattrlist}, /* setattrlist - not supported */
90 {&vnop_read_desc, (VOPFUNC)err_read}, /* read - not supported */
91 {&vnop_write_desc, (VOPFUNC)err_write}, /* write - not supported */
92 {&vnop_ioctl_desc, (VOPFUNC)err_ioctl}, /* ioctl - not supported */
93 {&vnop_select_desc, (VOPFUNC)synthfs_select}, /* select */
94 {&vnop_exchange_desc, (VOPFUNC)err_exchange}, /* exchange - not supported */
95 {&vnop_revoke_desc, (VOPFUNC)nop_revoke}, /* revoke - NOP */
96 {&vnop_mmap_desc, (VOPFUNC)synthfs_mmap}, /* mmap - DEBUGGER */
97 {&vnop_fsync_desc, (VOPFUNC)nop_fsync}, /* fsync - NOP */
98 {&vnop_remove_desc, (VOPFUNC)synthfs_remove}, /* remove */
99 {&vnop_link_desc, (VOPFUNC)err_link}, /* link - not supported */
100 {&vnop_rename_desc, (VOPFUNC)synthfs_rename}, /* rename */
101 {&vnop_mkdir_desc, (VOPFUNC)synthfs_mkdir}, /* mkdir */
102 {&vnop_rmdir_desc, (VOPFUNC)synthfs_rmdir}, /* rmdir */
103 {&vnop_symlink_desc, (VOPFUNC)synthfs_symlink}, /* symlink */
104 {&vnop_readdir_desc, (VOPFUNC)synthfs_readdir}, /* readdir */
105 {&vnop_readdirattr_desc, (VOPFUNC)err_readdirattr}, /* readdirattr - not supported */
106 {&vnop_readlink_desc, (VOPFUNC)synthfs_readlink}, /* readlink */
107 {&vnop_inactive_desc, (VOPFUNC)synthfs_inactive}, /* inactive */
108 {&vnop_reclaim_desc, (VOPFUNC)synthfs_reclaim}, /* reclaim */
109 {&vnop_pathconf_desc, (VOPFUNC)synthfs_pathconf}, /* pathconf */
110 {&vnop_advlock_desc, (VOPFUNC)err_advlock}, /* advlock - not supported */
111 {&vnop_allocate_desc, (VOPFUNC)err_allocate}, /* allocate - not supported */
112 {&vnop_pagein_desc, (VOPFUNC)err_pagein}, /* pagein - not supported */
113 {&vnop_pageout_desc, (VOPFUNC)err_pageout}, /* pageout - not supported */
91447636
A
114 {&vnop_searchfs_desc, (VOPFUNC)err_searchfs}, /* searchfs - not supported */
115 {&vnop_copyfile_desc, (VOPFUNC)err_copyfile}, /* copyfile - not supported */
116 { &vnop_blktooff_desc, (VOPFUNC)err_blktooff }, /* blktooff not supported */
117 { &vnop_offtoblk_desc, (VOPFUNC)err_offtoblk }, /* offtoblk not supported */
118 { &vnop_blockmap_desc, (VOPFUNC)err_blockmap }, /* blockmap not supported */
1c79356b
A
119 {(struct vnodeop_desc *) NULL, (int (*) ()) NULL}
120};
121
122/*
123 * Oh what a tangled web we weave. This structure will be used by
124 * bsd/vfs/vfs_conf.c to actually do the initialization of synthfs_vnodeop_p
125 */
126struct vnodeopv_desc synthfs_vnodeop_opv_desc =
127{&synthfs_vnodeop_p, synthfs_vnodeop_entries};
128
129
130
131/*
132 * Create a regular file
133#% create dvp L U U
134#% create vpp - L -
135#
91447636 136 vnop_create {
1c79356b
A
137 IN WILLRELE struct vnode *dvp;
138 OUT struct vnode **vpp;
139 IN struct componentname *cnp;
91447636 140 IN struct vnode_attr *vap;
1c79356b
A
141
142 We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is
143 a previous error.
144
145*/
146
147int
148synthfs_create(ap)
91447636 149struct vnop_create_args /* {
1c79356b
A
150 struct vnode *a_dvp;
151 struct vnode **a_vpp;
152 struct componentname *a_cnp;
91447636
A
153 struct vnode_attr *a_vap;
154 vfs_context_t a_context;
1c79356b
A
155} */ *ap;
156{
157#if DEBUG
158 struct vnode *dvp = ap->a_dvp;
159 char debugmsg[255];
160
161 sprintf(debugmsg, "synthfs_create: attempt to create '%s' in '%s' ?!", ap->a_cnp->cn_nameptr, VTOS(dvp)->s_name);
162 Debugger(debugmsg);
163#endif
164
55e303ae 165 return err_create(ap);
1c79356b
A
166}
167
168
169
170/*
171 * Open called.
172#% open vp L L L
173#
91447636 174 vnop_open {
1c79356b
A
175 IN struct vnode *vp;
176 IN int mode;
91447636 177 IN vfs_context_t a_context;
1c79356b
A
178 */
179
180int
181synthfs_open(ap)
91447636 182struct vnop_open_args /* {
1c79356b
A
183 struct vnode *a_vp;
184 int a_mode;
91447636 185 vfs_context_t a_context;
1c79356b
A
186} */ *ap;
187{
188 struct vnode *vp = ap->a_vp;
189
190 if (vp->v_type == VDIR) {
191 return 0;
192 } else {
193#if DEBUG
194 struct synthfsnode *sp = VTOS(vp);
195 char debugmsg[255];
196
197 sprintf(debugmsg, "synthfs_open: attempt to open '/%s' ?!", sp->s_name);
198 Debugger(debugmsg);
199#endif
200 };
201
202 return 0;
203}
204
205
206
207/*
208 * Mmap a file
209 *
210 * NB Currently unsupported.
211# XXX - not used
212#
91447636 213 vnop_mmap {
1c79356b
A
214 IN struct vnode *vp;
215 IN int fflags;
91447636 216 IN kauth_cred_t cred;
1c79356b
A
217 IN struct proc *p;
218
219 */
220
221/* ARGSUSED */
222
223int
91447636 224synthfs_mmap(__unused struct vnop_mmap_args *ap)
1c79356b 225{
1c79356b
A
226 return EINVAL;
227}
228
229
230
1c79356b
A
231/*
232#% getattr vp = = =
233#
91447636 234 vnop_getattr {
1c79356b 235 IN struct vnode *vp;
91447636
A
236 IN struct vnode_attr *vap;
237 IN vfs_context_t context;
1c79356b
A
238
239*/
240int
241synthfs_getattr(ap)
91447636 242struct vnop_getattr_args /* {
1c79356b 243 struct vnode *a_vp;
91447636
A
244 struct vnode_attr *a_vap;
245 vfs_context_t a_context;
1c79356b
A
246} */ *ap;
247{
91447636
A
248 struct vnode *vp = ap->a_vp;
249 struct vnode_attr *vap = ap->a_vap;
250 struct synthfsnode *sp = VTOS(vp);
251
252 VATTR_RETURN(vap, va_type, vp->v_type);
253 VATTR_RETURN(vap, va_mode, sp->s_mode);
254 VATTR_RETURN(vap, va_nlink, sp->s_linkcount);
255 VATTR_RETURN(vap, va_uid, sp->s_uid);
256 VATTR_RETURN(vap, va_gid, sp->s_gid);
257 VATTR_RETURN(vap, va_fsid, VTOVFS(vp)->mnt_vfsstat.f_fsid.val[0]);
258 VATTR_RETURN(vap, va_fileid, sp->s_nodeid);
1c79356b 259 switch (vp->v_type) {
91447636
A
260 case VDIR:
261 VATTR_RETURN(vap, va_data_size, (sp->s_u.d.d_entrycount + 2) * sizeof(struct dirent));
1c79356b
A
262 break;
263
91447636
A
264 case VREG:
265 VATTR_RETURN(vap, va_data_size, sp->s_u.f.f_size);
1c79356b
A
266 break;
267
91447636
A
268 case VLNK:
269 VATTR_RETURN(vap, va_data_size, sp->s_u.s.s_length);
1c79356b
A
270 break;
271
91447636
A
272 default:
273 VATTR_RETURN(vap, va_data_size, 0);
1c79356b 274 };
91447636
A
275 VATTR_RETURN(vap, va_iosize, 512);
276 vap->va_access_time.tv_sec = sp->s_accesstime.tv_sec;
277 vap->va_access_time.tv_nsec = sp->s_accesstime.tv_usec * 1000;
278 VATTR_SET_SUPPORTED(vap, va_access_time);
279 vap->va_modify_time.tv_sec = sp->s_modificationtime.tv_sec;
280 vap->va_modify_time.tv_nsec = sp->s_modificationtime.tv_usec * 1000;
281 VATTR_SET_SUPPORTED(vap, va_modify_time);
282 vap->va_change_time.tv_sec = sp->s_changetime.tv_sec;
283 vap->va_change_time.tv_nsec = sp->s_changetime.tv_usec * 1000;
284 VATTR_SET_SUPPORTED(vap, va_change_time);
285 VATTR_RETURN(vap, va_gen, sp->s_generation);
286 VATTR_RETURN(vap, va_flags, sp->s_flags);
287 VATTR_RETURN(vap, va_rdev, sp->s_rdev);
288 VATTR_RETURN(vap, va_filerev, 0);
289 VATTR_RETURN(vap, va_acl, NULL);
290
291 return (0);
1c79356b
A
292}
293
294
295
296/*
297 * Change the mode on a file or directory.
298 * vnode vp must be locked on entry.
299 */
91447636 300int synthfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct proc *p)
1c79356b
A
301{
302 struct synthfsnode *sp = VTOS(vp);
303 int result;
304
1c79356b
A
305 sp->s_mode &= ~ALLPERMS;
306 sp->s_mode |= (mode & ALLPERMS);
307 sp->s_nodeflags |= IN_CHANGE;
308#if RWSUPPORT
309 if ((vp->v_flag & VTEXT) && (sp->s_mode & S_ISTXT) == 0) (void) vnode_uncache(vp);
310#endif
311
312 return 0;
313}
314
315
316
317/*
318 * Change the flags on a file or directory.
319 * vnode vp must be locked on entry.
320 */
91447636 321int synthfs_chflags(struct vnode *vp, u_long flags, kauth_cred_t cred, struct proc *p)
1c79356b
A
322{
323 struct synthfsnode *sp = VTOS(vp);
1c79356b 324
91447636 325 sp->s_flags = flags;
1c79356b
A
326 sp->s_nodeflags |= IN_CHANGE;
327
328 return 0;
329}
330
331
332
333/*
334 * Perform chown operation on vnode vp;
335 * vnode vp must be locked on entry.
336 */
91447636 337int synthfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred, struct proc *p)
1c79356b
A
338{
339 struct synthfsnode *sp = VTOS(vp);
340 uid_t ouid;
341 gid_t ogid;
342 int result = 0;
91447636 343 int is_member;
1c79356b
A
344
345 if (uid == (uid_t)VNOVAL) uid = sp->s_uid;
346 if (gid == (gid_t)VNOVAL) gid = sp->s_gid;
347
1c79356b
A
348 ogid = sp->s_gid;
349 ouid = sp->s_uid;
350
351 sp->s_gid = gid;
352 sp->s_uid = uid;
353
354 if (ouid != uid || ogid != gid) sp->s_nodeflags |= IN_CHANGE;
91447636
A
355 if (ouid != uid && suser(cred, NULL)) sp->s_mode &= ~S_ISUID;
356 if (ogid != gid && suser(cred, NULL)) sp->s_mode &= ~S_ISGID;
1c79356b
A
357
358 return 0;
359}
360
361
362
363/*
364 * Set attribute vnode op. called from several syscalls
365#% setattr vp L L L
366#
91447636 367 vnop_setattr {
1c79356b 368 IN struct vnode *vp;
91447636
A
369 IN struct vnode_attr *vap;
370 IN vfs_context_t context;
1c79356b
A
371 */
372
373int
374synthfs_setattr(ap)
91447636 375struct vnop_setattr_args /* {
1c79356b 376struct vnode *a_vp;
91447636
A
377struct vnode_attr *a_vap;
378vfs_context_t a_context;
1c79356b
A
379} */ *ap;
380{
91447636
A
381 struct vnode *vp = ap->a_vp;
382 struct synthfsnode *sp = VTOS(vp);
383 struct vnode_attr *vap = ap->a_vap;
384 kauth_cred_t cred = vfs_context_ucred(ap->a_context);
385 struct proc *p = vfs_context_proc(ap->a_context);
386 struct timeval atimeval, mtimeval;
387 uid_t nuid;
388 gid_t ngid;
389 int result;
390
391 result = 0;
392
393 if (VATTR_IS_ACTIVE(vap, va_flags)) {
394 if ((result = synthfs_chflags(vp, vap->va_flags, cred, p))) {
395 goto Err_Exit;
396 }
397 }
398 VATTR_SET_SUPPORTED(vap, va_flags);
399
400 nuid = (uid_t)ngid = (gid_t)VNOVAL;
401 if (VATTR_IS_ACTIVE(vap, va_uid))
402 nuid = vap->va_uid;
403 if (VATTR_IS_ACTIVE(vap, va_gid))
404 ngid = vap->va_gid;
405 if (nuid != (uid_t)VNOVAL || ngid != (gid_t)VNOVAL) {
406 if ((result = synthfs_chown(vp, nuid, ngid, cred, p))) {
407 goto Err_Exit;
408 }
409 }
410 VATTR_SET_SUPPORTED(vap, va_uid);
411 VATTR_SET_SUPPORTED(vap, va_gid);
1c79356b 412
91447636 413 if (VATTR_IS_ACTIVE(vap, va_data_size)) {
1c79356b 414#if RWSUPPORT
91447636
A
415 if ((result = vnode_setsize(vp, vap->va_data_size, 0, ap->a_context))) {
416 goto Err_Exit;
417 };
418 VATTR_SET_SUPPORTED(vap, va_data_size);
1c79356b 419#else
91447636
A
420 result = EINVAL;
421 goto Err_Exit;
1c79356b 422#endif
91447636 423 }
1c79356b 424
91447636
A
425 sp = VTOS(vp);
426 if (VATTR_IS_ACTIVE(vap, va_access_time) || VATTR_IS_ACTIVE(vap, va_modify_time)) {
427 if (VATTR_IS_ACTIVE(vap, va_access_time)) {
428 sp->s_nodeflags |= IN_ACCESS;
429 atimeval.tv_sec = vap->va_access_time.tv_sec;
430 atimeval.tv_usec = vap->va_access_time.tv_nsec / 1000;
431 }
432 if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
433 sp->s_nodeflags |= IN_CHANGE | IN_UPDATE;
434 mtimeval.tv_sec = vap->va_modify_time.tv_sec;
435 mtimeval.tv_usec = vap->va_modify_time.tv_nsec / 1000;
436 }
437 if ((result = synthfs_update(vp, &atimeval, &mtimeval, 1))) {
438 goto Err_Exit;
439 }
440 }
441 VATTR_SET_SUPPORTED(vap, va_access_time);
442 VATTR_SET_SUPPORTED(vap, va_modify_time);
1c79356b 443
91447636
A
444 if (VATTR_IS_ACTIVE(vap, va_mode))
445 result = synthfs_chmod(vp, (int)vap->va_mode, cred, p);
446 VATTR_SET_SUPPORTED(vap, va_mode);
1c79356b 447
91447636 448 Err_Exit:
1c79356b 449
91447636 450 DBG_VOP(("synthfs_setattr: returning %d...\n", result));
1c79356b 451
91447636 452 return (result);
1c79356b
A
453}
454
455
456
457/*
458
459#% rename sourcePar_vp U U U
460#% rename source_vp U U U
461#% rename targetPar_vp L U U
462#% rename target_vp X U U
463#
91447636 464 vnop_rename {
1c79356b
A
465 IN WILLRELE struct vnode *sourcePar_vp;
466 IN WILLRELE struct vnode *source_vp;
467 IN struct componentname *source_cnp;
468 IN WILLRELE struct vnode *targetPar_vp;
469 IN WILLRELE struct vnode *target_vp;
470 IN struct componentname *target_cnp;
471
472
473 */
474
475/*
476 * On entry:
477 * source's parent directory is unlocked
478 * source file or directory is unlocked
479 * destination's parent directory is locked
480 * destination file or directory is locked if it exists
481 *
482 * On exit:
483 * all denodes should be released
484 *
485 */
486
487int
488synthfs_rename(ap)
91447636 489struct vnop_rename_args /* {
1c79356b
A
490 struct vnode *a_fdvp;
491 struct vnode *a_fvp;
492 struct componentname *a_fcnp;
493 struct vnode *a_tdvp;
494 struct vnode *a_tvp;
495 struct componentname *a_tcnp;
91447636 496 vfs_context_t a_context;
1c79356b
A
497} */ *ap;
498{
499 struct vnode *target_vp = ap->a_tvp;
500 struct vnode *targetPar_vp = ap->a_tdvp;
501 struct vnode *source_vp = ap->a_fvp;
502 struct vnode *sourcePar_vp = ap->a_fdvp;
503 struct componentname *target_cnp = ap->a_tcnp;
504 struct componentname *source_cnp = ap->a_fcnp;
1c79356b
A
505 struct synthfsnode *target_sp, *targetPar_sp, *source_sp, *sourcePar_sp;
506 u_short doingdirectory = 0, oldparent = 0, newparent = 0;
507 int retval = 0;
508 struct timeval tv;
509
510#if SYNTHFS_DIAGNOSTIC
511 if ((target_cnp->cn_flags & HASBUF) == 0 ||
512 (source_cnp->cn_flags & HASBUF) == 0)
513 panic("synthfs_rename: no name");
514#endif
515
516 DBG_ASSERT((ap->a_fdvp->v_type == VDIR) && (ap->a_tdvp->v_type == VDIR));
517 target_sp = targetPar_sp = source_sp = sourcePar_sp = NULL;
518
1c79356b
A
519
520 sourcePar_sp = VTOS(sourcePar_vp);
521 source_sp = VTOS(source_vp);
522 oldparent = sourcePar_sp->s_nodeid;
1c79356b
A
523
524 /*
525 * Be sure we are not renaming ".", "..", or an alias of ".". This
526 * leads to a crippled directory tree. It's pretty tough to do a
527 * "ls" or "pwd" with the "." directory entry missing, and "cd .."
528 * doesn't work if the ".." entry is missing.
529 */
530 if (source_sp->s_type == SYNTHFS_DIRECTORY) {
531 if ((source_cnp->cn_namelen == 1 && source_cnp->cn_nameptr[0] == '.')
532 || sourcePar_sp == source_sp
533 || (source_cnp->cn_flags & ISDOTDOT)
534 || (source_sp->s_nodeflags & IN_RENAME)) {
1c79356b
A
535 retval = EINVAL;
536 goto abortit;
537 }
538 source_sp->s_nodeflags |= IN_RENAME;
539 doingdirectory = TRUE;
540 }
541
542 /* Transit between abort and bad */
543
544 targetPar_sp = VTOS(targetPar_vp);
545 target_sp = target_vp ? VTOS(target_vp) : NULL;
546 newparent = targetPar_sp->s_nodeid;
547
1c79356b
A
548
549 /*
550 * If the destination exists, then be sure its type (file or dir)
551 * matches that of the source. And, if it is a directory make sure
552 * it is empty. Then delete the destination.
553 */
554 if (target_vp) {
1c79356b 555
1c79356b 556#if RWSUPPORT
91447636
A
557 if (target_vp->v_type == VREG) {
558 (void) vnode_uncache(target_vp);
559 };
1c79356b 560#endif
91447636 561 cache_purge(target_vp);
1c79356b 562
91447636 563 retval = synthfs_remove_internal(targetPar_vp, target_vp, target_cnp, ap->a_context);
1c79356b
A
564
565 target_vp = NULL;
566 target_sp = NULL;
567
568 if (retval) goto bad;
569 };
570
571
1c79356b
A
572 /* remove the existing entry from the namei cache: */
573 if (source_vp->v_type == VREG) cache_purge(source_vp);
574
575 retval = synthfs_move_rename_entry( source_vp, targetPar_vp, target_cnp->cn_nameptr);
576
1c79356b
A
577 if (retval) goto bad;
578
579 source_sp->s_nodeflags &= ~IN_RENAME;
580
581 /*
582 * Timestamp both parent directories.
583 * Note that if this is a rename within the same directory,
584 * (where targetPar_hp == sourcePar_hp)
585 * the code below is still safe and correct.
586 */
587 targetPar_sp->s_nodeflags |= IN_UPDATE;
588 sourcePar_sp->s_nodeflags |= IN_UPDATE;
91447636
A
589
590 microtime(&tv);
1c79356b
A
591 SYNTHFSTIMES(targetPar_sp, &tv, &tv);
592 SYNTHFSTIMES(sourcePar_sp, &tv, &tv);
593
1c79356b
A
594 return (retval);
595
596bad:;
597 if (retval && doingdirectory)
598 source_sp->s_nodeflags &= ~IN_RENAME;
599
91447636 600 return (retval);
1c79356b
A
601
602abortit:;
91447636 603 return (retval);
1c79356b
A
604}
605
606
607
608/*
609 * Mkdir system call
610
611#% mkdir dvp L U U
612#% mkdir vpp - L -
613#
91447636 614 vnop_mkdir {
1c79356b
A
615 IN WILLRELE struct vnode *dvp;
616 OUT struct vnode **vpp;
617 IN struct componentname *cnp;
91447636
A
618 IN struct vnode_attr *vap;
619 IN vfs_context_t context;
1c79356b
A
620
621 We are responsible for freeing the namei buffer, it is done in synthfs_makenode(), unless there is
622 a previous error.
623
624*/
625
626int
627synthfs_mkdir(ap)
91447636 628struct vnop_mkdir_args /* {
1c79356b
A
629 struct vnode *a_dvp;
630 struct vnode **a_vpp;
631 struct componentname *a_cnp;
91447636
A
632 struct vnode_attr *a_vap;
633 vfs_context_t a_context;
1c79356b
A
634} */ *ap;
635{
636 int retval;
637 struct vnode *dvp = ap->a_dvp;
638 struct componentname *cnp = ap->a_cnp;
639 int mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
640 struct vnode *vp = NULL;
641
91447636 642 *ap->a_vpp = NULL;
1c79356b 643
91447636
A
644 retval = synthfs_new_directory(VTOVFS(dvp), dvp, cnp->cn_nameptr, VTOSFS(dvp)->synthfs_nextid++, mode, vfs_context_proc(cnp->cn_context), &vp);
645 if (retval) goto Error_Exit;
1c79356b 646
91447636 647 *ap->a_vpp = vp;
1c79356b 648
91447636
A
649 retval = vnode_setattr(vp, ap->a_vap, ap->a_context);
650 if (retval != 0) goto Error_Exit;
1c79356b 651
91447636
A
652 Error_Exit:;
653 if (retval != 0) {
654 if (vp) synthfs_remove_directory(vp);
655 }
1c79356b
A
656
657 return retval;
658}
659
660
661
662/*
663
664#% remove dvp L U U
665#% remove vp L U U
666#
91447636 667 vnop_remove {
1c79356b
A
668 IN WILLRELE struct vnode *dvp;
669 IN WILLRELE struct vnode *vp;
670 IN struct componentname *cnp;
91447636
A
671 IN vfs_context_t context;
672
1c79356b
A
673 */
674
675int
676synthfs_remove(ap)
91447636 677struct vnop_remove_args /* {
1c79356b
A
678 struct vnode *a_dvp;
679 struct vnode *a_vp;
680 struct componentname *a_cnp;
91447636 681 vfs_context_t a_context;
1c79356b
A
682} */ *ap;
683{
91447636
A
684 return synthfs_remove_internal(ap->a_dvp, ap->a_vp, ap->a_cnp, ap->a_context);
685}
686
687static int
688synthfs_remove_internal(struct vnode *dvp, struct vnode *vp,
689 __unused struct componentname *cnp,
690 __unused vfs_context_t context)
691{
1c79356b 692 struct synthfsnode *sp = VTOS(vp);
91447636 693 struct timeval tv;
1c79356b
A
694 int retval = 0;
695
1c79356b
A
696 /* This is sort of silly right now but someday it may make sense... */
697 if (sp->s_nodeflags & IN_MODIFIED) {
91447636
A
698 microtime(&tv);
699 synthfs_update(vp, &tv, &tv, 0);
1c79356b
A
700 };
701
702 /* remove the entry from the namei cache: */
703 cache_purge(vp);
704
705 /* remove entry from tree and reclaim any resources consumed: */
706 switch (sp->s_type) {
707 case SYNTHFS_DIRECTORY:
708 synthfs_remove_directory(vp);
709 break;
710
711
712 case SYNTHFS_SYMLINK:
713 synthfs_remove_symlink(vp);
714 break;
715
716 case SYNTHFS_FILE:
717 /* Fall through to default case */
718
719 default:
720 synthfs_remove_entry(vp);
721 };
722
723out:
724
725 if (! retval)
726 VTOS(dvp)->s_nodeflags |= IN_CHANGE | IN_UPDATE;
727
1c79356b
A
728 return (retval);
729}
730
731
732
733/*
734#% rmdir dvp L U U
735#% rmdir vp L U U
736#
91447636 737 vnop_rmdir {
1c79356b
A
738 IN WILLRELE struct vnode *dvp;
739 IN WILLRELE struct vnode *vp;
740 IN struct componentname *cnp;
91447636 741 IN vfs_context_t context;
1c79356b
A
742
743 */
744
745int
746synthfs_rmdir(ap)
91447636 747 struct vnop_rmdir_args /* {
1c79356b
A
748 struct vnode *a_dvp;
749 struct vnode *a_vp;
750 struct componentname *a_cnp;
91447636 751 vfs_context_t a_context;
1c79356b
A
752} */ *ap;
753{
91447636 754 return synthfs_remove((struct vnop_remove_args *)ap);
1c79356b
A
755}
756
757
758
759/*
760 * synthfs_select - just say OK. Only possible op is readdir
761 *
762 * Locking policy: ignore
763 */
764int
91447636
A
765synthfs_select(__unused
766struct vnop_select_args /* {
1c79356b
A
767 struct vnode *a_vp;
768 int a_which;
769 int a_fflags;
91447636 770 kauth_cred_t a_cred;
0b4e3aa0 771 void *a_wql;
1c79356b 772 struct proc *a_p;
91447636 773} */ *ap)
1c79356b
A
774{
775 DBG_VOP(("synthfs_select called\n"));
776
777 return (1);
778}
779
780/*
781#
782#% symlink dvp L U U
783#% symlink vpp - U -
784#
91447636
A
785# XXX - note that the return vnode has already been vnode_put'ed
786# by the filesystem layer. To use it you must use vnode_get,
1c79356b
A
787# possibly with a further namei.
788#
91447636 789 vnop_symlink {
1c79356b
A
790 IN WILLRELE struct vnode *dvp;
791 OUT WILLRELE struct vnode **vpp;
792 IN struct componentname *cnp;
91447636 793 IN struct vnode_attr *vap;
1c79356b
A
794 IN char *target;
795
796 We are responsible for freeing the namei buffer, it is done in synthfs_makenode(), unless there is
797 a previous error.
798
799
800*/
801
802int
803synthfs_symlink(ap)
91447636 804 struct vnop_symlink_args /* {
1c79356b
A
805 struct vnode *a_dvp;
806 struct vnode **a_vpp;
807 struct componentname *a_cnp;
91447636 808 struct vnode_attr *a_vap;
1c79356b 809 char *a_target;
91447636 810 vfs_context_t a_context;
1c79356b
A
811 } */ *ap;
812{
813 struct vnode *dvp = ap->a_dvp;
814 struct vnode **vpp = ap->a_vpp;
815 struct componentname *cnp = ap->a_cnp;
816 int retval;
817
818 *vpp = NULL;
819
91447636 820 retval = synthfs_new_symlink(VTOVFS(dvp), dvp, cnp->cn_nameptr, VTOSFS(dvp)->synthfs_nextid++, ap->a_target, vfs_context_proc(cnp->cn_context), vpp);
1c79356b
A
821
822 return (retval);
823}
824
825
826
827/*
828#
829#% readlink vp L L L
830#
91447636 831 vnop_readlink {
1c79356b
A
832 IN struct vnode *vp;
833 INOUT struct uio *uio;
91447636 834 IN kauth_cred_t cred;
1c79356b
A
835 */
836
837int
838synthfs_readlink(ap)
91447636 839struct vnop_readlink_args /* {
1c79356b
A
840 struct vnode *a_vp;
841 struct uio *a_uio;
91447636 842 vfs_context_t a_context;
1c79356b
A
843} */ *ap;
844{
845 struct vnode *vp = ap->a_vp;
846 struct synthfsnode *sp = VTOS(vp);
847 struct uio *uio = ap->a_uio;
848 int retval;
849 unsigned long count;
850
851 if (ap->a_uio->uio_offset > sp->s_u.s.s_length) {
852 return 0;
853 };
854
91447636
A
855 // LP64todo - fix this!
856 if (uio->uio_offset + uio_resid(uio) <= sp->s_u.s.s_length) {
857 count = uio_resid(uio);
1c79356b
A
858 } else {
859 count = sp->s_u.s.s_length - uio->uio_offset;
860 };
861 retval = uiomove((void *)((unsigned char *)sp->s_u.s.s_symlinktarget + uio->uio_offset), count, uio);
862 return (retval);
863
864}
865
866
867
868
869
870
871/*
91447636
A
872 * Read directory entries.
873 */
1c79356b
A
874int
875synthfs_readdir(ap)
91447636
A
876struct vnop_readdir_args /* {
877 struct vnode *a_vp;
878 struct uio *a_uio;
879 int a_flags;
880 int *a_eofflag;
881 int *a_numdirent;
882 vfs_context_t a_context;
1c79356b
A
883} */ *ap;
884{
885 struct synthfsnode *sp = VTOS(ap->a_vp);
886 register struct uio *uio = ap->a_uio;
887 off_t diroffset; /* Offset into simulated directory file */
888 struct synthfsnode *entry;
889
91447636
A
890 DBG_VOP(("\tuio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio)));
891
892 if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF))
893 return (EINVAL);
1c79356b
A
894
895 /* We assume it's all one big buffer... */
896 if (uio->uio_iovcnt > 1) {
897 DBG_VOP(("\tuio->uio_iovcnt = %d?\n", uio->uio_iovcnt));
898 return EINVAL;
899 };
1c79356b
A
900
901 diroffset = 0;
902
903 /*
904 * We must synthesize . and ..
905 */
91447636 906 DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio)));
1c79356b
A
907 if (uio->uio_offset == diroffset)
908 {
909 DBG_VOP(("\tAdding .\n"));
910 diroffset += synthfs_adddirentry(sp->s_nodeid, DT_DIR, ".", uio);
91447636 911 DBG_VOP(("\t after adding ., uio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio)));
1c79356b 912 }
91447636 913 if ((uio_resid(uio) > 0) && (diroffset > uio->uio_offset)) {
1c79356b
A
914 /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */
915 return EINVAL;
916 };
917
918 if (uio->uio_offset == diroffset)
919 {
920 DBG_VOP(("\tAdding ..\n"));
921 if (sp->s_parent != NULL) {
922 diroffset += synthfs_adddirentry(sp->s_parent->s_nodeid, DT_DIR, "..", uio);
923 } else {
924 diroffset += synthfs_adddirentry(sp->s_nodeid, DT_DIR, "..", uio);
925 }
91447636 926 DBG_VOP(("\t after adding .., uio_offset = %d, uio_resid = %lld\n", (int) uio->uio_offset, uio_resid(uio)));
1c79356b 927 }
91447636 928 if ((uio_resid(uio) > 0) && (diroffset > uio->uio_offset)) {
1c79356b
A
929 /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */
930 return EINVAL;
931 };
932
933 /* OK, so much for the fakes. Now for the "real thing": */
934 TAILQ_FOREACH(entry, &sp->s_u.d.d_subnodes, s_sibling) {
935 if (diroffset == uio->uio_offset) {
936 /* Return this entry */
937 diroffset += synthfs_adddirentry(entry->s_nodeid, VTTOIF(STOV(entry)->v_type), entry->s_name, uio);
938 };
91447636 939 if ((uio_resid(uio) > 0) && (diroffset > uio->uio_offset)) {
1c79356b
A
940 /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */
941 return EINVAL;
942 };
943 };
944
945 if (ap->a_eofflag)
946 *ap->a_eofflag = (entry == NULL); /* If we ran all the way through the list, there is no more */
947
948 return 0;
949}
950
951
952
953/*
954
955#% lookup dvp L ? ?
956#% lookup vpp - L -
957
958 */
959
960int
961synthfs_cached_lookup(ap)
91447636 962 struct vnop_lookup_args /* {
1c79356b
A
963 struct vnode *a_dvp;
964 struct vnode **a_vpp;
965 struct componentname *a_cnp;
966 } */ *ap;
967{
968 struct vnode *dp = ap->a_dvp;
969 struct componentname *cnp = ap->a_cnp;
970 u_long nameiop = cnp->cn_nameiop;
971 u_long flags = cnp->cn_flags;
1c79356b
A
972 struct vnode **vpp = ap->a_vpp;
973 int result = 0;
974
975 DBG_VOP(("synthfs_cached_lookup called, name = %s, namelen = %ld\n", ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
91447636 976#if DEBUG
1c79356b 977 if (flags & ISLASTCN) DBG_VOP(("\tISLASTCN is set\n"));
91447636 978#endif
1c79356b
A
979
980 *vpp = NULL;
981
1c79356b
A
982 /*
983 * Look up an entry in the namei cache
984 */
985
986 result = cache_lookup(dp, vpp, cnp);
987 if (result == 0) {
988 /* There was no entry in the cache for this parent vnode/name pair:
989 do the full-blown pathname lookup
990 */
991 return synthfs_lookup(ap);
992 };
993 if (result == ENOENT) return result;
994
995 /* An entry matching the parent vnode/name was found in the cache: */
996
91447636 997 return (0);
1c79356b
A
998
999Err_Exit:;
91447636 1000 return result;
1c79356b
A
1001}
1002
1003
1004
1005int
1006synthfs_lookup(ap)
91447636 1007 struct vnop_lookup_args /* {
1c79356b
A
1008 struct vnode *a_dvp;
1009 struct vnode **a_vpp;
1010 struct componentname *a_cnp;
91447636 1011 vfs_context_t a_context;
1c79356b
A
1012 } */ *ap;
1013{
1014 struct vnode *dp = ap->a_dvp;
1015 struct synthfsnode *dsp = VTOS(dp);
1016 struct componentname *cnp = ap->a_cnp;
1017 u_long nameiop = cnp->cn_nameiop;
1018// char *nameptr = cnp->cn_nameptr;
1019 u_long flags = cnp->cn_flags;
1020 long namelen = cnp->cn_namelen;
91447636
A
1021// struct proc *p = cnp->cn_proc;
1022 vfs_context_t ctx = cnp->cn_context;
1023 kauth_cred_t cred = vfs_context_ucred(ctx);
1c79356b
A
1024 struct synthfsnode *entry;
1025 struct vnode *target_vp = NULL;
1026 int result = 0;
1027 boolean_t found = FALSE;
1028 boolean_t isDot = FALSE;
1029 boolean_t isDotDot = FALSE;
1030 struct vnode *starting_parent = dp;
1031
1032 DBG_VOP(("synthfs_lookup called, name = %s, namelen = %ld\n", ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
91447636 1033#if DEBUG
1c79356b
A
1034 if (flags & LOCKPARENT) DBG_VOP(("\tLOCKPARENT is set\n"));
1035 if (flags & ISLASTCN) DBG_VOP(("\tISLASTCN is set\n"));
91447636 1036#endif
1c79356b
A
1037
1038 *ap->a_vpp = NULL;
1039
1c79356b
A
1040 /* first check for "." and ".." */
1041 if (cnp->cn_nameptr[0] == '.') {
1042 if (namelen == 1) {
1043 /*
1044 "." requested
1045 */
1046 isDot = TRUE;
1047 found = TRUE;
1048
1049 target_vp = dp;
91447636 1050 vnode_get(target_vp);
1c79356b
A
1051
1052 result = 0;
1053
1054 goto Std_Exit;
1055 } else if ((namelen == 2) && (cnp->cn_nameptr[1] == '.')) {
1056 /*
1057 ".." requested
1058 */
1059 isDotDot = TRUE;
1060 found = TRUE;
1061
1062 if ((dsp->s_parent != NULL) && (dsp->s_parent != VTOS(dp))) {
1063 target_vp = STOV(dsp->s_parent);
1064 /*
1065 * Special case for ".." to prevent deadlock:
1066 * always release the parent vnode BEFORE trying to acquire
1067 * ITS parent. This avoids deadlocking with another lookup
91447636 1068 * starting from the target_vp trying to vnode_get() this directory.
1c79356b 1069 */
91447636
A
1070 result = vnode_get(target_vp);
1071
1c79356b
A
1072 } else {
1073 target_vp = dp;
1074 /* dp is alread locked and ref'ed */
1075 result = 0;
1076 }
1077
1078 goto Std_Exit;
1079 }
1080 }
1081
1082 /* finally, just look for entries by name (making sure the entry's length
1083 matches the cnp's namelen... */
1084 TAILQ_FOREACH(entry, &dsp->s_u.d.d_subnodes, s_sibling) {
1085 if ((bcmp(cnp->cn_nameptr, entry->s_name, (unsigned)namelen) == 0) &&
1086 (*(entry->s_name + namelen) == (char)0)) {
1087 found = TRUE;
1088 target_vp = STOV(entry);
91447636 1089 result = vnode_getwithref(target_vp); /* refcount is always > 0 for any vnode in this list... */
1c79356b 1090 if (result != 0) {
1c79356b
A
1091 goto Err_Exit;
1092 };
1093
1094 /* The specified entry was found and successfully acquired: */
1095 goto Std_Exit;
1096 };
1097 };
1098
1099 found = FALSE;
1100
1101Std_Exit:;
1102 if (found) {
1103 if ((nameiop == DELETE) && (flags & ISLASTCN)) {
1c79356b
A
1104
1105 /*
1106 * If the parent directory is "sticky" then the user must own
1107 * the directory, or the file in it, in order to be allowed to
1108 * delete it (unless the user is root). This implements
1109 * append-only directories
1110 */
1111 if ((dsp->s_mode & S_ISVTX) &&
91447636
A
1112 suser(cred, NULL) &&
1113 (kauth_cred_getuid(cred) != dsp->s_uid) &&
1c79356b
A
1114 (target_vp != NULL) &&
1115 (target_vp->v_type != VLNK) &&
91447636
A
1116 (VTOS(target_vp)->s_uid != kauth_cred_getuid(cred))) {
1117 vnode_put(target_vp);
1c79356b
A
1118 result = EPERM;
1119 goto Err_Exit;
1120 };
1121 };
1122
1123 if ((nameiop == RENAME) && (flags & WANTPARENT) && (flags * ISLASTCN)) {
1c79356b
A
1124
1125 if (isDot) {
91447636 1126 vnode_put(target_vp);
1c79356b
A
1127 result = EISDIR;
1128 goto Err_Exit;
1129 };
1130 };
1131 } else {
1132 /* The specified entry wasn't found: */
1133 result = ENOENT;
1134
1135 if ((flags & ISLASTCN) &&
1136 ((nameiop == CREATE) ||
1137 (nameiop == RENAME) ||
1138 ((nameiop == DELETE) && (flags & DOWHITEOUT) && (flags & ISWHITEOUT)))) {
91447636 1139 /* create a new entry */
1c79356b
A
1140 result = EJUSTRETURN;
1141 }
1142 };
1143
1c79356b
A
1144 *ap->a_vpp = target_vp;
1145
1146Err_Exit:;
1147 DBG_VOP(("synthfs_lookup: result = %d.\n", result));
1148 if (found) {
1149 if (target_vp) {
91447636 1150 DBG_VOP(("synthfs_lookup: target_vp = 0x%08X \n", (u_long)target_vp));
1c79356b
A
1151 } else {
1152 DBG_VOP(("synthfs_lookup: found = true but target_vp = NULL?\n"));
1153 };
1154 } else {
1155 DBG_VOP(("synthf_lookup: target not found.\n"));
1156 };
91447636 1157 DBG_VOP(("synthfs_lookup: dp = %08X; starting_parent = 0x%08X .\n", (u_long)dp, (u_long)starting_parent));
1c79356b
A
1158
1159 return result;
1160}
1161
1162
1163
1164/*
1165
1166#% pathconf vp L L L
1167#
91447636 1168 vnop_pathconf {
1c79356b
A
1169 IN struct vnode *vp;
1170 IN int name;
1171 OUT register_t *retval;
1172*/
1173int
1174synthfs_pathconf(ap)
91447636 1175struct vnop_pathconf_args /* {
1c79356b
A
1176 struct vnode *a_vp;
1177 int a_name;
1178 int *a_retval;
91447636 1179 vfs_context_t a_context;
1c79356b
A
1180} */ *ap;
1181{
1182 DBG_VOP(("synthfs_pathconf called\n"));
1183
1184 switch (ap->a_name)
1185 {
1186 case _PC_LINK_MAX:
1187 *ap->a_retval = LINK_MAX;
1188 return (0);
1189 case _PC_NAME_MAX:
1190 *ap->a_retval = NAME_MAX;
1191 return (0);
1192 case _PC_PATH_MAX:
1193 *ap->a_retval = PATH_MAX;
1194 return (0);
1195 case _PC_PIPE_BUF:
1196 *ap->a_retval = PIPE_BUF;
1197 return (0);
1198 case _PC_CHOWN_RESTRICTED:
2d21ac55 1199 *ap->a_retval = 200112; /* _POSIX_CHOWN_RESTRICTED */
1c79356b
A
1200 return (0);
1201 case _PC_NO_TRUNC:
2d21ac55 1202 *ap->a_retval = 200112; /* _POSIX_NO_TRUNC */
1c79356b
A
1203 return (0);
1204 default:
1205 return (EINVAL);
1206 }
1207 /* NOTREACHED */
1208}
1209
1210
1211/*
1212 * Update the access, modified, and node change times as specified by the
1213 * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is
1214 * used to specify that the node needs to be updated but that the times have
1215 * already been set. The access and modified times are taken from the second
1216 * and third parameters; the node change time is always taken from the current
1217 * time. If waitfor is set, then wait for the disk write of the node to
1218 * complete.
1219 */
1c79356b
A
1220
1221int
91447636 1222synthfs_update(struct vnode *vp, struct timeval *access, struct timeval *modify, __unused int waitfor)
1c79356b 1223{
1c79356b 1224 struct synthfsnode *sp = VTOS(vp);
91447636 1225 struct timeval tv;
1c79356b
A
1226
1227 DBG_ASSERT(sp != NULL);
1c79356b
A
1228
1229 if (((sp->s_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) != 0) &&
91447636
A
1230 !(VTOVFS(vp)->mnt_flag & MNT_RDONLY)) {
1231 if (sp->s_nodeflags & IN_ACCESS) sp->s_accesstime = *access;
1232 if (sp->s_nodeflags & IN_UPDATE) sp->s_modificationtime = *modify;
1233 if (sp->s_nodeflags & IN_CHANGE) {
1234
1235 microtime(&tv);
1236 sp->s_changetime = tv;
1237 }
1c79356b
A
1238 };
1239
1240 /* After the updates are finished, clear the flags */
1241 sp->s_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
1242
1c79356b
A
1243 return 0;
1244}
1245
1246
1247
1248/*******************************************************************************************
1249
1250 Utility/housekeeping vnode operations:
1251
1252 ******************************************************************************************/
1253
1254
1c79356b
A
1255/*
1256#
1257#% inactive vp L U U
1258#
91447636 1259 vnop_inactive {
1c79356b
A
1260 IN struct vnode *vp;
1261 IN struct proc *p;
1262
1263*/
1264
1265int
1266synthfs_inactive(ap)
91447636 1267struct vnop_inactive_args /* {
1c79356b 1268 struct vnode *a_vp;
91447636 1269 vfs_context_t a_context;
1c79356b
A
1270} */ *ap;
1271{
1272 struct vnode *vp = ap->a_vp;
1c79356b
A
1273 struct synthfsnode *sp = VTOS(vp);
1274 struct timeval tv;
1275
91447636 1276#if DEBUG
1c79356b
A
1277 if (vp->v_usecount != 0)
1278 DBG_VOP(("synthfs_inactive: bad usecount = %d\n", vp->v_usecount ));
91447636 1279#endif
1c79356b
A
1280
1281 /*
1282 * Ignore nodes related to stale file handles.
1283 */
1284 if (vp->v_type == VNON)
1285 goto out;
1286
1287 /* This is sort of silly but might make sense in the future: */
1288 if (sp->s_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) {
91447636
A
1289 microtime(&tv);
1290 synthfs_update(vp, &tv, &tv, 0);
1c79356b
A
1291 }
1292
1293out:
1c79356b
A
1294 /*
1295 * If we are done with the inode, reclaim it
1296 * so that it can be reused immediately.
1297 */
1298 if (vp->v_type == VNON) {
91447636 1299 vnode_recycle(vp);
1c79356b
A
1300 };
1301
1302 return 0;
1303}
1304
1305
1306
1307/*
1308 * synthfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
1309 *
1310 * Locking policy: ignored
1311 */
1312int
1313synthfs_reclaim(ap)
91447636 1314 struct vnop_reclaim_args /* { struct vnode *a_vp; struct proc *a_p; } */ *ap;
1c79356b
A
1315{
1316 struct vnode *vp = ap->a_vp;
1317 struct synthfsnode *sp = VTOS(vp);
1318 void *name = sp->s_name;
1319
1320 sp->s_name = NULL;
1321 FREE(name, M_TEMP);
1322
1323 vp->v_data = NULL;
1324 FREE((void *)sp, M_SYNTHFS);
1325
1326 return (0);
1327}