hammer2 - initial mkdir skeleton
[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
MD
85{
86 struct vnode *vp;
87 struct hammer2_inode *ip;
88 struct hammer2_mount *hmp;
89
df9ea374 90 kprintf("hammer2_reclaim\n");
703720e4
MD
91 vp = ap->a_vp;
92 ip = VTOI(vp);
9c2e0de0
MD
93 if (ip == NULL)
94 return(0);
703720e4 95
9c2e0de0 96 hmp = ip->hmp;
54eb943b 97 hammer2_inode_lock_ex(ip);
703720e4 98 vp->v_data = NULL;
0e92b724 99 ip->vp = 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
MD
115{
116 kprintf("hammer2_fsync\n");
117 return (EOPNOTSUPP);
118}
119
e118c14f 120static
703720e4 121int
e118c14f 122hammer2_vop_access(struct vop_access_args *ap)
703720e4 123{
37494cab
MD
124 hammer2_inode_t *ip = VTOI(ap->a_vp);
125 uid_t uid;
126 gid_t gid;
127 int error;
128
129 uid = hammer2_to_unix_xid(&ip->ip_data.uid);
130 gid = hammer2_to_unix_xid(&ip->ip_data.gid);
131
132 error = vop_helper_access(ap, uid, gid, ip->ip_data.mode,
133 ip->ip_data.uflags);
134 return (error);
703720e4
MD
135}
136
e118c14f 137static
703720e4 138int
e118c14f 139hammer2_vop_getattr(struct vop_getattr_args *ap)
703720e4 140{
cd4b3d92
MD
141 hammer2_mount_t *hmp;
142 hammer2_inode_t *ip;
703720e4
MD
143 struct vnode *vp;
144 struct vattr *vap;
703720e4
MD
145
146 vp = ap->a_vp;
147 vap = ap->a_vap;
148
cd4b3d92
MD
149 ip = VTOI(vp);
150 hmp = ip->hmp;
151
9c2e0de0 152 kprintf("hammer2_getattr iplock %p\n", &ip->chain.lk);
703720e4 153
703720e4
MD
154 hammer2_inode_lock_sh(ip);
155
cd4b3d92
MD
156 vap->va_fsid = hmp->mp->mnt_stat.f_fsid.val[0];
157 vap->va_fileid = ip->ip_data.inum;
158 vap->va_mode = ip->ip_data.mode;
159 vap->va_nlink = ip->ip_data.nlinks;
703720e4
MD
160 vap->va_uid = 0;
161 vap->va_gid = 0;
cd4b3d92
MD
162 vap->va_rmajor = 0;
163 vap->va_rminor = 0;
164 vap->va_size = ip->ip_data.size;
df9ea374 165 vap->va_blocksize = HAMMER2_PBUFSIZE;
cd4b3d92
MD
166 vap->va_flags = ip->ip_data.uflags;
167 hammer2_time_to_timespec(ip->ip_data.ctime, &vap->va_ctime);
168 hammer2_time_to_timespec(ip->ip_data.mtime, &vap->va_mtime);
169 hammer2_time_to_timespec(ip->ip_data.mtime, &vap->va_atime);
170 vap->va_gen = 1;
171 vap->va_bytes = vap->va_size;
172 vap->va_type = hammer2_get_vtype(ip);
173 vap->va_filerev = 0;
174 vap->va_uid_uuid = ip->ip_data.uid;
175 vap->va_gid_uuid = ip->ip_data.gid;
176 vap->va_vaflags = VA_UID_UUID_VALID | VA_GID_UUID_VALID |
177 VA_FSID_UUID_VALID;
703720e4
MD
178
179 hammer2_inode_unlock_sh(ip);
180
181 return (0);
182}
183
e118c14f 184static
703720e4 185int
e118c14f 186hammer2_vop_readdir(struct vop_readdir_args *ap)
703720e4 187{
e028fa74
MD
188 hammer2_mount_t *hmp;
189 hammer2_inode_t *ip;
190 hammer2_inode_t *xip;
191 hammer2_chain_t *parent;
192 hammer2_chain_t *chain;
193 hammer2_key_t lkey;
194 struct uio *uio;
195 off_t *cookies;
196 off_t saveoff;
197 int cookie_index;
198 int ncookies;
199 int error;
200 int dtype;
201 int r;
202
203 ip = VTOI(ap->a_vp);
204 hmp = ip->hmp;
205 uio = ap->a_uio;
206 saveoff = uio->uio_offset;
207
208 /*
209 * Setup cookies directory entry cookies if requested
210 */
211 if (ap->a_ncookies) {
212 ncookies = uio->uio_resid / 16 + 1;
213 if (ncookies > 1024)
214 ncookies = 1024;
215 cookies = kmalloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK);
216 } else {
217 ncookies = -1;
218 cookies = NULL;
219 }
220 cookie_index = 0;
221
222 /*
223 * Handle artificial entries. To ensure that only positive 64 bit
224 * quantities are returned to userland we always strip off bit 63.
225 * The hash code is designed such that codes 0x0000-0x7FFF are not
226 * used, allowing us to use these codes for articial entries.
227 *
228 * Entry 0 is used for '.' and entry 1 is used for '..'. Do not
229 * allow '..' to cross the mount point into (e.g.) the super-root.
230 */
231 error = 0;
232 chain = (void *)(intptr_t)-1; /* non-NULL early done means not eof */
233
234 if (saveoff == 0) {
235 r = vop_write_dirent(&error, uio,
236 ip->ip_data.inum &
237 HAMMER2_DIRHASH_USERMSK,
238 DT_DIR, 1, ".");
239 if (r)
240 goto done;
241 if (cookies)
242 cookies[cookie_index] = saveoff;
243 ++saveoff;
244 ++cookie_index;
245 if (cookie_index == ncookies)
246 goto done;
247 }
248 if (saveoff == 1) {
249 if (ip->pip == NULL || ip == hmp->iroot)
250 xip = ip;
251 else
252 xip = ip->pip;
253
254 r = vop_write_dirent(&error, uio,
255 xip->ip_data.inum &
256 HAMMER2_DIRHASH_USERMSK,
257 DT_DIR, 2, "..");
258 if (r)
259 goto done;
260 if (cookies)
261 cookies[cookie_index] = saveoff;
262 ++saveoff;
263 ++cookie_index;
264 if (cookie_index == ncookies)
265 goto done;
266 }
267
268 lkey = saveoff | HAMMER2_DIRHASH_VISIBLE;
269
270 parent = &ip->chain;
271 hammer2_chain_ref(hmp, parent);
272 error = hammer2_chain_lock(hmp, parent);
273 if (error) {
274 hammer2_chain_put(hmp, parent);
275 goto done;
276 }
277 chain = hammer2_chain_lookup(hmp, &parent, lkey, (hammer2_key_t)-1);
278 while (chain) {
279 /* XXX chain error */
280 if (chain->bref.type != HAMMER2_BREF_TYPE_INODE)
281 continue;
282 dtype = hammer2_get_dtype(chain->u.ip);
283 saveoff = chain->bref.key & HAMMER2_DIRHASH_USERMSK;
284 r = vop_write_dirent(&error, uio,
285 chain->u.ip->ip_data.inum &
286 HAMMER2_DIRHASH_USERMSK,
287 dtype, chain->u.ip->ip_data.name_len,
288 chain->u.ip->ip_data.filename);
289 if (r)
290 break;
291 if (cookies)
292 cookies[cookie_index] = saveoff;
293 ++saveoff;
294 ++cookie_index;
295 if (cookie_index == ncookies)
296 break;
297
298 chain = hammer2_chain_next(hmp, &parent, chain,
299 lkey, (hammer2_key_t)-1);
300 }
301 hammer2_chain_put(hmp, parent);
302done:
303 if (ap->a_eofflag)
304 *ap->a_eofflag = (chain == NULL);
305 uio->uio_offset = saveoff;
306 if (error && cookie_index == 0) {
307 if (cookies) {
308 kfree(cookies, M_TEMP);
309 *ap->a_ncookies = 0;
310 *ap->a_cookies = NULL;
311 }
312 } else {
313 if (cookies) {
314 *ap->a_ncookies = cookie_index;
315 *ap->a_cookies = cookies;
316 }
317 }
318 return (error);
703720e4
MD
319}
320
e118c14f 321static
703720e4 322int
e118c14f 323hammer2_vop_read(struct vop_read_args *ap)
703720e4 324{
47902fef
VS
325 return (EOPNOTSUPP);
326}
703720e4 327
e118c14f 328static
47902fef 329int
e118c14f 330hammer2_vop_write(struct vop_write_args *ap)
47902fef
VS
331{
332 return (EOPNOTSUPP);
703720e4
MD
333}
334
e118c14f 335static
703720e4 336int
e118c14f 337hammer2_vop_nresolve(struct vop_nresolve_args *ap)
703720e4 338{
37494cab
MD
339 hammer2_inode_t *dip;
340 hammer2_mount_t *hmp;
341 hammer2_chain_t *parent;
342 hammer2_chain_t *chain;
343 struct namecache *ncp;
344 const uint8_t *name;
345 size_t name_len;
346 hammer2_key_t lhc;
347 int error = 0;
348 struct vnode *vp;
349
350 dip = VTOI(ap->a_dvp);
351 hmp = dip->hmp;
352 ncp = ap->a_nch->ncp;
353 name = ncp->nc_name;
354 name_len = ncp->nc_nlen;
355 lhc = hammer2_dirhash(name, name_len);
356
357 /*
358 * Note: In DragonFly the kernel handles '.' and '..'.
359 */
360 parent = &dip->chain;
361 hammer2_chain_ref(hmp, parent);
362 hammer2_chain_lock(hmp, parent);
363 chain = hammer2_chain_lookup(hmp, &parent,
364 lhc, lhc + HAMMER2_DIRHASH_LOMASK);
365 while (chain) {
366 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
367 chain->u.ip &&
368 name_len == chain->data->ipdata.name_len &&
369 bcmp(name, chain->data->ipdata.filename, name_len) == 0) {
370 break;
371 }
372 chain = hammer2_chain_next(hmp, &parent, chain,
373 lhc, lhc + HAMMER2_DIRHASH_LOMASK);
374 }
375 hammer2_chain_put(hmp, parent);
376
377 if (chain) {
378 vp = hammer2_igetv(chain->u.ip, &error);
379 if (error == 0) {
380 vn_unlock(vp);
381 cache_setvp(ap->a_nch, vp);
382 vrele(vp);
383 }
384 hammer2_chain_put(hmp, chain);
385 } else {
386 error = ENOENT;
387 cache_setvp(ap->a_nch, NULL);
388 }
389 return error;
390}
391
392static
393int
394hammer2_vop_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
395{
396 hammer2_inode_t *dip;
397 hammer2_inode_t *ip;
398 hammer2_mount_t *hmp;
399 int error;
400
401 dip = VTOI(ap->a_dvp);
402 hmp = dip->hmp;
403
404 if ((ip = dip->pip) == NULL) {
405 *ap->a_vpp = NULL;
406 return ENOENT;
407 }
408 hammer2_chain_ref(hmp, &ip->chain);
409 hammer2_chain_lock(hmp, &ip->chain);
410 *ap->a_vpp = hammer2_igetv(ip, &error);
411 hammer2_chain_put(hmp, &ip->chain);
412
413 return error;
414}
415
416static
417int
418hammer2_vop_nmkdir(struct vop_nmkdir_args *ap)
419{
420 hammer2_mount_t *hmp;
421 hammer2_inode_t *dip;
422 hammer2_inode_t *nip;
423 struct namecache *ncp;
424 const uint8_t *name;
425 size_t name_len;
426 int error;
427
428 dip = VTOI(ap->a_dvp);
429 hmp = dip->hmp;
430 ncp = ap->a_nch->ncp;
431 name = ncp->nc_name;
432 name_len = ncp->nc_nlen;
433
434 error = hammer2_create_inode(hmp, ap->a_vap, ap->a_cred,
435 dip, name, name_len, &nip);
436 if (error) {
437 KKASSERT(nip == NULL);
438 *ap->a_vpp = NULL;
439 return error;
440 }
441 *ap->a_vpp = hammer2_igetv(nip, &error);
442 hammer2_chain_put(hmp, &nip->chain);
443
444 if (error == 0) {
445 cache_setunresolved(ap->a_nch);
446 cache_setvp(ap->a_nch, *ap->a_vpp);
447 }
448 return error;
703720e4
MD
449}
450
e118c14f 451static
703720e4 452int
e118c14f 453hammer2_vop_bmap(struct vop_bmap_args *ap)
703720e4
MD
454{
455 kprintf("hammer2_bmap\n");
456 return (EOPNOTSUPP);
457}
458
e118c14f 459static
703720e4 460int
e118c14f 461hammer2_vop_open(struct vop_open_args *ap)
703720e4
MD
462{
463 kprintf("hammer2_open\n");
464 return vop_stdopen(ap);
465}
466
e118c14f 467static
703720e4 468int
e118c14f 469hammer2_vop_strategy(struct vop_strategy_args *ap)
703720e4
MD
470{
471 struct vnode *vp;
472 struct bio *biop;
473 struct buf *bp;
474 struct hammer2_inode *ip;
475 int error;
476
477 vp = ap->a_vp;
478 biop = ap->a_bio;
479 bp = biop->bio_buf;
480 ip = VTOI(vp);
481
482 switch(bp->b_cmd) {
9c2e0de0
MD
483 case BUF_CMD_READ:
484 case BUF_CMD_WRITE:
703720e4
MD
485 default:
486 bp->b_error = error = EINVAL;
487 bp->b_flags |= B_ERROR;
488 biodone(biop);
489 break;
490 }
491
492 return (error);
493}
494
e118c14f 495static
f0206a67 496int
e118c14f 497hammer2_vop_mountctl(struct vop_mountctl_args *ap)
f0206a67
VS
498{
499 struct mount *mp;
500 struct hammer2_mount *hmp;
501 int rc;
502
503 switch (ap->a_op) {
504 case (MOUNTCTL_SET_EXPORT):
505 mp = ap->a_head.a_ops->head.vv_mount;
506 hmp = MPTOH2(mp);
507
508 if (ap->a_ctllen != sizeof(struct export_args))
509 rc = (EINVAL);
510 else
10c5dee0
MD
511 rc = vfs_export(mp, &hmp->export,
512 (const struct export_args *)ap->a_ctl);
f0206a67
VS
513 break;
514 default:
515 rc = vop_stdmountctl(ap);
516 break;
517 }
518 return (rc);
519}
520
703720e4
MD
521struct vop_ops hammer2_vnode_vops = {
522 .vop_default = vop_defaultop,
e118c14f 523 .vop_fsync = hammer2_vop_fsync,
703720e4
MD
524 .vop_getpages = vop_stdgetpages,
525 .vop_putpages = vop_stdputpages,
e118c14f
MD
526 .vop_access = hammer2_vop_access,
527 .vop_getattr = hammer2_vop_getattr,
528 .vop_readdir = hammer2_vop_readdir,
529 .vop_read = hammer2_vop_read,
530 .vop_write = hammer2_vop_write,
531 .vop_open = hammer2_vop_open,
532 .vop_inactive = hammer2_vop_inactive,
533 .vop_reclaim = hammer2_vop_reclaim,
534 .vop_nresolve = hammer2_vop_nresolve,
37494cab
MD
535 .vop_nlookupdotdot = hammer2_vop_nlookupdotdot,
536 .vop_nmkdir = hammer2_vop_nmkdir,
e118c14f
MD
537 .vop_mountctl = hammer2_vop_mountctl,
538 .vop_bmap = hammer2_vop_bmap,
539 .vop_strategy = hammer2_vop_strategy,
703720e4
MD
540};
541
542struct vop_ops hammer2_spec_vops = {
543
544};
545
546struct vop_ops hammer2_fifo_vops = {
547
548};