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