puffs_vfsops.c revision 1.11.2.3 1 1.11.2.3 ad /* $NetBSD: puffs_vfsops.c,v 1.11.2.3 2007/01/12 01:04:05 ad Exp $ */
2 1.11.2.2 ad
3 1.11.2.2 ad /*
4 1.11.2.2 ad * Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
5 1.11.2.2 ad *
6 1.11.2.2 ad * Development of this software was supported by the
7 1.11.2.2 ad * Google Summer of Code program and the Ulla Tuominen Foundation.
8 1.11.2.2 ad * The Google SoC project was mentored by Bill Studenmund.
9 1.11.2.2 ad *
10 1.11.2.2 ad * Redistribution and use in source and binary forms, with or without
11 1.11.2.2 ad * modification, are permitted provided that the following conditions
12 1.11.2.2 ad * are met:
13 1.11.2.2 ad * 1. Redistributions of source code must retain the above copyright
14 1.11.2.2 ad * notice, this list of conditions and the following disclaimer.
15 1.11.2.2 ad * 2. Redistributions in binary form must reproduce the above copyright
16 1.11.2.2 ad * notice, this list of conditions and the following disclaimer in the
17 1.11.2.2 ad * documentation and/or other materials provided with the distribution.
18 1.11.2.2 ad * 3. The name of the company nor the name of the author may be used to
19 1.11.2.2 ad * endorse or promote products derived from this software without specific
20 1.11.2.2 ad * prior written permission.
21 1.11.2.2 ad *
22 1.11.2.2 ad * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23 1.11.2.2 ad * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 1.11.2.2 ad * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 1.11.2.2 ad * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 1.11.2.2 ad * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 1.11.2.2 ad * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 1.11.2.2 ad * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 1.11.2.2 ad * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 1.11.2.2 ad * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 1.11.2.2 ad * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 1.11.2.2 ad * SUCH DAMAGE.
33 1.11.2.2 ad */
34 1.11.2.2 ad
35 1.11.2.2 ad #include <sys/cdefs.h>
36 1.11.2.3 ad __KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.11.2.3 2007/01/12 01:04:05 ad Exp $");
37 1.11.2.2 ad
38 1.11.2.2 ad #include <sys/param.h>
39 1.11.2.2 ad #include <sys/mount.h>
40 1.11.2.2 ad #include <sys/malloc.h>
41 1.11.2.2 ad #include <sys/extattr.h>
42 1.11.2.2 ad #include <sys/queue.h>
43 1.11.2.2 ad #include <sys/vnode.h>
44 1.11.2.2 ad #include <sys/dirent.h>
45 1.11.2.2 ad #include <sys/kauth.h>
46 1.11.2.2 ad
47 1.11.2.2 ad #include <lib/libkern/libkern.h>
48 1.11.2.2 ad
49 1.11.2.2 ad #include <fs/puffs/puffs_msgif.h>
50 1.11.2.2 ad #include <fs/puffs/puffs_sys.h>
51 1.11.2.2 ad
52 1.11.2.2 ad VFS_PROTOS(puffs);
53 1.11.2.2 ad
54 1.11.2.2 ad MALLOC_DEFINE(M_PUFFS, "puffs", "pass-to-userspace file system structures");
55 1.11.2.2 ad
56 1.11.2.2 ad int
57 1.11.2.2 ad puffs_mount(struct mount *mp, const char *path, void *data,
58 1.11.2.2 ad struct nameidata *ndp, struct lwp *l)
59 1.11.2.2 ad {
60 1.11.2.2 ad struct puffs_mount *pmp;
61 1.11.2.3 ad struct puffs_args *args;
62 1.11.2.3 ad char namebuf[PUFFSNAMESIZE+sizeof(PUFFS_NAMEPREFIX)+1]; /* spooky */
63 1.11.2.3 ad int error = 0;
64 1.11.2.2 ad
65 1.11.2.2 ad if (mp->mnt_flag & MNT_GETARGS) {
66 1.11.2.2 ad pmp = MPTOPUFFSMP(mp);
67 1.11.2.2 ad return copyout(&pmp->pmp_args, data, sizeof(struct puffs_args));
68 1.11.2.2 ad }
69 1.11.2.2 ad
70 1.11.2.2 ad /* update is not supported currently */
71 1.11.2.2 ad if (mp->mnt_flag & MNT_UPDATE)
72 1.11.2.2 ad return EOPNOTSUPP;
73 1.11.2.2 ad
74 1.11.2.2 ad /*
75 1.11.2.2 ad * We need the file system name
76 1.11.2.2 ad */
77 1.11.2.2 ad if (!data)
78 1.11.2.2 ad return EINVAL;
79 1.11.2.2 ad
80 1.11.2.3 ad MALLOC(args, struct puffs_args *, sizeof(struct puffs_args),
81 1.11.2.3 ad M_PUFFS, M_WAITOK);
82 1.11.2.3 ad
83 1.11.2.3 ad error = copyin(data, args, sizeof(struct puffs_args));
84 1.11.2.2 ad if (error)
85 1.11.2.3 ad goto out;
86 1.11.2.3 ad
87 1.11.2.3 ad /* devel phase */
88 1.11.2.3 ad if (args->pa_vers != (PUFFSVERSION | PUFFSDEVELVERS)) {
89 1.11.2.3 ad printf("puffs_mount: development version mismatch\n");
90 1.11.2.3 ad error = EINVAL;
91 1.11.2.3 ad goto out;
92 1.11.2.3 ad }
93 1.11.2.3 ad
94 1.11.2.3 ad /* nuke spy bits */
95 1.11.2.3 ad args->pa_flags &= PUFFS_KFLAG_MASK;
96 1.11.2.2 ad
97 1.11.2.2 ad /* build real name */
98 1.11.2.3 ad (void)strlcpy(namebuf, PUFFS_NAMEPREFIX, sizeof(namebuf));
99 1.11.2.3 ad (void)strlcat(namebuf, args->pa_name, sizeof(namebuf));
100 1.11.2.2 ad
101 1.11.2.2 ad /* inform user server if it got the max request size it wanted */
102 1.11.2.3 ad if (args->pa_maxreqlen == 0 || args->pa_maxreqlen > PUFFS_REQ_MAXSIZE)
103 1.11.2.3 ad args->pa_maxreqlen = PUFFS_REQ_MAXSIZE;
104 1.11.2.3 ad else if (args->pa_maxreqlen < PUFFS_REQSTRUCT_MAX)
105 1.11.2.3 ad args->pa_maxreqlen = PUFFS_REQSTRUCT_MAX;
106 1.11.2.3 ad (void)strlcpy(args->pa_name, namebuf, sizeof(args->pa_name));
107 1.11.2.2 ad
108 1.11.2.3 ad error = copyout(args, data, sizeof(struct puffs_args));
109 1.11.2.2 ad if (error)
110 1.11.2.3 ad goto out;
111 1.11.2.2 ad
112 1.11.2.2 ad error = set_statvfs_info(path, UIO_USERSPACE, namebuf,
113 1.11.2.2 ad UIO_SYSSPACE, mp, l);
114 1.11.2.2 ad if (error)
115 1.11.2.3 ad goto out;
116 1.11.2.3 ad mp->mnt_stat.f_iosize = DEV_BSIZE;
117 1.11.2.2 ad
118 1.11.2.2 ad MALLOC(pmp, struct puffs_mount *, sizeof(struct puffs_mount),
119 1.11.2.2 ad M_PUFFS, M_WAITOK | M_ZERO);
120 1.11.2.2 ad
121 1.11.2.2 ad mp->mnt_fs_bshift = DEV_BSHIFT;
122 1.11.2.2 ad mp->mnt_dev_bshift = DEV_BSHIFT;
123 1.11.2.2 ad mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */
124 1.11.2.2 ad mp->mnt_data = pmp;
125 1.11.2.2 ad
126 1.11.2.2 ad pmp->pmp_status = PUFFSTAT_MOUNTING;
127 1.11.2.2 ad pmp->pmp_nextreq = 0;
128 1.11.2.2 ad pmp->pmp_mp = mp;
129 1.11.2.3 ad pmp->pmp_req_maxsize = args->pa_maxreqlen;
130 1.11.2.3 ad pmp->pmp_args = *args;
131 1.11.2.2 ad
132 1.11.2.2 ad /*
133 1.11.2.2 ad * Inform the fileops processing code that we have a mountpoint.
134 1.11.2.2 ad * If it doesn't know about anyone with our pid/fd having the
135 1.11.2.2 ad * device open, punt
136 1.11.2.2 ad */
137 1.11.2.3 ad if (puffs_setpmp(l->l_proc->p_pid, args->pa_fd, pmp)) {
138 1.11.2.2 ad FREE(pmp, M_PUFFS);
139 1.11.2.3 ad error = ENOENT;
140 1.11.2.3 ad goto out;
141 1.11.2.2 ad }
142 1.11.2.2 ad
143 1.11.2.2 ad simple_lock_init(&pmp->pmp_lock);
144 1.11.2.2 ad TAILQ_INIT(&pmp->pmp_req_touser);
145 1.11.2.2 ad TAILQ_INIT(&pmp->pmp_req_replywait);
146 1.11.2.2 ad TAILQ_INIT(&pmp->pmp_req_sizepark);
147 1.11.2.2 ad
148 1.11.2.2 ad DPRINTF(("puffs_mount: mount point at %p, puffs specific at %p\n",
149 1.11.2.2 ad mp, MPTOPUFFSMP(mp)));
150 1.11.2.2 ad
151 1.11.2.2 ad vfs_getnewfsid(mp);
152 1.11.2.2 ad
153 1.11.2.3 ad out:
154 1.11.2.3 ad FREE(args, M_PUFFS);
155 1.11.2.3 ad return error;
156 1.11.2.2 ad }
157 1.11.2.2 ad
158 1.11.2.2 ad /*
159 1.11.2.2 ad * This is called from the first "Hello, I'm alive" ioctl
160 1.11.2.2 ad * from userspace.
161 1.11.2.2 ad */
162 1.11.2.2 ad int
163 1.11.2.2 ad puffs_start2(struct puffs_mount *pmp, struct puffs_startreq *sreq)
164 1.11.2.2 ad {
165 1.11.2.2 ad struct puffs_node *pn;
166 1.11.2.2 ad struct mount *mp;
167 1.11.2.2 ad
168 1.11.2.2 ad mp = PMPTOMP(pmp);
169 1.11.2.2 ad
170 1.11.2.2 ad simple_lock(&pmp->pmp_lock);
171 1.11.2.2 ad
172 1.11.2.2 ad /*
173 1.11.2.2 ad * if someone has issued a VFS_ROOT() already, fill in the
174 1.11.2.2 ad * vnode cookie.
175 1.11.2.2 ad */
176 1.11.2.2 ad pn = NULL;
177 1.11.2.2 ad if (pmp->pmp_root) {
178 1.11.2.2 ad pn = VPTOPP(pmp->pmp_root);
179 1.11.2.2 ad pn->pn_cookie = sreq->psr_cookie;
180 1.11.2.2 ad }
181 1.11.2.2 ad
182 1.11.2.2 ad /* We're good to fly */
183 1.11.2.2 ad pmp->pmp_rootcookie = sreq->psr_cookie;
184 1.11.2.2 ad pmp->pmp_status = PUFFSTAT_RUNNING;
185 1.11.2.2 ad simple_unlock(&pmp->pmp_lock);
186 1.11.2.2 ad
187 1.11.2.3 ad /* do the VFS_STATVFS() we missed out on in sys_mount() */
188 1.11.2.3 ad copy_statvfs_info(&sreq->psr_sb, mp);
189 1.11.2.3 ad (void)memcpy(&mp->mnt_stat, &sreq->psr_sb, sizeof(mp->mnt_stat));
190 1.11.2.3 ad mp->mnt_stat.f_iosize = DEV_BSIZE;
191 1.11.2.3 ad
192 1.11.2.2 ad DPRINTF(("puffs_start2: root vp %p, cur root pnode %p, cookie %p\n",
193 1.11.2.2 ad pmp->pmp_root, pn, sreq->psr_cookie));
194 1.11.2.2 ad
195 1.11.2.2 ad return 0;
196 1.11.2.2 ad }
197 1.11.2.2 ad
198 1.11.2.2 ad int
199 1.11.2.2 ad puffs_start(struct mount *mp, int flags, struct lwp *l)
200 1.11.2.2 ad {
201 1.11.2.2 ad
202 1.11.2.2 ad /*
203 1.11.2.2 ad * This cannot travel to userspace, as this is called from
204 1.11.2.2 ad * the kernel context of the process doing mount(2). But
205 1.11.2.2 ad * it's probably a safe bet that the process doing mount(2)
206 1.11.2.2 ad * realizes it needs to start the filesystem also...
207 1.11.2.2 ad */
208 1.11.2.2 ad return 0;
209 1.11.2.2 ad }
210 1.11.2.2 ad
211 1.11.2.2 ad int
212 1.11.2.2 ad puffs_unmount(struct mount *mp, int mntflags, struct lwp *l)
213 1.11.2.2 ad {
214 1.11.2.2 ad struct puffs_mount *pmp;
215 1.11.2.2 ad int error, force;
216 1.11.2.2 ad
217 1.11.2.2 ad PUFFS_VFSREQ(unmount);
218 1.11.2.2 ad
219 1.11.2.2 ad error = 0;
220 1.11.2.2 ad force = mntflags & MNT_FORCE;
221 1.11.2.2 ad pmp = MPTOPUFFSMP(mp);
222 1.11.2.2 ad
223 1.11.2.2 ad DPRINTF(("puffs_unmount: detach filesystem from vfs, current "
224 1.11.2.2 ad "status 0x%x\n", pmp->pmp_status));
225 1.11.2.2 ad
226 1.11.2.2 ad /*
227 1.11.2.2 ad * flush all the vnodes. VOP_RECLAIM() takes care that the
228 1.11.2.2 ad * root vnode does not get flushed until unmount. The
229 1.11.2.2 ad * userspace root node cookie is stored in the mount
230 1.11.2.2 ad * structure, so we can always re-instantiate a root vnode,
231 1.11.2.2 ad * should userspace unmount decide it doesn't want to
232 1.11.2.2 ad * cooperate.
233 1.11.2.2 ad */
234 1.11.2.2 ad error = vflush(mp, NULLVP, force ? FORCECLOSE : 0);
235 1.11.2.2 ad if (error)
236 1.11.2.2 ad goto out;
237 1.11.2.2 ad
238 1.11.2.2 ad /*
239 1.11.2.2 ad * If we are not DYING, we should ask userspace's opinion
240 1.11.2.2 ad * about the situation
241 1.11.2.2 ad */
242 1.11.2.3 ad simple_lock(&pmp->pmp_lock);
243 1.11.2.2 ad if (pmp->pmp_status != PUFFSTAT_DYING) {
244 1.11.2.3 ad pmp->pmp_unmounting = 1;
245 1.11.2.3 ad simple_unlock(&pmp->pmp_lock);
246 1.11.2.3 ad
247 1.11.2.2 ad unmount_arg.pvfsr_flags = mntflags;
248 1.11.2.2 ad unmount_arg.pvfsr_pid = puffs_lwp2pid(l);
249 1.11.2.3 ad
250 1.11.2.2 ad error = puffs_vfstouser(pmp, PUFFS_VFS_UNMOUNT,
251 1.11.2.2 ad &unmount_arg, sizeof(unmount_arg));
252 1.11.2.3 ad DPRINTF(("puffs_unmount: error %d force %d\n", error, force));
253 1.11.2.3 ad
254 1.11.2.3 ad simple_lock(&pmp->pmp_lock);
255 1.11.2.3 ad pmp->pmp_unmounting = 0;
256 1.11.2.3 ad wakeup(&pmp->pmp_unmounting);
257 1.11.2.2 ad }
258 1.11.2.2 ad
259 1.11.2.2 ad /*
260 1.11.2.2 ad * if userspace cooperated or we really need to die,
261 1.11.2.2 ad * screw what userland thinks and just die.
262 1.11.2.2 ad */
263 1.11.2.2 ad if (error == 0 || force) {
264 1.11.2.2 ad pmp->pmp_status = PUFFSTAT_DYING;
265 1.11.2.2 ad puffs_nukebypmp(pmp);
266 1.11.2.3 ad simple_unlock(&pmp->pmp_lock);
267 1.11.2.2 ad FREE(pmp, M_PUFFS);
268 1.11.2.2 ad error = 0;
269 1.11.2.3 ad } else {
270 1.11.2.3 ad simple_unlock(&pmp->pmp_lock);
271 1.11.2.2 ad }
272 1.11.2.2 ad
273 1.11.2.2 ad out:
274 1.11.2.2 ad DPRINTF(("puffs_unmount: return %d\n", error));
275 1.11.2.2 ad return error;
276 1.11.2.2 ad }
277 1.11.2.2 ad
278 1.11.2.2 ad /*
279 1.11.2.2 ad * This doesn't need to travel to userspace
280 1.11.2.2 ad */
281 1.11.2.2 ad int
282 1.11.2.2 ad puffs_root(struct mount *mp, struct vnode **vpp)
283 1.11.2.2 ad {
284 1.11.2.2 ad struct puffs_mount *pmp;
285 1.11.2.2 ad struct puffs_node *pn;
286 1.11.2.2 ad struct vnode *vp;
287 1.11.2.2 ad
288 1.11.2.2 ad pmp = MPTOPUFFSMP(mp);
289 1.11.2.2 ad
290 1.11.2.2 ad /*
291 1.11.2.2 ad * pmp_lock must be held if vref()'ing or vrele()'ing the
292 1.11.2.3 ad * root vnode. the latter is controlled by puffs_inactive().
293 1.11.2.2 ad */
294 1.11.2.2 ad simple_lock(&pmp->pmp_lock);
295 1.11.2.2 ad vp = pmp->pmp_root;
296 1.11.2.2 ad if (vp) {
297 1.11.2.2 ad pn = VPTOPP(vp);
298 1.11.2.3 ad if (vget(vp, LK_EXCLUSIVE | LK_RETRY)) {
299 1.11.2.3 ad pmp->pmp_root = NULL;
300 1.11.2.3 ad goto grabnew;
301 1.11.2.3 ad }
302 1.11.2.2 ad simple_unlock(&pmp->pmp_lock);
303 1.11.2.2 ad *vpp = vp;
304 1.11.2.2 ad return 0;
305 1.11.2.2 ad }
306 1.11.2.2 ad grabnew:
307 1.11.2.2 ad simple_unlock(&pmp->pmp_lock);
308 1.11.2.2 ad
309 1.11.2.2 ad /*
310 1.11.2.2 ad * So, didn't have the magic root vnode available.
311 1.11.2.2 ad * No matter, grab another an stuff it with the cookie.
312 1.11.2.2 ad */
313 1.11.2.2 ad if (puffs_getvnode(mp, pmp->pmp_rootcookie, VDIR, 0, 0, &vp))
314 1.11.2.2 ad panic("sloppy programming");
315 1.11.2.2 ad
316 1.11.2.2 ad simple_lock(&pmp->pmp_lock);
317 1.11.2.2 ad /*
318 1.11.2.2 ad * check if by mysterious force someone else created a root
319 1.11.2.2 ad * vnode while we were executing.
320 1.11.2.2 ad */
321 1.11.2.2 ad if (pmp->pmp_root) {
322 1.11.2.2 ad vref(pmp->pmp_root);
323 1.11.2.2 ad simple_unlock(&pmp->pmp_lock);
324 1.11.2.2 ad puffs_putvnode(vp);
325 1.11.2.2 ad vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
326 1.11.2.2 ad *vpp = pmp->pmp_root;
327 1.11.2.2 ad return 0;
328 1.11.2.2 ad }
329 1.11.2.2 ad
330 1.11.2.2 ad /* store cache */
331 1.11.2.2 ad vp->v_flag = VROOT;
332 1.11.2.2 ad pmp->pmp_root = vp;
333 1.11.2.2 ad simple_unlock(&pmp->pmp_lock);
334 1.11.2.2 ad
335 1.11.2.2 ad vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
336 1.11.2.2 ad
337 1.11.2.2 ad *vpp = vp;
338 1.11.2.2 ad return 0;
339 1.11.2.2 ad }
340 1.11.2.2 ad
341 1.11.2.2 ad int
342 1.11.2.2 ad puffs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg, struct lwp *l)
343 1.11.2.2 ad {
344 1.11.2.2 ad
345 1.11.2.2 ad return EOPNOTSUPP;
346 1.11.2.2 ad }
347 1.11.2.2 ad
348 1.11.2.2 ad int
349 1.11.2.2 ad puffs_statvfs(struct mount *mp, struct statvfs *sbp, struct lwp *l)
350 1.11.2.2 ad {
351 1.11.2.2 ad struct puffs_vfsreq_statvfs *statvfs_arg; /* too big for stack */
352 1.11.2.2 ad struct puffs_mount *pmp;
353 1.11.2.2 ad int error = 0;
354 1.11.2.2 ad
355 1.11.2.2 ad pmp = MPTOPUFFSMP(mp);
356 1.11.2.2 ad
357 1.11.2.2 ad /*
358 1.11.2.2 ad * If we are mounting, it means that the userspace counterpart
359 1.11.2.2 ad * is calling mount(2), but mount(2) also calls statvfs. So
360 1.11.2.2 ad * requesting statvfs from userspace would mean a deadlock.
361 1.11.2.2 ad * Compensate.
362 1.11.2.2 ad */
363 1.11.2.2 ad if (pmp->pmp_status == PUFFSTAT_MOUNTING)
364 1.11.2.2 ad return EINPROGRESS;
365 1.11.2.2 ad
366 1.11.2.2 ad /* too big for stack */
367 1.11.2.2 ad MALLOC(statvfs_arg, struct puffs_vfsreq_statvfs *,
368 1.11.2.2 ad sizeof(struct puffs_vfsreq_statvfs), M_PUFFS, M_WAITOK | M_ZERO);
369 1.11.2.2 ad statvfs_arg->pvfsr_pid = puffs_lwp2pid(l);
370 1.11.2.2 ad
371 1.11.2.2 ad error = puffs_vfstouser(pmp, PUFFS_VFS_STATVFS,
372 1.11.2.2 ad statvfs_arg, sizeof(*statvfs_arg));
373 1.11.2.3 ad statvfs_arg->pvfsr_sb.f_iosize = DEV_BSIZE;
374 1.11.2.2 ad
375 1.11.2.2 ad /*
376 1.11.2.2 ad * Try to produce a sensible result even in the event
377 1.11.2.2 ad * of userspace error.
378 1.11.2.2 ad *
379 1.11.2.2 ad * XXX: cache the copy in non-error case
380 1.11.2.2 ad */
381 1.11.2.2 ad if (!error) {
382 1.11.2.2 ad copy_statvfs_info(&statvfs_arg->pvfsr_sb, mp);
383 1.11.2.2 ad (void)memcpy(sbp, &statvfs_arg->pvfsr_sb,
384 1.11.2.2 ad sizeof(struct statvfs));
385 1.11.2.2 ad } else {
386 1.11.2.2 ad copy_statvfs_info(sbp, mp);
387 1.11.2.2 ad }
388 1.11.2.2 ad
389 1.11.2.2 ad FREE(statvfs_arg, M_PUFFS);
390 1.11.2.3 ad return error;
391 1.11.2.2 ad }
392 1.11.2.2 ad
393 1.11.2.2 ad int
394 1.11.2.2 ad puffs_sync(struct mount *mp, int waitfor, struct kauth_cred *cred,
395 1.11.2.2 ad struct lwp *l)
396 1.11.2.2 ad {
397 1.11.2.3 ad struct vnode *vp, *nvp;
398 1.11.2.3 ad int error, rv;
399 1.11.2.3 ad int ppflags;
400 1.11.2.2 ad
401 1.11.2.2 ad PUFFS_VFSREQ(sync);
402 1.11.2.2 ad
403 1.11.2.3 ad error = 0;
404 1.11.2.3 ad ppflags = PGO_CLEANIT | PGO_ALLPAGES;
405 1.11.2.3 ad if (waitfor == MNT_WAIT)
406 1.11.2.3 ad ppflags |= PGO_SYNCIO;
407 1.11.2.3 ad
408 1.11.2.3 ad /*
409 1.11.2.3 ad * Sync all data from nodes. The user server can still cache
410 1.11.2.3 ad * metadata and control its syncing with VFS_SYNC. However,
411 1.11.2.3 ad * we just push all data with VOP_FSYNC already here to avoid
412 1.11.2.3 ad * an extra pingpong query from userspace requesting that
413 1.11.2.3 ad * data (and besides, there's no framework yet to handle it).
414 1.11.2.3 ad */
415 1.11.2.3 ad simple_lock(&mntvnode_slock);
416 1.11.2.3 ad loop:
417 1.11.2.3 ad for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) {
418 1.11.2.3 ad /* check if we're on the right list */
419 1.11.2.3 ad if (vp->v_mount != mp)
420 1.11.2.3 ad goto loop;
421 1.11.2.3 ad
422 1.11.2.3 ad simple_lock(&vp->v_interlock);
423 1.11.2.3 ad nvp = TAILQ_NEXT(vp, v_mntvnodes);
424 1.11.2.3 ad
425 1.11.2.3 ad if (vp->v_type != VREG || UVM_OBJ_IS_CLEAN(&vp->v_uobj)) {
426 1.11.2.3 ad simple_unlock(&vp->v_interlock);
427 1.11.2.3 ad continue;
428 1.11.2.3 ad }
429 1.11.2.3 ad
430 1.11.2.3 ad simple_unlock(&mntvnode_slock);
431 1.11.2.3 ad
432 1.11.2.3 ad /*
433 1.11.2.3 ad * Here we try to get a reference to the vnode and to
434 1.11.2.3 ad * lock it. This is mostly cargo-culted, but I will
435 1.11.2.3 ad * offer an explanation to why I believe this might
436 1.11.2.3 ad * actually do the right thing.
437 1.11.2.3 ad *
438 1.11.2.3 ad * If the vnode is a goner, we quite obviously don't need
439 1.11.2.3 ad * to sync it.
440 1.11.2.3 ad *
441 1.11.2.3 ad * If the vnode was busy, we don't need to sync it because
442 1.11.2.3 ad * this is never called with MNT_WAIT except from
443 1.11.2.3 ad * dounmount(), when we are wait-flushing all the dirty
444 1.11.2.3 ad * vnodes through other routes in any case. So there,
445 1.11.2.3 ad * sync() doesn't actually sync. Happy now?
446 1.11.2.3 ad */
447 1.11.2.3 ad rv = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK);
448 1.11.2.3 ad if (rv) {
449 1.11.2.3 ad simple_lock(&mntvnode_slock);
450 1.11.2.3 ad if (rv == ENOENT)
451 1.11.2.3 ad goto loop;
452 1.11.2.3 ad continue;
453 1.11.2.3 ad }
454 1.11.2.3 ad
455 1.11.2.3 ad simple_lock(&vp->v_interlock);
456 1.11.2.3 ad rv = VOP_PUTPAGES(vp, 0, 0, ppflags);
457 1.11.2.3 ad if (rv)
458 1.11.2.3 ad error = rv;
459 1.11.2.3 ad vput(vp);
460 1.11.2.3 ad simple_lock(&mntvnode_slock);
461 1.11.2.3 ad }
462 1.11.2.3 ad simple_unlock(&mntvnode_slock);
463 1.11.2.3 ad
464 1.11.2.3 ad /* sync fs */
465 1.11.2.2 ad sync_arg.pvfsr_waitfor = waitfor;
466 1.11.2.2 ad puffs_credcvt(&sync_arg.pvfsr_cred, cred);
467 1.11.2.2 ad sync_arg.pvfsr_pid = puffs_lwp2pid(l);
468 1.11.2.2 ad
469 1.11.2.3 ad rv = puffs_vfstouser(MPTOPUFFSMP(mp), PUFFS_VFS_SYNC,
470 1.11.2.2 ad &sync_arg, sizeof(sync_arg));
471 1.11.2.3 ad if (rv)
472 1.11.2.3 ad error = rv;
473 1.11.2.2 ad
474 1.11.2.2 ad return error;
475 1.11.2.2 ad }
476 1.11.2.2 ad
477 1.11.2.2 ad int
478 1.11.2.2 ad puffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
479 1.11.2.2 ad {
480 1.11.2.2 ad
481 1.11.2.2 ad return EOPNOTSUPP;
482 1.11.2.2 ad }
483 1.11.2.2 ad
484 1.11.2.2 ad #if 0
485 1.11.2.2 ad /*ARGSUSED*/
486 1.11.2.2 ad int
487 1.11.2.2 ad puffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
488 1.11.2.2 ad {
489 1.11.2.2 ad
490 1.11.2.2 ad return EOPNOTSUPP;
491 1.11.2.2 ad }
492 1.11.2.2 ad
493 1.11.2.2 ad /*ARGSUSED*/
494 1.11.2.2 ad int
495 1.11.2.2 ad puffs_vptofh(struct vnode *vp, struct fid *fhp)
496 1.11.2.2 ad {
497 1.11.2.2 ad
498 1.11.2.2 ad return EOPNOTSUPP;
499 1.11.2.2 ad }
500 1.11.2.2 ad #endif
501 1.11.2.2 ad
502 1.11.2.2 ad void
503 1.11.2.2 ad puffs_init()
504 1.11.2.2 ad {
505 1.11.2.2 ad
506 1.11.2.2 ad #ifdef _LKM
507 1.11.2.2 ad malloc_type_attach(M_PUFFS);
508 1.11.2.2 ad pool_init(&puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0,
509 1.11.2.2 ad "puffspnpl", &pool_allocator_nointr);
510 1.11.2.2 ad #endif
511 1.11.2.2 ad
512 1.11.2.2 ad return;
513 1.11.2.2 ad }
514 1.11.2.2 ad
515 1.11.2.2 ad void
516 1.11.2.2 ad puffs_done()
517 1.11.2.2 ad {
518 1.11.2.2 ad
519 1.11.2.2 ad #ifdef _LKM
520 1.11.2.2 ad pool_destroy(&puffs_pnpool);
521 1.11.2.2 ad malloc_type_detach(M_PUFFS);
522 1.11.2.2 ad #endif
523 1.11.2.2 ad
524 1.11.2.2 ad return;
525 1.11.2.2 ad }
526 1.11.2.2 ad
527 1.11.2.2 ad int
528 1.11.2.2 ad puffs_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ts)
529 1.11.2.2 ad {
530 1.11.2.2 ad
531 1.11.2.2 ad return EOPNOTSUPP;
532 1.11.2.2 ad }
533 1.11.2.2 ad
534 1.11.2.2 ad const struct vnodeopv_desc * const puffs_vnodeopv_descs[] = {
535 1.11.2.2 ad &puffs_vnodeop_opv_desc,
536 1.11.2.2 ad &puffs_specop_opv_desc,
537 1.11.2.2 ad &puffs_fifoop_opv_desc,
538 1.11.2.3 ad &puffs_msgop_opv_desc,
539 1.11.2.2 ad NULL,
540 1.11.2.2 ad };
541 1.11.2.2 ad
542 1.11.2.2 ad struct vfsops puffs_vfsops = {
543 1.11.2.2 ad MOUNT_PUFFS,
544 1.11.2.2 ad puffs_mount, /* mount */
545 1.11.2.2 ad puffs_start, /* start */
546 1.11.2.2 ad puffs_unmount, /* unmount */
547 1.11.2.2 ad puffs_root, /* root */
548 1.11.2.2 ad puffs_quotactl, /* quotactl */
549 1.11.2.2 ad puffs_statvfs, /* statvfs */
550 1.11.2.2 ad puffs_sync, /* sync */
551 1.11.2.2 ad puffs_vget, /* vget */
552 1.11.2.3 ad (void *)eopnotsupp, /* fhtovp */
553 1.11.2.3 ad (void *)eopnotsupp, /* vptofh */
554 1.11.2.2 ad puffs_init, /* init */
555 1.11.2.2 ad NULL, /* reinit */
556 1.11.2.2 ad puffs_done, /* done */
557 1.11.2.2 ad NULL, /* mountroot */
558 1.11.2.2 ad puffs_snapshot, /* snapshot */
559 1.11.2.2 ad vfs_stdextattrctl, /* extattrctl */
560 1.11.2.2 ad puffs_vnodeopv_descs, /* vnodeops */
561 1.11.2.2 ad 0, /* refcount */
562 1.11.2.2 ad { NULL, NULL }
563 1.11.2.2 ad };
564 1.11.2.2 ad VFS_ATTACH(puffs_vfsops);
565