hammer2 - correct saveoff in hammer2_vop_readdir()
[dragonfly.git] / sys / vfs / hammer2 / hammer2_vnops.c
CommitLineData
e118c14f
MD
1/*
2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@dragonflybsd.org>
6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific, prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
703720e4
MD
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/fcntl.h>
39#include <sys/buf.h>
40#include <sys/proc.h>
41#include <sys/namei.h>
42#include <sys/mount.h>
43#include <sys/vnode.h>
f0206a67 44#include <sys/mountctl.h>
e028fa74 45#include <sys/dirent.h>
703720e4
MD
46
47#include "hammer2.h"
48
703720e4
MD
49/*
50 * Last reference to a vnode is going away but it is still cached.
51 */
e118c14f 52static
703720e4 53int
e118c14f 54hammer2_vop_inactive(struct vop_inactive_args *ap)
703720e4
MD
55{
56 struct vnode *vp;
57 struct hammer2_inode *ip;
e118c14f 58#if 0
703720e4 59 struct hammer2_mount *hmp;
e118c14f 60#endif
703720e4
MD
61
62 kprintf("hammer2_inactive\n");
63
64 vp = ap->a_vp;
65 ip = VTOI(vp);
703720e4 66
df9ea374
MD
67 /*
68 * Degenerate case
69 */
70 if (ip == NULL) {
71 vrecycle(vp);
72 return (0);
73 }
74
703720e4
MD
75 return (0);
76}
77
78/*
79 * Reclaim a vnode so that it can be reused; after the inode is
80 * disassociated, the filesystem must manage it alone.
81 */
e118c14f 82static
703720e4 83int
e118c14f 84hammer2_vop_reclaim(struct vop_reclaim_args *ap)
703720e4 85{
703720e4
MD
86 struct hammer2_inode *ip;
87 struct hammer2_mount *hmp;
b7926f31 88 struct vnode *vp;
703720e4 89
703720e4
MD
90 vp = ap->a_vp;
91 ip = VTOI(vp);
9c2e0de0
MD
92 if (ip == NULL)
93 return(0);
9c2e0de0 94 hmp = ip->hmp;
b7926f31 95
54eb943b 96 hammer2_inode_lock_ex(ip);
703720e4 97 vp->v_data = NULL;
0e92b724 98 ip->vp = NULL;
b7926f31 99 hammer2_chain_flush(hmp, &ip->chain, NULL);
54eb943b 100 hammer2_inode_unlock_ex(ip);
9c2e0de0 101 hammer2_chain_drop(hmp, &ip->chain); /* vp ref removed */
54eb943b
MD
102
103 /*
104 * XXX handle background sync when ip dirty, kernel will no longer
105 * notify us regarding this inode because there is no longer a
106 * vnode attached to it.
107 */
703720e4
MD
108
109 return (0);
110}
111
e118c14f 112static
703720e4 113int
e118c14f 114hammer2_vop_fsync(struct vop_fsync_args *ap)
703720e4 115{
b7926f31
MD
116 struct hammer2_inode *ip;
117 struct hammer2_mount *hmp;
118 struct vnode *vp;
119
120 vp = ap->a_vp;
121 ip = VTOI(vp);
122 hmp = ip->hmp;
123
124 hammer2_inode_lock_ex(ip);
125 vfsync(vp, ap->a_waitfor, 1, NULL, NULL);
126 hammer2_chain_flush(hmp, &ip->chain, NULL);
127 hammer2_inode_unlock_ex(ip);
128 return (0);
703720e4
MD
129}
130
e118c14f 131static
703720e4 132int
e118c14f 133hammer2_vop_access(struct vop_access_args *ap)
703720e4 134{
37494cab
MD
135 hammer2_inode_t *ip = VTOI(ap->a_vp);
136 uid_t uid;
137 gid_t gid;
138 int error;
139
140 uid = hammer2_to_unix_xid(&ip->ip_data.uid);
141 gid = hammer2_to_unix_xid(&ip->ip_data.gid);
142
143 error = vop_helper_access(ap, uid, gid, ip->ip_data.mode,
144 ip->ip_data.uflags);
145 return (error);
703720e4
MD
146}
147
e118c14f 148static
703720e4 149int
e118c14f 150hammer2_vop_getattr(struct vop_getattr_args *ap)
703720e4 151{
cd4b3d92
MD
152 hammer2_mount_t *hmp;
153 hammer2_inode_t *ip;
703720e4
MD
154 struct vnode *vp;
155 struct vattr *vap;
703720e4
MD
156
157 vp = ap->a_vp;
158 vap = ap->a_vap;
159
cd4b3d92
MD
160 ip = VTOI(vp);
161 hmp = ip->hmp;
162
9c2e0de0 163 kprintf("hammer2_getattr iplock %p\n", &ip->chain.lk);
703720e4 164
703720e4
MD
165 hammer2_inode_lock_sh(ip);
166
cd4b3d92
MD
167 vap->va_fsid = hmp->mp->mnt_stat.f_fsid.val[0];
168 vap->va_fileid = ip->ip_data.inum;
169 vap->va_mode = ip->ip_data.mode;
170 vap->va_nlink = ip->ip_data.nlinks;
703720e4
MD
171 vap->va_uid = 0;
172 vap->va_gid = 0;
cd4b3d92
MD
173 vap->va_rmajor = 0;
174 vap->va_rminor = 0;
175 vap->va_size = ip->ip_data.size;
df9ea374 176 vap->va_blocksize = HAMMER2_PBUFSIZE;
cd4b3d92
MD
177 vap->va_flags = ip->ip_data.uflags;
178 hammer2_time_to_timespec(ip->ip_data.ctime, &vap->va_ctime);
179 hammer2_time_to_timespec(ip->ip_data.mtime, &vap->va_mtime);
180 hammer2_time_to_timespec(ip->ip_data.mtime, &vap->va_atime);
181 vap->va_gen = 1;
182 vap->va_bytes = vap->va_size;
183 vap->va_type = hammer2_get_vtype(ip);
184 vap->va_filerev = 0;
185 vap->va_uid_uuid = ip->ip_data.uid;
186 vap->va_gid_uuid = ip->ip_data.gid;
187 vap->va_vaflags = VA_UID_UUID_VALID | VA_GID_UUID_VALID |
188 VA_FSID_UUID_VALID;
703720e4
MD
189
190 hammer2_inode_unlock_sh(ip);
191
192 return (0);
193}
194
e118c14f 195static
703720e4 196int
e118c14f 197hammer2_vop_readdir(struct vop_readdir_args *ap)
703720e4 198{
e028fa74
MD
199 hammer2_mount_t *hmp;
200 hammer2_inode_t *ip;
201 hammer2_inode_t *xip;
202 hammer2_chain_t *parent;
203 hammer2_chain_t *chain;
204 hammer2_key_t lkey;
205 struct uio *uio;
206 off_t *cookies;
207 off_t saveoff;
208 int cookie_index;
209 int ncookies;
210 int error;
211 int dtype;
212 int r;
213
214 ip = VTOI(ap->a_vp);
215 hmp = ip->hmp;
216 uio = ap->a_uio;
217 saveoff = uio->uio_offset;
218
219 /*
220 * Setup cookies directory entry cookies if requested
221 */
222 if (ap->a_ncookies) {
223 ncookies = uio->uio_resid / 16 + 1;
224 if (ncookies > 1024)
225 ncookies = 1024;
226 cookies = kmalloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK);
227 } else {
228 ncookies = -1;
229 cookies = NULL;
230 }
231 cookie_index = 0;
232
233 /*
234 * Handle artificial entries. To ensure that only positive 64 bit
235 * quantities are returned to userland we always strip off bit 63.
236 * The hash code is designed such that codes 0x0000-0x7FFF are not
237 * used, allowing us to use these codes for articial entries.
238 *
239 * Entry 0 is used for '.' and entry 1 is used for '..'. Do not
240 * allow '..' to cross the mount point into (e.g.) the super-root.
241 */
242 error = 0;
243 chain = (void *)(intptr_t)-1; /* non-NULL early done means not eof */
244
245 if (saveoff == 0) {
246 r = vop_write_dirent(&error, uio,
247 ip->ip_data.inum &
248 HAMMER2_DIRHASH_USERMSK,
249 DT_DIR, 1, ".");
250 if (r)
251 goto done;
252 if (cookies)
253 cookies[cookie_index] = saveoff;
254 ++saveoff;
255 ++cookie_index;
256 if (cookie_index == ncookies)
257 goto done;
258 }
259 if (saveoff == 1) {
260 if (ip->pip == NULL || ip == hmp->iroot)
261 xip = ip;
262 else
263 xip = ip->pip;
264
265 r = vop_write_dirent(&error, uio,
266 xip->ip_data.inum &
267 HAMMER2_DIRHASH_USERMSK,
268 DT_DIR, 2, "..");
269 if (r)
270 goto done;
271 if (cookies)
272 cookies[cookie_index] = saveoff;
273 ++saveoff;
274 ++cookie_index;
275 if (cookie_index == ncookies)
276 goto done;
277 }
278
279 lkey = saveoff | HAMMER2_DIRHASH_VISIBLE;
280
281 parent = &ip->chain;
282 hammer2_chain_ref(hmp, parent);
283 error = hammer2_chain_lock(hmp, parent);
284 if (error) {
285 hammer2_chain_put(hmp, parent);
286 goto done;
287 }
288 chain = hammer2_chain_lookup(hmp, &parent, lkey, (hammer2_key_t)-1);
289 while (chain) {
290 /* XXX chain error */
291 if (chain->bref.type != HAMMER2_BREF_TYPE_INODE)
292 continue;
293 dtype = hammer2_get_dtype(chain->u.ip);
294 saveoff = chain->bref.key & HAMMER2_DIRHASH_USERMSK;
295 r = vop_write_dirent(&error, uio,
296 chain->u.ip->ip_data.inum &
297 HAMMER2_DIRHASH_USERMSK,
298 dtype, chain->u.ip->ip_data.name_len,
299 chain->u.ip->ip_data.filename);
300 if (r)
301 break;
302 if (cookies)
303 cookies[cookie_index] = saveoff;
e028fa74 304 ++cookie_index;
e028fa74
MD
305 chain = hammer2_chain_next(hmp, &parent, chain,
306 lkey, (hammer2_key_t)-1);
028a55bb
MD
307 if (chain) {
308 saveoff = (chain->bref.key &
309 HAMMER2_DIRHASH_USERMSK) + 1;
310 } else {
311 saveoff = (hammer2_key_t)-1;
312 }
313 if (cookie_index == ncookies)
314 break;
e028fa74
MD
315 }
316 hammer2_chain_put(hmp, parent);
028a55bb
MD
317 if (chain)
318 hammer2_chain_put(hmp, chain);
e028fa74
MD
319done:
320 if (ap->a_eofflag)
321 *ap->a_eofflag = (chain == NULL);
322 uio->uio_offset = saveoff;
323 if (error && cookie_index == 0) {
324 if (cookies) {
325 kfree(cookies, M_TEMP);
326 *ap->a_ncookies = 0;
327 *ap->a_cookies = NULL;
328 }
329 } else {
330 if (cookies) {
331 *ap->a_ncookies = cookie_index;
332 *ap->a_cookies = cookies;
333 }
334 }
335 return (error);
703720e4
MD
336}
337
e118c14f 338static
703720e4 339int
e118c14f 340hammer2_vop_read(struct vop_read_args *ap)
703720e4 341{
47902fef
VS
342 return (EOPNOTSUPP);
343}
703720e4 344
e118c14f 345static
47902fef 346int
e118c14f 347hammer2_vop_write(struct vop_write_args *ap)
47902fef
VS
348{
349 return (EOPNOTSUPP);
703720e4
MD
350}
351
e118c14f 352static
703720e4 353int
e118c14f 354hammer2_vop_nresolve(struct vop_nresolve_args *ap)
703720e4 355{
37494cab
MD
356 hammer2_inode_t *dip;
357 hammer2_mount_t *hmp;
358 hammer2_chain_t *parent;
359 hammer2_chain_t *chain;
360 struct namecache *ncp;
361 const uint8_t *name;
362 size_t name_len;
363 hammer2_key_t lhc;
364 int error = 0;
365 struct vnode *vp;
366
367 dip = VTOI(ap->a_dvp);
368 hmp = dip->hmp;
369 ncp = ap->a_nch->ncp;
370 name = ncp->nc_name;
371 name_len = ncp->nc_nlen;
372 lhc = hammer2_dirhash(name, name_len);
373
374 /*
375 * Note: In DragonFly the kernel handles '.' and '..'.
376 */
377 parent = &dip->chain;
378 hammer2_chain_ref(hmp, parent);
379 hammer2_chain_lock(hmp, parent);
380 chain = hammer2_chain_lookup(hmp, &parent,
381 lhc, lhc + HAMMER2_DIRHASH_LOMASK);
382 while (chain) {
383 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
384 chain->u.ip &&
385 name_len == chain->data->ipdata.name_len &&
386 bcmp(name, chain->data->ipdata.filename, name_len) == 0) {
387 break;
388 }
389 chain = hammer2_chain_next(hmp, &parent, chain,
390 lhc, lhc + HAMMER2_DIRHASH_LOMASK);
391 }
392 hammer2_chain_put(hmp, parent);
393
394 if (chain) {
395 vp = hammer2_igetv(chain->u.ip, &error);
396 if (error == 0) {
397 vn_unlock(vp);
398 cache_setvp(ap->a_nch, vp);
399 vrele(vp);
400 }
401 hammer2_chain_put(hmp, chain);
402 } else {
403 error = ENOENT;
404 cache_setvp(ap->a_nch, NULL);
405 }
406 return error;
407}
408
409static
410int
411hammer2_vop_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
412{
413 hammer2_inode_t *dip;
414 hammer2_inode_t *ip;
415 hammer2_mount_t *hmp;
416 int error;
417
418 dip = VTOI(ap->a_dvp);
419 hmp = dip->hmp;
420
421 if ((ip = dip->pip) == NULL) {
422 *ap->a_vpp = NULL;
423 return ENOENT;
424 }
425 hammer2_chain_ref(hmp, &ip->chain);
426 hammer2_chain_lock(hmp, &ip->chain);
427 *ap->a_vpp = hammer2_igetv(ip, &error);
428 hammer2_chain_put(hmp, &ip->chain);
429
430 return error;
431}
432
433static
434int
435hammer2_vop_nmkdir(struct vop_nmkdir_args *ap)
436{
437 hammer2_mount_t *hmp;
438 hammer2_inode_t *dip;
439 hammer2_inode_t *nip;
440 struct namecache *ncp;
441 const uint8_t *name;
442 size_t name_len;
443 int error;
444
445 dip = VTOI(ap->a_dvp);
446 hmp = dip->hmp;
447 ncp = ap->a_nch->ncp;
448 name = ncp->nc_name;
449 name_len = ncp->nc_nlen;
450
451 error = hammer2_create_inode(hmp, ap->a_vap, ap->a_cred,
452 dip, name, name_len, &nip);
453 if (error) {
454 KKASSERT(nip == NULL);
455 *ap->a_vpp = NULL;
456 return error;
457 }
458 *ap->a_vpp = hammer2_igetv(nip, &error);
459 hammer2_chain_put(hmp, &nip->chain);
460
461 if (error == 0) {
462 cache_setunresolved(ap->a_nch);
463 cache_setvp(ap->a_nch, *ap->a_vpp);
464 }
465 return error;
703720e4
MD
466}
467
e118c14f 468static
703720e4 469int
e118c14f 470hammer2_vop_bmap(struct vop_bmap_args *ap)
703720e4
MD
471{
472 kprintf("hammer2_bmap\n");
473 return (EOPNOTSUPP);
474}
475
e118c14f 476static
703720e4 477int
e118c14f 478hammer2_vop_open(struct vop_open_args *ap)
703720e4
MD
479{
480 kprintf("hammer2_open\n");
481 return vop_stdopen(ap);
482}
483
e118c14f 484static
703720e4 485int
e118c14f 486hammer2_vop_strategy(struct vop_strategy_args *ap)
703720e4
MD
487{
488 struct vnode *vp;
489 struct bio *biop;
490 struct buf *bp;
491 struct hammer2_inode *ip;
492 int error;
493
494 vp = ap->a_vp;
495 biop = ap->a_bio;
496 bp = biop->bio_buf;
497 ip = VTOI(vp);
498
499 switch(bp->b_cmd) {
9c2e0de0
MD
500 case BUF_CMD_READ:
501 case BUF_CMD_WRITE:
703720e4
MD
502 default:
503 bp->b_error = error = EINVAL;
504 bp->b_flags |= B_ERROR;
505 biodone(biop);
506 break;
507 }
508
509 return (error);
510}
511
e118c14f 512static
f0206a67 513int
e118c14f 514hammer2_vop_mountctl(struct vop_mountctl_args *ap)
f0206a67
VS
515{
516 struct mount *mp;
517 struct hammer2_mount *hmp;
518 int rc;
519
520 switch (ap->a_op) {
521 case (MOUNTCTL_SET_EXPORT):
522 mp = ap->a_head.a_ops->head.vv_mount;
523 hmp = MPTOH2(mp);
524
525 if (ap->a_ctllen != sizeof(struct export_args))
526 rc = (EINVAL);
527 else
10c5dee0
MD
528 rc = vfs_export(mp, &hmp->export,
529 (const struct export_args *)ap->a_ctl);
f0206a67
VS
530 break;
531 default:
532 rc = vop_stdmountctl(ap);
533 break;
534 }
535 return (rc);
536}
537
703720e4
MD
538struct vop_ops hammer2_vnode_vops = {
539 .vop_default = vop_defaultop,
e118c14f 540 .vop_fsync = hammer2_vop_fsync,
703720e4
MD
541 .vop_getpages = vop_stdgetpages,
542 .vop_putpages = vop_stdputpages,
e118c14f
MD
543 .vop_access = hammer2_vop_access,
544 .vop_getattr = hammer2_vop_getattr,
545 .vop_readdir = hammer2_vop_readdir,
546 .vop_read = hammer2_vop_read,
547 .vop_write = hammer2_vop_write,
548 .vop_open = hammer2_vop_open,
549 .vop_inactive = hammer2_vop_inactive,
550 .vop_reclaim = hammer2_vop_reclaim,
551 .vop_nresolve = hammer2_vop_nresolve,
37494cab
MD
552 .vop_nlookupdotdot = hammer2_vop_nlookupdotdot,
553 .vop_nmkdir = hammer2_vop_nmkdir,
e118c14f
MD
554 .vop_mountctl = hammer2_vop_mountctl,
555 .vop_bmap = hammer2_vop_bmap,
556 .vop_strategy = hammer2_vop_strategy,
703720e4
MD
557};
558
559struct vop_ops hammer2_spec_vops = {
560
561};
562
563struct vop_ops hammer2_fifo_vops = {
564
565};