1*0a6a1f1dSLionel Sambuc /* $NetBSD: chfs_vnops.c,v 1.28 2015/04/20 23:03:09 riastradh Exp $ */
2d65f6f70SBen Gras
3d65f6f70SBen Gras /*-
4d65f6f70SBen Gras * Copyright (c) 2010 Department of Software Engineering,
5d65f6f70SBen Gras * University of Szeged, Hungary
6d65f6f70SBen Gras * Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
7d65f6f70SBen Gras * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
8d65f6f70SBen Gras * All rights reserved.
9d65f6f70SBen Gras *
10d65f6f70SBen Gras * This code is derived from software contributed to The NetBSD Foundation
11d65f6f70SBen Gras * by the Department of Software Engineering, University of Szeged, Hungary
12d65f6f70SBen Gras *
13d65f6f70SBen Gras * Redistribution and use in source and binary forms, with or without
14d65f6f70SBen Gras * modification, are permitted provided that the following conditions
15d65f6f70SBen Gras * are met:
16d65f6f70SBen Gras * 1. Redistributions of source code must retain the above copyright
17d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer.
18d65f6f70SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
19d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer in the
20d65f6f70SBen Gras * documentation and/or other materials provided with the distribution.
21d65f6f70SBen Gras *
22d65f6f70SBen Gras * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23d65f6f70SBen Gras * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24d65f6f70SBen Gras * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25d65f6f70SBen Gras * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26d65f6f70SBen Gras * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27d65f6f70SBen Gras * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28d65f6f70SBen Gras * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29d65f6f70SBen Gras * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30d65f6f70SBen Gras * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31d65f6f70SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32d65f6f70SBen Gras * SUCH DAMAGE.
33d65f6f70SBen Gras */
34d65f6f70SBen Gras
35d65f6f70SBen Gras #include <sys/param.h>
36d65f6f70SBen Gras #include <miscfs/specfs/specdev.h>
37d65f6f70SBen Gras #include <miscfs/fifofs/fifo.h>
38d65f6f70SBen Gras #include <miscfs/genfs/genfs.h>
39d65f6f70SBen Gras #include <ufs/ufs/dir.h>
40d65f6f70SBen Gras #include <ufs/ufs/ufs_extern.h>
41d65f6f70SBen Gras #include <uvm/uvm.h>
42d65f6f70SBen Gras #include <sys/namei.h>
43d65f6f70SBen Gras #include <sys/stat.h>
44d65f6f70SBen Gras #include <sys/fcntl.h>
45d65f6f70SBen Gras #include <sys/buf.h>
46d65f6f70SBen Gras #include <sys/fstrans.h>
47d65f6f70SBen Gras #include <sys/vnode.h>
48d65f6f70SBen Gras
49d65f6f70SBen Gras #include "chfs.h"
50d65f6f70SBen Gras
51d65f6f70SBen Gras #define READ_S "chfs_read"
52d65f6f70SBen Gras
53d65f6f70SBen Gras int
chfs_lookup(void * v)54d65f6f70SBen Gras chfs_lookup(void *v)
55d65f6f70SBen Gras {
56*0a6a1f1dSLionel Sambuc struct vnode *dvp = ((struct vop_lookup_v2_args *) v)->a_dvp;
57*0a6a1f1dSLionel Sambuc struct vnode **vpp = ((struct vop_lookup_v2_args *) v)->a_vpp;
58*0a6a1f1dSLionel Sambuc struct componentname *cnp = ((struct vop_lookup_v2_args *) v)->a_cnp;
59d65f6f70SBen Gras
60d65f6f70SBen Gras int error;
61d65f6f70SBen Gras struct chfs_inode* ip;
62d65f6f70SBen Gras struct ufsmount* ump;
63d65f6f70SBen Gras struct chfs_mount* chmp;
64d65f6f70SBen Gras struct chfs_vnode_cache* chvc;
65d65f6f70SBen Gras struct chfs_dirent* fd;
66d65f6f70SBen Gras
67d65f6f70SBen Gras dbg("lookup(): %s\n", cnp->cn_nameptr);
68d65f6f70SBen Gras
69d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(dvp));
70d65f6f70SBen Gras
71d65f6f70SBen Gras *vpp = NULL;
72d65f6f70SBen Gras
7384d9c625SLionel Sambuc /* Check accessibility of requested node as a first step. */
74d65f6f70SBen Gras error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred);
75d65f6f70SBen Gras if (error != 0) {
76d65f6f70SBen Gras goto out;
77d65f6f70SBen Gras }
78d65f6f70SBen Gras
7984d9c625SLionel Sambuc /* If requesting the last path component on a read-only file system
8084d9c625SLionel Sambuc * with a write operation, deny it. */
81d65f6f70SBen Gras if ((cnp->cn_flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY)
82d65f6f70SBen Gras && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
83d65f6f70SBen Gras error = EROFS;
84d65f6f70SBen Gras goto out;
85d65f6f70SBen Gras }
86d65f6f70SBen Gras
8784d9c625SLionel Sambuc /* Avoid doing a linear scan of the directory if the requested
8884d9c625SLionel Sambuc * directory/name couple is already in the cache. */
8984d9c625SLionel Sambuc if (cache_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen,
9084d9c625SLionel Sambuc cnp->cn_nameiop, cnp->cn_flags, NULL, vpp)) {
91*0a6a1f1dSLionel Sambuc return (*vpp == NULLVP ? ENOENT : 0);
92d65f6f70SBen Gras }
93d65f6f70SBen Gras
94d65f6f70SBen Gras ip = VTOI(dvp);
95d65f6f70SBen Gras ump = VFSTOUFS(dvp->v_mount);
96d65f6f70SBen Gras chmp = ump->um_chfs;
97d65f6f70SBen Gras if (ip->ino == 0) {
98d65f6f70SBen Gras ip->ino = ++chmp->chm_max_vno;
99d65f6f70SBen Gras }
100d65f6f70SBen Gras mutex_enter(&chmp->chm_lock_vnocache);
101d65f6f70SBen Gras chvc = chfs_vnode_cache_get(chmp, ip->ino);
102d65f6f70SBen Gras mutex_exit(&chmp->chm_lock_vnocache);
103d65f6f70SBen Gras
10484d9c625SLionel Sambuc /* We cannot be requesting the parent directory of the root node. */
10584d9c625SLionel Sambuc KASSERT(IMPLIES(ip->ch_type == CHT_DIR && chvc->pvno == chvc->vno,
106d65f6f70SBen Gras !(cnp->cn_flags & ISDOTDOT)));
107d65f6f70SBen Gras
108d65f6f70SBen Gras if (cnp->cn_flags & ISDOTDOT) {
109d65f6f70SBen Gras VOP_UNLOCK(dvp);
110d65f6f70SBen Gras error = VFS_VGET(dvp->v_mount, ip->chvc->pvno, vpp);
111d65f6f70SBen Gras vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
112d65f6f70SBen Gras } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
113d65f6f70SBen Gras vref(dvp);
114d65f6f70SBen Gras *vpp = dvp;
115d65f6f70SBen Gras error = 0;
116d65f6f70SBen Gras } else {
117d65f6f70SBen Gras fd = chfs_dir_lookup(ip, cnp);
118d65f6f70SBen Gras
119d65f6f70SBen Gras if (fd == NULL) {
120d65f6f70SBen Gras dbg("fd null\n");
12184d9c625SLionel Sambuc /* The entry was not found in the directory.
12284d9c625SLionel Sambuc * This is OK if we are creating or renaming an
12384d9c625SLionel Sambuc * entry and are working on the last component of
12484d9c625SLionel Sambuc * the path name. */
125d65f6f70SBen Gras if ((cnp->cn_flags & ISLASTCN) && (cnp->cn_nameiop == CREATE
126d65f6f70SBen Gras || cnp->cn_nameiop == RENAME)) {
127d65f6f70SBen Gras error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
128d65f6f70SBen Gras if (error) {
129d65f6f70SBen Gras dbg("after the entry was not found in dir\n");
130d65f6f70SBen Gras goto out;
131d65f6f70SBen Gras }
132d65f6f70SBen Gras
133d65f6f70SBen Gras dbg("return EJUSTRETURN\n");
134d65f6f70SBen Gras error = EJUSTRETURN;
135d65f6f70SBen Gras } else {
136d65f6f70SBen Gras error = ENOENT;
137d65f6f70SBen Gras }
138d65f6f70SBen Gras } else {
13984d9c625SLionel Sambuc /* If we are not at the last path component and
14084d9c625SLionel Sambuc * found a non-directory or non-link entry (which
14184d9c625SLionel Sambuc * may itself be pointing to a directory), raise
14284d9c625SLionel Sambuc * an error. */
14384d9c625SLionel Sambuc if ((fd->type != CHT_DIR && fd->type != CHT_LNK) && !(cnp->cn_flags
144d65f6f70SBen Gras & ISLASTCN)) {
145d65f6f70SBen Gras error = ENOTDIR;
146d65f6f70SBen Gras goto out;
147d65f6f70SBen Gras }
148d65f6f70SBen Gras
149d65f6f70SBen Gras dbg("vno@allocating new vnode: %llu\n",
150d65f6f70SBen Gras (unsigned long long)fd->vno);
151d65f6f70SBen Gras error = VFS_VGET(dvp->v_mount, fd->vno, vpp);
152d65f6f70SBen Gras }
153d65f6f70SBen Gras }
15484d9c625SLionel Sambuc /* Store the result of this lookup in the cache. Avoid this if the
15584d9c625SLionel Sambuc * request was for creation, as it does not improve timings on
15684d9c625SLionel Sambuc * emprical tests. */
15784d9c625SLionel Sambuc if (cnp->cn_nameiop != CREATE && (cnp->cn_flags & ISDOTDOT) == 0) {
15884d9c625SLionel Sambuc cache_enter(dvp, *vpp, cnp->cn_nameptr, cnp->cn_namelen,
15984d9c625SLionel Sambuc cnp->cn_flags);
16084d9c625SLionel Sambuc }
161d65f6f70SBen Gras
162d65f6f70SBen Gras out:
163*0a6a1f1dSLionel Sambuc /* If there were no errors, *vpp cannot be NULL. */
164*0a6a1f1dSLionel Sambuc KASSERT(IFF(error == 0, *vpp != NULL));
165d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(dvp));
166d65f6f70SBen Gras
167*0a6a1f1dSLionel Sambuc if (error)
168d65f6f70SBen Gras return error;
169*0a6a1f1dSLionel Sambuc if (*vpp != dvp)
170*0a6a1f1dSLionel Sambuc VOP_UNLOCK(*vpp);
171*0a6a1f1dSLionel Sambuc return 0;
172d65f6f70SBen Gras }
173d65f6f70SBen Gras
174d65f6f70SBen Gras /* --------------------------------------------------------------------- */
175d65f6f70SBen Gras
176d65f6f70SBen Gras int
chfs_create(void * v)177d65f6f70SBen Gras chfs_create(void *v)
178d65f6f70SBen Gras {
179*0a6a1f1dSLionel Sambuc struct vop_create_v3_args /* {
180d65f6f70SBen Gras struct vnode *a_dvp;
181d65f6f70SBen Gras struct vnode **a_vpp;
182d65f6f70SBen Gras struct componentname *a_cnp;
183d65f6f70SBen Gras struct vattr *a_vap;
184d65f6f70SBen Gras } */*ap = v;
185d65f6f70SBen Gras int error, mode;
186d65f6f70SBen Gras dbg("create()\n");
187d65f6f70SBen Gras
188d65f6f70SBen Gras mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
189d65f6f70SBen Gras
190d65f6f70SBen Gras if ((mode & IFMT) == 0) {
191d65f6f70SBen Gras if (ap->a_vap->va_type == VREG)
192d65f6f70SBen Gras mode |= IFREG;
193d65f6f70SBen Gras if (ap->a_vap->va_type == VSOCK)
194d65f6f70SBen Gras mode |= IFSOCK;
195d65f6f70SBen Gras }
196d65f6f70SBen Gras
197d65f6f70SBen Gras error = chfs_makeinode(mode, ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap->va_type);
198d65f6f70SBen Gras
199d65f6f70SBen Gras if (error) {
200d65f6f70SBen Gras dbg("error: %d\n", error);
201d65f6f70SBen Gras return error;
202d65f6f70SBen Gras }
203d65f6f70SBen Gras
204d65f6f70SBen Gras VN_KNOTE(ap->a_dvp, NOTE_WRITE);
205d65f6f70SBen Gras return 0;
206d65f6f70SBen Gras }
207d65f6f70SBen Gras /* --------------------------------------------------------------------- */
208d65f6f70SBen Gras
209d65f6f70SBen Gras int
chfs_mknod(void * v)210d65f6f70SBen Gras chfs_mknod(void *v)
211d65f6f70SBen Gras {
212*0a6a1f1dSLionel Sambuc struct vnode *dvp = ((struct vop_mknod_v3_args *) v)->a_dvp;
213*0a6a1f1dSLionel Sambuc struct vnode **vpp = ((struct vop_mknod_v3_args *) v)->a_vpp;
214*0a6a1f1dSLionel Sambuc struct componentname *cnp = ((struct vop_mknod_v3_args *) v)->a_cnp;
215*0a6a1f1dSLionel Sambuc struct vattr *vap = ((struct vop_mknod_v3_args *) v)->a_vap;
216d65f6f70SBen Gras int mode, err = 0;
217d65f6f70SBen Gras struct chfs_inode *ip;
218d65f6f70SBen Gras struct vnode *vp;
219d65f6f70SBen Gras
220d65f6f70SBen Gras struct ufsmount *ump;
221d65f6f70SBen Gras struct chfs_mount *chmp;
222d65f6f70SBen Gras
223d65f6f70SBen Gras struct chfs_full_dnode *fd;
224d65f6f70SBen Gras struct buf *bp;
225d65f6f70SBen Gras int len;
226d65f6f70SBen Gras dbg("mknod()\n");
227d65f6f70SBen Gras
228d65f6f70SBen Gras ump = VFSTOUFS(dvp->v_mount);
229d65f6f70SBen Gras chmp = ump->um_chfs;
230d65f6f70SBen Gras
23184d9c625SLionel Sambuc /* Check type of node. */
232d65f6f70SBen Gras if (vap->va_type != VBLK && vap->va_type != VCHR && vap->va_type != VFIFO)
233d65f6f70SBen Gras return EINVAL;
234d65f6f70SBen Gras
235d65f6f70SBen Gras vp = *vpp;
236d65f6f70SBen Gras
237d65f6f70SBen Gras mode = MAKEIMODE(vap->va_type, vap->va_mode);
238d65f6f70SBen Gras
239d65f6f70SBen Gras if ((mode & IFMT) == 0) {
240d65f6f70SBen Gras switch (vap->va_type) {
241d65f6f70SBen Gras case VBLK:
242d65f6f70SBen Gras mode |= IFBLK;
243d65f6f70SBen Gras break;
244d65f6f70SBen Gras case VCHR:
245d65f6f70SBen Gras mode |= IFCHR;
246d65f6f70SBen Gras break;
247d65f6f70SBen Gras case VFIFO:
248d65f6f70SBen Gras mode |= IFIFO;
249d65f6f70SBen Gras break;
250d65f6f70SBen Gras default:
251d65f6f70SBen Gras break;
252d65f6f70SBen Gras }
253d65f6f70SBen Gras }
254d65f6f70SBen Gras
25584d9c625SLionel Sambuc /* Create a new node. */
256d65f6f70SBen Gras err = chfs_makeinode(mode, dvp, &vp, cnp, vap->va_type);
257d65f6f70SBen Gras
258d65f6f70SBen Gras ip = VTOI(vp);
259d65f6f70SBen Gras if (vap->va_rdev != VNOVAL)
260d65f6f70SBen Gras ip->rdev = vap->va_rdev;
261d65f6f70SBen Gras
262d65f6f70SBen Gras if (vap->va_type == VFIFO)
263d65f6f70SBen Gras vp->v_op = chfs_fifoop_p;
264d65f6f70SBen Gras else {
265d65f6f70SBen Gras vp->v_op = chfs_specop_p;
266d65f6f70SBen Gras spec_node_init(vp, ip->rdev);
267d65f6f70SBen Gras }
268d65f6f70SBen Gras
269d65f6f70SBen Gras if (err)
270d65f6f70SBen Gras return err;
271d65f6f70SBen Gras
27284d9c625SLionel Sambuc /* Device is written out as a data node. */
273d65f6f70SBen Gras len = sizeof(dev_t);
274d65f6f70SBen Gras chfs_set_vnode_size(vp, len);
275d65f6f70SBen Gras bp = getiobuf(vp, true);
276d65f6f70SBen Gras bp->b_bufsize = bp->b_resid = len;
277d65f6f70SBen Gras bp->b_data = kmem_alloc(len, KM_SLEEP);
278d65f6f70SBen Gras memcpy(bp->b_data, &ip->rdev, len);
279d65f6f70SBen Gras bp->b_blkno = 0;
280d65f6f70SBen Gras
281d65f6f70SBen Gras fd = chfs_alloc_full_dnode();
282d65f6f70SBen Gras
283d65f6f70SBen Gras mutex_enter(&chmp->chm_lock_mountfields);
284d65f6f70SBen Gras
285d65f6f70SBen Gras err = chfs_write_flash_dnode(chmp, vp, bp, fd);
286d65f6f70SBen Gras if (err) {
287d65f6f70SBen Gras mutex_exit(&chmp->chm_lock_mountfields);
288d65f6f70SBen Gras kmem_free(bp->b_data, len);
289d65f6f70SBen Gras return err;
290d65f6f70SBen Gras }
291d65f6f70SBen Gras
29284d9c625SLionel Sambuc /* Add data node to the inode. */
293d65f6f70SBen Gras err = chfs_add_full_dnode_to_inode(chmp, ip, fd);
294d65f6f70SBen Gras if (err) {
295d65f6f70SBen Gras mutex_exit(&chmp->chm_lock_mountfields);
296d65f6f70SBen Gras kmem_free(bp->b_data, len);
297d65f6f70SBen Gras return err;
298d65f6f70SBen Gras }
299d65f6f70SBen Gras
300d65f6f70SBen Gras mutex_exit(&chmp->chm_lock_mountfields);
301d65f6f70SBen Gras
302d65f6f70SBen Gras *vpp = vp;
303d65f6f70SBen Gras kmem_free(bp->b_data, len);
304d65f6f70SBen Gras putiobuf(bp);
305d65f6f70SBen Gras
306d65f6f70SBen Gras return 0;
307d65f6f70SBen Gras }
308d65f6f70SBen Gras
309d65f6f70SBen Gras /* --------------------------------------------------------------------- */
310d65f6f70SBen Gras
311d65f6f70SBen Gras int
chfs_open(void * v)312d65f6f70SBen Gras chfs_open(void *v)
313d65f6f70SBen Gras {
314d65f6f70SBen Gras struct vnode *vp = ((struct vop_open_args *) v)->a_vp;
315d65f6f70SBen Gras int mode = ((struct vop_open_args *) v)->a_mode;
316d65f6f70SBen Gras dbg("open()\n");
317d65f6f70SBen Gras
318d65f6f70SBen Gras int error;
319d65f6f70SBen Gras struct chfs_inode *ip;
320d65f6f70SBen Gras
321d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(vp));
322d65f6f70SBen Gras
323d65f6f70SBen Gras ip = VTOI(vp);
324d65f6f70SBen Gras
325d65f6f70SBen Gras KASSERT(vp->v_size == ip->size);
326d65f6f70SBen Gras if (ip->chvc->nlink < 1) {
327d65f6f70SBen Gras error = ENOENT;
328d65f6f70SBen Gras goto out;
329d65f6f70SBen Gras }
330d65f6f70SBen Gras
33184d9c625SLionel Sambuc /* If the file is marked append-only, deny write requests. */
332d65f6f70SBen Gras if (ip->flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE)
333d65f6f70SBen Gras error = EPERM;
334d65f6f70SBen Gras else
335d65f6f70SBen Gras error = 0;
336d65f6f70SBen Gras
337d65f6f70SBen Gras out:
338d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(vp));
339d65f6f70SBen Gras return error;
340d65f6f70SBen Gras }
341d65f6f70SBen Gras
342d65f6f70SBen Gras /* --------------------------------------------------------------------- */
343d65f6f70SBen Gras
344d65f6f70SBen Gras int
chfs_close(void * v)345d65f6f70SBen Gras chfs_close(void *v)
346d65f6f70SBen Gras {
347d65f6f70SBen Gras struct vnode *vp = ((struct vop_close_args *) v)->a_vp;
348d65f6f70SBen Gras dbg("close()\n");
349d65f6f70SBen Gras
350d65f6f70SBen Gras struct chfs_inode *ip;
351d65f6f70SBen Gras
352d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(vp));
353d65f6f70SBen Gras
354d65f6f70SBen Gras ip = VTOI(vp);
355d65f6f70SBen Gras
356d65f6f70SBen Gras if (ip->chvc->nlink > 0) {
357d65f6f70SBen Gras chfs_update(vp, NULL, NULL, UPDATE_CLOSE);
358d65f6f70SBen Gras }
359d65f6f70SBen Gras
360d65f6f70SBen Gras return 0;
361d65f6f70SBen Gras }
362d65f6f70SBen Gras
363d65f6f70SBen Gras /* --------------------------------------------------------------------- */
364d65f6f70SBen Gras
365d65f6f70SBen Gras int
chfs_access(void * v)366d65f6f70SBen Gras chfs_access(void *v)
367d65f6f70SBen Gras {
368d65f6f70SBen Gras struct vnode *vp = ((struct vop_access_args *) v)->a_vp;
369d65f6f70SBen Gras int mode = ((struct vop_access_args *) v)->a_mode;
370d65f6f70SBen Gras kauth_cred_t cred = ((struct vop_access_args *) v)->a_cred;
371d65f6f70SBen Gras
372d65f6f70SBen Gras dbg("access()\n");
373d65f6f70SBen Gras struct chfs_inode *ip = VTOI(vp);
374d65f6f70SBen Gras
375d65f6f70SBen Gras if (mode & VWRITE) {
376d65f6f70SBen Gras switch (vp->v_type) {
377d65f6f70SBen Gras case VLNK:
378d65f6f70SBen Gras case VDIR:
379d65f6f70SBen Gras case VREG:
380d65f6f70SBen Gras if (vp->v_mount->mnt_flag & MNT_RDONLY)
381d65f6f70SBen Gras return (EROFS);
382d65f6f70SBen Gras break;
383d65f6f70SBen Gras case VBLK:
384d65f6f70SBen Gras case VCHR:
385d65f6f70SBen Gras case VSOCK:
386d65f6f70SBen Gras case VFIFO:
387d65f6f70SBen Gras break;
388d65f6f70SBen Gras default:
389d65f6f70SBen Gras break;
390d65f6f70SBen Gras }
391d65f6f70SBen Gras }
392d65f6f70SBen Gras
393d65f6f70SBen Gras if (mode & VWRITE && ip->flags & IMMUTABLE)
394d65f6f70SBen Gras return (EPERM);
395d65f6f70SBen Gras
39684d9c625SLionel Sambuc return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
39784d9c625SLionel Sambuc ip->mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
39884d9c625SLionel Sambuc ip->mode & ALLPERMS, ip->uid, ip->gid, mode, cred));
399d65f6f70SBen Gras }
400d65f6f70SBen Gras
401d65f6f70SBen Gras /* --------------------------------------------------------------------- */
402d65f6f70SBen Gras
403d65f6f70SBen Gras int
chfs_getattr(void * v)404d65f6f70SBen Gras chfs_getattr(void *v)
405d65f6f70SBen Gras {
406d65f6f70SBen Gras struct vnode *vp = ((struct vop_getattr_args *) v)->a_vp;
407d65f6f70SBen Gras struct vattr *vap = ((struct vop_getattr_args *) v)->a_vap;
408d65f6f70SBen Gras
409d65f6f70SBen Gras struct chfs_inode *ip = VTOI(vp);
410d65f6f70SBen Gras dbg("getattr()\n");
411d65f6f70SBen Gras
412d65f6f70SBen Gras KASSERT(vp->v_size == ip->size);
413d65f6f70SBen Gras
414d65f6f70SBen Gras vattr_null(vap);
415d65f6f70SBen Gras CHFS_ITIMES(ip, NULL, NULL, NULL);
416d65f6f70SBen Gras
41784d9c625SLionel Sambuc vap->va_type = CHTTOVT(ip->ch_type);
418d65f6f70SBen Gras vap->va_mode = ip->mode & ALLPERMS;
419d65f6f70SBen Gras vap->va_nlink = ip->chvc->nlink;
420d65f6f70SBen Gras vap->va_uid = ip->uid;
421d65f6f70SBen Gras vap->va_gid = ip->gid;
422d65f6f70SBen Gras vap->va_fsid = ip->dev;
423d65f6f70SBen Gras vap->va_fileid = ip->ino;
424d65f6f70SBen Gras vap->va_size = ip->size;
425d65f6f70SBen Gras vap->va_blocksize = PAGE_SIZE;
426d65f6f70SBen Gras vap->va_atime.tv_sec = ip->atime;
427d65f6f70SBen Gras vap->va_atime.tv_nsec = 0;
428d65f6f70SBen Gras vap->va_mtime.tv_sec = ip->mtime;
429d65f6f70SBen Gras vap->va_mtime.tv_nsec = 0;
430d65f6f70SBen Gras vap->va_ctime.tv_sec = ip->ctime;
431d65f6f70SBen Gras vap->va_ctime.tv_nsec = 0;
432d65f6f70SBen Gras vap->va_gen = ip->version;
433d65f6f70SBen Gras vap->va_flags = ip->flags;
434d65f6f70SBen Gras vap->va_rdev = ip->rdev;
435d65f6f70SBen Gras vap->va_bytes = round_page(ip->size);
436d65f6f70SBen Gras vap->va_filerev = VNOVAL;
437d65f6f70SBen Gras vap->va_vaflags = 0;
438d65f6f70SBen Gras vap->va_spare = VNOVAL;
439d65f6f70SBen Gras
440d65f6f70SBen Gras return 0;
441d65f6f70SBen Gras }
442d65f6f70SBen Gras
443d65f6f70SBen Gras /* --------------------------------------------------------------------- */
444d65f6f70SBen Gras
445d65f6f70SBen Gras /* Note: modelled after tmpfs's same function */
446d65f6f70SBen Gras
447d65f6f70SBen Gras int
chfs_setattr(void * v)448d65f6f70SBen Gras chfs_setattr(void *v)
449d65f6f70SBen Gras {
450d65f6f70SBen Gras struct vnode *vp = ((struct vop_setattr_args *) v)->a_vp;
451d65f6f70SBen Gras struct vattr *vap = ((struct vop_setattr_args *) v)->a_vap;
452d65f6f70SBen Gras kauth_cred_t cred = ((struct vop_setattr_args *) v)->a_cred;
453d65f6f70SBen Gras
454d65f6f70SBen Gras struct chfs_inode *ip;
455d65f6f70SBen Gras struct ufsmount *ump = VFSTOUFS(vp->v_mount);
456d65f6f70SBen Gras struct chfs_mount *chmp = ump->um_chfs;
457d65f6f70SBen Gras int error = 0;
458d65f6f70SBen Gras
459d65f6f70SBen Gras dbg("setattr()\n");
460d65f6f70SBen Gras
461d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(vp));
462d65f6f70SBen Gras ip = VTOI(vp);
463d65f6f70SBen Gras
464d65f6f70SBen Gras /* Abort if any unsettable attribute is given. */
465d65f6f70SBen Gras if (vap->va_type != VNON || vap->va_nlink != VNOVAL ||
466d65f6f70SBen Gras vap->va_fsid != VNOVAL || vap->va_fileid != VNOVAL ||
467d65f6f70SBen Gras vap->va_blocksize != VNOVAL /*|| GOODTIME(&vap->va_ctime)*/ ||
468d65f6f70SBen Gras vap->va_gen != VNOVAL || vap->va_rdev != VNOVAL ||
469d65f6f70SBen Gras vap->va_bytes != VNOVAL) {
470d65f6f70SBen Gras return EINVAL;
471d65f6f70SBen Gras }
472d65f6f70SBen Gras
47384d9c625SLionel Sambuc /* set flags */
47484d9c625SLionel Sambuc if (error == 0 && (vap->va_flags != VNOVAL)) {
475d65f6f70SBen Gras error = chfs_chflags(vp, vap->va_flags, cred);
47684d9c625SLionel Sambuc return error;
47784d9c625SLionel Sambuc }
478d65f6f70SBen Gras
47984d9c625SLionel Sambuc if (ip->flags & (IMMUTABLE | APPEND)) {
48084d9c625SLionel Sambuc error = EPERM;
48184d9c625SLionel Sambuc return error;
48284d9c625SLionel Sambuc }
48384d9c625SLionel Sambuc
48484d9c625SLionel Sambuc /* set size */
48584d9c625SLionel Sambuc if (error == 0 && (vap->va_size != VNOVAL)) {
486d65f6f70SBen Gras error = chfs_chsize(vp, vap->va_size, cred);
48784d9c625SLionel Sambuc if (error)
48884d9c625SLionel Sambuc return error;
48984d9c625SLionel Sambuc }
490d65f6f70SBen Gras
49184d9c625SLionel Sambuc /* set owner */
49284d9c625SLionel Sambuc if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL)) {
493d65f6f70SBen Gras error = chfs_chown(vp, vap->va_uid, vap->va_gid, cred);
49484d9c625SLionel Sambuc if (error)
49584d9c625SLionel Sambuc return error;
49684d9c625SLionel Sambuc }
497d65f6f70SBen Gras
49884d9c625SLionel Sambuc /* set mode */
49984d9c625SLionel Sambuc if (error == 0 && (vap->va_mode != VNOVAL)) {
500d65f6f70SBen Gras error = chfs_chmod(vp, vap->va_mode, cred);
50184d9c625SLionel Sambuc if (error)
50284d9c625SLionel Sambuc return error;
50384d9c625SLionel Sambuc }
504d65f6f70SBen Gras
50584d9c625SLionel Sambuc /* set time */
506d65f6f70SBen Gras if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
50784d9c625SLionel Sambuc error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
50884d9c625SLionel Sambuc NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->uid, cred));
509d65f6f70SBen Gras if (error)
510d65f6f70SBen Gras return error;
511d65f6f70SBen Gras if (vap->va_atime.tv_sec != VNOVAL)
512d65f6f70SBen Gras ip->iflag |= IN_ACCESS;
513d65f6f70SBen Gras if (vap->va_mtime.tv_sec != VNOVAL)
514d65f6f70SBen Gras ip->iflag |= IN_CHANGE | IN_UPDATE;
515d65f6f70SBen Gras error = chfs_update(vp,
516d65f6f70SBen Gras &vap->va_atime, &vap->va_mtime, UPDATE_WAIT);
517d65f6f70SBen Gras if (error)
518d65f6f70SBen Gras return error;
519d65f6f70SBen Gras }
520d65f6f70SBen Gras
52184d9c625SLionel Sambuc /* Write it out. */
522d65f6f70SBen Gras mutex_enter(&chmp->chm_lock_mountfields);
523d65f6f70SBen Gras error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
524d65f6f70SBen Gras mutex_exit(&chmp->chm_lock_mountfields);
525d65f6f70SBen Gras
526d65f6f70SBen Gras return error;
527d65f6f70SBen Gras }
528d65f6f70SBen Gras
529d65f6f70SBen Gras int
chfs_chmod(struct vnode * vp,int mode,kauth_cred_t cred)530d65f6f70SBen Gras chfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred)
531d65f6f70SBen Gras {
532d65f6f70SBen Gras struct chfs_inode *ip = VTOI(vp);
533d65f6f70SBen Gras int error;
534d65f6f70SBen Gras dbg("chmod\n");
535d65f6f70SBen Gras
53684d9c625SLionel Sambuc error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
53784d9c625SLionel Sambuc NULL, genfs_can_chmod(vp->v_type, cred, ip->uid, ip->gid, mode));
538d65f6f70SBen Gras if (error)
539d65f6f70SBen Gras return error;
540d65f6f70SBen Gras ip->mode &= ~ALLPERMS;
541d65f6f70SBen Gras ip->mode |= (mode & ALLPERMS);
542d65f6f70SBen Gras ip->iflag |= IN_CHANGE;
543d65f6f70SBen Gras
544d65f6f70SBen Gras error = chfs_update(vp, NULL, NULL, UPDATE_WAIT);
545d65f6f70SBen Gras if (error)
546d65f6f70SBen Gras return error;
547d65f6f70SBen Gras
548d65f6f70SBen Gras return 0;
549d65f6f70SBen Gras }
550d65f6f70SBen Gras
551d65f6f70SBen Gras int
chfs_chown(struct vnode * vp,uid_t uid,gid_t gid,kauth_cred_t cred)552d65f6f70SBen Gras chfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred)
553d65f6f70SBen Gras {
554d65f6f70SBen Gras struct chfs_inode *ip = VTOI(vp);
555d65f6f70SBen Gras int error;
556d65f6f70SBen Gras dbg("chown\n");
557d65f6f70SBen Gras
558d65f6f70SBen Gras if (uid == (uid_t)VNOVAL)
559d65f6f70SBen Gras uid = ip->uid;
560d65f6f70SBen Gras if (gid == (gid_t)VNOVAL)
561d65f6f70SBen Gras gid = ip->gid;
562d65f6f70SBen Gras
56384d9c625SLionel Sambuc error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
56484d9c625SLionel Sambuc NULL, genfs_can_chown(cred, ip->uid, ip->gid, uid, gid));
565d65f6f70SBen Gras if (error)
566d65f6f70SBen Gras return error;
567d65f6f70SBen Gras
568d65f6f70SBen Gras ip->gid = gid;
569d65f6f70SBen Gras ip->uid = uid;
570d65f6f70SBen Gras ip->iflag |= IN_CHANGE;
571d65f6f70SBen Gras
572d65f6f70SBen Gras error = chfs_update(vp, NULL, NULL, UPDATE_WAIT);
573d65f6f70SBen Gras if (error)
574d65f6f70SBen Gras return error;
575d65f6f70SBen Gras
576d65f6f70SBen Gras return 0;
577d65f6f70SBen Gras }
578d65f6f70SBen Gras
579d65f6f70SBen Gras
580d65f6f70SBen Gras /* --------------------------------------------------------------------- */
581d65f6f70SBen Gras /* calculates ((off_t)blk * chmp->chm_chm_fs_bsize) */
58284d9c625SLionel Sambuc #define chfs_lblktosize(chmp, blk) \
583d65f6f70SBen Gras (((off_t)(blk)) << (chmp)->chm_fs_bshift)
584d65f6f70SBen Gras
585d65f6f70SBen Gras /* calculates (loc % chmp->chm_chm_fs_bsize) */
58684d9c625SLionel Sambuc #define chfs_blkoff(chmp, loc) \
587d65f6f70SBen Gras ((loc) & (chmp)->chm_fs_qbmask)
588d65f6f70SBen Gras
589d65f6f70SBen Gras /* calculates (loc / chmp->chm_chm_fs_bsize) */
59084d9c625SLionel Sambuc #define chfs_lblkno(chmp, loc) \
591d65f6f70SBen Gras ((loc) >> (chmp)->chm_fs_bshift)
592d65f6f70SBen Gras
593d65f6f70SBen Gras /* calculates roundup(size, chmp->chm_chm_fs_fsize) */
59484d9c625SLionel Sambuc #define chfs_fragroundup(chmp, size) \
595d65f6f70SBen Gras (((size) + (chmp)->chm_fs_qfmask) & (chmp)->chm_fs_fmask)
596d65f6f70SBen Gras
59784d9c625SLionel Sambuc #define chfs_blksize(chmp, ip, lbn) \
59884d9c625SLionel Sambuc (((lbn) >= UFS_NDADDR || (ip)->size >= chfs_lblktosize(chmp, (lbn) + 1)) \
599d65f6f70SBen Gras ? (chmp)->chm_fs_bsize \
60084d9c625SLionel Sambuc : (chfs_fragroundup(chmp, chfs_blkoff(chmp, (ip)->size))))
601d65f6f70SBen Gras
602d65f6f70SBen Gras /* calculates roundup(size, chmp->chm_chm_fs_bsize) */
60384d9c625SLionel Sambuc #define chfs_blkroundup(chmp, size) \
604d65f6f70SBen Gras (((size) + (chmp)->chm_fs_qbmask) & (chmp)->chm_fs_bmask)
605d65f6f70SBen Gras
60684d9c625SLionel Sambuc /* from ffs read */
607d65f6f70SBen Gras int
chfs_read(void * v)608d65f6f70SBen Gras chfs_read(void *v)
609d65f6f70SBen Gras {
610d65f6f70SBen Gras struct vop_read_args /* {
611d65f6f70SBen Gras struct vnode *a_vp;
612d65f6f70SBen Gras struct uio *a_uio;
613d65f6f70SBen Gras int a_ioflag;
614d65f6f70SBen Gras kauth_cred_t a_cred;
615d65f6f70SBen Gras } */ *ap = v;
616d65f6f70SBen Gras struct vnode *vp;
617d65f6f70SBen Gras struct chfs_inode *ip;
618d65f6f70SBen Gras struct uio *uio;
619d65f6f70SBen Gras struct ufsmount *ump;
620d65f6f70SBen Gras struct buf *bp;
621d65f6f70SBen Gras struct chfs_mount *chmp;
622d65f6f70SBen Gras daddr_t lbn, nextlbn;
623d65f6f70SBen Gras off_t bytesinfile;
624d65f6f70SBen Gras long size, xfersize, blkoffset;
625d65f6f70SBen Gras int error, ioflag;
626d65f6f70SBen Gras vsize_t bytelen;
627d65f6f70SBen Gras bool usepc = false;
628d65f6f70SBen Gras
629d65f6f70SBen Gras dbg("chfs_read\n");
630d65f6f70SBen Gras
631d65f6f70SBen Gras vp = ap->a_vp;
632d65f6f70SBen Gras ip = VTOI(vp);
633d65f6f70SBen Gras ump = ip->ump;
634d65f6f70SBen Gras uio = ap->a_uio;
635d65f6f70SBen Gras ioflag = ap->a_ioflag;
636d65f6f70SBen Gras error = 0;
637d65f6f70SBen Gras
638d65f6f70SBen Gras dbg("ip->size:%llu\n", (unsigned long long)ip->size);
639d65f6f70SBen Gras
640d65f6f70SBen Gras #ifdef DIAGNOSTIC
641d65f6f70SBen Gras if (uio->uio_rw != UIO_READ)
642d65f6f70SBen Gras panic("%s: mode", READ_S);
643d65f6f70SBen Gras
644d65f6f70SBen Gras if (vp->v_type == VLNK) {
645d65f6f70SBen Gras if (ip->size < ump->um_maxsymlinklen)
646d65f6f70SBen Gras panic("%s: short symlink", READ_S);
647d65f6f70SBen Gras } else if (vp->v_type != VREG && vp->v_type != VDIR)
648d65f6f70SBen Gras panic("%s: type %d", READ_S, vp->v_type);
649d65f6f70SBen Gras #endif
650d65f6f70SBen Gras chmp = ip->chmp;
651d65f6f70SBen Gras if ((u_int64_t)uio->uio_offset > ump->um_maxfilesize)
652d65f6f70SBen Gras return (EFBIG);
653d65f6f70SBen Gras if (uio->uio_resid == 0)
654d65f6f70SBen Gras return (0);
655d65f6f70SBen Gras
656d65f6f70SBen Gras fstrans_start(vp->v_mount, FSTRANS_SHARED);
657d65f6f70SBen Gras
658d65f6f70SBen Gras if (uio->uio_offset >= ip->size)
659d65f6f70SBen Gras goto out;
660d65f6f70SBen Gras
661d65f6f70SBen Gras usepc = vp->v_type == VREG;
662d65f6f70SBen Gras bytelen = 0;
663d65f6f70SBen Gras if (usepc) {
664d65f6f70SBen Gras const int advice = IO_ADV_DECODE(ap->a_ioflag);
665d65f6f70SBen Gras
666d65f6f70SBen Gras while (uio->uio_resid > 0) {
667d65f6f70SBen Gras if (ioflag & IO_DIRECT) {
668d65f6f70SBen Gras genfs_directio(vp, uio, ioflag);
669d65f6f70SBen Gras }
670d65f6f70SBen Gras bytelen = MIN(ip->size - uio->uio_offset,
671d65f6f70SBen Gras uio->uio_resid);
672d65f6f70SBen Gras if (bytelen == 0)
673d65f6f70SBen Gras break;
674d65f6f70SBen Gras error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
675d65f6f70SBen Gras UBC_READ | UBC_PARTIALOK |
676d65f6f70SBen Gras (UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0));
677d65f6f70SBen Gras if (error)
678d65f6f70SBen Gras break;
679d65f6f70SBen Gras
680d65f6f70SBen Gras }
681d65f6f70SBen Gras goto out;
682d65f6f70SBen Gras }
683d65f6f70SBen Gras
684d65f6f70SBen Gras dbg("start reading\n");
685d65f6f70SBen Gras for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
686d65f6f70SBen Gras bytesinfile = ip->size - uio->uio_offset;
687d65f6f70SBen Gras if (bytesinfile <= 0)
688d65f6f70SBen Gras break;
68984d9c625SLionel Sambuc lbn = chfs_lblkno(chmp, uio->uio_offset);
690d65f6f70SBen Gras nextlbn = lbn + 1;
69184d9c625SLionel Sambuc size = chfs_blksize(chmp, ip, lbn);
69284d9c625SLionel Sambuc blkoffset = chfs_blkoff(chmp, uio->uio_offset);
693d65f6f70SBen Gras xfersize = MIN(MIN(chmp->chm_fs_bsize - blkoffset, uio->uio_resid),
694d65f6f70SBen Gras bytesinfile);
695d65f6f70SBen Gras
69684d9c625SLionel Sambuc if (chfs_lblktosize(chmp, nextlbn) >= ip->size) {
697*0a6a1f1dSLionel Sambuc error = bread(vp, lbn, size, 0, &bp);
698d65f6f70SBen Gras dbg("after bread\n");
699d65f6f70SBen Gras } else {
70084d9c625SLionel Sambuc int nextsize = chfs_blksize(chmp, ip, nextlbn);
701d65f6f70SBen Gras dbg("size: %ld\n", size);
702d65f6f70SBen Gras error = breadn(vp, lbn,
703*0a6a1f1dSLionel Sambuc size, &nextlbn, &nextsize, 1, 0, &bp);
704d65f6f70SBen Gras dbg("after breadN\n");
705d65f6f70SBen Gras }
706d65f6f70SBen Gras if (error)
707d65f6f70SBen Gras break;
708d65f6f70SBen Gras
709d65f6f70SBen Gras /*
710d65f6f70SBen Gras * We should only get non-zero b_resid when an I/O error
711d65f6f70SBen Gras * has occurred, which should cause us to break above.
712d65f6f70SBen Gras * However, if the short read did not cause an error,
713d65f6f70SBen Gras * then we want to ensure that we do not uiomove bad
714d65f6f70SBen Gras * or uninitialized data.
715d65f6f70SBen Gras */
716d65f6f70SBen Gras size -= bp->b_resid;
717d65f6f70SBen Gras if (size < xfersize) {
718d65f6f70SBen Gras if (size == 0)
719d65f6f70SBen Gras break;
720d65f6f70SBen Gras xfersize = size;
721d65f6f70SBen Gras }
722d65f6f70SBen Gras dbg("uiomove\n");
723d65f6f70SBen Gras error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
724d65f6f70SBen Gras if (error)
725d65f6f70SBen Gras break;
726d65f6f70SBen Gras brelse(bp, 0);
727d65f6f70SBen Gras }
72884d9c625SLionel Sambuc
729d65f6f70SBen Gras if (bp != NULL)
730d65f6f70SBen Gras brelse(bp, 0);
731d65f6f70SBen Gras
732d65f6f70SBen Gras out:
73384d9c625SLionel Sambuc // FIXME HACK
73484d9c625SLionel Sambuc ip->ino = ip->chvc->vno;
73584d9c625SLionel Sambuc
736d65f6f70SBen Gras if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
737d65f6f70SBen Gras ip->iflag |= IN_ACCESS;
738d65f6f70SBen Gras if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) {
739d65f6f70SBen Gras if (error) {
740d65f6f70SBen Gras fstrans_done(vp->v_mount);
741d65f6f70SBen Gras return error;
742d65f6f70SBen Gras }
743d65f6f70SBen Gras error = chfs_update(vp, NULL, NULL, UPDATE_WAIT);
744d65f6f70SBen Gras }
745d65f6f70SBen Gras }
746d65f6f70SBen Gras
747d65f6f70SBen Gras dbg("[END]\n");
748d65f6f70SBen Gras fstrans_done(vp->v_mount);
74984d9c625SLionel Sambuc
750d65f6f70SBen Gras return (error);
751d65f6f70SBen Gras }
752d65f6f70SBen Gras
753d65f6f70SBen Gras
754d65f6f70SBen Gras /* --------------------------------------------------------------------- */
755d65f6f70SBen Gras
756d65f6f70SBen Gras /* from ffs write */
757d65f6f70SBen Gras int
chfs_write(void * v)758d65f6f70SBen Gras chfs_write(void *v)
759d65f6f70SBen Gras {
760d65f6f70SBen Gras struct vop_write_args /* {
761d65f6f70SBen Gras struct vnode *a_vp;
762d65f6f70SBen Gras struct uio *a_uio;
763d65f6f70SBen Gras int a_ioflag;
764d65f6f70SBen Gras kauth_cred_t a_cred;
765d65f6f70SBen Gras } */ *ap = v;
766d65f6f70SBen Gras struct vnode *vp ;
767d65f6f70SBen Gras struct uio *uio;
768d65f6f70SBen Gras struct chfs_inode *ip;
769d65f6f70SBen Gras struct chfs_mount *chmp;
770d65f6f70SBen Gras struct lwp *l;
771d65f6f70SBen Gras kauth_cred_t cred;
772d65f6f70SBen Gras off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize;
773d65f6f70SBen Gras int blkoffset, error, flags, ioflag, resid;
774d65f6f70SBen Gras int aflag;
775d65f6f70SBen Gras int extended=0;
776d65f6f70SBen Gras vsize_t bytelen;
777d65f6f70SBen Gras bool async;
778d65f6f70SBen Gras struct ufsmount *ump;
779d65f6f70SBen Gras
780d65f6f70SBen Gras
781d65f6f70SBen Gras cred = ap->a_cred;
782d65f6f70SBen Gras ioflag = ap->a_ioflag;
783d65f6f70SBen Gras uio = ap->a_uio;
784d65f6f70SBen Gras vp = ap->a_vp;
785d65f6f70SBen Gras ip = VTOI(vp);
786d65f6f70SBen Gras ump = ip->ump;
787d65f6f70SBen Gras
788d65f6f70SBen Gras dbg("write\n");
789d65f6f70SBen Gras
790d65f6f70SBen Gras KASSERT(vp->v_size == ip->size);
791d65f6f70SBen Gras
792d65f6f70SBen Gras switch (vp->v_type) {
793d65f6f70SBen Gras case VREG:
794d65f6f70SBen Gras if (ioflag & IO_APPEND)
795d65f6f70SBen Gras uio->uio_offset = ip->size;
796d65f6f70SBen Gras if ((ip->flags & APPEND) && uio->uio_offset != ip->size)
797d65f6f70SBen Gras return (EPERM);
798d65f6f70SBen Gras /* FALLTHROUGH */
799d65f6f70SBen Gras case VLNK:
800d65f6f70SBen Gras break;
801d65f6f70SBen Gras case VDIR:
802d65f6f70SBen Gras if ((ioflag & IO_SYNC) == 0)
803d65f6f70SBen Gras panic("chfs_write: nonsync dir write");
804d65f6f70SBen Gras break;
805d65f6f70SBen Gras default:
806d65f6f70SBen Gras panic("chfs_write: type");
807d65f6f70SBen Gras }
808d65f6f70SBen Gras
809d65f6f70SBen Gras chmp = ip->chmp;
810d65f6f70SBen Gras if (uio->uio_offset < 0 ||
811d65f6f70SBen Gras (u_int64_t)uio->uio_offset +
812d65f6f70SBen Gras uio->uio_resid > ump->um_maxfilesize) {
813d65f6f70SBen Gras dbg("uio->uio_offset = %lld | uio->uio_offset + "
814d65f6f70SBen Gras "uio->uio_resid (%llu) > ump->um_maxfilesize (%lld)\n",
815d65f6f70SBen Gras (long long)uio->uio_offset,
816d65f6f70SBen Gras (uint64_t)uio->uio_offset + uio->uio_resid,
817d65f6f70SBen Gras (long long)ump->um_maxfilesize);
818d65f6f70SBen Gras return (EFBIG);
819d65f6f70SBen Gras }
820d65f6f70SBen Gras /*
821d65f6f70SBen Gras * Maybe this should be above the vnode op call, but so long as
822d65f6f70SBen Gras * file servers have no limits, I don't think it matters.
823d65f6f70SBen Gras */
824d65f6f70SBen Gras l = curlwp;
825d65f6f70SBen Gras if (vp->v_type == VREG && l &&
826d65f6f70SBen Gras uio->uio_offset + uio->uio_resid >
827d65f6f70SBen Gras l->l_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
828d65f6f70SBen Gras mutex_enter(proc_lock);
829d65f6f70SBen Gras psignal(l->l_proc, SIGXFSZ);
830d65f6f70SBen Gras mutex_exit(proc_lock);
831d65f6f70SBen Gras return (EFBIG);
832d65f6f70SBen Gras }
833d65f6f70SBen Gras if (uio->uio_resid == 0)
834d65f6f70SBen Gras return (0);
835d65f6f70SBen Gras
836d65f6f70SBen Gras fstrans_start(vp->v_mount, FSTRANS_SHARED);
837d65f6f70SBen Gras
838d65f6f70SBen Gras flags = ioflag & IO_SYNC ? B_SYNC : 0;
839d65f6f70SBen Gras async = vp->v_mount->mnt_flag & MNT_ASYNC;
840d65f6f70SBen Gras origoff = uio->uio_offset;
841d65f6f70SBen Gras resid = uio->uio_resid;
842d65f6f70SBen Gras osize = ip->size;
843d65f6f70SBen Gras error = 0;
844d65f6f70SBen Gras
84584d9c625SLionel Sambuc preallocoff = round_page(chfs_blkroundup(chmp,
846d65f6f70SBen Gras MAX(osize, uio->uio_offset)));
847d65f6f70SBen Gras aflag = ioflag & IO_SYNC ? B_SYNC : 0;
848d65f6f70SBen Gras nsize = MAX(osize, uio->uio_offset + uio->uio_resid);
84984d9c625SLionel Sambuc endallocoff = nsize - chfs_blkoff(chmp, nsize);
850d65f6f70SBen Gras
851d65f6f70SBen Gras /*
852d65f6f70SBen Gras * if we're increasing the file size, deal with expanding
853d65f6f70SBen Gras * the fragment if there is one.
854d65f6f70SBen Gras */
855d65f6f70SBen Gras
85684d9c625SLionel Sambuc if (nsize > osize && chfs_lblkno(chmp, osize) < UFS_NDADDR &&
85784d9c625SLionel Sambuc chfs_lblkno(chmp, osize) != chfs_lblkno(chmp, nsize) &&
85884d9c625SLionel Sambuc chfs_blkroundup(chmp, osize) != osize) {
859d65f6f70SBen Gras off_t eob;
860d65f6f70SBen Gras
86184d9c625SLionel Sambuc eob = chfs_blkroundup(chmp, osize);
862d65f6f70SBen Gras uvm_vnp_setwritesize(vp, eob);
863d65f6f70SBen Gras error = ufs_balloc_range(vp, osize, eob - osize, cred, aflag);
864d65f6f70SBen Gras if (error)
865d65f6f70SBen Gras goto out;
866d65f6f70SBen Gras if (flags & B_SYNC) {
867d65f6f70SBen Gras mutex_enter(vp->v_interlock);
868d65f6f70SBen Gras VOP_PUTPAGES(vp,
869d65f6f70SBen Gras trunc_page(osize & chmp->chm_fs_bmask),
870d65f6f70SBen Gras round_page(eob),
871d65f6f70SBen Gras PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
872d65f6f70SBen Gras }
873d65f6f70SBen Gras }
874d65f6f70SBen Gras
875d65f6f70SBen Gras while (uio->uio_resid > 0) {
876d65f6f70SBen Gras int ubc_flags = UBC_WRITE;
877d65f6f70SBen Gras bool overwrite; /* if we're overwrite a whole block */
878d65f6f70SBen Gras off_t newoff;
879d65f6f70SBen Gras
880d65f6f70SBen Gras if (ioflag & IO_DIRECT) {
881d65f6f70SBen Gras genfs_directio(vp, uio, ioflag | IO_JOURNALLOCKED);
882d65f6f70SBen Gras }
883d65f6f70SBen Gras
884d65f6f70SBen Gras oldoff = uio->uio_offset;
88584d9c625SLionel Sambuc blkoffset = chfs_blkoff(chmp, uio->uio_offset);
886d65f6f70SBen Gras bytelen = MIN(chmp->chm_fs_bsize - blkoffset, uio->uio_resid);
887d65f6f70SBen Gras if (bytelen == 0) {
888d65f6f70SBen Gras break;
889d65f6f70SBen Gras }
890d65f6f70SBen Gras
891d65f6f70SBen Gras /*
892d65f6f70SBen Gras * if we're filling in a hole, allocate the blocks now and
893d65f6f70SBen Gras * initialize the pages first. if we're extending the file,
894d65f6f70SBen Gras * we can safely allocate blocks without initializing pages
895d65f6f70SBen Gras * since the new blocks will be inaccessible until the write
896d65f6f70SBen Gras * is complete.
897d65f6f70SBen Gras */
898d65f6f70SBen Gras overwrite = uio->uio_offset >= preallocoff &&
899d65f6f70SBen Gras uio->uio_offset < endallocoff;
900d65f6f70SBen Gras if (!overwrite && (vp->v_vflag & VV_MAPPED) == 0 &&
90184d9c625SLionel Sambuc chfs_blkoff(chmp, uio->uio_offset) == 0 &&
902d65f6f70SBen Gras (uio->uio_offset & PAGE_MASK) == 0) {
903d65f6f70SBen Gras vsize_t len;
904d65f6f70SBen Gras
905d65f6f70SBen Gras len = trunc_page(bytelen);
90684d9c625SLionel Sambuc len -= chfs_blkoff(chmp, len);
907d65f6f70SBen Gras if (len > 0) {
908d65f6f70SBen Gras overwrite = true;
909d65f6f70SBen Gras bytelen = len;
910d65f6f70SBen Gras }
911d65f6f70SBen Gras }
912d65f6f70SBen Gras
913d65f6f70SBen Gras newoff = oldoff + bytelen;
914d65f6f70SBen Gras if (vp->v_size < newoff) {
915d65f6f70SBen Gras uvm_vnp_setwritesize(vp, newoff);
916d65f6f70SBen Gras }
917d65f6f70SBen Gras
918d65f6f70SBen Gras if (!overwrite) {
919d65f6f70SBen Gras error = ufs_balloc_range(vp, uio->uio_offset, bytelen,
920d65f6f70SBen Gras cred, aflag);
921d65f6f70SBen Gras if (error)
922d65f6f70SBen Gras break;
923d65f6f70SBen Gras } else {
924d65f6f70SBen Gras genfs_node_wrlock(vp);
925d65f6f70SBen Gras error = GOP_ALLOC(vp, uio->uio_offset, bytelen,
926d65f6f70SBen Gras aflag, cred);
927d65f6f70SBen Gras genfs_node_unlock(vp);
928d65f6f70SBen Gras if (error)
929d65f6f70SBen Gras break;
930d65f6f70SBen Gras ubc_flags |= UBC_FAULTBUSY;
931d65f6f70SBen Gras }
932d65f6f70SBen Gras
933d65f6f70SBen Gras /*
934d65f6f70SBen Gras * copy the data.
935d65f6f70SBen Gras */
936d65f6f70SBen Gras
937d65f6f70SBen Gras ubc_flags |= UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0;
938d65f6f70SBen Gras error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
939d65f6f70SBen Gras IO_ADV_DECODE(ioflag), ubc_flags);
940d65f6f70SBen Gras
941d65f6f70SBen Gras /*
942d65f6f70SBen Gras * update UVM's notion of the size now that we've
943d65f6f70SBen Gras * copied the data into the vnode's pages.
944d65f6f70SBen Gras *
945d65f6f70SBen Gras * we should update the size even when uiomove failed.
946d65f6f70SBen Gras */
947d65f6f70SBen Gras
948d65f6f70SBen Gras if (vp->v_size < newoff) {
949d65f6f70SBen Gras uvm_vnp_setsize(vp, newoff);
950d65f6f70SBen Gras extended = 1;
951d65f6f70SBen Gras }
952d65f6f70SBen Gras
953d65f6f70SBen Gras if (error)
954d65f6f70SBen Gras break;
955d65f6f70SBen Gras
956d65f6f70SBen Gras /*
957d65f6f70SBen Gras * flush what we just wrote if necessary.
958d65f6f70SBen Gras * XXXUBC simplistic async flushing.
959d65f6f70SBen Gras */
960d65f6f70SBen Gras
961d65f6f70SBen Gras if (!async && oldoff >> 16 != uio->uio_offset >> 16) {
962d65f6f70SBen Gras mutex_enter(vp->v_interlock);
963d65f6f70SBen Gras error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16,
964d65f6f70SBen Gras (uio->uio_offset >> 16) << 16,
965d65f6f70SBen Gras PGO_CLEANIT | PGO_JOURNALLOCKED);
966d65f6f70SBen Gras if (error)
967d65f6f70SBen Gras break;
968d65f6f70SBen Gras }
969d65f6f70SBen Gras }
970d65f6f70SBen Gras out:
971d65f6f70SBen Gras if (error == 0 && ioflag & IO_SYNC) {
972d65f6f70SBen Gras mutex_enter(vp->v_interlock);
973d65f6f70SBen Gras error = VOP_PUTPAGES(vp,
974d65f6f70SBen Gras trunc_page(origoff & chmp->chm_fs_bmask),
97584d9c625SLionel Sambuc round_page(chfs_blkroundup(chmp, uio->uio_offset)),
976d65f6f70SBen Gras PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
977d65f6f70SBen Gras }
978d65f6f70SBen Gras ip->iflag |= IN_CHANGE | IN_UPDATE;
97984d9c625SLionel Sambuc if (resid > uio->uio_resid && ap->a_cred) {
98084d9c625SLionel Sambuc if (ip->mode & ISUID) {
98184d9c625SLionel Sambuc if (kauth_authorize_vnode(ap->a_cred,
98284d9c625SLionel Sambuc KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0)
98384d9c625SLionel Sambuc ip->mode &= ~ISUID;
98484d9c625SLionel Sambuc }
98584d9c625SLionel Sambuc
98684d9c625SLionel Sambuc if (ip->mode & ISGID) {
98784d9c625SLionel Sambuc if (kauth_authorize_vnode(ap->a_cred,
98884d9c625SLionel Sambuc KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0)
98984d9c625SLionel Sambuc ip->mode &= ~ISGID;
99084d9c625SLionel Sambuc }
991d65f6f70SBen Gras }
992d65f6f70SBen Gras if (resid > uio->uio_resid)
993d65f6f70SBen Gras VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
994d65f6f70SBen Gras if (error) {
995d65f6f70SBen Gras (void) UFS_TRUNCATE(vp, osize, ioflag & IO_SYNC, ap->a_cred);
996d65f6f70SBen Gras uio->uio_offset -= resid - uio->uio_resid;
997d65f6f70SBen Gras uio->uio_resid = resid;
998d65f6f70SBen Gras } else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC)
999d65f6f70SBen Gras error = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
1000d65f6f70SBen Gras
100184d9c625SLionel Sambuc //FIXME HACK
1002d65f6f70SBen Gras chfs_set_vnode_size(vp, vp->v_size);
1003d65f6f70SBen Gras
1004d65f6f70SBen Gras
1005d65f6f70SBen Gras KASSERT(vp->v_size == ip->size);
1006d65f6f70SBen Gras fstrans_done(vp->v_mount);
1007d65f6f70SBen Gras
1008d65f6f70SBen Gras mutex_enter(&chmp->chm_lock_mountfields);
1009d65f6f70SBen Gras error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
1010d65f6f70SBen Gras mutex_exit(&chmp->chm_lock_mountfields);
1011d65f6f70SBen Gras
1012d65f6f70SBen Gras return (error);
1013d65f6f70SBen Gras }
1014d65f6f70SBen Gras
1015d65f6f70SBen Gras
1016d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1017d65f6f70SBen Gras
1018d65f6f70SBen Gras int
chfs_fsync(void * v)1019d65f6f70SBen Gras chfs_fsync(void *v)
1020d65f6f70SBen Gras {
1021d65f6f70SBen Gras struct vop_fsync_args /* {
1022d65f6f70SBen Gras struct vnode *a_vp;
1023d65f6f70SBen Gras kauth_cred_t a_cred;
1024d65f6f70SBen Gras int a_flags;
1025d65f6f70SBen Gras off_t offlo;
1026d65f6f70SBen Gras off_t offhi;
1027d65f6f70SBen Gras } */ *ap = v;
1028d65f6f70SBen Gras struct vnode *vp = ap->a_vp;
1029d65f6f70SBen Gras
1030d65f6f70SBen Gras if (ap->a_flags & FSYNC_CACHE) {
1031d65f6f70SBen Gras return ENODEV;
1032d65f6f70SBen Gras }
103384d9c625SLionel Sambuc vflushbuf(vp, ap->a_flags);
1034d65f6f70SBen Gras
1035d65f6f70SBen Gras return 0;
1036d65f6f70SBen Gras }
1037d65f6f70SBen Gras
1038d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1039d65f6f70SBen Gras
1040d65f6f70SBen Gras int
chfs_remove(void * v)1041d65f6f70SBen Gras chfs_remove(void *v)
1042d65f6f70SBen Gras {
1043d65f6f70SBen Gras struct vnode *dvp = ((struct vop_remove_args *) v)->a_dvp;
1044d65f6f70SBen Gras struct vnode *vp = ((struct vop_remove_args *) v)->a_vp;
1045d65f6f70SBen Gras struct componentname *cnp = (((struct vop_remove_args *) v)->a_cnp);
1046d65f6f70SBen Gras dbg("remove\n");
1047d65f6f70SBen Gras
1048d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(dvp));
1049d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(vp));
1050d65f6f70SBen Gras
1051d65f6f70SBen Gras struct chfs_inode *ip = VTOI(vp);
1052d65f6f70SBen Gras struct chfs_inode *parent = VTOI(dvp);
1053d65f6f70SBen Gras int error = 0;
1054d65f6f70SBen Gras
105584d9c625SLionel Sambuc if (vp->v_type == VDIR || (ip->flags & (IMMUTABLE | APPEND)) ||
105684d9c625SLionel Sambuc (parent->flags & APPEND)) {
105784d9c625SLionel Sambuc error = EPERM;
105884d9c625SLionel Sambuc goto out;
105984d9c625SLionel Sambuc }
106084d9c625SLionel Sambuc
1061d65f6f70SBen Gras KASSERT(ip->chvc->vno != ip->chvc->pvno);
1062d65f6f70SBen Gras
1063d65f6f70SBen Gras error = chfs_do_unlink(ip,
1064d65f6f70SBen Gras parent, cnp->cn_nameptr, cnp->cn_namelen);
1065d65f6f70SBen Gras
106684d9c625SLionel Sambuc out:
1067d65f6f70SBen Gras vput(dvp);
1068d65f6f70SBen Gras vput(vp);
1069d65f6f70SBen Gras
1070d65f6f70SBen Gras return error;
1071d65f6f70SBen Gras }
1072d65f6f70SBen Gras
1073d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1074d65f6f70SBen Gras
1075d65f6f70SBen Gras int
chfs_link(void * v)1076d65f6f70SBen Gras chfs_link(void *v)
1077d65f6f70SBen Gras {
1078*0a6a1f1dSLionel Sambuc struct vnode *dvp = ((struct vop_link_v2_args *) v)->a_dvp;
1079*0a6a1f1dSLionel Sambuc struct vnode *vp = ((struct vop_link_v2_args *) v)->a_vp;
1080*0a6a1f1dSLionel Sambuc struct componentname *cnp = ((struct vop_link_v2_args *) v)->a_cnp;
1081d65f6f70SBen Gras
1082d65f6f70SBen Gras struct chfs_inode *ip, *parent;
1083d65f6f70SBen Gras int error = 0;
1084d65f6f70SBen Gras
1085d65f6f70SBen Gras if (vp->v_type == VDIR) {
1086d65f6f70SBen Gras VOP_ABORTOP(dvp, cnp);
1087d65f6f70SBen Gras error = EISDIR;
1088d65f6f70SBen Gras goto out;
1089d65f6f70SBen Gras }
1090d65f6f70SBen Gras if (dvp->v_mount != vp->v_mount) {
1091d65f6f70SBen Gras VOP_ABORTOP(dvp, cnp);
1092d65f6f70SBen Gras error = EXDEV;
1093d65f6f70SBen Gras goto out;
1094d65f6f70SBen Gras }
1095d65f6f70SBen Gras if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE))) {
1096d65f6f70SBen Gras VOP_ABORTOP(dvp, cnp);
1097d65f6f70SBen Gras goto out;
1098d65f6f70SBen Gras }
1099d65f6f70SBen Gras
1100d65f6f70SBen Gras parent = VTOI(dvp);
1101d65f6f70SBen Gras ip = VTOI(vp);
1102d65f6f70SBen Gras
1103d65f6f70SBen Gras error = chfs_do_link(ip,
110484d9c625SLionel Sambuc parent, cnp->cn_nameptr, cnp->cn_namelen, ip->ch_type);
1105d65f6f70SBen Gras
1106d65f6f70SBen Gras if (dvp != vp)
1107d65f6f70SBen Gras VOP_UNLOCK(vp);
1108d65f6f70SBen Gras out:
1109d65f6f70SBen Gras return error;
1110d65f6f70SBen Gras }
1111d65f6f70SBen Gras
1112d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1113d65f6f70SBen Gras
1114d65f6f70SBen Gras int
chfs_rename(void * v)1115d65f6f70SBen Gras chfs_rename(void *v)
1116d65f6f70SBen Gras {
1117d65f6f70SBen Gras struct vnode *fdvp = ((struct vop_rename_args *) v)->a_fdvp;
1118d65f6f70SBen Gras struct vnode *fvp = ((struct vop_rename_args *) v)->a_fvp;
1119d65f6f70SBen Gras struct componentname *fcnp = ((struct vop_rename_args *) v)->a_fcnp;
1120d65f6f70SBen Gras struct vnode *tdvp = ((struct vop_rename_args *) v)->a_tdvp;
1121d65f6f70SBen Gras struct vnode *tvp = ((struct vop_rename_args *) v)->a_tvp;
1122d65f6f70SBen Gras struct componentname *tcnp = ((struct vop_rename_args *) v)->a_tcnp;
1123d65f6f70SBen Gras
1124d65f6f70SBen Gras struct chfs_inode *oldparent, *old;
1125d65f6f70SBen Gras struct chfs_inode *newparent;
112684d9c625SLionel Sambuc struct chfs_dirent *fd;
1127d65f6f70SBen Gras struct chfs_inode *ip;
1128d65f6f70SBen Gras int error = 0;
1129d65f6f70SBen Gras dbg("rename\n");
1130d65f6f70SBen Gras
1131d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(tdvp));
1132d65f6f70SBen Gras KASSERT(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
1133d65f6f70SBen Gras
1134d65f6f70SBen Gras oldparent = VTOI(fdvp);
1135d65f6f70SBen Gras old = VTOI(fvp);
1136d65f6f70SBen Gras newparent = VTOI(tdvp);
1137d65f6f70SBen Gras if (tvp) {
1138d65f6f70SBen Gras dbg("tvp not null\n");
1139d65f6f70SBen Gras ip = VTOI(tvp);
1140d65f6f70SBen Gras if (tvp->v_type == VDIR) {
1141d65f6f70SBen Gras TAILQ_FOREACH(fd, &ip->dents, fds) {
1142d65f6f70SBen Gras if (fd->vno) {
1143d65f6f70SBen Gras error = ENOTEMPTY;
1144d65f6f70SBen Gras goto out_unlocked;
1145d65f6f70SBen Gras }
1146d65f6f70SBen Gras }
1147d65f6f70SBen Gras }
1148d65f6f70SBen Gras error = chfs_do_unlink(ip,
1149d65f6f70SBen Gras newparent, tcnp->cn_nameptr, tcnp->cn_namelen);
1150d65f6f70SBen Gras vput(tvp);
1151d65f6f70SBen Gras }
1152d65f6f70SBen Gras VFS_VGET(tdvp->v_mount, old->ino, &tvp);
1153d65f6f70SBen Gras ip = VTOI(tvp);
1154d65f6f70SBen Gras
115584d9c625SLionel Sambuc /* link new */
1156d65f6f70SBen Gras error = chfs_do_link(ip,
115784d9c625SLionel Sambuc newparent, tcnp->cn_nameptr, tcnp->cn_namelen, ip->ch_type);
115884d9c625SLionel Sambuc /* remove old */
1159d65f6f70SBen Gras error = chfs_do_unlink(old,
1160d65f6f70SBen Gras oldparent, fcnp->cn_nameptr, fcnp->cn_namelen);
1161d65f6f70SBen Gras
1162d65f6f70SBen Gras out_unlocked:
116384d9c625SLionel Sambuc /* Release target nodes. */
1164d65f6f70SBen Gras if (tdvp == tvp)
1165d65f6f70SBen Gras vrele(tdvp);
1166d65f6f70SBen Gras else
1167d65f6f70SBen Gras vput(tdvp);
1168d65f6f70SBen Gras if (tvp != NULL)
1169d65f6f70SBen Gras vput(tvp);
1170d65f6f70SBen Gras
117184d9c625SLionel Sambuc /* Release source nodes. */
1172d65f6f70SBen Gras vrele(fdvp);
1173d65f6f70SBen Gras vrele(fvp);
1174d65f6f70SBen Gras
1175d65f6f70SBen Gras return error;
1176d65f6f70SBen Gras }
1177d65f6f70SBen Gras
1178d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1179d65f6f70SBen Gras
1180d65f6f70SBen Gras int
chfs_mkdir(void * v)1181d65f6f70SBen Gras chfs_mkdir(void *v)
1182d65f6f70SBen Gras {
1183*0a6a1f1dSLionel Sambuc struct vnode *dvp = ((struct vop_mkdir_v3_args *) v)->a_dvp;
1184*0a6a1f1dSLionel Sambuc struct vnode **vpp = ((struct vop_mkdir_v3_args *)v)->a_vpp;
1185*0a6a1f1dSLionel Sambuc struct componentname *cnp = ((struct vop_mkdir_v3_args *) v)->a_cnp;
1186*0a6a1f1dSLionel Sambuc struct vattr *vap = ((struct vop_mkdir_v3_args *) v)->a_vap;
1187d65f6f70SBen Gras dbg("mkdir()\n");
1188d65f6f70SBen Gras
1189d65f6f70SBen Gras int mode;
1190d65f6f70SBen Gras
1191d65f6f70SBen Gras mode = vap->va_mode & ACCESSPERMS;
1192d65f6f70SBen Gras if ((mode & IFMT) == 0) {
1193d65f6f70SBen Gras mode |= IFDIR;
1194d65f6f70SBen Gras }
1195d65f6f70SBen Gras
1196d65f6f70SBen Gras KASSERT(vap->va_type == VDIR);
1197d65f6f70SBen Gras
1198d65f6f70SBen Gras return chfs_makeinode(mode, dvp, vpp, cnp, VDIR);
1199d65f6f70SBen Gras }
1200d65f6f70SBen Gras
1201d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1202d65f6f70SBen Gras
1203d65f6f70SBen Gras int
chfs_rmdir(void * v)1204d65f6f70SBen Gras chfs_rmdir(void *v)
1205d65f6f70SBen Gras {
1206d65f6f70SBen Gras struct vnode *dvp = ((struct vop_rmdir_args *) v)->a_dvp;
1207d65f6f70SBen Gras struct vnode *vp = ((struct vop_rmdir_args *) v)->a_vp;
1208d65f6f70SBen Gras struct componentname *cnp = ((struct vop_rmdir_args *) v)->a_cnp;
1209d65f6f70SBen Gras dbg("rmdir()\n");
1210d65f6f70SBen Gras
1211d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(dvp));
1212d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(vp));
1213d65f6f70SBen Gras
1214d65f6f70SBen Gras struct chfs_inode *ip = VTOI(vp);
1215d65f6f70SBen Gras struct chfs_inode *parent = VTOI(dvp);
1216d65f6f70SBen Gras struct chfs_dirent *fd;
1217d65f6f70SBen Gras int error = 0;
1218d65f6f70SBen Gras
1219d65f6f70SBen Gras if (vp->v_type != VDIR) {
1220d65f6f70SBen Gras error = ENOTDIR;
1221d65f6f70SBen Gras goto out;
1222d65f6f70SBen Gras }
1223d65f6f70SBen Gras
1224d65f6f70SBen Gras KASSERT(ip->chvc->vno != ip->chvc->pvno);
1225d65f6f70SBen Gras
1226d65f6f70SBen Gras TAILQ_FOREACH(fd, &ip->dents, fds) {
1227d65f6f70SBen Gras if (fd->vno) {
1228d65f6f70SBen Gras error = ENOTEMPTY;
1229d65f6f70SBen Gras goto out;
1230d65f6f70SBen Gras }
1231d65f6f70SBen Gras }
1232d65f6f70SBen Gras
1233d65f6f70SBen Gras error = chfs_do_unlink(ip,
1234d65f6f70SBen Gras parent, cnp->cn_nameptr, cnp->cn_namelen);
1235d65f6f70SBen Gras
1236d65f6f70SBen Gras out:
1237d65f6f70SBen Gras vput(dvp);
1238d65f6f70SBen Gras vput(vp);
1239d65f6f70SBen Gras
1240d65f6f70SBen Gras return error;
1241d65f6f70SBen Gras }
1242d65f6f70SBen Gras
1243d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1244d65f6f70SBen Gras
1245d65f6f70SBen Gras int
chfs_symlink(void * v)1246d65f6f70SBen Gras chfs_symlink(void *v)
1247d65f6f70SBen Gras {
1248*0a6a1f1dSLionel Sambuc struct vnode *dvp = ((struct vop_symlink_v3_args *) v)->a_dvp;
1249*0a6a1f1dSLionel Sambuc struct vnode **vpp = ((struct vop_symlink_v3_args *) v)->a_vpp;
1250*0a6a1f1dSLionel Sambuc struct componentname *cnp = ((struct vop_symlink_v3_args *) v)->a_cnp;
1251*0a6a1f1dSLionel Sambuc struct vattr *vap = ((struct vop_symlink_v3_args *) v)->a_vap;
1252*0a6a1f1dSLionel Sambuc char *target = ((struct vop_symlink_v3_args *) v)->a_target;
1253d65f6f70SBen Gras
1254d65f6f70SBen Gras struct ufsmount *ump;
1255d65f6f70SBen Gras struct chfs_mount *chmp;
1256d65f6f70SBen Gras struct vnode *vp;
1257d65f6f70SBen Gras struct chfs_inode *ip;
1258d65f6f70SBen Gras int len, err;
1259d65f6f70SBen Gras struct chfs_full_dnode *fd;
1260d65f6f70SBen Gras struct buf *bp;
1261d65f6f70SBen Gras dbg("symlink()\n");
1262d65f6f70SBen Gras
1263d65f6f70SBen Gras ump = VFSTOUFS(dvp->v_mount);
1264d65f6f70SBen Gras chmp = ump->um_chfs;
1265d65f6f70SBen Gras
1266d65f6f70SBen Gras err = chfs_makeinode(IFLNK | vap->va_mode, dvp, vpp, cnp, VLNK);
1267d65f6f70SBen Gras if (err)
1268d65f6f70SBen Gras return (err);
1269d65f6f70SBen Gras VN_KNOTE(dvp, NOTE_WRITE);
1270d65f6f70SBen Gras vp = *vpp;
1271d65f6f70SBen Gras len = strlen(target);
1272d65f6f70SBen Gras ip = VTOI(vp);
1273d65f6f70SBen Gras /* TODO max symlink len instead of "100" */
1274d65f6f70SBen Gras if (len < 100) {
127584d9c625SLionel Sambuc /* symlink path stored as a data node */
1276d65f6f70SBen Gras ip->target = kmem_alloc(len, KM_SLEEP);
1277d65f6f70SBen Gras memcpy(ip->target, target, len);
1278d65f6f70SBen Gras chfs_set_vnode_size(vp, len);
1279d65f6f70SBen Gras ip->iflag |= IN_CHANGE | IN_UPDATE;
1280d65f6f70SBen Gras
1281d65f6f70SBen Gras bp = getiobuf(vp, true);
1282d65f6f70SBen Gras bp->b_bufsize = bp->b_resid = len;
1283d65f6f70SBen Gras bp->b_data = kmem_alloc(len, KM_SLEEP);
1284d65f6f70SBen Gras memcpy(bp->b_data, target, len);
1285d65f6f70SBen Gras bp->b_blkno = 0;
1286d65f6f70SBen Gras
1287d65f6f70SBen Gras fd = chfs_alloc_full_dnode();
1288d65f6f70SBen Gras
1289d65f6f70SBen Gras mutex_enter(&chmp->chm_lock_mountfields);
1290d65f6f70SBen Gras
129184d9c625SLionel Sambuc /* write out the data node */
1292d65f6f70SBen Gras err = chfs_write_flash_dnode(chmp, vp, bp, fd);
1293d65f6f70SBen Gras if (err) {
1294d65f6f70SBen Gras mutex_exit(&chmp->chm_lock_mountfields);
1295d65f6f70SBen Gras goto out;
1296d65f6f70SBen Gras }
1297d65f6f70SBen Gras
129884d9c625SLionel Sambuc /* add it to the inode */
1299d65f6f70SBen Gras err = chfs_add_full_dnode_to_inode(chmp, ip, fd);
1300d65f6f70SBen Gras if (err) {
1301d65f6f70SBen Gras mutex_exit(&chmp->chm_lock_mountfields);
1302d65f6f70SBen Gras goto out;
1303d65f6f70SBen Gras }
1304d65f6f70SBen Gras
1305d65f6f70SBen Gras mutex_exit(&chmp->chm_lock_mountfields);
1306d65f6f70SBen Gras
1307d65f6f70SBen Gras kmem_free(bp->b_data, len);
1308d65f6f70SBen Gras putiobuf(bp);
1309d65f6f70SBen Gras
1310d65f6f70SBen Gras uvm_vnp_setsize(vp, len);
1311d65f6f70SBen Gras } else {
1312*0a6a1f1dSLionel Sambuc err = ufs_bufio(UIO_WRITE, vp, target, len, (off_t)0,
1313*0a6a1f1dSLionel Sambuc IO_NODELOCKED, cnp->cn_cred, (size_t *)0, NULL);
1314d65f6f70SBen Gras }
1315d65f6f70SBen Gras
1316d65f6f70SBen Gras out:
1317d65f6f70SBen Gras if (err)
1318*0a6a1f1dSLionel Sambuc vrele(vp);
1319d65f6f70SBen Gras
1320d65f6f70SBen Gras return (err);
1321d65f6f70SBen Gras }
1322d65f6f70SBen Gras
1323d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1324d65f6f70SBen Gras
1325d65f6f70SBen Gras int
chfs_readdir(void * v)1326d65f6f70SBen Gras chfs_readdir(void *v)
1327d65f6f70SBen Gras {
1328d65f6f70SBen Gras struct vnode *vp = ((struct vop_readdir_args *) v)->a_vp;
1329d65f6f70SBen Gras struct uio *uio = ((struct vop_readdir_args *) v)->a_uio;
1330d65f6f70SBen Gras int *eofflag = ((struct vop_readdir_args *) v)->a_eofflag;
1331d65f6f70SBen Gras
1332d65f6f70SBen Gras int error = 0;
1333d65f6f70SBen Gras off_t skip, offset;
1334d65f6f70SBen Gras struct chfs_inode *ip;
1335d65f6f70SBen Gras struct chfs_dirent *fd;
1336d65f6f70SBen Gras
1337d65f6f70SBen Gras struct ufsmount *ump;
1338d65f6f70SBen Gras struct chfs_mount *chmp;
1339d65f6f70SBen Gras struct chfs_vnode_cache *chvc;
1340d65f6f70SBen Gras
1341d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(vp));
1342d65f6f70SBen Gras
1343d65f6f70SBen Gras /* This operation only makes sense on directory nodes. */
1344d65f6f70SBen Gras if (vp->v_type != VDIR) {
1345d65f6f70SBen Gras error = ENOTDIR;
1346d65f6f70SBen Gras goto out;
1347d65f6f70SBen Gras }
1348d65f6f70SBen Gras
1349d65f6f70SBen Gras ip = VTOI(vp);
1350d65f6f70SBen Gras
1351d65f6f70SBen Gras /* uiomove in chfs_filldir automatically increments the
1352d65f6f70SBen Gras * uio_offset by an arbitrary size, so we discard any change
1353d65f6f70SBen Gras * to uio_offset and set it to our own value on return
1354d65f6f70SBen Gras */
1355d65f6f70SBen Gras offset = uio->uio_offset;
1356d65f6f70SBen Gras
135784d9c625SLionel Sambuc /* Add this entry. */
1358d65f6f70SBen Gras if (offset == CHFS_OFFSET_DOT) {
135984d9c625SLionel Sambuc error = chfs_filldir(uio, ip->ino, ".", 1, CHT_DIR);
1360d65f6f70SBen Gras if (error == -1) {
1361d65f6f70SBen Gras error = 0;
1362d65f6f70SBen Gras goto outok;
1363d65f6f70SBen Gras } else if (error != 0)
1364d65f6f70SBen Gras goto outok;
1365d65f6f70SBen Gras
1366d65f6f70SBen Gras offset = CHFS_OFFSET_DOTDOT;
1367d65f6f70SBen Gras }
1368d65f6f70SBen Gras
136984d9c625SLionel Sambuc /* Add parent entry. */
1370d65f6f70SBen Gras if (offset == CHFS_OFFSET_DOTDOT) {
1371d65f6f70SBen Gras ump = VFSTOUFS(vp->v_mount);
1372d65f6f70SBen Gras chmp = ump->um_chfs;
1373d65f6f70SBen Gras mutex_enter(&chmp->chm_lock_vnocache);
1374d65f6f70SBen Gras chvc = chfs_vnode_cache_get(chmp, ip->ino);
1375d65f6f70SBen Gras mutex_exit(&chmp->chm_lock_vnocache);
1376d65f6f70SBen Gras
137784d9c625SLionel Sambuc error = chfs_filldir(uio, chvc->pvno, "..", 2, CHT_DIR);
1378d65f6f70SBen Gras if (error == -1) {
1379d65f6f70SBen Gras error = 0;
1380d65f6f70SBen Gras goto outok;
1381d65f6f70SBen Gras } else if (error != 0) {
1382d65f6f70SBen Gras goto outok;
1383d65f6f70SBen Gras }
1384d65f6f70SBen Gras
138584d9c625SLionel Sambuc /* Has child or not? */
1386d65f6f70SBen Gras if (TAILQ_EMPTY(&ip->dents)) {
1387d65f6f70SBen Gras offset = CHFS_OFFSET_EOF;
1388d65f6f70SBen Gras } else {
1389d65f6f70SBen Gras offset = CHFS_OFFSET_FIRST;
1390d65f6f70SBen Gras }
1391d65f6f70SBen Gras }
1392d65f6f70SBen Gras
1393d65f6f70SBen Gras if (offset != CHFS_OFFSET_EOF) {
139484d9c625SLionel Sambuc /* Child entries. */
1395d65f6f70SBen Gras skip = offset - CHFS_OFFSET_FIRST;
1396d65f6f70SBen Gras
1397d65f6f70SBen Gras TAILQ_FOREACH(fd, &ip->dents, fds) {
1398d65f6f70SBen Gras /* seek to offset by skipping items */
1399d65f6f70SBen Gras /* XXX race conditions by changed dirent? */
1400d65f6f70SBen Gras if (skip > 0) {
1401d65f6f70SBen Gras skip--;
1402d65f6f70SBen Gras continue;
1403d65f6f70SBen Gras }
1404d65f6f70SBen Gras
1405d65f6f70SBen Gras if (fd->vno != 0) {
1406d65f6f70SBen Gras error = chfs_filldir(uio, fd->vno,
1407d65f6f70SBen Gras fd->name, fd->nsize, fd->type);
1408d65f6f70SBen Gras if (error == -1) {
1409d65f6f70SBen Gras error = 0;
1410d65f6f70SBen Gras goto outok;
1411d65f6f70SBen Gras } else if (error != 0) {
1412d65f6f70SBen Gras dbg("err %d\n", error);
1413d65f6f70SBen Gras goto outok;
1414d65f6f70SBen Gras }
1415d65f6f70SBen Gras }
1416d65f6f70SBen Gras offset++;
1417d65f6f70SBen Gras }
1418d65f6f70SBen Gras }
1419d65f6f70SBen Gras offset = CHFS_OFFSET_EOF;
1420d65f6f70SBen Gras
1421d65f6f70SBen Gras outok:
1422d65f6f70SBen Gras uio->uio_offset = offset;
1423d65f6f70SBen Gras
1424d65f6f70SBen Gras if (eofflag != NULL) {
1425d65f6f70SBen Gras *eofflag = (error == 0 &&
1426d65f6f70SBen Gras uio->uio_offset == CHFS_OFFSET_EOF);
1427d65f6f70SBen Gras }
1428d65f6f70SBen Gras
1429d65f6f70SBen Gras out:
1430d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(vp));
1431d65f6f70SBen Gras
1432d65f6f70SBen Gras return error;
1433d65f6f70SBen Gras }
1434d65f6f70SBen Gras
1435d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1436d65f6f70SBen Gras
1437d65f6f70SBen Gras int
chfs_readlink(void * v)1438d65f6f70SBen Gras chfs_readlink(void *v)
1439d65f6f70SBen Gras {
1440d65f6f70SBen Gras
1441d65f6f70SBen Gras struct vnode *vp = ((struct vop_readlink_args *) v)->a_vp;
1442d65f6f70SBen Gras struct uio *uio = ((struct vop_readlink_args *) v)->a_uio;
1443d65f6f70SBen Gras kauth_cred_t cred = ((struct vop_readlink_args *) v)->a_cred;
1444d65f6f70SBen Gras
1445d65f6f70SBen Gras struct chfs_inode *ip = VTOI(vp);
1446d65f6f70SBen Gras
1447d65f6f70SBen Gras dbg("readlink()\n");
1448d65f6f70SBen Gras
1449d65f6f70SBen Gras /* TODO max symlink len instead of "100" */
1450d65f6f70SBen Gras if (ip->size < 100) {
1451d65f6f70SBen Gras uiomove(ip->target, ip->size, uio);
1452d65f6f70SBen Gras return (0);
1453d65f6f70SBen Gras }
1454d65f6f70SBen Gras
1455*0a6a1f1dSLionel Sambuc return (UFS_BUFRD(vp, uio, 0, cred));
1456d65f6f70SBen Gras }
1457d65f6f70SBen Gras
1458d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1459d65f6f70SBen Gras
1460d65f6f70SBen Gras int
chfs_inactive(void * v)1461d65f6f70SBen Gras chfs_inactive(void *v)
1462d65f6f70SBen Gras {
1463d65f6f70SBen Gras struct vnode *vp = ((struct vop_inactive_args *) v)->a_vp;
1464d65f6f70SBen Gras struct chfs_inode *ip = VTOI(vp);
1465d65f6f70SBen Gras struct chfs_vnode_cache *chvc;
1466d65f6f70SBen Gras dbg("inactive | vno: %llu\n", (unsigned long long)ip->ino);
1467d65f6f70SBen Gras
1468d65f6f70SBen Gras KASSERT(VOP_ISLOCKED(vp));
1469d65f6f70SBen Gras
147084d9c625SLionel Sambuc /* Reclaim only if there is no link to the node. */
1471d65f6f70SBen Gras if (ip->ino) {
1472d65f6f70SBen Gras chvc = ip->chvc;
1473d65f6f70SBen Gras if (chvc->nlink)
1474d65f6f70SBen Gras *((struct vop_inactive_args *) v)->a_recycle = 0;
1475d65f6f70SBen Gras } else {
1476d65f6f70SBen Gras *((struct vop_inactive_args *) v)->a_recycle = 1;
1477d65f6f70SBen Gras }
1478d65f6f70SBen Gras
1479d65f6f70SBen Gras VOP_UNLOCK(vp);
1480d65f6f70SBen Gras
1481d65f6f70SBen Gras return 0;
1482d65f6f70SBen Gras }
1483d65f6f70SBen Gras
1484d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1485d65f6f70SBen Gras
1486d65f6f70SBen Gras int
chfs_reclaim(void * v)1487d65f6f70SBen Gras chfs_reclaim(void *v)
1488d65f6f70SBen Gras {
1489d65f6f70SBen Gras struct vop_reclaim_args *ap = v;
1490d65f6f70SBen Gras struct vnode *vp = ap->a_vp;
1491d65f6f70SBen Gras struct chfs_inode *ip = VTOI(vp);
1492d65f6f70SBen Gras struct chfs_mount *chmp = ip->chmp;
1493d65f6f70SBen Gras struct chfs_dirent *fd;
1494d65f6f70SBen Gras
149584d9c625SLionel Sambuc mutex_enter(&chmp->chm_lock_mountfields);
1496d65f6f70SBen Gras
1497d65f6f70SBen Gras mutex_enter(&chmp->chm_lock_vnocache);
149884d9c625SLionel Sambuc ip->chvc->state = VNO_STATE_CHECKEDABSENT;
1499d65f6f70SBen Gras mutex_exit(&chmp->chm_lock_vnocache);
1500d65f6f70SBen Gras
1501d65f6f70SBen Gras chfs_update(vp, NULL, NULL, UPDATE_CLOSE);
1502d65f6f70SBen Gras
150384d9c625SLionel Sambuc /* Clean fragments. */
150484d9c625SLionel Sambuc chfs_kill_fragtree(chmp, &ip->fragtree);
1505d65f6f70SBen Gras
150684d9c625SLionel Sambuc /* Clean dirents. */
1507d65f6f70SBen Gras fd = TAILQ_FIRST(&ip->dents);
1508d65f6f70SBen Gras while (fd) {
1509d65f6f70SBen Gras TAILQ_REMOVE(&ip->dents, fd, fds);
1510d65f6f70SBen Gras chfs_free_dirent(fd);
1511d65f6f70SBen Gras fd = TAILQ_FIRST(&ip->dents);
1512d65f6f70SBen Gras }
1513d65f6f70SBen Gras
1514d65f6f70SBen Gras cache_purge(vp);
1515*0a6a1f1dSLionel Sambuc vcache_remove(vp->v_mount, &ip->ino, sizeof(ip->ino));
1516d65f6f70SBen Gras if (ip->devvp) {
1517d65f6f70SBen Gras vrele(ip->devvp);
1518d65f6f70SBen Gras ip->devvp = 0;
1519d65f6f70SBen Gras }
1520d65f6f70SBen Gras
1521d65f6f70SBen Gras genfs_node_destroy(vp);
1522d65f6f70SBen Gras pool_put(&chfs_inode_pool, vp->v_data);
1523d65f6f70SBen Gras vp->v_data = NULL;
152484d9c625SLionel Sambuc
152584d9c625SLionel Sambuc mutex_exit(&chmp->chm_lock_mountfields);
152684d9c625SLionel Sambuc
1527d65f6f70SBen Gras return (0);
1528d65f6f70SBen Gras }
1529d65f6f70SBen Gras
1530d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1531d65f6f70SBen Gras
1532d65f6f70SBen Gras int
chfs_advlock(void * v)1533d65f6f70SBen Gras chfs_advlock(void *v)
1534d65f6f70SBen Gras {
1535d65f6f70SBen Gras return 0;
1536d65f6f70SBen Gras }
1537d65f6f70SBen Gras
1538d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1539d65f6f70SBen Gras int
chfs_strategy(void * v)1540d65f6f70SBen Gras chfs_strategy(void *v)
1541d65f6f70SBen Gras {
1542d65f6f70SBen Gras struct vop_strategy_args /* {
1543d65f6f70SBen Gras const struct vnodeop_desc *a_desc;
1544d65f6f70SBen Gras struct vnode *a_vp;
1545d65f6f70SBen Gras struct buf *a_bp;
1546d65f6f70SBen Gras } */ *ap = v;
1547d65f6f70SBen Gras struct chfs_full_dnode *fd;
1548d65f6f70SBen Gras struct buf *bp = ap->a_bp;
1549d65f6f70SBen Gras struct vnode *vp = ap->a_vp;
1550d65f6f70SBen Gras struct chfs_inode *ip = VTOI(vp);
1551d65f6f70SBen Gras struct chfs_mount *chmp = ip->chmp;
1552d65f6f70SBen Gras int read = (bp->b_flags & B_READ) ? 1 : 0;
1553d65f6f70SBen Gras int err = 0;
1554d65f6f70SBen Gras
1555d65f6f70SBen Gras if (read) {
1556d65f6f70SBen Gras err = chfs_read_data(chmp, vp, bp);
1557d65f6f70SBen Gras } else {
1558d65f6f70SBen Gras mutex_enter(&chmp->chm_lock_mountfields);
1559d65f6f70SBen Gras
156084d9c625SLionel Sambuc fd = chfs_alloc_full_dnode();
156184d9c625SLionel Sambuc
1562d65f6f70SBen Gras err = chfs_write_flash_dnode(chmp, vp, bp, fd);
1563d65f6f70SBen Gras if (err) {
1564d65f6f70SBen Gras mutex_exit(&chmp->chm_lock_mountfields);
1565d65f6f70SBen Gras goto out;
1566d65f6f70SBen Gras }
1567d65f6f70SBen Gras
156884d9c625SLionel Sambuc ip = VTOI(vp);
1569d65f6f70SBen Gras err = chfs_add_full_dnode_to_inode(chmp, ip, fd);
1570d65f6f70SBen Gras
1571d65f6f70SBen Gras mutex_exit(&chmp->chm_lock_mountfields);
1572d65f6f70SBen Gras }
1573d65f6f70SBen Gras out:
1574d65f6f70SBen Gras biodone(bp);
1575d65f6f70SBen Gras return err;
1576d65f6f70SBen Gras }
1577d65f6f70SBen Gras
1578d65f6f70SBen Gras int
chfs_bmap(void * v)1579d65f6f70SBen Gras chfs_bmap(void *v)
1580d65f6f70SBen Gras {
1581d65f6f70SBen Gras struct vop_bmap_args /* {
1582d65f6f70SBen Gras struct vnode *a_vp;
1583d65f6f70SBen Gras daddr_t a_bn;
1584d65f6f70SBen Gras struct vnode **a_vpp;
1585d65f6f70SBen Gras daddr_t *a_bnp;
1586d65f6f70SBen Gras int *a_runp;
1587d65f6f70SBen Gras int *a_runb;
1588d65f6f70SBen Gras } */ *ap = v;
1589d65f6f70SBen Gras if (ap->a_vpp != NULL)
1590d65f6f70SBen Gras *ap->a_vpp = ap->a_vp;
1591d65f6f70SBen Gras if (ap->a_bnp != NULL)
1592d65f6f70SBen Gras *ap->a_bnp = ap->a_bn;
1593d65f6f70SBen Gras if (ap->a_runp != NULL)
1594d65f6f70SBen Gras *ap->a_runp = 0;
1595d65f6f70SBen Gras return (0);
1596d65f6f70SBen Gras }
1597d65f6f70SBen Gras
1598d65f6f70SBen Gras /*
1599d65f6f70SBen Gras * vnode operations vector used for files stored in a chfs file system.
1600d65f6f70SBen Gras */
1601d65f6f70SBen Gras int
1602d65f6f70SBen Gras (**chfs_vnodeop_p)(void *);
1603d65f6f70SBen Gras const struct vnodeopv_entry_desc chfs_vnodeop_entries[] =
1604d65f6f70SBen Gras {
1605d65f6f70SBen Gras { &vop_default_desc, vn_default_error },
1606d65f6f70SBen Gras { &vop_lookup_desc, chfs_lookup },
1607d65f6f70SBen Gras { &vop_create_desc, chfs_create },
1608d65f6f70SBen Gras { &vop_mknod_desc, chfs_mknod },
1609d65f6f70SBen Gras { &vop_open_desc, chfs_open },
1610d65f6f70SBen Gras { &vop_close_desc, chfs_close },
1611d65f6f70SBen Gras { &vop_access_desc, chfs_access },
1612d65f6f70SBen Gras { &vop_getattr_desc, chfs_getattr },
1613d65f6f70SBen Gras { &vop_setattr_desc, chfs_setattr },
1614d65f6f70SBen Gras { &vop_read_desc, chfs_read },
1615d65f6f70SBen Gras { &vop_write_desc, chfs_write },
1616*0a6a1f1dSLionel Sambuc { &vop_fallocate_desc, genfs_eopnotsupp },
1617*0a6a1f1dSLionel Sambuc { &vop_fdiscard_desc, genfs_eopnotsupp },
1618d65f6f70SBen Gras { &vop_ioctl_desc, genfs_enoioctl },
1619d65f6f70SBen Gras { &vop_fcntl_desc, genfs_fcntl },
1620d65f6f70SBen Gras { &vop_poll_desc, genfs_poll },
1621d65f6f70SBen Gras { &vop_kqfilter_desc, genfs_kqfilter },
1622d65f6f70SBen Gras { &vop_revoke_desc, genfs_revoke },
1623d65f6f70SBen Gras { &vop_mmap_desc, genfs_mmap },
1624d65f6f70SBen Gras { &vop_fsync_desc, chfs_fsync },
1625d65f6f70SBen Gras { &vop_seek_desc, genfs_seek },
1626d65f6f70SBen Gras { &vop_remove_desc, chfs_remove },
1627d65f6f70SBen Gras { &vop_link_desc, chfs_link },
1628d65f6f70SBen Gras { &vop_rename_desc, chfs_rename },
1629d65f6f70SBen Gras { &vop_mkdir_desc, chfs_mkdir },
1630d65f6f70SBen Gras { &vop_rmdir_desc, chfs_rmdir },
1631d65f6f70SBen Gras { &vop_symlink_desc, chfs_symlink },
1632d65f6f70SBen Gras { &vop_readdir_desc, chfs_readdir },
1633d65f6f70SBen Gras { &vop_readlink_desc, chfs_readlink },
1634d65f6f70SBen Gras { &vop_abortop_desc, genfs_abortop },
1635d65f6f70SBen Gras { &vop_inactive_desc, chfs_inactive },
1636d65f6f70SBen Gras { &vop_reclaim_desc, chfs_reclaim },
1637d65f6f70SBen Gras { &vop_lock_desc, genfs_lock },
1638d65f6f70SBen Gras { &vop_unlock_desc, genfs_unlock },
1639d65f6f70SBen Gras { &vop_bmap_desc, chfs_bmap },
1640d65f6f70SBen Gras { &vop_strategy_desc, chfs_strategy },
1641d65f6f70SBen Gras { &vop_print_desc, ufs_print },
1642d65f6f70SBen Gras { &vop_pathconf_desc, ufs_pathconf },
1643d65f6f70SBen Gras { &vop_islocked_desc, genfs_islocked },
1644d65f6f70SBen Gras { &vop_advlock_desc, chfs_advlock },
1645d65f6f70SBen Gras { &vop_bwrite_desc, vn_bwrite },
1646d65f6f70SBen Gras { &vop_getpages_desc, genfs_getpages },
1647d65f6f70SBen Gras { &vop_putpages_desc, genfs_putpages },
1648d65f6f70SBen Gras { NULL, NULL } };
1649d65f6f70SBen Gras
1650d65f6f70SBen Gras const struct vnodeopv_desc chfs_vnodeop_opv_desc =
1651d65f6f70SBen Gras { &chfs_vnodeop_p, chfs_vnodeop_entries };
1652d65f6f70SBen Gras
1653d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1654d65f6f70SBen Gras
1655d65f6f70SBen Gras /*
1656d65f6f70SBen Gras * vnode operations vector used for special devices stored in a chfs
1657d65f6f70SBen Gras * file system.
1658d65f6f70SBen Gras */
1659d65f6f70SBen Gras int
1660d65f6f70SBen Gras (**chfs_specop_p)(void *);
1661d65f6f70SBen Gras const struct vnodeopv_entry_desc chfs_specop_entries[] =
1662d65f6f70SBen Gras {
1663d65f6f70SBen Gras { &vop_default_desc, vn_default_error },
1664d65f6f70SBen Gras { &vop_lookup_desc, spec_lookup },
1665d65f6f70SBen Gras { &vop_create_desc, spec_create },
1666d65f6f70SBen Gras { &vop_mknod_desc, spec_mknod },
1667d65f6f70SBen Gras { &vop_open_desc, spec_open },
1668d65f6f70SBen Gras { &vop_close_desc, ufsspec_close },
1669d65f6f70SBen Gras { &vop_access_desc, chfs_access },
1670d65f6f70SBen Gras { &vop_getattr_desc, chfs_getattr },
1671d65f6f70SBen Gras { &vop_setattr_desc, chfs_setattr },
1672d65f6f70SBen Gras { &vop_read_desc, chfs_read },
1673d65f6f70SBen Gras { &vop_write_desc, chfs_write },
1674*0a6a1f1dSLionel Sambuc { &vop_fallocate_desc, spec_fallocate },
1675*0a6a1f1dSLionel Sambuc { &vop_fdiscard_desc, spec_fdiscard },
1676d65f6f70SBen Gras { &vop_ioctl_desc, spec_ioctl },
1677d65f6f70SBen Gras { &vop_fcntl_desc, genfs_fcntl },
1678d65f6f70SBen Gras { &vop_poll_desc, spec_poll },
1679d65f6f70SBen Gras { &vop_kqfilter_desc, spec_kqfilter },
1680d65f6f70SBen Gras { &vop_revoke_desc, spec_revoke },
1681d65f6f70SBen Gras { &vop_mmap_desc, spec_mmap },
1682d65f6f70SBen Gras { &vop_fsync_desc, spec_fsync },
1683d65f6f70SBen Gras { &vop_seek_desc, spec_seek },
1684d65f6f70SBen Gras { &vop_remove_desc, spec_remove },
1685d65f6f70SBen Gras { &vop_link_desc, spec_link },
1686d65f6f70SBen Gras { &vop_rename_desc, spec_rename },
1687d65f6f70SBen Gras { &vop_mkdir_desc, spec_mkdir },
1688d65f6f70SBen Gras { &vop_rmdir_desc, spec_rmdir },
1689d65f6f70SBen Gras { &vop_symlink_desc, spec_symlink },
1690d65f6f70SBen Gras { &vop_readdir_desc, spec_readdir },
1691d65f6f70SBen Gras { &vop_readlink_desc, spec_readlink },
1692d65f6f70SBen Gras { &vop_abortop_desc, spec_abortop },
1693d65f6f70SBen Gras { &vop_inactive_desc, chfs_inactive },
1694d65f6f70SBen Gras { &vop_reclaim_desc, chfs_reclaim },
1695d65f6f70SBen Gras { &vop_lock_desc, genfs_lock },
1696d65f6f70SBen Gras { &vop_unlock_desc, genfs_unlock },
1697d65f6f70SBen Gras { &vop_bmap_desc, spec_bmap },
1698d65f6f70SBen Gras { &vop_strategy_desc, spec_strategy },
1699d65f6f70SBen Gras { &vop_print_desc, ufs_print },
1700d65f6f70SBen Gras { &vop_pathconf_desc, spec_pathconf },
1701d65f6f70SBen Gras { &vop_islocked_desc, genfs_islocked },
1702d65f6f70SBen Gras { &vop_advlock_desc, spec_advlock },
1703d65f6f70SBen Gras { &vop_bwrite_desc, vn_bwrite },
1704d65f6f70SBen Gras { &vop_getpages_desc, spec_getpages },
1705d65f6f70SBen Gras { &vop_putpages_desc, spec_putpages },
1706d65f6f70SBen Gras { NULL, NULL } };
1707d65f6f70SBen Gras
1708d65f6f70SBen Gras const struct vnodeopv_desc chfs_specop_opv_desc =
1709d65f6f70SBen Gras { &chfs_specop_p, chfs_specop_entries };
1710d65f6f70SBen Gras
1711d65f6f70SBen Gras /* --------------------------------------------------------------------- */
1712d65f6f70SBen Gras /*
1713d65f6f70SBen Gras * vnode operations vector used for fifos stored in a chfs file system.
1714d65f6f70SBen Gras */
1715d65f6f70SBen Gras int
1716d65f6f70SBen Gras (**chfs_fifoop_p)(void *);
1717d65f6f70SBen Gras const struct vnodeopv_entry_desc chfs_fifoop_entries[] =
1718d65f6f70SBen Gras {
1719d65f6f70SBen Gras { &vop_default_desc, vn_default_error },
1720d65f6f70SBen Gras { &vop_lookup_desc, vn_fifo_bypass },
1721d65f6f70SBen Gras { &vop_create_desc, vn_fifo_bypass },
1722d65f6f70SBen Gras { &vop_mknod_desc, vn_fifo_bypass },
1723d65f6f70SBen Gras { &vop_open_desc, vn_fifo_bypass },
1724d65f6f70SBen Gras { &vop_close_desc, ufsfifo_close },
1725d65f6f70SBen Gras { &vop_access_desc, chfs_access },
1726d65f6f70SBen Gras { &vop_getattr_desc, chfs_getattr },
1727d65f6f70SBen Gras { &vop_setattr_desc, chfs_setattr },
1728d65f6f70SBen Gras { &vop_read_desc, ufsfifo_read },
1729d65f6f70SBen Gras { &vop_write_desc, ufsfifo_write },
1730*0a6a1f1dSLionel Sambuc { &vop_fallocate_desc, vn_fifo_bypass },
1731*0a6a1f1dSLionel Sambuc { &vop_fdiscard_desc, vn_fifo_bypass },
1732d65f6f70SBen Gras { &vop_ioctl_desc, vn_fifo_bypass },
1733d65f6f70SBen Gras { &vop_fcntl_desc, genfs_fcntl },
1734d65f6f70SBen Gras { &vop_poll_desc, vn_fifo_bypass },
1735d65f6f70SBen Gras { &vop_kqfilter_desc, vn_fifo_bypass },
1736d65f6f70SBen Gras { &vop_revoke_desc, vn_fifo_bypass },
1737d65f6f70SBen Gras { &vop_mmap_desc, vn_fifo_bypass },
1738d65f6f70SBen Gras { &vop_fsync_desc, vn_fifo_bypass },
1739d65f6f70SBen Gras { &vop_seek_desc, vn_fifo_bypass },
1740d65f6f70SBen Gras { &vop_remove_desc, vn_fifo_bypass },
1741d65f6f70SBen Gras { &vop_link_desc, vn_fifo_bypass },
1742d65f6f70SBen Gras { &vop_rename_desc, vn_fifo_bypass },
1743d65f6f70SBen Gras { &vop_mkdir_desc, vn_fifo_bypass },
1744d65f6f70SBen Gras { &vop_rmdir_desc, vn_fifo_bypass },
1745d65f6f70SBen Gras { &vop_symlink_desc, vn_fifo_bypass },
1746d65f6f70SBen Gras { &vop_readdir_desc, vn_fifo_bypass },
1747d65f6f70SBen Gras { &vop_readlink_desc, vn_fifo_bypass },
1748d65f6f70SBen Gras { &vop_abortop_desc, vn_fifo_bypass },
1749d65f6f70SBen Gras { &vop_inactive_desc, chfs_inactive },
1750d65f6f70SBen Gras { &vop_reclaim_desc, chfs_reclaim },
1751d65f6f70SBen Gras { &vop_lock_desc, genfs_lock },
1752d65f6f70SBen Gras { &vop_unlock_desc, genfs_unlock },
1753d65f6f70SBen Gras { &vop_bmap_desc, vn_fifo_bypass },
1754d65f6f70SBen Gras { &vop_strategy_desc, vn_fifo_bypass },
1755d65f6f70SBen Gras { &vop_print_desc, ufs_print },
1756d65f6f70SBen Gras { &vop_pathconf_desc, vn_fifo_bypass },
1757d65f6f70SBen Gras { &vop_islocked_desc, genfs_islocked },
1758d65f6f70SBen Gras { &vop_advlock_desc, vn_fifo_bypass },
1759d65f6f70SBen Gras { &vop_bwrite_desc, genfs_nullop },
1760d65f6f70SBen Gras { &vop_getpages_desc, genfs_badop },
1761d65f6f70SBen Gras { &vop_putpages_desc, vn_fifo_bypass },
1762d65f6f70SBen Gras { NULL, NULL } };
1763d65f6f70SBen Gras
1764d65f6f70SBen Gras const struct vnodeopv_desc chfs_fifoop_opv_desc =
1765d65f6f70SBen Gras { &chfs_fifoop_p, chfs_fifoop_entries };
1766