]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/gnu/fs/reiserfs/reiserfs_vnops.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / 6 / sys / gnu / fs / reiserfs / reiserfs_vnops.c
1 /*-
2  * Copyright 2000 Hans Reiser
3  * See README for licensing and copyright details
4  * 
5  * Ported to FreeBSD by Jean-Sébastien Pédron <jspedron@club-internet.fr>
6  * 
7  * $FreeBSD$
8  */
9
10 #include <gnu/fs/reiserfs/reiserfs_fs.h>
11
12 static vop_access_t     reiserfs_access;
13 static vop_bmap_t       reiserfs_bmap;
14 static vop_getattr_t    reiserfs_getattr;
15 static vop_open_t       reiserfs_open;
16 static vop_pathconf_t   reiserfs_pathconf;
17 static vop_readlink_t   reiserfs_readlink;
18 static vop_strategy_t   reiserfs_strategy;
19
20 /* Global vfs data structures for ReiserFS */
21 struct vop_vector reiserfs_vnodeops = {
22         .vop_default      = &default_vnodeops,
23
24         .vop_access       = reiserfs_access,
25         .vop_bmap         = reiserfs_bmap,
26         .vop_cachedlookup = reiserfs_lookup,
27         .vop_getattr      = reiserfs_getattr,
28         .vop_inactive     = reiserfs_inactive,
29         .vop_lookup       = vfs_cache_lookup,
30         .vop_open         = reiserfs_open,
31         .vop_reclaim      = reiserfs_reclaim,
32         .vop_read         = reiserfs_read,
33         .vop_readdir      = reiserfs_readdir,
34         .vop_readlink     = reiserfs_readlink,
35         .vop_pathconf     = reiserfs_pathconf,
36         .vop_strategy     = reiserfs_strategy,
37 };
38
39 struct vop_vector reiserfs_specops = {
40         .vop_default  = &default_vnodeops,
41
42         .vop_access   = reiserfs_access,
43         .vop_getattr  = reiserfs_getattr,
44         .vop_inactive = reiserfs_inactive,
45         .vop_reclaim  = reiserfs_reclaim,
46 };
47
48 /* -------------------------------------------------------------------
49  * vnode operations
50  * -------------------------------------------------------------------*/
51
52 static int
53 reiserfs_access(struct vop_access_args *ap)
54 {
55         int error;
56         struct vnode *vp = ap->a_vp;
57         struct reiserfs_node *ip = VTOI(vp);
58         mode_t mode = ap->a_mode;
59
60         /*
61          * Disallow write attempts on read-only file systems; unless the file
62          * is a socket, fifo, or a block or character device resident on the
63          * file system.
64          */
65         if (mode & VWRITE) {
66                 switch (vp->v_type) {
67                 case VDIR:
68                 case VLNK:
69                 case VREG:
70                         if (vp->v_mount->mnt_flag & MNT_RDONLY) {
71                                 reiserfs_log(LOG_DEBUG,
72                                     "no write access (read-only fs)\n");
73                                 return (EROFS);
74                         }
75                         break;
76                 default:
77                         break;
78                 }
79         }
80
81         /* If immutable bit set, nobody gets to write it. */
82         if ((mode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT))) {
83                 reiserfs_log(LOG_DEBUG, "no write access (immutable)\n");
84                 return (EPERM);
85         }
86
87         error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid,
88             ap->a_mode, ap->a_cred, NULL);
89         return (error);
90 }
91
92 static int
93 reiserfs_getattr(struct vop_getattr_args *ap)
94 {
95         struct vnode *vp         = ap->a_vp;
96         struct vattr *vap        = ap->a_vap;
97         struct reiserfs_node *ip = VTOI(vp);
98
99         vap->va_fsid      = dev2udev(ip->i_dev);
100         vap->va_fileid    = ip->i_number;
101         vap->va_mode      = ip->i_mode & ~S_IFMT;
102         vap->va_nlink     = ip->i_nlink;
103         vap->va_uid       = ip->i_uid;
104         vap->va_gid       = ip->i_gid;
105         //XXX vap->va_rdev      = ip->i_rdev;
106         vap->va_size      = ip->i_size;
107         vap->va_atime     = ip->i_atime;
108         vap->va_mtime     = ip->i_mtime;
109         vap->va_ctime     = ip->i_ctime;
110         vap->va_flags     = ip->i_flags;
111         vap->va_gen       = ip->i_generation;
112         vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
113         vap->va_bytes     = dbtob((u_quad_t)ip->i_blocks);
114         vap->va_type      = vp->v_type;
115         //XXX vap->va_filerev   = ip->i_modrev;
116
117         return (0);
118 }
119
120 /* Return POSIX pathconf information applicable to ReiserFS filesystems */
121 static int
122 reiserfs_pathconf(struct vop_pathconf_args *ap)
123 {
124         switch (ap->a_name) {
125         case _PC_LINK_MAX:
126                 *ap->a_retval = REISERFS_LINK_MAX;
127                 return (0);
128         case _PC_NAME_MAX:
129                 *ap->a_retval =
130                     REISERFS_MAX_NAME(VTOI(ap->a_vp)->i_reiserfs->s_blocksize);
131                 return (0);
132         case _PC_PATH_MAX:
133                 *ap->a_retval = PATH_MAX;
134                 return (0);
135         case _PC_PIPE_BUF:
136                 *ap->a_retval = PIPE_BUF;
137                 return (0);
138         case _PC_CHOWN_RESTRICTED:
139                 *ap->a_retval = 1;
140                 return (0);
141         case _PC_NO_TRUNC:
142                 *ap->a_retval = 1;
143                 return (0);
144         default:
145                 return (EINVAL);
146         }
147 }
148
149 static int
150 reiserfs_open(struct vop_open_args *ap)
151 {
152         /* Files marked append-only must be opened for appending. */
153         if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
154             (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
155                 return (EPERM);
156
157         vnode_create_vobject_off(ap->a_vp, VTOI(ap->a_vp)->i_size, ap->a_td);
158
159         return (0);
160 }
161
162 /* Return target name of a symbolic link */
163 static int
164 reiserfs_readlink(struct vop_readlink_args *ap)
165 {
166         struct vnode *vp = ap->a_vp;
167
168         reiserfs_log(LOG_DEBUG, "redirect to VOP_READ()\n");
169         return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
170 }
171
172 /* Bmap converts the logical block number of a file to its physical
173  * block number on the disk. */
174 static int
175 reiserfs_bmap(ap)
176         struct vop_bmap_args /* {
177                                 struct vnode *a_vp;
178                                 daddr_t a_bn;
179                                 struct bufobj **a_bop;
180                                 daddr_t *a_bnp;
181                                 int *a_runp;
182                                 int *a_runb;
183                                 } */ *ap;
184 {
185         daddr_t blkno;
186         struct buf *bp;
187         struct cpu_key key;
188         struct item_head *ih;
189
190         struct vnode *vp = ap->a_vp;
191         struct reiserfs_node *ip = VTOI(vp);
192         struct reiserfs_sb_info *sbi = ip->i_reiserfs;
193         INITIALIZE_PATH(path);
194
195         /* Prepare the key to look for the 'block'-th block of file
196          * (XXX we suppose that statfs.f_iosize == sbi->s_blocksize) */
197         make_cpu_key(&key, ip, (off_t)ap->a_bn * sbi->s_blocksize + 1,
198             TYPE_ANY, 3);
199
200         /* Search item */
201         if (search_for_position_by_key(sbi, &key, &path) != POSITION_FOUND) {
202                 reiserfs_log(LOG_DEBUG, "position not found\n");
203                 pathrelse(&path);
204                 return (ENOENT);
205         }
206
207         bp = get_last_bp(&path);
208         ih = get_ih(&path);
209
210         if (is_indirect_le_ih(ih)) {
211                 /* Indirect item can be read by the underlying layer, instead of
212                  * VOP_STRATEGY. */
213                 int i;
214                 uint32_t *ind_item = (uint32_t *)B_I_PITEM(bp, ih);
215                 reiserfs_log(LOG_DEBUG, "found an INDIRECT item\n");
216                 blkno = get_block_num(ind_item, path.pos_in_item);
217
218                 /* Read-ahead */
219                 if (ap->a_runb) {
220                         uint32_t count = 0;
221                         for (i = path.pos_in_item - 1; i >= 0; --i) {
222                                 if ((blkno - get_block_num(ind_item, i)) !=
223                                     count + 1)
224                                         break;
225                                 ++count;
226                         }
227
228                         /*
229                          * This count isn't expressed in DEV_BSIZE base but
230                          * in fs' own block base
231                          * (see sys/vm/vnode_pager.c:vnode_pager_addr())
232                          */
233                         *ap->a_runb = count;
234                         reiserfs_log(LOG_DEBUG,
235                             " read-ahead: %d blocks before\n", *ap->a_runb);
236                 }
237                 if (ap->a_runp) {
238                         uint32_t count = 0;
239                         /*
240                          * ih is an uint32_t array, that's why we use
241                          * its length (in bytes) divided by 4 to know
242                          * the number of items
243                          */
244                         for (i = path.pos_in_item + 1;
245                             i < ih_item_len(ih) / 4; ++i) {
246                                 if ((get_block_num(ind_item, i) - blkno) !=
247                                     count + 1)
248                                         break;
249                                 ++count;
250                         }
251
252                         /*
253                          * This count isn't expressed in DEV_BSIZE base but
254                          * in fs' own block base
255                          * (see sys/vm/vnode_pager.c:vnode_pager_addr()) */
256                         *ap->a_runp = count;
257                         reiserfs_log(LOG_DEBUG,
258                             " read-ahead: %d blocks after\n", *ap->a_runp);
259                 }
260
261                 /* Indirect items can be read using the device VOP_STRATEGY */
262                 if (ap->a_bop)
263                         *ap->a_bop = &VTOI(ap->a_vp)->i_devvp->v_bufobj;
264
265                 /* Convert the block number into DEV_BSIZE base */
266                 blkno *= btodb(sbi->s_blocksize);
267         } else {
268                 /*
269                  * Direct item are not DEV_BSIZE aligned, VOP_STRATEGY will
270                  * have to handle this case specifically
271                  */
272                 reiserfs_log(LOG_DEBUG, "found a DIRECT item\n");
273                 blkno = ap->a_bn;
274
275                 if (ap->a_runp)
276                         *ap->a_runp = 0;
277                 if (ap->a_runb)
278                         *ap->a_runb = 0;
279
280                 /* Direct item must be read by reiserfs_strategy */
281                 if (ap->a_bop)
282                         *ap->a_bop = &vp->v_bufobj;
283         }
284
285         if (ap->a_bnp)
286                 *ap->a_bnp = blkno;
287
288         pathrelse(&path);
289
290         if (ap->a_bnp) {
291                 reiserfs_log(LOG_DEBUG, "logical block: %ju (%ju),"
292                     " physical block: %ju (%ju)\n",
293                     (intmax_t)ap->a_bn,
294                     (intmax_t)(ap->a_bn / btodb(sbi->s_blocksize)),
295                     (intmax_t)*ap->a_bnp,
296                     (intmax_t)(*ap->a_bnp / btodb(sbi->s_blocksize)));
297         }
298
299         return (0);
300 }
301
302 /* Does simply the same as reiserfs_read. It's called when reiserfs_bmap find
303  * an direct item. */
304 static int
305 reiserfs_strategy(struct vop_strategy_args /* {
306                                               struct vnode *a_vp;
307                                               struct buf *a_bp;
308                                               } */ *ap)
309 {
310         int error;
311         struct uio auio;
312         struct iovec aiov;
313         struct reiserfs_node *ip;
314         struct buf *bp = ap->a_bp;
315         struct vnode *vp = ap->a_vp;
316
317         reiserfs_log(LOG_DEBUG, "logical block: %ju,"
318             " physical block: %ju\n", (intmax_t)bp->b_lblkno,
319             (intmax_t)bp->b_blkno);
320
321         ip = VTOI(vp);
322
323         if (bp->b_iocmd == BIO_READ) {
324                 /* Prepare the uio structure */
325                 reiserfs_log(LOG_DEBUG, "prepare uio structure\n");
326                 aiov.iov_base = bp->b_data;
327                 aiov.iov_len  = MIN(bp->b_bcount, ip->i_size);
328                 reiserfs_log(LOG_DEBUG, "  vector length: %ju\n",
329                     (intmax_t)aiov.iov_len);
330
331                 auio.uio_iov    = &aiov;
332                 auio.uio_iovcnt = 1;
333                 auio.uio_offset = 0;
334                 auio.uio_rw     = UIO_READ;
335                 auio.uio_segflg = UIO_SYSSPACE;
336                 auio.uio_td     = curthread;
337                 auio.uio_resid  = bp->b_bcount;
338                 reiserfs_log(LOG_DEBUG, "  buffer length: %u\n",
339                     auio.uio_resid);
340
341                 reiserfs_log(LOG_DEBUG, "reading block #%ju\n",
342                     (intmax_t)bp->b_blkno);
343                 error = reiserfs_get_block(ip, bp->b_blkno, 0, &auio);
344         } else {
345                 /* No write support yet */
346                 error = (EOPNOTSUPP);
347                 bp->b_error    = error;
348                 bp->b_ioflags |= BIO_ERROR;
349         }
350
351         bufdone(bp);
352         return (error);
353 }