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