chfs_vnode.c revision 1.11 1 /* $NetBSD: chfs_vnode.c,v 1.11 2014/09/01 16:33:20 he Exp $ */
2
3 /*-
4 * Copyright (c) 2010 Department of Software Engineering,
5 * University of Szeged, Hungary
6 * Copyright (C) 2010 Tamas Toth <ttoth (at) inf.u-szeged.hu>
7 * Copyright (C) 2010 Adam Hoka <ahoka (at) NetBSD.org>
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by the Department of Software Engineering, University of Szeged, Hungary
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include "chfs.h"
36 #include "chfs_inode.h"
37 #include <sys/malloc.h>
38 #include <sys/kauth.h>
39 #include <sys/namei.h>
40 #include <sys/uio.h>
41 #include <sys/buf.h>
42
43 #include <miscfs/genfs/genfs.h>
44
45 /* chfs_vnode_lookup - lookup for a vnode */
46 struct vnode *
47 chfs_vnode_lookup(struct chfs_mount *chmp, ino_t vno)
48 {
49 struct vnode *vp;
50 struct chfs_inode *ip;
51
52 TAILQ_FOREACH(vp, &chmp->chm_fsmp->mnt_vnodelist, v_mntvnodes) {
53 ip = VTOI(vp);
54 if (ip && ip->ino == vno)
55 return vp;
56 }
57 return NULL;
58 }
59
60 /* chfs_readvnode - reads a vnode from the flash and setups its inode */
61 int
62 chfs_readvnode(struct mount *mp, ino_t ino, struct vnode **vpp)
63 {
64 struct ufsmount* ump = VFSTOUFS(mp);
65 struct chfs_mount *chmp = ump->um_chfs;
66 struct chfs_vnode_cache *chvc;
67 struct chfs_flash_vnode *chfvn;
68 struct chfs_inode *ip;
69 int err;
70 char* buf;
71 size_t retlen, len;
72 struct vnode* vp = NULL;
73 dbg("readvnode | ino: %llu\n", (unsigned long long)ino);
74
75 len = sizeof(struct chfs_flash_vnode);
76
77 KASSERT(vpp != NULL);
78
79 if (vpp != NULL) {
80 vp = *vpp;
81 }
82
83 ip = VTOI(vp);
84 chvc = ip->chvc;
85
86 /* root node is in-memory only */
87 if (chvc && ino != CHFS_ROOTINO) {
88 dbg("offset: %" PRIu32 ", lnr: %d\n",
89 CHFS_GET_OFS(chvc->v->nref_offset), chvc->v->nref_lnr);
90
91 KASSERT((void *)chvc != (void *)chvc->v);
92
93 /* reading */
94 buf = kmem_alloc(len, KM_SLEEP);
95 err = chfs_read_leb(chmp, chvc->v->nref_lnr, buf,
96 CHFS_GET_OFS(chvc->v->nref_offset), len, &retlen);
97 if (err) {
98 kmem_free(buf, len);
99 return err;
100 }
101 if (retlen != len) {
102 chfs_err("Error reading vnode: read: %zu insted of: %zu\n",
103 len, retlen);
104 kmem_free(buf, len);
105 return EIO;
106 }
107 chfvn = (struct chfs_flash_vnode*)buf;
108
109 /* setup inode fields */
110 chfs_set_vnode_size(vp, chfvn->dn_size);
111 ip->mode = chfvn->mode;
112 ip->ch_type = IFTOCHT(ip->mode);
113 vp->v_type = CHTTOVT(ip->ch_type);
114 ip->version = chfvn->version;
115 ip->uid = chfvn->uid;
116 ip->gid = chfvn->gid;
117 ip->atime = chfvn->atime;
118 ip->mtime = chfvn->mtime;
119 ip->ctime = chfvn->ctime;
120
121 kmem_free(buf, len);
122 }
123
124
125 *vpp = vp;
126 return 0;
127 }
128
129 /*
130 * chfs_readddirent -
131 * reads a directory entry from flash and adds it to its inode
132 */
133 int
134 chfs_readdirent(struct mount *mp, struct chfs_node_ref *chnr, struct chfs_inode *pdir)
135 {
136 struct ufsmount *ump = VFSTOUFS(mp);
137 struct chfs_mount *chmp = ump->um_chfs;
138 struct chfs_flash_dirent_node chfdn;
139 struct chfs_dirent *fd;
140 size_t len = sizeof(struct chfs_flash_dirent_node);
141 size_t retlen;
142 int err = 0;
143
144 /* read flash_dirent_node */
145 err = chfs_read_leb(chmp, chnr->nref_lnr, (char *)&chfdn,
146 CHFS_GET_OFS(chnr->nref_offset), len, &retlen);
147 if (err) {
148 return err;
149 }
150 if (retlen != len) {
151 chfs_err("Error reading vnode: read: %zu insted of: %zu\n",
152 retlen, len);
153 return EIO;
154 }
155
156 /* set fields of dirent */
157 fd = chfs_alloc_dirent(chfdn.nsize + 1);
158 fd->version = chfdn.version;
159 fd->vno = chfdn.vno;
160 fd->type = chfdn.dtype;
161 fd->nsize = chfdn.nsize;
162
163 /* read the name of the dirent */
164 err = chfs_read_leb(chmp, chnr->nref_lnr, fd->name,
165 CHFS_GET_OFS(chnr->nref_offset) + len, chfdn.nsize, &retlen);
166 if (err) {
167 return err;
168 }
169
170 if (retlen != chfdn.nsize) {
171 chfs_err("Error reading vnode: read: %zu insted of: %zu\n",
172 len, retlen);
173 return EIO;
174 }
175
176 fd->name[fd->nsize] = 0;
177 fd->nref = chnr;
178
179 /* add to inode */
180 chfs_add_fd_to_inode(chmp, pdir, fd);
181 return 0;
182 }
183
184 /* chfs_makeinode - makes a new file and initializes its structures */
185 int
186 chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
187 struct componentname *cnp, enum vtype type)
188 {
189 struct chfs_inode *ip, *pdir;
190 struct vnode *vp;
191 struct ufsmount* ump = VFSTOUFS(dvp->v_mount);
192 struct chfs_mount* chmp = ump->um_chfs;
193 struct chfs_vnode_cache* chvc;
194 int error;
195 ino_t vno;
196 struct chfs_dirent *nfd;
197
198 dbg("makeinode\n");
199 pdir = VTOI(dvp);
200
201 *vpp = NULL;
202
203 /* number of vnode will be the new maximum */
204 vno = ++(chmp->chm_max_vno);
205
206 error = VFS_VGET(dvp->v_mount, vno, &vp);
207 if (error)
208 return (error);
209
210 /* setup vnode cache */
211 mutex_enter(&chmp->chm_lock_vnocache);
212 chvc = chfs_vnode_cache_get(chmp, vno);
213
214 chvc->pvno = pdir->ino;
215 chvc->vno_version = kmem_alloc(sizeof(uint64_t), KM_SLEEP);
216 *(chvc->vno_version) = 1;
217 if (type != VDIR)
218 chvc->nlink = 1;
219 else
220 chvc->nlink = 2;
221 chvc->state = VNO_STATE_CHECKEDABSENT;
222 mutex_exit(&chmp->chm_lock_vnocache);
223
224 /* setup inode */
225 ip = VTOI(vp);
226 ip->ino = vno;
227
228 if (type == VDIR)
229 chfs_set_vnode_size(vp, 512);
230 else
231 chfs_set_vnode_size(vp, 0);
232
233 ip->uid = kauth_cred_geteuid(cnp->cn_cred);
234 ip->gid = kauth_cred_getegid(cnp->cn_cred);
235 ip->version = 1;
236 ip->iflag |= (IN_ACCESS | IN_CHANGE | IN_UPDATE);
237
238 ip->chvc = chvc;
239 ip->target = NULL;
240
241 ip->mode = mode;
242 vp->v_type = type; /* Rest init'd in getnewvnode(). */
243 ip->ch_type = VTTOCHT(vp->v_type);
244
245 /* authorize setting SGID if needed */
246 if (ip->mode & ISGID) {
247 error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY,
248 vp, NULL, genfs_can_chmod(vp->v_type, cnp->cn_cred, ip->uid,
249 ip->gid, mode));
250 if (error)
251 ip->mode &= ~ISGID;
252 }
253
254 /* write vnode information to the flash */
255 chfs_update(vp, NULL, NULL, UPDATE_WAIT);
256
257 mutex_enter(&chmp->chm_lock_mountfields);
258
259 error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
260 if (error) {
261 mutex_exit(&chmp->chm_lock_mountfields);
262 vput(vp);
263 return error;
264 }
265
266 /* update parent's vnode information and write it to the flash */
267 pdir->iflag |= (IN_ACCESS | IN_CHANGE | IN_MODIFY | IN_UPDATE);
268 chfs_update(dvp, NULL, NULL, UPDATE_WAIT);
269
270 error = chfs_write_flash_vnode(chmp, pdir, ALLOC_NORMAL);
271 if (error) {
272 mutex_exit(&chmp->chm_lock_mountfields);
273 vput(vp);
274 return error;
275 }
276
277 /* setup directory entry */
278 nfd = chfs_alloc_dirent(cnp->cn_namelen + 1);
279 nfd->vno = ip->ino;
280 nfd->version = (++pdir->chvc->highest_version);
281 nfd->type = ip->ch_type;
282 nfd->nsize = cnp->cn_namelen;
283 memcpy(&(nfd->name), cnp->cn_nameptr, cnp->cn_namelen);
284 nfd->name[nfd->nsize] = 0;
285 nfd->nhash = hash32_buf(nfd->name, cnp->cn_namelen, HASH32_BUF_INIT);
286
287 /* write out */
288 error = chfs_write_flash_dirent(chmp, pdir, ip, nfd, ip->ino, ALLOC_NORMAL);
289 if (error) {
290 mutex_exit(&chmp->chm_lock_mountfields);
291 vput(vp);
292 return error;
293 }
294
295 //TODO set parent's dir times
296
297 /* add dirent to parent */
298 chfs_add_fd_to_inode(chmp, pdir, nfd);
299
300 pdir->chvc->nlink++;
301
302 mutex_exit(&chmp->chm_lock_mountfields);
303
304 VOP_UNLOCK(vp);
305 *vpp = vp;
306 return (0);
307 }
308
309 /* chfs_set_vnode_size - updates size of vnode and also inode */
310 void
311 chfs_set_vnode_size(struct vnode *vp, size_t size)
312 {
313 struct chfs_inode *ip;
314
315 KASSERT(vp != NULL);
316
317 ip = VTOI(vp);
318 KASSERT(ip != NULL);
319
320 ip->size = size;
321 vp->v_size = vp->v_writesize = size;
322 return;
323 }
324
325 /*
326 * chfs_change_size_free - updates free size
327 * "change" parameter is positive if we have to increase the size
328 * and negative if we have to decrease it
329 */
330 void
331 chfs_change_size_free(struct chfs_mount *chmp,
332 struct chfs_eraseblock *cheb, int change)
333 {
334 KASSERT(mutex_owned(&chmp->chm_lock_sizes));
335 KASSERT((int)(chmp->chm_free_size + change) >= 0);
336 KASSERT((int)(cheb->free_size + change) >= 0);
337 KASSERT((int)(cheb->free_size + change) <= chmp->chm_ebh->eb_size);
338 chmp->chm_free_size += change;
339 cheb->free_size += change;
340 return;
341 }
342
343 /*
344 * chfs_change_size_dirty - updates dirty size
345 * "change" parameter is positive if we have to increase the size
346 * and negative if we have to decrease it
347 */
348 void
349 chfs_change_size_dirty(struct chfs_mount *chmp,
350 struct chfs_eraseblock *cheb, int change)
351 {
352 KASSERT(mutex_owned(&chmp->chm_lock_sizes));
353 KASSERT((int)(chmp->chm_dirty_size + change) >= 0);
354 KASSERT((int)(cheb->dirty_size + change) >= 0);
355 KASSERT((int)(cheb->dirty_size + change) <= chmp->chm_ebh->eb_size);
356 chmp->chm_dirty_size += change;
357 cheb->dirty_size += change;
358 return;
359 }
360
361 /*
362 * chfs_change_size_unchecked - updates unchecked size
363 * "change" parameter is positive if we have to increase the size
364 * and negative if we have to decrease it
365 */
366 void
367 chfs_change_size_unchecked(struct chfs_mount *chmp,
368 struct chfs_eraseblock *cheb, int change)
369 {
370 KASSERT(mutex_owned(&chmp->chm_lock_sizes));
371 KASSERT((int)(chmp->chm_unchecked_size + change) >= 0);
372 KASSERT((int)(cheb->unchecked_size + change) >= 0);
373 KASSERT((int)(cheb->unchecked_size + change) <= chmp->chm_ebh->eb_size);
374 chmp->chm_unchecked_size += change;
375 cheb->unchecked_size += change;
376 return;
377 }
378
379 /*
380 * chfs_change_size_used - updates used size
381 * "change" parameter is positive if we have to increase the size
382 * and negative if we have to decrease it
383 */
384 void
385 chfs_change_size_used(struct chfs_mount *chmp,
386 struct chfs_eraseblock *cheb, int change)
387 {
388 KASSERT(mutex_owned(&chmp->chm_lock_sizes));
389 KASSERT((int)(chmp->chm_used_size + change) >= 0);
390 KASSERT((int)(cheb->used_size + change) >= 0);
391 KASSERT((int)(cheb->used_size + change) <= chmp->chm_ebh->eb_size);
392 chmp->chm_used_size += change;
393 cheb->used_size += change;
394 return;
395 }
396
397 /*
398 * chfs_change_size_wasted - updates wasted size
399 * "change" parameter is positive if we have to increase the size
400 * and negative if we have to decrease it
401 */
402 void
403 chfs_change_size_wasted(struct chfs_mount *chmp,
404 struct chfs_eraseblock *cheb, int change)
405 {
406 KASSERT(mutex_owned(&chmp->chm_lock_sizes));
407 KASSERT((int)(chmp->chm_wasted_size + change) >= 0);
408 KASSERT((int)(cheb->wasted_size + change) >= 0);
409 KASSERT((int)(cheb->wasted_size + change) <= chmp->chm_ebh->eb_size);
410 chmp->chm_wasted_size += change;
411 cheb->wasted_size += change;
412 return;
413 }
414
415