1147476Sdumbbell/*-
2147476Sdumbbell * Copyright 2000 Hans Reiser
3147476Sdumbbell * See README for licensing and copyright details
4147476Sdumbbell *
5147476Sdumbbell * Ported to FreeBSD by Jean-S�bastien P�dron <jspedron@club-internet.fr>
6147476Sdumbbell *
7147476Sdumbbell * $FreeBSD$
8147476Sdumbbell */
9147476Sdumbbell
10147476Sdumbbell#include <gnu/fs/reiserfs/reiserfs_fs.h>
11147476Sdumbbell
12147476Sdumbbellstatic vop_access_t	reiserfs_access;
13147476Sdumbbellstatic vop_bmap_t	reiserfs_bmap;
14147476Sdumbbellstatic vop_getattr_t	reiserfs_getattr;
15147476Sdumbbellstatic vop_open_t	reiserfs_open;
16147476Sdumbbellstatic vop_pathconf_t	reiserfs_pathconf;
17147476Sdumbbellstatic vop_readlink_t	reiserfs_readlink;
18147476Sdumbbellstatic vop_strategy_t	reiserfs_strategy;
19166774Spjdstatic vop_vptofh_t	reiserfs_vptofh;
20147476Sdumbbell
21147476Sdumbbell/* Global vfs data structures for ReiserFS */
22147476Sdumbbellstruct vop_vector reiserfs_vnodeops = {
23147476Sdumbbell	.vop_default      = &default_vnodeops,
24147476Sdumbbell
25147476Sdumbbell	.vop_access       = reiserfs_access,
26147476Sdumbbell	.vop_bmap         = reiserfs_bmap,
27147476Sdumbbell	.vop_cachedlookup = reiserfs_lookup,
28147476Sdumbbell	.vop_getattr      = reiserfs_getattr,
29147476Sdumbbell	.vop_inactive     = reiserfs_inactive,
30147476Sdumbbell	.vop_lookup       = vfs_cache_lookup,
31147476Sdumbbell	.vop_open         = reiserfs_open,
32147476Sdumbbell	.vop_reclaim      = reiserfs_reclaim,
33147476Sdumbbell	.vop_read         = reiserfs_read,
34147476Sdumbbell	.vop_readdir      = reiserfs_readdir,
35147476Sdumbbell	.vop_readlink     = reiserfs_readlink,
36147476Sdumbbell	.vop_pathconf     = reiserfs_pathconf,
37147476Sdumbbell	.vop_strategy     = reiserfs_strategy,
38166774Spjd	.vop_vptofh       = reiserfs_vptofh,
39147476Sdumbbell};
40147476Sdumbbell
41147476Sdumbbellstruct vop_vector reiserfs_specops = {
42147476Sdumbbell	.vop_default  = &default_vnodeops,
43147476Sdumbbell
44147476Sdumbbell	.vop_access   = reiserfs_access,
45147476Sdumbbell	.vop_getattr  = reiserfs_getattr,
46147476Sdumbbell	.vop_inactive = reiserfs_inactive,
47147476Sdumbbell	.vop_reclaim  = reiserfs_reclaim,
48147476Sdumbbell};
49147476Sdumbbell
50147476Sdumbbell/* -------------------------------------------------------------------
51147476Sdumbbell * vnode operations
52147476Sdumbbell * -------------------------------------------------------------------*/
53147476Sdumbbell
54147476Sdumbbellstatic int
55147476Sdumbbellreiserfs_access(struct vop_access_args *ap)
56147476Sdumbbell{
57147476Sdumbbell	int error;
58147476Sdumbbell	struct vnode *vp = ap->a_vp;
59147476Sdumbbell	struct reiserfs_node *ip = VTOI(vp);
60184413Strasz	accmode_t accmode = ap->a_accmode;
61147476Sdumbbell
62147476Sdumbbell	/*
63147476Sdumbbell	 * Disallow write attempts on read-only file systems; unless the file
64147476Sdumbbell	 * is a socket, fifo, or a block or character device resident on the
65147476Sdumbbell	 * file system.
66147476Sdumbbell	 */
67184413Strasz	if (accmode & VWRITE) {
68147476Sdumbbell		switch (vp->v_type) {
69147476Sdumbbell		case VDIR:
70147476Sdumbbell		case VLNK:
71147476Sdumbbell		case VREG:
72147476Sdumbbell			if (vp->v_mount->mnt_flag & MNT_RDONLY) {
73147476Sdumbbell				reiserfs_log(LOG_DEBUG,
74147476Sdumbbell				    "no write access (read-only fs)\n");
75147476Sdumbbell				return (EROFS);
76147476Sdumbbell			}
77147476Sdumbbell			break;
78147476Sdumbbell		default:
79147476Sdumbbell			break;
80147476Sdumbbell		}
81147476Sdumbbell	}
82147476Sdumbbell
83147476Sdumbbell	/* If immutable bit set, nobody gets to write it. */
84184413Strasz	if ((accmode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT))) {
85147476Sdumbbell		reiserfs_log(LOG_DEBUG, "no write access (immutable)\n");
86147476Sdumbbell		return (EPERM);
87147476Sdumbbell	}
88147476Sdumbbell
89147476Sdumbbell	error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid,
90184413Strasz	    ap->a_accmode, ap->a_cred, NULL);
91147476Sdumbbell	return (error);
92147476Sdumbbell}
93147476Sdumbbell
94147476Sdumbbellstatic int
95147476Sdumbbellreiserfs_getattr(struct vop_getattr_args *ap)
96147476Sdumbbell{
97147476Sdumbbell	struct vnode *vp         = ap->a_vp;
98147476Sdumbbell	struct vattr *vap        = ap->a_vap;
99147476Sdumbbell	struct reiserfs_node *ip = VTOI(vp);
100147476Sdumbbell
101147476Sdumbbell	vap->va_fsid      = dev2udev(ip->i_dev);
102147476Sdumbbell	vap->va_fileid    = ip->i_number;
103147476Sdumbbell	vap->va_mode      = ip->i_mode & ~S_IFMT;
104147476Sdumbbell	vap->va_nlink     = ip->i_nlink;
105147476Sdumbbell	vap->va_uid       = ip->i_uid;
106147476Sdumbbell	vap->va_gid       = ip->i_gid;
107147476Sdumbbell	//XXX vap->va_rdev      = ip->i_rdev;
108147476Sdumbbell	vap->va_size      = ip->i_size;
109147476Sdumbbell	vap->va_atime     = ip->i_atime;
110147476Sdumbbell	vap->va_mtime     = ip->i_mtime;
111147476Sdumbbell	vap->va_ctime     = ip->i_ctime;
112147476Sdumbbell	vap->va_flags     = ip->i_flags;
113147476Sdumbbell	vap->va_gen       = ip->i_generation;
114147476Sdumbbell	vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
115147476Sdumbbell	vap->va_bytes     = dbtob((u_quad_t)ip->i_blocks);
116147476Sdumbbell	vap->va_type      = vp->v_type;
117147476Sdumbbell	//XXX vap->va_filerev   = ip->i_modrev;
118147476Sdumbbell
119147476Sdumbbell	return (0);
120147476Sdumbbell}
121147476Sdumbbell
122147476Sdumbbell/* Return POSIX pathconf information applicable to ReiserFS filesystems */
123147476Sdumbbellstatic int
124147476Sdumbbellreiserfs_pathconf(struct vop_pathconf_args *ap)
125147476Sdumbbell{
126147476Sdumbbell	switch (ap->a_name) {
127147476Sdumbbell	case _PC_LINK_MAX:
128147476Sdumbbell		*ap->a_retval = REISERFS_LINK_MAX;
129147476Sdumbbell		return (0);
130147476Sdumbbell	case _PC_NAME_MAX:
131147476Sdumbbell		*ap->a_retval =
132147476Sdumbbell		    REISERFS_MAX_NAME(VTOI(ap->a_vp)->i_reiserfs->s_blocksize);
133147476Sdumbbell		return (0);
134147476Sdumbbell	case _PC_PATH_MAX:
135147476Sdumbbell		*ap->a_retval = PATH_MAX;
136147476Sdumbbell		return (0);
137147476Sdumbbell	case _PC_PIPE_BUF:
138147476Sdumbbell		*ap->a_retval = PIPE_BUF;
139147476Sdumbbell		return (0);
140147476Sdumbbell	case _PC_CHOWN_RESTRICTED:
141147476Sdumbbell		*ap->a_retval = 1;
142147476Sdumbbell		return (0);
143147476Sdumbbell	case _PC_NO_TRUNC:
144147476Sdumbbell		*ap->a_retval = 1;
145147476Sdumbbell		return (0);
146147476Sdumbbell	default:
147147476Sdumbbell		return (EINVAL);
148147476Sdumbbell	}
149147476Sdumbbell}
150147476Sdumbbell
151147476Sdumbbellstatic int
152147476Sdumbbellreiserfs_open(struct vop_open_args *ap)
153147476Sdumbbell{
154147476Sdumbbell	/* Files marked append-only must be opened for appending. */
155147476Sdumbbell	if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
156147476Sdumbbell	    (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
157147476Sdumbbell		return (EPERM);
158147476Sdumbbell
159147476Sdumbbell	vnode_create_vobject(ap->a_vp, VTOI(ap->a_vp)->i_size, ap->a_td);
160147476Sdumbbell
161147476Sdumbbell	return (0);
162147476Sdumbbell}
163147476Sdumbbell
164147476Sdumbbell/* Return target name of a symbolic link */
165147476Sdumbbellstatic int
166147476Sdumbbellreiserfs_readlink(struct vop_readlink_args *ap)
167147476Sdumbbell{
168147476Sdumbbell	struct vnode *vp = ap->a_vp;
169147476Sdumbbell
170147476Sdumbbell	reiserfs_log(LOG_DEBUG, "redirect to VOP_READ()\n");
171147476Sdumbbell	return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
172147476Sdumbbell}
173147476Sdumbbell
174147476Sdumbbell/* Bmap converts the logical block number of a file to its physical
175147476Sdumbbell * block number on the disk. */
176147476Sdumbbellstatic int
177147476Sdumbbellreiserfs_bmap(ap)
178147476Sdumbbell	struct vop_bmap_args /* {
179147476Sdumbbell				struct vnode *a_vp;
180147476Sdumbbell				daddr_t a_bn;
181147476Sdumbbell				struct bufobj **a_bop;
182147476Sdumbbell				daddr_t *a_bnp;
183147476Sdumbbell				int *a_runp;
184147476Sdumbbell				int *a_runb;
185147476Sdumbbell				} */ *ap;
186147476Sdumbbell{
187147476Sdumbbell	daddr_t blkno;
188147476Sdumbbell	struct buf *bp;
189147476Sdumbbell	struct cpu_key key;
190147476Sdumbbell	struct item_head *ih;
191147476Sdumbbell
192147476Sdumbbell	struct vnode *vp = ap->a_vp;
193147476Sdumbbell	struct reiserfs_node *ip = VTOI(vp);
194147476Sdumbbell	struct reiserfs_sb_info *sbi = ip->i_reiserfs;
195147476Sdumbbell	INITIALIZE_PATH(path);
196147476Sdumbbell
197147476Sdumbbell	/* Prepare the key to look for the 'block'-th block of file
198147476Sdumbbell	 * (XXX we suppose that statfs.f_iosize == sbi->s_blocksize) */
199147476Sdumbbell	make_cpu_key(&key, ip, (off_t)ap->a_bn * sbi->s_blocksize + 1,
200147476Sdumbbell	    TYPE_ANY, 3);
201147476Sdumbbell
202147476Sdumbbell	/* Search item */
203147476Sdumbbell	if (search_for_position_by_key(sbi, &key, &path) != POSITION_FOUND) {
204147476Sdumbbell		reiserfs_log(LOG_DEBUG, "position not found\n");
205147476Sdumbbell		pathrelse(&path);
206147476Sdumbbell		return (ENOENT);
207147476Sdumbbell	}
208147476Sdumbbell
209147476Sdumbbell	bp = get_last_bp(&path);
210147476Sdumbbell	ih = get_ih(&path);
211147476Sdumbbell
212147476Sdumbbell	if (is_indirect_le_ih(ih)) {
213147476Sdumbbell		/* Indirect item can be read by the underlying layer, instead of
214147476Sdumbbell		 * VOP_STRATEGY. */
215147476Sdumbbell		int i;
216147476Sdumbbell		uint32_t *ind_item = (uint32_t *)B_I_PITEM(bp, ih);
217147476Sdumbbell		reiserfs_log(LOG_DEBUG, "found an INDIRECT item\n");
218147476Sdumbbell		blkno = get_block_num(ind_item, path.pos_in_item);
219147476Sdumbbell
220147476Sdumbbell		/* Read-ahead */
221147476Sdumbbell		if (ap->a_runb) {
222147476Sdumbbell			uint32_t count = 0;
223147476Sdumbbell			for (i = path.pos_in_item - 1; i >= 0; --i) {
224147476Sdumbbell				if ((blkno - get_block_num(ind_item, i)) !=
225147476Sdumbbell				    count + 1)
226147476Sdumbbell					break;
227147476Sdumbbell				++count;
228147476Sdumbbell			}
229147476Sdumbbell
230147476Sdumbbell			/*
231147476Sdumbbell			 * This count isn't expressed in DEV_BSIZE base but
232147476Sdumbbell			 * in fs' own block base
233147476Sdumbbell			 * (see sys/vm/vnode_pager.c:vnode_pager_addr())
234147476Sdumbbell			 */
235147476Sdumbbell			*ap->a_runb = count;
236147476Sdumbbell			reiserfs_log(LOG_DEBUG,
237147476Sdumbbell			    " read-ahead: %d blocks before\n", *ap->a_runb);
238147476Sdumbbell		}
239147476Sdumbbell		if (ap->a_runp) {
240147476Sdumbbell			uint32_t count = 0;
241147476Sdumbbell			/*
242147476Sdumbbell			 * ih is an uint32_t array, that's why we use
243147476Sdumbbell			 * its length (in bytes) divided by 4 to know
244147476Sdumbbell			 * the number of items
245147476Sdumbbell			 */
246147476Sdumbbell			for (i = path.pos_in_item + 1;
247147476Sdumbbell			    i < ih_item_len(ih) / 4; ++i) {
248147476Sdumbbell				if ((get_block_num(ind_item, i) - blkno) !=
249147476Sdumbbell				    count + 1)
250147476Sdumbbell					break;
251147476Sdumbbell				++count;
252147476Sdumbbell			}
253147476Sdumbbell
254147476Sdumbbell			/*
255147476Sdumbbell			 * This count isn't expressed in DEV_BSIZE base but
256147476Sdumbbell			 * in fs' own block base
257147476Sdumbbell			 * (see sys/vm/vnode_pager.c:vnode_pager_addr()) */
258147476Sdumbbell			*ap->a_runp = count;
259147476Sdumbbell			reiserfs_log(LOG_DEBUG,
260147476Sdumbbell			    " read-ahead: %d blocks after\n", *ap->a_runp);
261147476Sdumbbell		}
262147476Sdumbbell
263147476Sdumbbell		/* Indirect items can be read using the device VOP_STRATEGY */
264147476Sdumbbell		if (ap->a_bop)
265147476Sdumbbell			*ap->a_bop = &VTOI(ap->a_vp)->i_devvp->v_bufobj;
266147476Sdumbbell
267147476Sdumbbell		/* Convert the block number into DEV_BSIZE base */
268147476Sdumbbell		blkno *= btodb(sbi->s_blocksize);
269147476Sdumbbell	} else {
270147476Sdumbbell		/*
271147476Sdumbbell		 * Direct item are not DEV_BSIZE aligned, VOP_STRATEGY will
272147476Sdumbbell		 * have to handle this case specifically
273147476Sdumbbell		 */
274147476Sdumbbell		reiserfs_log(LOG_DEBUG, "found a DIRECT item\n");
275147476Sdumbbell		blkno = ap->a_bn;
276147476Sdumbbell
277147476Sdumbbell		if (ap->a_runp)
278147476Sdumbbell			*ap->a_runp = 0;
279147476Sdumbbell		if (ap->a_runb)
280147476Sdumbbell			*ap->a_runb = 0;
281147476Sdumbbell
282147476Sdumbbell		/* Direct item must be read by reiserfs_strategy */
283147476Sdumbbell		if (ap->a_bop)
284147476Sdumbbell			*ap->a_bop = &vp->v_bufobj;
285147476Sdumbbell	}
286147476Sdumbbell
287147476Sdumbbell	if (ap->a_bnp)
288147476Sdumbbell		*ap->a_bnp = blkno;
289147476Sdumbbell
290147476Sdumbbell	pathrelse(&path);
291147476Sdumbbell
292147476Sdumbbell	if (ap->a_bnp) {
293147476Sdumbbell		reiserfs_log(LOG_DEBUG, "logical block: %ju (%ju),"
294147476Sdumbbell		    " physical block: %ju (%ju)\n",
295147476Sdumbbell		    (intmax_t)ap->a_bn,
296147476Sdumbbell		    (intmax_t)(ap->a_bn / btodb(sbi->s_blocksize)),
297147476Sdumbbell		    (intmax_t)*ap->a_bnp,
298147476Sdumbbell		    (intmax_t)(*ap->a_bnp / btodb(sbi->s_blocksize)));
299147476Sdumbbell	}
300147476Sdumbbell
301147476Sdumbbell	return (0);
302147476Sdumbbell}
303147476Sdumbbell
304147476Sdumbbell/* Does simply the same as reiserfs_read. It's called when reiserfs_bmap find
305147476Sdumbbell * an direct item. */
306147476Sdumbbellstatic int
307147476Sdumbbellreiserfs_strategy(struct vop_strategy_args /* {
308147476Sdumbbell					      struct vnode *a_vp;
309147476Sdumbbell					      struct buf *a_bp;
310147476Sdumbbell					      } */ *ap)
311147476Sdumbbell{
312147476Sdumbbell	int error;
313147476Sdumbbell	struct uio auio;
314147476Sdumbbell	struct iovec aiov;
315147476Sdumbbell	struct reiserfs_node *ip;
316147476Sdumbbell	struct buf *bp = ap->a_bp;
317147476Sdumbbell	struct vnode *vp = ap->a_vp;
318147476Sdumbbell
319147476Sdumbbell	reiserfs_log(LOG_DEBUG, "logical block: %ju,"
320147476Sdumbbell	    " physical block: %ju\n", (intmax_t)bp->b_lblkno,
321147476Sdumbbell	    (intmax_t)bp->b_blkno);
322147476Sdumbbell
323147476Sdumbbell	ip = VTOI(vp);
324147476Sdumbbell
325147476Sdumbbell	if (bp->b_iocmd == BIO_READ) {
326147476Sdumbbell		/* Prepare the uio structure */
327147476Sdumbbell		reiserfs_log(LOG_DEBUG, "prepare uio structure\n");
328147476Sdumbbell		aiov.iov_base = bp->b_data;
329147476Sdumbbell		aiov.iov_len  = MIN(bp->b_bcount, ip->i_size);
330147476Sdumbbell		reiserfs_log(LOG_DEBUG, "  vector length: %ju\n",
331147476Sdumbbell		    (intmax_t)aiov.iov_len);
332147476Sdumbbell
333147476Sdumbbell		auio.uio_iov    = &aiov;
334147476Sdumbbell		auio.uio_iovcnt = 1;
335147476Sdumbbell		auio.uio_offset = 0;
336147476Sdumbbell		auio.uio_rw     = UIO_READ;
337147476Sdumbbell		auio.uio_segflg = UIO_SYSSPACE;
338147476Sdumbbell		auio.uio_td     = curthread;
339147476Sdumbbell		auio.uio_resid  = bp->b_bcount;
340147476Sdumbbell		reiserfs_log(LOG_DEBUG, "  buffer length: %u\n",
341147476Sdumbbell		    auio.uio_resid);
342147476Sdumbbell
343147476Sdumbbell		reiserfs_log(LOG_DEBUG, "reading block #%ju\n",
344147476Sdumbbell		    (intmax_t)bp->b_blkno);
345147476Sdumbbell		error = reiserfs_get_block(ip, bp->b_blkno, 0, &auio);
346147476Sdumbbell	} else {
347147476Sdumbbell		/* No write support yet */
348147476Sdumbbell		error = (EOPNOTSUPP);
349147476Sdumbbell		bp->b_error    = error;
350147476Sdumbbell		bp->b_ioflags |= BIO_ERROR;
351147476Sdumbbell	}
352147476Sdumbbell
353186194Strasz	if (error) {
354186194Strasz		bp->b_ioflags |= BIO_ERROR;
355186194Strasz		bp->b_error = error;
356186194Strasz	}
357186194Strasz
358147476Sdumbbell	bufdone(bp);
359186194Strasz	return (0);
360147476Sdumbbell}
361166774Spjd
362166774Spjd/*
363166774Spjd * Vnode pointer to File handle
364166774Spjd */
365166774Spjdstatic int
366166774Spjdreiserfs_vptofh(struct vop_vptofh_args /* {
367166774Spjd					  struct vnode *a_vp;
368166774Spjd					  struct fid *a_fhp;
369166774Spjd					  } */ *ap)
370166774Spjd{
371166774Spjd	struct rfid *rfhp;
372166774Spjd	struct reiserfs_node *ip;
373166774Spjd
374166774Spjd	ip = VTOI(ap->a_vp);
375166774Spjd	reiserfs_log(LOG_DEBUG,
376166774Spjd	    "fill *fhp with inode (dirid=%d, objectid=%d)\n",
377166774Spjd	    ip->i_ino, ip->i_number);
378166774Spjd
379166774Spjd	rfhp = (struct rfid *)ap->a_fhp;
380166774Spjd	rfhp->rfid_len      = sizeof(struct rfid);
381166774Spjd	rfhp->rfid_dirid    = ip->i_ino;
382166774Spjd	rfhp->rfid_objectid = ip->i_number;
383166774Spjd	rfhp->rfid_gen      = ip->i_generation;
384166774Spjd
385166774Spjd	reiserfs_log(LOG_DEBUG, "return it\n");
386166774Spjd	return (0);
387166774Spjd}
388