chfs_vnode.c revision 1.10.4.2 1 /* $NetBSD: chfs_vnode.c,v 1.10.4.2 2015/01/17 12:10:53 martin 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/kauth.h>
38 #include <sys/namei.h>
39 #include <sys/uio.h>
40 #include <sys/buf.h>
41
42 #include <miscfs/genfs/genfs.h>
43
44 /* chfs_vnode_lookup - lookup for a vnode */
45 struct vnode *
46 chfs_vnode_lookup(struct chfs_mount *chmp, ino_t vno)
47 {
48 struct vnode *vp;
49 struct chfs_inode *ip;
50
51 TAILQ_FOREACH(vp, &chmp->chm_fsmp->mnt_vnodelist, v_mntvnodes) {
52 ip = VTOI(vp);
53 if (ip && ip->ino == vno)
54 return vp;
55 }
56 return NULL;
57 }
58
59 /* chfs_readvnode - reads a vnode from the flash and setups its inode */
60 int
61 chfs_readvnode(struct mount *mp, ino_t ino, struct vnode **vpp)
62 {
63 struct ufsmount* ump = VFSTOUFS(mp);
64 struct chfs_mount *chmp = ump->um_chfs;
65 struct chfs_vnode_cache *chvc;
66 struct chfs_flash_vnode *chfvn;
67 struct chfs_inode *ip;
68 int err;
69 char* buf;
70 size_t retlen, len;
71 struct vnode* vp = NULL;
72 dbg("readvnode | ino: %llu\n", (unsigned long long)ino);
73
74 len = sizeof(struct chfs_flash_vnode);
75
76 KASSERT(vpp != NULL);
77
78 if (vpp != NULL) {
79 vp = *vpp;
80 }
81
82 ip = VTOI(vp);
83 chvc = ip->chvc;
84
85 /* root node is in-memory only */
86 if (chvc && ino != CHFS_ROOTINO) {
87 dbg("offset: %" PRIu32 ", lnr: %d\n",
88 CHFS_GET_OFS(chvc->v->nref_offset), chvc->v->nref_lnr);
89
90 KASSERT((void *)chvc != (void *)chvc->v);
91
92 /* reading */
93 buf = kmem_alloc(len, KM_SLEEP);
94 err = chfs_read_leb(chmp, chvc->v->nref_lnr, buf,
95 CHFS_GET_OFS(chvc->v->nref_offset), len, &retlen);
96 if (err) {
97 kmem_free(buf, len);
98 return err;
99 }
100 if (retlen != len) {
101 chfs_err("Error reading vnode: read: %zu insted of: %zu\n",
102 len, retlen);
103 kmem_free(buf, len);
104 return EIO;
105 }
106 chfvn = (struct chfs_flash_vnode*)buf;
107
108 /* setup inode fields */
109 chfs_set_vnode_size(vp, chfvn->dn_size);
110 ip->mode = chfvn->mode;
111 ip->ch_type = IFTOCHT(ip->mode);
112 vp->v_type = CHTTOVT(ip->ch_type);
113 ip->version = chfvn->version;
114 ip->uid = chfvn->uid;
115 ip->gid = chfvn->gid;
116 ip->atime = chfvn->atime;
117 ip->mtime = chfvn->mtime;
118 ip->ctime = chfvn->ctime;
119
120 kmem_free(buf, len);
121 }
122
123
124 *vpp = vp;
125 return 0;
126 }
127
128 /*
129 * chfs_readddirent -
130 * reads a directory entry from flash and adds it to its inode
131 */
132 int
133 chfs_readdirent(struct mount *mp, struct chfs_node_ref *chnr, struct chfs_inode *pdir)
134 {
135 struct ufsmount *ump = VFSTOUFS(mp);
136 struct chfs_mount *chmp = ump->um_chfs;
137 struct chfs_flash_dirent_node chfdn;
138 struct chfs_dirent *fd;
139 size_t len = sizeof(struct chfs_flash_dirent_node);
140 size_t retlen;
141 int err = 0;
142
143 /* read flash_dirent_node */
144 err = chfs_read_leb(chmp, chnr->nref_lnr, (char *)&chfdn,
145 CHFS_GET_OFS(chnr->nref_offset), len, &retlen);
146 if (err) {
147 return err;
148 }
149 if (retlen != len) {
150 chfs_err("Error reading vnode: read: %zu insted of: %zu\n",
151 retlen, len);
152 return EIO;
153 }
154
155 /* set fields of dirent */
156 fd = chfs_alloc_dirent(chfdn.nsize + 1);
157 fd->version = chfdn.version;
158 fd->vno = chfdn.vno;
159 fd->type = chfdn.dtype;
160 fd->nsize = chfdn.nsize;
161
162 /* read the name of the dirent */
163 err = chfs_read_leb(chmp, chnr->nref_lnr, fd->name,
164 CHFS_GET_OFS(chnr->nref_offset) + len, chfdn.nsize, &retlen);
165 if (err) {
166 return err;
167 }
168
169 if (retlen != chfdn.nsize) {
170 chfs_err("Error reading vnode: read: %zu insted of: %zu\n",
171 len, retlen);
172 return EIO;
173 }
174
175 fd->name[fd->nsize] = 0;
176 fd->nref = chnr;
177
178 /* add to inode */
179 chfs_add_fd_to_inode(chmp, pdir, fd);
180 return 0;
181 }
182
183 /* chfs_makeinode - makes a new file and initializes its structures */
184 int
185 chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
186 struct componentname *cnp, enum vtype type)
187 {
188 struct chfs_inode *ip, *pdir;
189 struct vnode *vp;
190 struct ufsmount* ump = VFSTOUFS(dvp->v_mount);
191 struct chfs_mount* chmp = ump->um_chfs;
192 struct chfs_vnode_cache* chvc;
193 int error;
194 ino_t vno;
195 struct chfs_dirent *nfd;
196
197 dbg("makeinode\n");
198 pdir = VTOI(dvp);
199
200 *vpp = NULL;
201
202 /* number of vnode will be the new maximum */
203 vno = ++(chmp->chm_max_vno);
204
205 error = VFS_VGET(dvp->v_mount, vno, &vp);
206 if (error)
207 return (error);
208
209 /* setup vnode cache */
210 mutex_enter(&chmp->chm_lock_vnocache);
211 chvc = chfs_vnode_cache_get(chmp, vno);
212
213 chvc->pvno = pdir->ino;
214 chvc->vno_version = kmem_alloc(sizeof(uint64_t), KM_SLEEP);
215 *(chvc->vno_version) = 1;
216 if (type != VDIR)
217 chvc->nlink = 1;
218 else
219 chvc->nlink = 2;
220 chvc->state = VNO_STATE_CHECKEDABSENT;
221 mutex_exit(&chmp->chm_lock_vnocache);
222
223 /* setup inode */
224 ip = VTOI(vp);
225 ip->ino = vno;
226
227 if (type == VDIR)
228 chfs_set_vnode_size(vp, 512);
229 else
230 chfs_set_vnode_size(vp, 0);
231
232 ip->uid = kauth_cred_geteuid(cnp->cn_cred);
233 ip->gid = kauth_cred_getegid(cnp->cn_cred);
234 ip->version = 1;
235 ip->iflag |= (IN_ACCESS | IN_CHANGE | IN_UPDATE);
236
237 ip->chvc = chvc;
238 ip->target = NULL;
239
240 ip->mode = mode;
241 vp->v_type = type; /* Rest init'd in getnewvnode(). */
242 ip->ch_type = VTTOCHT(vp->v_type);
243
244 /* authorize setting SGID if needed */
245 if (ip->mode & ISGID) {
246 error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY,
247 vp, NULL, genfs_can_chmod(vp->v_type, cnp->cn_cred, ip->uid,
248 ip->gid, mode));
249 if (error)
250 ip->mode &= ~ISGID;
251 }
252
253 /* write vnode information to the flash */
254 chfs_update(vp, NULL, NULL, UPDATE_WAIT);
255
256 mutex_enter(&chmp->chm_lock_mountfields);
257
258 error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
259 if (error) {
260 mutex_exit(&chmp->chm_lock_mountfields);
261 vput(vp);
262 return error;
263 }
264
265 /* update parent's vnode information and write it to the flash */
266 pdir->iflag |= (IN_ACCESS | IN_CHANGE | IN_MODIFY | IN_UPDATE);
267 chfs_update(dvp, NULL, NULL, UPDATE_WAIT);
268
269 error = chfs_write_flash_vnode(chmp, pdir, ALLOC_NORMAL);
270 if (error) {
271 mutex_exit(&chmp->chm_lock_mountfields);
272 vput(vp);
273 return error;
274 }
275
276 /* setup directory entry */
277 nfd = chfs_alloc_dirent(cnp->cn_namelen + 1);
278 nfd->vno = ip->ino;
279 nfd->version = (++pdir->chvc->highest_version);
280 nfd->type = ip->ch_type;
281 nfd->nsize = cnp->cn_namelen;
282 memcpy(&(nfd->name), cnp->cn_nameptr, cnp->cn_namelen);
283 nfd->name[nfd->nsize] = 0;
284 nfd->nhash = hash32_buf(nfd->name, cnp->cn_namelen, HASH32_BUF_INIT);
285
286 /* write out */
287 error = chfs_write_flash_dirent(chmp, pdir, ip, nfd, ip->ino, ALLOC_NORMAL);
288 if (error) {
289 mutex_exit(&chmp->chm_lock_mountfields);
290 vput(vp);
291 return error;
292 }
293
294 //TODO set parent's dir times
295
296 /* add dirent to parent */
297 chfs_add_fd_to_inode(chmp, pdir, nfd);
298
299 pdir->chvc->nlink++;
300
301 mutex_exit(&chmp->chm_lock_mountfields);
302
303 VOP_UNLOCK(vp);
304 *vpp = vp;
305 return (0);
306 }
307
308 /* chfs_set_vnode_size - updates size of vnode and also inode */
309 void
310 chfs_set_vnode_size(struct vnode *vp, size_t size)
311 {
312 struct chfs_inode *ip;
313
314 KASSERT(vp != NULL);
315
316 ip = VTOI(vp);
317 KASSERT(ip != NULL);
318
319 ip->size = size;
320 vp->v_size = vp->v_writesize = size;
321 return;
322 }
323
324 /*
325 * chfs_change_size_free - updates free size
326 * "change" parameter is positive if we have to increase the size
327 * and negative if we have to decrease it
328 */
329 void
330 chfs_change_size_free(struct chfs_mount *chmp,
331 struct chfs_eraseblock *cheb, int change)
332 {
333 KASSERT(mutex_owned(&chmp->chm_lock_sizes));
334 KASSERT((int)(chmp->chm_free_size + change) >= 0);
335 KASSERT((int)(cheb->free_size + change) >= 0);
336 KASSERT((int)(cheb->free_size + change) <= chmp->chm_ebh->eb_size);
337 chmp->chm_free_size += change;
338 cheb->free_size += change;
339 return;
340 }
341
342 /*
343 * chfs_change_size_dirty - updates dirty size
344 * "change" parameter is positive if we have to increase the size
345 * and negative if we have to decrease it
346 */
347 void
348 chfs_change_size_dirty(struct chfs_mount *chmp,
349 struct chfs_eraseblock *cheb, int change)
350 {
351 KASSERT(mutex_owned(&chmp->chm_lock_sizes));
352 KASSERT((int)(chmp->chm_dirty_size + change) >= 0);
353 KASSERT((int)(cheb->dirty_size + change) >= 0);
354 KASSERT((int)(cheb->dirty_size + change) <= chmp->chm_ebh->eb_size);
355 chmp->chm_dirty_size += change;
356 cheb->dirty_size += change;
357 return;
358 }
359
360 /*
361 * chfs_change_size_unchecked - updates unchecked size
362 * "change" parameter is positive if we have to increase the size
363 * and negative if we have to decrease it
364 */
365 void
366 chfs_change_size_unchecked(struct chfs_mount *chmp,
367 struct chfs_eraseblock *cheb, int change)
368 {
369 KASSERT(mutex_owned(&chmp->chm_lock_sizes));
370 KASSERT((int)(chmp->chm_unchecked_size + change) >= 0);
371 KASSERT((int)(cheb->unchecked_size + change) >= 0);
372 KASSERT((int)(cheb->unchecked_size + change) <= chmp->chm_ebh->eb_size);
373 chmp->chm_unchecked_size += change;
374 cheb->unchecked_size += change;
375 return;
376 }
377
378 /*
379 * chfs_change_size_used - updates used size
380 * "change" parameter is positive if we have to increase the size
381 * and negative if we have to decrease it
382 */
383 void
384 chfs_change_size_used(struct chfs_mount *chmp,
385 struct chfs_eraseblock *cheb, int change)
386 {
387 KASSERT(mutex_owned(&chmp->chm_lock_sizes));
388 KASSERT((int)(chmp->chm_used_size + change) >= 0);
389 KASSERT((int)(cheb->used_size + change) >= 0);
390 KASSERT((int)(cheb->used_size + change) <= chmp->chm_ebh->eb_size);
391 chmp->chm_used_size += change;
392 cheb->used_size += change;
393 return;
394 }
395
396 /*
397 * chfs_change_size_wasted - updates wasted size
398 * "change" parameter is positive if we have to increase the size
399 * and negative if we have to decrease it
400 */
401 void
402 chfs_change_size_wasted(struct chfs_mount *chmp,
403 struct chfs_eraseblock *cheb, int change)
404 {
405 KASSERT(mutex_owned(&chmp->chm_lock_sizes));
406 KASSERT((int)(chmp->chm_wasted_size + change) >= 0);
407 KASSERT((int)(cheb->wasted_size + change) >= 0);
408 KASSERT((int)(cheb->wasted_size + change) <= chmp->chm_ebh->eb_size);
409 chmp->chm_wasted_size += change;
410 cheb->wasted_size += change;
411 return;
412 }
413
414