1 |
/* ext2 file system. |
/* Copyright 2002 Johan Rydberg, jrydberg@rtmk.org. |
|
Copyright 2002 Johan Rydberg, jrydberg@rtmk.org. |
|
2 |
|
|
3 |
This program is free software; you can redistribute it and/or modify |
This program is free software; you can redistribute it and/or modify |
4 |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
14 |
along with this program; if not, write to the Free Software |
along with this program; if not, write to the Free Software |
15 |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
16 |
|
|
17 |
|
#include <sys/param.h> |
18 |
#include <stdio.h> |
#include <stdio.h> |
19 |
|
#include <errno.h> |
20 |
|
#include <stdlib.h> |
21 |
|
#include <string.h> |
22 |
|
#include <dirent.h> |
23 |
|
|
24 |
#include "nova-intern.h" |
#include "io-vfs.h" |
25 |
#include "module.h" |
#include "io-vnode.h" |
|
#include "vfs.h" |
|
26 |
#include "io-buf.h" |
#include "io-buf.h" |
27 |
|
#include "module.h" |
28 |
|
|
29 |
#include "fs-ext2.h" |
#include "fs-ext2.h" |
30 |
#include "fs-spec.h" |
#include "fs-spec.h" |
31 |
|
|
32 |
|
#include "nova-intern.h" |
33 |
|
|
34 |
#ifndef DEV_BSIZE |
#ifndef DEV_BSIZE |
35 |
# define DEV_BSIZE 512 |
# define DEV_BSIZE 512 |
36 |
#endif |
#endif |
37 |
|
|
38 |
#define EXT2_DINODE_SIZE (sizeof (struct ext2fs_dinode)) |
/* Hash buckets for fast <VFS, INO> lookup. */ |
39 |
/* The minimum length for a directory entry. |
struct queue_entry ext2fs_hash_buckets [256]; |
40 |
XXX Does ext2fs need this? */ |
pthread_mutex_t ext2fs_hash_lock = PTHREAD_MUTEX_INITIALIZER; |
41 |
#define EXT2FS_MINENT 12 |
|
42 |
|
/* Hash function for calculating hash bucket index. */ |
43 |
static int ext2fs_mountroot (struct vfs *vfs, dev_t rootdev); |
#define EXT2FS_HASH(VFS, INO) ((unsigned int) (((int) (VFS) >> 3) + (INO)) % 256) |
44 |
static int ext2fs_root (struct vfs *vfs, struct vnode **vpp); |
|
45 |
static int ext2fs_lookup (struct vnode *vp, char *cname, struct vnode **vpp); |
/* Forward declarations. */ |
46 |
static int ext2fs_open (struct vnode *vp, int mode, struct ucred *ucred, struct proc *p); |
static void add_cache (struct vnode *vp); |
47 |
static int ext2fs_access (struct vnode *vp, int mode, struct ucred *ucred, struct proc *p); |
static void remove_cache (struct vnode *vp); |
48 |
static int ext2fs_read (struct vnode *vp, struct io_uio *uio, struct ucred *ucred); |
static struct vnode *lookup_cache (struct vfs *vfs, ino_t ino); |
49 |
|
extern struct vnode_ops ext2fs_vnops; |
|
static struct vfs_ops ext2fs_vfsops = |
|
|
{ |
|
|
0, /* mount */ |
|
|
0, /* umount */ |
|
|
ext2fs_mountroot, /* mountroot */ |
|
|
ext2fs_root /* root */ |
|
|
}; |
|
|
|
|
|
static struct vnode_ops ext2fs_vnops = |
|
|
{ |
|
|
ext2fs_open, |
|
|
ext2fs_access, |
|
|
ext2fs_lookup, |
|
|
0, /* strategy */ |
|
|
ext2fs_read |
|
|
}; |
|
|
|
|
50 |
|
|
51 |
/* Map indirect blocks from logical block numbers to filesystem blocks. */ |
/* Map indirect blocks from logical block numbers to filesystem blocks. */ |
52 |
u_int32_t |
u_int32_t |
53 |
ext2fs_bmap (struct ext2fs_softc *sc, int level, u_int32_t mblk, |
search_bmap (struct ext2fs_softc *sc, int level, u_int32_t mblk, |
54 |
u_int32_t lblk, u_int32_t addr_per_block) |
u_int32_t lblk, u_int32_t addr_per_block, int *runp) |
55 |
{ |
{ |
56 |
struct io_buf *bp; |
struct io_buf *bp; |
57 |
u_int32_t b = 0; |
u_int32_t b = 0; |
67 |
} |
} |
68 |
|
|
69 |
/* Read the map block into memory. */ |
/* Read the map block into memory. */ |
70 |
err = io_bread (sc->sc_vp, fsbtodb (sc, mblk), sc->sc_bsize, &bp); |
err = io_buf_read (sc->sc_vp, fsbtodb (sc, mblk), sc->sc_bsize, 0, &bp); |
71 |
if (err) |
if (err) |
72 |
return err; |
return err; |
73 |
|
|
74 |
/* Look up block in table. If LEVEL isn't zero, indirect further. */ |
/* Look up block in table. If LEVEL isn't zero, indirect further. */ |
75 |
b = ((u_int32_t *) bp->b_data) [lblk / addr_per_block]; |
b = ((u_int32_t *) bp->data) [lblk / addr_per_block]; |
76 |
io_brelease (bp); |
|
77 |
|
if (runp && !level) |
78 |
|
{ |
79 |
|
u_int32_t *p = ((u_int32_t *) bp->data); |
80 |
|
int blkno = lblk / addr_per_block, i; |
81 |
|
|
82 |
|
*runp = 0; |
83 |
|
|
84 |
|
for (i = blkno; i < (int) ((sc->sc_bsize/sizeof b) - 1); i++) |
85 |
|
{ |
86 |
|
if (p [i + 1] == p [i] + 1) |
87 |
|
{ (*runp)++; continue; } |
88 |
|
break; |
89 |
|
} |
90 |
|
} |
91 |
|
|
92 |
|
io_buf_release (bp); |
93 |
if (level != 0) |
if (level != 0) |
94 |
return ext2fs_bmap (sc, level - 1, b, lblk % (sc->sc_bsize / sizeof b), |
return search_bmap (sc, level - 1, b, lblk % (sc->sc_bsize / sizeof b), |
95 |
addr_per_block / (sc->sc_bsize / sizeof b)); |
addr_per_block / (sc->sc_bsize / sizeof b), runp); |
96 |
return b; |
return b; |
97 |
} |
} |
98 |
|
|
99 |
/* Map a logical block number to a filesystem block number. */ |
/* Map a logical block number to a filesystem block number. */ |
100 |
static u_int32_t |
static u_int32_t |
101 |
getblk (struct ext2fs_softc *sc, struct ext2fs_dinode *ip, u_int32_t lblk) |
getblk (struct ext2fs_softc *sc, struct ext2fs_dinode *ip, u_int32_t lblk, |
102 |
|
int *runp) |
103 |
{ |
{ |
104 |
u_int32_t addr_per_block = sc->sc_bsize / sizeof (u_int32_t); |
u_int32_t addr_per_block = sc->sc_bsize / sizeof (u_int32_t); |
105 |
int indirect; |
int indirect; |
106 |
|
|
107 |
if (lblk < NDIRECT) |
if (lblk < NDIRECT) |
108 |
return ip->blocks [lblk]; |
{ |
109 |
|
if (runp) |
110 |
|
{ |
111 |
|
*runp = 0; |
112 |
|
for (indirect = lblk; indirect < NDIRECT - 1; indirect++) |
113 |
|
{ |
114 |
|
if (ip->blocks [indirect] + 1 == ip->blocks [indirect + 1]) |
115 |
|
{ (*runp)++; continue; } |
116 |
|
break; |
117 |
|
} |
118 |
|
} |
119 |
|
return ip->blocks [lblk]; |
120 |
|
} |
121 |
lblk = lblk - NDIRECT; |
lblk = lblk - NDIRECT; |
122 |
|
|
123 |
for (indirect = 0; lblk >= addr_per_block; ) |
for (indirect = 0; lblk >= addr_per_block; ) |
126 |
addr_per_block = addr_per_block * addr_per_block; |
addr_per_block = addr_per_block * addr_per_block; |
127 |
indirect++; |
indirect++; |
128 |
} |
} |
129 |
return ext2fs_bmap (sc, indirect, ip->blocks [NDIRECT + indirect], |
return |
130 |
lblk, addr_per_block / (sc->sc_bsize / sizeof (u_int32_t))); |
search_bmap (sc, indirect, ip->blocks [NDIRECT + indirect], |
131 |
|
lblk, addr_per_block / (sc->sc_bsize / sizeof (u_int32_t)), |
132 |
|
runp); |
133 |
} |
} |
134 |
|
|
135 |
/* Initialize the vnode associated with a new inode. */ |
/* Initialize the vnode associated with a new inode. */ |
|
|
|
136 |
int |
int |
137 |
ext2fs_vinit (struct vfs *vfs, struct vnode **vpp) |
ext2fs_vinit (struct vfs *vfs, struct vnode **vpp) |
138 |
{ |
{ |
139 |
struct ext2fs_inode *ip; |
struct inode *ip; |
140 |
struct vnode *vp; |
struct vnode *vp; |
141 |
|
|
142 |
vp = *vpp; |
vp = *vpp; |
143 |
ip = (struct ext2fs_inode *) vp->v_data; |
ip = VTOI (vp); |
144 |
|
|
145 |
vp->v_type = IFTOVT (ip->dinode.mode); |
vp->v_type = IFTOVT (ip->i_dinode.mode); |
146 |
if (vp->v_type == VBLK || vp->v_type == VCHR) |
if (vp->v_type == VBLK || vp->v_type == VCHR) |
147 |
{ |
{ |
148 |
vp->v_ops = &specfs_vnops; |
vp->v_ops = &specfs_vnops; |
149 |
vp->v_rdev = (dev_t) ip->dinode.blocks [0]; |
vp->v_rdev = (dev_t) ip->i_dinode.blocks [0]; |
150 |
} |
} |
151 |
|
|
152 |
return 0; |
return 0; |
156 |
in from disk. If it is in core, wait for the lock bit to clear, then |
in from disk. If it is in core, wait for the lock bit to clear, then |
157 |
return the inode locked. Detection and handling of mount points must be |
return the inode locked. Detection and handling of mount points must be |
158 |
done by the calling routine. */ |
done by the calling routine. */ |
|
|
|
159 |
int |
int |
160 |
ext2fs_vget (struct vfs *vfs, ino_t ino, struct vnode **vpp) |
ext2fs_vget (struct vfs *vfs, ino_t ino, struct vnode **vpp) |
161 |
{ |
{ |
162 |
struct ext2fs_softc *sc = (struct ext2fs_softc *) vfs->vfs_data; |
struct ext2fs_softc *sc = (struct ext2fs_softc *) vfs->vfs_data; |
163 |
struct ext2fs_inode *ip; |
struct inode *ip; |
164 |
struct io_buf *bp; |
struct io_buf *bp; |
165 |
struct vnode *vp; |
struct vnode *vp; |
166 |
int err; |
int err; |
167 |
|
|
168 |
/* ??? lookup in inode cache. */ |
*vpp = lookup_cache (vfs, ino); |
169 |
|
if (*vpp) |
170 |
|
{ |
171 |
|
trace_printf ("ino %d is cache", ino); |
172 |
|
return 0; |
173 |
|
} |
174 |
|
|
175 |
err = vgetnode (vfs, /* &ext2fs_ops */ &ext2fs_vnops, &vp); |
err = getnewvnode (vfs, &ext2fs_vnops, &vp); |
176 |
if (err) |
if (err) |
177 |
return err; |
return err; |
178 |
|
|
179 |
ip = malloc (sizeof (struct ext2fs_inode)); |
ip = malloc (sizeof (struct inode)); |
180 |
if (! ip) |
if (! ip) |
181 |
return ENOMEM; |
return ENOMEM; |
182 |
vp->v_data = ip; |
vp->v_data = ip; |
183 |
ip->sc = (struct ext2fs_softc *) vfs->vfs_data; |
ip->i_sc = (struct ext2fs_softc *) vfs->vfs_data; |
184 |
|
ip->i_number = ino; |
185 |
|
|
186 |
if (ino == ROOTINO) |
if (ino == ROOTINO) |
187 |
vp->v_flag |= VROOT; |
vp->v_flags |= VROOT; |
188 |
|
|
189 |
/* Read in the disk contents for the inode, copy into the inode. */ |
/* Read in the disk contents for the inode, copy into the inode. */ |
190 |
err = io_bread (sc->sc_vp, fsbtodb (sc, ino_to_fsba (sc, ino)), |
err = io_buf_read (sc->sc_vp, fsbtodb (sc, ino_to_fsba (sc, ino)), |
191 |
(int) sc->sc_bsize, &bp); |
(int) sc->sc_bsize, 0, &bp); |
192 |
if (err) |
if (err) |
193 |
{ free (ip); return err; } |
{ free (ip); return err; } |
194 |
|
|
195 |
memcpy (&ip->dinode, bp->b_data + (ino_to_fsbo (sc, ino) * EXT2_DINODE_SIZE), |
memcpy (&ip->i_dinode, bp->data + (ino_to_fsbo (sc, ino) * EXT2_DINODE_SIZE), |
196 |
sizeof (struct ext2fs_dinode)); |
sizeof (struct ext2fs_dinode)); |
197 |
io_brelease (bp); |
io_buf_release (bp); |
198 |
|
|
199 |
/* If the inode was deleted, reset all fields */ |
/* If the inode was deleted, reset all fields */ |
200 |
if (ip->dinode.dtime != 0) |
if (ip->i_dinode.dtime != 0) |
201 |
{ |
{ |
202 |
ip->dinode.mode = ip->dinode.size = ip->dinode.nblocks = 0; |
ip->i_dinode.mode = ip->i_dinode.size = ip->i_dinode.nblocks = 0; |
203 |
memset (& ip->dinode.blocks, 0, sizeof ip->dinode.blocks); |
memset (& ip->i_dinode.blocks, 0, sizeof ip->i_dinode.blocks); |
204 |
} |
} |
205 |
|
|
206 |
/* Initialize the vnode from the inode, check for aliases. |
/* Initialize the vnode from the inode, check for aliases. |
208 |
err = ext2fs_vinit (vfs, &vp); |
err = ext2fs_vinit (vfs, &vp); |
209 |
if (err) |
if (err) |
210 |
return err; |
return err; |
211 |
|
add_cache (vp); |
212 |
|
|
213 |
*vpp = vp; |
*vpp = vp; |
214 |
return 0; |
return 0; |
215 |
} |
} |
216 |
|
|
217 |
static int |
/* Return root vnode of file system VFS. */ |
218 |
|
int |
219 |
ext2fs_root (struct vfs *vfs, struct vnode **vpp) |
ext2fs_root (struct vfs *vfs, struct vnode **vpp) |
220 |
{ |
{ |
221 |
return ext2fs_vget (vfs, ROOTINO, vpp); |
return ext2fs_vget (vfs, ROOTINO, vpp); |
222 |
} |
} |
223 |
|
|
224 |
static int |
|
225 |
|
/* Check if we can mount a root file system on device |
226 |
|
ROOTDEV. VFS is our mountpoint structure. */ |
227 |
|
int |
228 |
ext2fs_mountroot (struct vfs *vfs, dev_t rootdev) |
ext2fs_mountroot (struct vfs *vfs, dev_t rootdev) |
229 |
{ |
{ |
230 |
struct ext2fs_softc *sc; |
struct ext2fs_softc *sc; |
232 |
struct vnode *vp; |
struct vnode *vp; |
233 |
int err, i; |
int err, i; |
234 |
|
|
235 |
#define LOSE { if (bp) io_brelease (bp); goto lose; } |
#define LOSE { if (bp) io_buf_release (bp); goto lose; } |
236 |
|
|
237 |
err = vdevvp (vfs, rootdev, VBLK, &vp); |
err = vdevvp (vfs, rootdev, VBLK, &vp); |
238 |
if (err) |
if (err) |
244 |
{ err = ENOMEM; LOSE; } |
{ err = ENOMEM; LOSE; } |
245 |
memset (sc, 0, sizeof (struct ext2fs_softc)); |
memset (sc, 0, sizeof (struct ext2fs_softc)); |
246 |
|
|
247 |
err = io_bread (vp, (SBOFF / DEV_BSIZE), SBSIZE, &bp); |
trace_printf ("before read"); |
248 |
|
|
249 |
|
err = io_buf_read (vp, (SBOFF / DEV_BSIZE), SBSIZE, 0, &bp); |
250 |
if (err) |
if (err) |
251 |
LOSE; |
LOSE; |
252 |
memcpy (&sc->sc_sb, bp->b_data, sizeof (struct ext2fs)); |
memcpy (&sc->sc_sb, bp->data, sizeof (struct ext2fs)); |
253 |
io_brelease (bp); bp = 0; |
io_buf_release (bp); bp = 0; |
254 |
|
|
255 |
|
trace_printf ("after read"); |
256 |
|
|
257 |
if (sc->sc_sb.e2fs_magic != E2FS_MAGIC) |
if (sc->sc_sb.e2fs_magic != E2FS_MAGIC) |
258 |
{ err = ESTALE; LOSE; } |
{ err = ESTALE; LOSE; } |
259 |
|
|
|
/* ??? */ |
|
|
|
|
260 |
sc->sc_ncg = howmany (sc->sc_sb.e2fs_bcount - sc->sc_sb.e2fs_first_dblock, |
sc->sc_ncg = howmany (sc->sc_sb.e2fs_bcount - sc->sc_sb.e2fs_first_dblock, |
261 |
sc->sc_sb.e2fs_bpg); |
sc->sc_sb.e2fs_bpg); |
262 |
|
|
275 |
if (! sc->sc_gd) |
if (! sc->sc_gd) |
276 |
{ err = ENOMEM; LOSE; } |
{ err = ENOMEM; LOSE; } |
277 |
|
|
278 |
for (i = 0; i < sc->sc_ngdb; i++) |
for (i = 0; i < sc->sc_ngdb; bp = 0, i++) |
279 |
{ |
{ |
280 |
err = io_bread (vp, fsbtodb (sc, (sc->sc_bsize > 1024 ? 0 : 1) + i + 1), |
err = io_buf_read (vp, fsbtodb (sc, (sc->sc_bsize > 1024 ? 0 : 1) + i + 1), |
281 |
sc->sc_bsize, &bp); |
sc->sc_bsize, 0, &bp); |
282 |
if (err) |
if (err) |
283 |
LOSE; |
LOSE; |
284 |
|
|
285 |
memcpy (& sc->sc_gd [i * sc->sc_bsize / sizeof (struct ext2_gd)], |
memcpy (& sc->sc_gd [i * sc->sc_bsize / sizeof (struct ext2_gd)], |
286 |
bp->b_data, sc->sc_bsize); |
bp->data, sc->sc_bsize); |
287 |
io_brelease (bp); |
io_buf_release (bp); |
288 |
} |
} |
289 |
|
|
290 |
vfs->vfs_data = sc; |
vfs->vfs_data = sc; |
291 |
|
vfs->vfs_bsize = sc->sc_bsize; |
292 |
|
vfs->vfs_devvp = sc->sc_vp; |
293 |
return 0; |
return 0; |
294 |
|
|
295 |
lose: |
lose: |
296 |
|
if (bp) |
297 |
|
io_buf_release (bp); |
298 |
return err; |
return err; |
299 |
} |
} |
300 |
|
|
301 |
static int |
/* Open vnode VP, with file modes MODE. */ |
302 |
ext2fs_open (struct vnode *vp, int mode, struct ucred *ucred, struct proc *p) |
int |
303 |
|
ext2fs_open (struct vnode *vp, int mode, struct ucred *ucred) |
304 |
{ |
{ |
305 |
return 0; |
return 0; |
306 |
} |
} |
307 |
|
|
308 |
static int |
/* Check if user with credentials UCRED may access vnode VP |
309 |
ext2fs_access (struct vnode *vp, int mode, struct ucred *ucred, struct proc *p) |
with mode MODE. ??? need P? */ |
310 |
|
int |
311 |
|
ext2fs_access (struct vnode *vp, int mode, struct ucred *ucred) |
312 |
{ |
{ |
313 |
return 0; |
return 0; |
314 |
} |
} |
315 |
|
|
316 |
|
/* Get attributes for VP. Put them in VA. */ |
317 |
|
int |
318 |
|
ext2fs_getattr (struct vnode *vp, struct vattr *va) |
319 |
|
{ |
320 |
|
struct inode *ip = VTOI (vp); |
321 |
|
|
322 |
|
va->va_type = vp->v_type; |
323 |
|
va->va_mode = ip->i_dinode.mode; |
324 |
|
va->va_uid = ip->i_dinode.uid; |
325 |
|
va->va_gid = ip->i_dinode.gid; |
326 |
|
va->va_size = ip->i_dinode.size; |
327 |
|
va->va_atime.tv_sec = ip->i_dinode.atime; |
328 |
|
va->va_mtime.tv_sec = ip->i_dinode.mtime; |
329 |
|
va->va_ctime.tv_sec = ip->i_dinode.ctime; |
330 |
|
return 0; |
331 |
|
} |
332 |
|
|
333 |
/* Look up component CNAME in directory VP. If found, return vnode |
/* Look up component CNAME in directory VP. If found, return vnode |
334 |
in VPP. */ |
in VPP. */ |
335 |
static int |
int |
336 |
ext2fs_lookup (struct vnode *vp, char *cname, struct vnode **vpp) |
ext2fs_lookup (struct vnode *vp, char *cname, struct vnode **vpp) |
337 |
{ |
{ |
338 |
struct ext2fs_inode *ip; |
struct inode *ip; |
339 |
struct ext2fs_softc *sc; |
struct ext2fs_softc *sc; |
340 |
u_int32_t blk_no, off; |
u_int32_t blk_no, off; |
341 |
struct io_buf *bp; |
struct io_buf *bp = 0; |
342 |
size_t res, left; |
size_t res, left; |
343 |
ino_t ino = 0; |
ino_t ino = 0; |
344 |
int err, x = 0; |
int err, x = 0; |
346 |
if (vp->v_type != VDIR) |
if (vp->v_type != VDIR) |
347 |
return ENOTDIR; |
return ENOTDIR; |
348 |
|
|
349 |
ip = (struct ext2fs_inode *) vp->v_data; |
ip = VTOI (vp); |
350 |
sc = ip->sc; |
sc = ip->i_sc; |
351 |
|
|
352 |
off = 0; |
off = 0; |
353 |
res = ip->dinode.size; |
res = ip->i_dinode.size; |
354 |
|
|
355 |
while (res) |
while (res) |
356 |
{ |
{ |
357 |
struct ext2fs_dirent *d; |
struct ext2fs_dirent *d; |
358 |
|
|
359 |
res -= sc->sc_bsize; |
res -= sc->sc_bsize; |
360 |
blk_no = getblk (ip->sc, &ip->dinode, lblkno (ip->sc, off)); |
blk_no = getblk (ip->i_sc, &ip->i_dinode, lblkno (ip->i_sc, off), 0); |
361 |
if (! blk_no) |
if (! blk_no) |
362 |
continue; |
continue; |
363 |
off += sc->sc_bsize; |
off += sc->sc_bsize; |
364 |
|
|
365 |
err = io_bread (sc->sc_vp, fsbtodb (sc, blk_no), sc->sc_bsize, &bp); |
err = io_buf_read (sc->sc_vp, fsbtodb (sc, blk_no), sc->sc_bsize, 0, &bp); |
366 |
if (err) |
if (err) |
367 |
return err; |
return err; |
368 |
d = (struct ext2fs_dirent *) bp->b_data; |
|
369 |
|
d = (struct ext2fs_dirent *) bp->data; |
370 |
left = sc->sc_bsize; |
left = sc->sc_bsize; |
371 |
|
|
372 |
while (left >= EXT2FS_MINENT) |
while (left >= EXT2FS_MINENT) |
390 |
d = (struct ext2fs_dirent *) ((void *)d + d->reclen); |
d = (struct ext2fs_dirent *) ((void *)d + d->reclen); |
391 |
} |
} |
392 |
|
|
393 |
io_brelease (bp); |
io_buf_release (bp); |
394 |
} |
} |
395 |
return ENOENT; |
return ENOENT; |
396 |
|
|
397 |
found: |
found: |
398 |
|
if (bp) |
399 |
|
io_buf_release (bp); |
400 |
return ext2fs_vget (sc->sc_vfs, ino, vpp); |
return ext2fs_vget (sc->sc_vfs, ino, vpp); |
401 |
} |
} |
402 |
|
|
403 |
static int |
/* Read data from vnode VP. Put the data in UIO. Offset into file (vnode) |
404 |
|
is UIO->uio_offset. User credentials is located in UCRED. */ |
405 |
|
int |
406 |
ext2fs_read (struct vnode *vp, struct io_uio *uio, struct ucred *ucred) |
ext2fs_read (struct vnode *vp, struct io_uio *uio, struct ucred *ucred) |
407 |
{ |
{ |
408 |
off_t bytesinfile, blkoffset; |
off_t bytesinfile, blkoffset; |
409 |
struct ext2fs_inode *ip; |
struct inode *ip = VTOI (vp); |
410 |
struct ext2fs_softc *sc; |
struct ext2fs_softc *sc; |
411 |
struct io_buf *bp; |
struct io_buf *bp; |
412 |
size_t xfersize; |
ssize_t xfersize; |
|
int err; |
|
413 |
u_int32_t blk_no; |
u_int32_t blk_no; |
414 |
|
int err; |
415 |
|
|
416 |
ip = (struct ext2fs_inode *) vp->v_data; |
sc = ip->i_sc; |
|
sc = ip->sc; |
|
417 |
|
|
418 |
if ((u_int64_t) uio->uio_offset > ((u_int64_t) 0x80000000 * sc->sc_bsize - 1)) |
if ((u_int64_t) uio->uio_offset > ((u_int64_t) 0x80000000 * sc->sc_bsize - 1)) |
419 |
return EFBIG; |
return EFBIG; |
423 |
|
|
424 |
for (err = 0; uio->uio_resid > 0; bp = NULL) |
for (err = 0; uio->uio_resid > 0; bp = NULL) |
425 |
{ |
{ |
426 |
if ((bytesinfile = ip->dinode.size - uio->uio_offset) <= 0) |
if ((bytesinfile = ip->i_dinode.size - uio->uio_offset) <= 0) |
427 |
break; |
break; |
428 |
|
|
429 |
blk_no = getblk (sc, &ip->dinode, lblkno (sc, uio->uio_offset)); |
blk_no = getblk (sc, &ip->i_dinode, lblkno (sc, uio->uio_offset), 0); |
430 |
if (! blk_no) |
if (! blk_no) |
431 |
{ |
{ |
|
printf ("hole in file for offset %d\n", uio->uio_offset); |
|
|
fflush (stdout); |
|
|
|
|
432 |
uio->uio_offset += sc->sc_bsize; |
uio->uio_offset += sc->sc_bsize; |
433 |
uio->uio_resid -= sc->sc_bsize; |
uio->uio_resid -= sc->sc_bsize; |
434 |
|
|
436 |
continue; |
continue; |
437 |
} |
} |
438 |
|
|
439 |
err = io_bread (sc->sc_vp, fsbtodb (sc, blk_no), sc->sc_bsize, &bp); |
err = io_buf_read (vp, fsbtodb (sc, blk_no), sc->sc_bsize, ucred, &bp); |
440 |
if (err) |
if (err) |
441 |
break; |
break; |
442 |
|
|
443 |
blkoffset = blkoff (sc, uio->uio_offset); |
blkoffset = blkoff (sc, uio->uio_offset); |
444 |
xfersize = sc->sc_bsize - blkoffset; |
xfersize = sc->sc_bsize - blkoffset; |
445 |
|
|
446 |
if (uio->uio_resid < xfersize) |
if (uio->uio_resid < (size_t) xfersize) |
447 |
xfersize = uio->uio_resid; |
xfersize = uio->uio_resid; |
448 |
if (bytesinfile < xfersize) |
if (bytesinfile < xfersize) |
449 |
xfersize = bytesinfile; |
xfersize = bytesinfile; |
450 |
|
|
451 |
err = io_uio_move (uio, bp->b_data + blkoffset, xfersize); |
err = io_uio_move (uio, bp->data + blkoffset, xfersize); |
452 |
if (err) |
if (err) |
453 |
break; |
break; |
454 |
io_brelease (bp); |
io_buf_release (bp); |
455 |
} |
} |
456 |
|
|
457 |
if (bp) |
if (bp) |
458 |
io_brelease (bp); |
io_buf_release (bp); |
459 |
return err; |
return err; |
460 |
} |
} |
461 |
|
|
462 |
|
/* Return target name of a symbolic link, vnode VP. */ |
463 |
|
int |
464 |
|
ext2fs_readlink (struct vnode *vp, struct io_uio *uio, |
465 |
|
struct ucred *ucred) |
466 |
|
{ |
467 |
|
struct inode *ip = VTOI (vp); |
468 |
|
int isize; |
469 |
|
|
470 |
|
isize = ip->i_dinode.size; |
471 |
|
if (ip->i_dinode.nblocks == 0) |
472 |
|
{ |
473 |
|
io_uio_move (uio, &ip->i_dinode.blocks[0], isize); |
474 |
|
return 0; |
475 |
|
} |
476 |
|
return (VOP_READ (vp, uio, ucred)); |
477 |
|
} |
478 |
|
|
479 |
|
|
480 |
|
/* Return block number of offset OFFSET into vnode VP. |
481 |
|
Block number is returned in *BLKNO. Number of sequental |
482 |
|
blocks is returned in *RUNP. Return error code. */ |
483 |
|
int |
484 |
|
ext2fs_bmap (struct vnode *vp, off_t offset, off_t *blkno, int *runp) |
485 |
|
{ |
486 |
|
struct inode *ip = VTOI (vp); |
487 |
|
struct ext2fs_softc *sc = ip->i_sc; |
488 |
|
|
489 |
|
*blkno = fsbtodb (sc, getblk (sc, &ip->i_dinode, lblkno (sc, offset), runp)); |
490 |
|
return 0; |
491 |
|
} |
492 |
|
|
493 |
|
/* Vnode VP became inactive. We do nothing right now. */ |
494 |
|
int |
495 |
|
ext2fs_inactive (struct vnode *vp) |
496 |
|
{ |
497 |
|
return 0; |
498 |
|
} |
499 |
|
|
500 |
|
/* The system is reclaiming vnode VP. We free all resources |
501 |
|
(ie the inode) that this vnode holds. */ |
502 |
|
int |
503 |
|
ext2fs_reclaim (struct vnode *vp) |
504 |
|
{ |
505 |
|
struct inode *ip = VTOI (vp); |
506 |
|
|
507 |
|
remove_cache (vp); |
508 |
|
free (ip); |
509 |
|
vp->v_data = 0; |
510 |
|
return 0; |
511 |
|
} |
512 |
|
|
513 |
|
/* Convert the on-disk entries to <sys/dirent.h> entries. |
514 |
|
We put the dir entries in UIO. */ |
515 |
|
int |
516 |
|
ext2fs_readdir (struct vnode *vp, struct io_uio *uio, struct ucred *ucred) |
517 |
|
{ |
518 |
|
size_t count, readcnt; |
519 |
|
struct io_iovec iov; |
520 |
|
struct io_uio auio; |
521 |
|
void *dirbuf; |
522 |
|
int error; |
523 |
|
|
524 |
|
if (vp->v_type != VDIR) |
525 |
|
return ENOTDIR; |
526 |
|
|
527 |
|
count = uio->uio_resid; |
528 |
|
/* count -= (uio->uio_offset + count) & (sc->sc_bsize - 1); */ |
529 |
|
if (count <= 0) |
530 |
|
return EINVAL; |
531 |
|
|
532 |
|
dirbuf = malloc (count); |
533 |
|
if (! dirbuf) |
534 |
|
return ENOMEM; |
535 |
|
memset (dirbuf, 0, count); |
536 |
|
io_iov_init (&iov, dirbuf, count); |
537 |
|
io_uio_init (&auio, IO_UIO_WRITE, IO_UIO_SYSSPACE, uio->uio_offset, |
538 |
|
count, &iov, 1, 0); |
539 |
|
|
540 |
|
error = VOP_READ (vp, &auio, ucred); |
541 |
|
if (error == 0) |
542 |
|
{ |
543 |
|
struct ext2fs_dirent *dp; |
544 |
|
struct dirent de; |
545 |
|
|
546 |
|
readcnt = count - auio.uio_resid; |
547 |
|
|
548 |
|
trace_printf ("count is %d", readcnt); |
549 |
|
|
550 |
|
for (dp = (struct ext2fs_dirent *) dirbuf; |
551 |
|
(char *)dp < (char *)dirbuf + readcnt;) |
552 |
|
{ |
553 |
|
trace_printf ("dp ino %d type %d", dp->ino, dp->file_type); |
554 |
|
|
555 |
|
if (dp->reclen == 0 || dp->ino == 0) |
556 |
|
{ |
557 |
|
error = EIO; |
558 |
|
break; |
559 |
|
} |
560 |
|
|
561 |
|
de.d_fileno = dp->ino; |
562 |
|
de.d_namlen = dp->namlen; |
563 |
|
de.d_reclen = ((sizeof de - 256 + dp->namlen + 1) + 3) & ~3; |
564 |
|
de.d_type = dp->file_type; |
565 |
|
strncpy (de.d_name, dp->name, dp->namlen); |
566 |
|
de.d_name [dp->namlen] = 0; |
567 |
|
|
568 |
|
/* printf ("read reclen %d: '%s'\n", dp->reclen, dp->name); */ |
569 |
|
|
570 |
|
if (de.d_reclen > uio->uio_resid) |
571 |
|
break; |
572 |
|
|
573 |
|
error = io_uio_move (uio, (void *) &de, de.d_reclen); |
574 |
|
if (error) |
575 |
|
break; |
576 |
|
|
577 |
|
/* advance dp */ |
578 |
|
dp = (struct ext2fs_dirent *) ((char *)dp + dp->reclen); |
579 |
|
} |
580 |
|
} |
581 |
|
|
582 |
|
free (dirbuf); |
583 |
|
return error; |
584 |
|
} |
585 |
|
|
586 |
|
/* ??? */ |
587 |
|
int |
588 |
|
ext2fs_strategy (struct io_buf *bp) |
589 |
|
{ |
590 |
|
struct inode *ip = VTOI (bp->vp); |
591 |
|
struct ext2fs_softc *sc = ip->i_sc; |
592 |
|
|
593 |
|
bp->dev = sc->sc_vp->v_rdev; |
594 |
|
return specfs_strategy (bp); |
595 |
|
} |
596 |
|
|
597 |
|
|
598 |
|
struct vfs_ops ext2fs_vfsops = |
599 |
|
{ |
600 |
|
0, /* mount */ |
601 |
|
0, /* umount */ |
602 |
|
ext2fs_mountroot, /* mountroot */ |
603 |
|
ext2fs_root /* root */ |
604 |
|
}; |
605 |
|
|
606 |
|
struct vnode_ops ext2fs_vnops = |
607 |
|
{ |
608 |
|
ext2fs_open, |
609 |
|
ext2fs_access, |
610 |
|
ext2fs_lookup, |
611 |
|
ext2fs_strategy, |
612 |
|
ext2fs_read, |
613 |
|
0, /* write */ |
614 |
|
ext2fs_getattr, |
615 |
|
0, /* setattr */ |
616 |
|
ext2fs_bmap, |
617 |
|
ext2fs_reclaim, |
618 |
|
ext2fs_inactive, |
619 |
|
ext2fs_readlink, |
620 |
|
ext2fs_readdir |
621 |
|
}; |
622 |
|
|
623 |
|
|
624 |
|
/* Add vnode VP to the hash lookup table. We get |
625 |
|
inode number from the inode structure. */ |
626 |
|
static void |
627 |
|
add_cache (struct vnode *vp) |
628 |
|
{ |
629 |
|
struct inode *ip = VTOI (vp); |
630 |
|
int hash_index = EXT2FS_HASH (vp->v_vfsp, ip->i_number); |
631 |
|
|
632 |
|
pthread_mutex_lock (&vp->v_lock); |
633 |
|
pthread_mutex_lock (&ext2fs_hash_lock); |
634 |
|
queue_enter (&ext2fs_hash_buckets [hash_index], vp, struct vnode *, v_hashq); |
635 |
|
pthread_mutex_unlock (&vp->v_lock); |
636 |
|
pthread_mutex_unlock (&ext2fs_hash_lock); |
637 |
|
} |
638 |
|
|
639 |
|
/* Remove VP from hash lookup table. We get inode |
640 |
|
number from the inode structure. */ |
641 |
|
static void |
642 |
|
remove_cache (struct vnode *vp) |
643 |
|
{ |
644 |
|
struct inode *ip = VTOI (vp); |
645 |
|
int hash_index = EXT2FS_HASH (vp->v_vfsp, ip->i_number); |
646 |
|
|
647 |
|
pthread_mutex_lock (&vp->v_lock); |
648 |
|
pthread_mutex_lock (&ext2fs_hash_lock); |
649 |
|
queue_remove (&ext2fs_hash_buckets [hash_index], vp, struct vnode *, v_hashq); |
650 |
|
pthread_mutex_unlock (&ext2fs_hash_lock); |
651 |
|
pthread_mutex_unlock (&vp->v_lock); |
652 |
|
} |
653 |
|
|
654 |
|
/* Look in hash table for a vnode that belongs to |
655 |
|
file system VFS and has the inode number INO. If |
656 |
|
we find it, we obtain a reference to it and return. |
657 |
|
If we did not find any vnode, we return NULL. */ |
658 |
|
static struct vnode * |
659 |
|
lookup_cache (struct vfs *vfs, ino_t ino) |
660 |
|
{ |
661 |
|
int hash_index = EXT2FS_HASH (vfs, ino); |
662 |
|
struct vnode *vp; |
663 |
|
|
664 |
|
pthread_mutex_lock (&ext2fs_hash_lock); |
665 |
|
queue_iterate (&ext2fs_hash_buckets [hash_index], vp, |
666 |
|
struct vnode *, v_hashq) |
667 |
|
{ |
668 |
|
struct inode *ip = VTOI (vp); |
669 |
|
|
670 |
|
if (vp->v_vfsp == vfs && ip->i_number == ino) |
671 |
|
{ |
672 |
|
vhold (vp); |
673 |
|
pthread_mutex_unlock (&ext2fs_hash_lock); |
674 |
|
return vp; |
675 |
|
} |
676 |
|
} |
677 |
|
pthread_mutex_unlock (&ext2fs_hash_lock); |
678 |
|
return NULL; |
679 |
|
} |
680 |
|
|
681 |
static int |
static int |
682 |
ext2fs_init (struct md_descriptor *mdd) |
ext2fs_init (struct md_descriptor *mdd) |
683 |
{ |
{ |
684 |
|
int i; |
685 |
|
|
686 |
|
for (i = 0; i < 256; i++) |
687 |
|
queue_init (&ext2fs_hash_buckets[i]); |
688 |
|
|
689 |
md_attach (mdd, (void *) &ext2fs_vfsops); |
md_attach (mdd, (void *) &ext2fs_vfsops); |
690 |
return 0; |
return 0; |
691 |
} |
} |