1/* $NetBSD: chfs_write.c,v 1.1 2011/11/24 15:51:32 ahoka Exp $ */ 2 3/*- 4 * Copyright (c) 2010 Department of Software Engineering, 5 * University of Szeged, Hungary 6 * Copyright (C) 2010 David Tengeri <dtengeri@inf.u-szeged.hu> 7 * Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu> 8 * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org> 9 * All rights reserved. 10 * 11 * This code is derived from software contributed to The NetBSD Foundation 12 * by the Department of Software Engineering, University of Szeged, Hungary 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36/* 37 * chfs_write.c 38 * 39 * Created on: 2010.02.17. 40 * Author: dtengeri 41 */ 42 43#include <sys/param.h> 44#include <sys/buf.h> 45 46#include "chfs.h" 47 48int 49chfs_write_flash_vnode(struct chfs_mount *chmp, 50 struct chfs_inode *ip, int prio) 51{ 52 KASSERT(mutex_owned(&chmp->chm_lock_mountfields)); 53 54 struct chfs_flash_vnode *fvnode; 55 struct chfs_vnode_cache* chvc; 56 struct chfs_node_ref *nref; 57 struct iovec vec; 58 size_t size, retlen; 59 int err = 0, retries = 0; 60 61 if (ip->ino == CHFS_ROOTINO) 62 return 0; 63 64 fvnode = chfs_alloc_flash_vnode(); 65 if (!fvnode) 66 return ENOMEM; 67 68 chvc = ip->chvc; 69 70 /* setting up flash_vnode members */ 71 size = sizeof(*fvnode); 72 //dbg("size: %zu | PADDED: %zu\n", size, CHFS_PAD(size)); 73 fvnode->magic = htole16(CHFS_FS_MAGIC_BITMASK); 74 fvnode->type = htole16(CHFS_NODETYPE_VNODE); 75 fvnode->length = htole32(CHFS_PAD(size)); 76 fvnode->hdr_crc = htole32(crc32(0, (uint8_t *)fvnode, 77 CHFS_NODE_HDR_SIZE - 4)); 78 fvnode->vno = htole64(ip->ino); 79 fvnode->version = htole64(++ip->chvc->highest_version); 80 fvnode->mode = htole32(ip->mode); 81 fvnode->dn_size = htole32(ip->size); 82 fvnode->atime = htole32(ip->atime); 83 fvnode->ctime = htole32(ip->ctime); 84 fvnode->mtime = htole32(ip->mtime); 85 fvnode->gid = htole32(ip->gid); 86 fvnode->uid = htole32(ip->uid); 87 fvnode->node_crc = htole32(crc32(0, (uint8_t *)fvnode, size - 4)); 88 89 /* write out flash_vnode */ 90retry: 91 if (prio == ALLOC_GC) { 92 /* the GC calls this function */ 93 err = chfs_reserve_space_gc(chmp, CHFS_PAD(size)); 94 if (err) 95 goto out; 96 } else { 97 chfs_gc_trigger(chmp); 98 if (prio == ALLOC_NORMAL) 99 err = chfs_reserve_space_normal(chmp, 100 CHFS_PAD(size), ALLOC_NORMAL); 101 else 102 err = chfs_reserve_space_normal(chmp, 103 CHFS_PAD(size), ALLOC_DELETION); 104 if (err) 105 goto out; 106 } 107 108 nref = chfs_alloc_node_ref(chmp->chm_nextblock); 109 if (!nref) { 110 err = ENOMEM; 111 goto out; 112 } 113 114 mutex_enter(&chmp->chm_lock_sizes); 115 116 nref->nref_offset = chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size; 117 chfs_change_size_free(chmp, chmp->chm_nextblock, -CHFS_PAD(size)); 118 vec.iov_base = fvnode; 119 vec.iov_len = CHFS_PAD(size); 120 err = chfs_write_wbuf(chmp, &vec, 1, nref->nref_offset, &retlen); 121 if (err || retlen != CHFS_PAD(size)) { 122 chfs_err("error while writing out flash vnode to the media\n"); 123 chfs_err("err: %d | size: %zu | retlen : %zu\n", 124 err, CHFS_PAD(size), retlen); 125 chfs_change_size_dirty(chmp, 126 chmp->chm_nextblock, CHFS_PAD(size)); 127 if (retries) { 128 err = EIO; 129 mutex_exit(&chmp->chm_lock_sizes); 130 goto out; 131 } 132 133 retries++; 134 mutex_exit(&chmp->chm_lock_sizes); 135 goto retry; 136 } 137 //Everything went well 138 chfs_change_size_used(chmp, 139 &chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size)); 140 mutex_exit(&chmp->chm_lock_sizes); 141 142 chfs_add_vnode_ref_to_vc(chmp, chvc, nref); 143 KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size); 144out: 145 chfs_free_flash_vnode(fvnode); 146 return err; 147} 148 149int 150chfs_write_flash_dirent(struct chfs_mount *chmp, struct chfs_inode *pdir, 151 struct chfs_inode *ip, struct chfs_dirent *fd, 152 ino_t ino, int prio) 153{ 154 KASSERT(mutex_owned(&chmp->chm_lock_mountfields)); 155 156 struct chfs_flash_dirent_node *fdirent; 157 struct chfs_node_ref *nref; 158 struct iovec vec[2]; 159 size_t size, retlen; 160 int err = 0, retries = 0; 161 uint8_t *name; 162 size_t namelen; 163 164 KASSERT(fd->vno != CHFS_ROOTINO); 165 166 fdirent = chfs_alloc_flash_dirent(); 167 if (!fdirent) 168 return ENOMEM; 169 170 size = sizeof(*fdirent) + fd->nsize; 171 namelen = CHFS_PAD(size) - sizeof(*fdirent); 172 173 name = kmem_zalloc(namelen, KM_SLEEP); 174 memcpy(name, fd->name, fd->nsize); 175 //dbg("namelen: %zu | nsize: %hhu\n", namelen, fd->nsize); 176 177 178 //dbg("size: %zu | PADDED: %zu\n", size, CHFS_PAD(size)); 179 fdirent->magic = htole16(CHFS_FS_MAGIC_BITMASK); 180 fdirent->type = htole16(CHFS_NODETYPE_DIRENT); 181 fdirent->length = htole32(CHFS_PAD(size)); 182 fdirent->hdr_crc = htole32(crc32(0, (uint8_t *)fdirent, 183 CHFS_NODE_HDR_SIZE - 4)); 184 fdirent->vno = htole64(ino); 185 fdirent->pvno = htole64(pdir->ino); 186 fdirent->version = htole64(++pdir->chvc->highest_version); 187 fdirent->mctime = ip?ip->ctime:0; 188 fdirent->nsize = fd->nsize; 189 fdirent->dtype = fd->type; 190 fdirent->name_crc = crc32(0, (uint8_t *)&(fd->name), fd->nsize); 191 fdirent->node_crc = crc32(0, (uint8_t *)fdirent, sizeof(*fdirent) - 4); 192 193 vec[0].iov_base = fdirent; 194 vec[0].iov_len = sizeof(*fdirent); 195 vec[1].iov_base = name; 196 vec[1].iov_len = namelen; 197 198retry: 199 if (prio == ALLOC_GC) { 200 /* the GC calls this function */ 201 err = chfs_reserve_space_gc(chmp, CHFS_PAD(size)); 202 if (err) 203 goto out; 204 } else { 205 chfs_gc_trigger(chmp); 206 if (prio == ALLOC_NORMAL) 207 err = chfs_reserve_space_normal(chmp, 208 CHFS_PAD(size), ALLOC_NORMAL); 209 else 210 err = chfs_reserve_space_normal(chmp, 211 CHFS_PAD(size), ALLOC_DELETION); 212 if (err) 213 goto out; 214 } 215 216 nref = chfs_alloc_node_ref(chmp->chm_nextblock); 217 if (!nref) { 218 err = ENOMEM; 219 goto out; 220 } 221 222 mutex_enter(&chmp->chm_lock_sizes); 223 224 nref->nref_offset = chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size; 225 chfs_change_size_free(chmp, chmp->chm_nextblock, -CHFS_PAD(size)); 226 227 err = chfs_write_wbuf(chmp, vec, 2, nref->nref_offset, &retlen); 228 if (err || retlen != CHFS_PAD(size)) { 229 chfs_err("error while writing out flash dirent node to the media\n"); 230 chfs_err("err: %d | size: %zu | retlen : %zu\n", 231 err, CHFS_PAD(size), retlen); 232 chfs_change_size_dirty(chmp, 233 chmp->chm_nextblock, CHFS_PAD(size)); 234 if (retries) { 235 err = EIO; 236 mutex_exit(&chmp->chm_lock_sizes); 237 goto out; 238 } 239 240 retries++; 241 mutex_exit(&chmp->chm_lock_sizes); 242 goto retry; 243 } 244 245 246 // Everything went well 247 chfs_change_size_used(chmp, 248 &chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size)); 249 mutex_exit(&chmp->chm_lock_sizes); 250 KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size); 251 fd->nref = nref; 252 if (prio != ALLOC_DELETION) { 253 chfs_add_node_to_list(chmp, 254 pdir->chvc, nref, &pdir->chvc->dirents); 255 } 256out: 257 chfs_free_flash_dirent(fdirent); 258 return err; 259} 260 261/** 262 * chfs_write_flash_dnode - write out a data node to flash 263 * @chmp: chfs mount structure 264 * @vp: vnode where the data belongs to 265 * @bp: buffer contains data 266 */ 267int 268chfs_write_flash_dnode(struct chfs_mount *chmp, struct vnode *vp, 269 struct buf *bp, struct chfs_full_dnode *fd) 270{ 271 KASSERT(mutex_owned(&chmp->chm_lock_mountfields)); 272 273 int err = 0, retries = 0; 274 size_t size, retlen; 275 off_t ofs; 276 struct chfs_flash_data_node *dnode; 277 struct chfs_node_ref *nref; 278 struct chfs_inode *ip = VTOI(vp); 279 struct iovec vec[2]; 280 uint32_t len; 281 void *tmpbuf = NULL; 282 283 KASSERT(ip->ino != CHFS_ROOTINO); 284 285 dnode = chfs_alloc_flash_dnode(); 286 if (!dnode) 287 return ENOMEM; 288 289 /* initialize flash data node */ 290 ofs = bp->b_blkno * PAGE_SIZE; 291 //dbg("vp->v_size: %ju, bp->b_blkno: %ju, bp-b_data: %p," 292 // " bp->b_resid: %ju\n", 293 // (uintmax_t )vp->v_size, (uintmax_t )bp->b_blkno, 294 // bp->b_data, (uintmax_t )bp->b_resid); 295 //dbg("[XXX]vp->v_size - ofs: %llu\n", (vp->v_size - ofs)); 296 len = MIN((vp->v_size - ofs), bp->b_resid); 297 size = sizeof(*dnode) + len; 298 299 dnode->magic = htole16(CHFS_FS_MAGIC_BITMASK); 300 dnode->type = htole16(CHFS_NODETYPE_DATA); 301 dnode->length = htole32(CHFS_PAD(size)); 302 dnode->hdr_crc = htole32(crc32(0, (uint8_t *)dnode, 303 CHFS_NODE_HDR_SIZE - 4)); 304 dnode->vno = htole64(ip->ino); 305 dnode->version = htole64(++ip->chvc->highest_version); 306 dnode->offset = htole64(ofs); 307 dnode->data_length = htole32(len); 308 dnode->data_crc = htole32(crc32(0, (uint8_t *)bp->b_data, len)); 309 dnode->node_crc = htole32(crc32(0, (uint8_t *)dnode, 310 sizeof(*dnode) - 4)); 311 312 dbg("dnode @%llu %ub v%llu\n", (unsigned long long)dnode->offset, 313 dnode->data_length, (unsigned long long)dnode->version); 314 315 if (CHFS_PAD(size) - sizeof(*dnode)) { 316 tmpbuf = kmem_zalloc(CHFS_PAD(size) 317 - sizeof(*dnode), KM_SLEEP); 318 memcpy(tmpbuf, bp->b_data, len); 319 } 320 321 /* creating iovecs for wbuf */ 322 vec[0].iov_base = dnode; 323 vec[0].iov_len = sizeof(*dnode); 324 vec[1].iov_base = tmpbuf; 325 vec[1].iov_len = CHFS_PAD(size) - sizeof(*dnode); 326 327 fd->frags = 0; 328 fd->ofs = ofs; 329 fd->size = len; 330 331retry: 332 333 /* Reserve space for data node. This will set up the next eraseblock 334 * where to we will write. 335 */ 336 337 chfs_gc_trigger(chmp); 338 err = chfs_reserve_space_normal(chmp, 339 CHFS_PAD(size), ALLOC_NORMAL); 340 if (err) 341 goto out; 342 343 nref = chfs_alloc_node_ref(chmp->chm_nextblock); 344 if (!nref) { 345 err = ENOMEM; 346 goto out; 347 } 348 349 nref->nref_offset = 350 chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size; 351 352 KASSERT(nref->nref_offset < chmp->chm_ebh->eb_size); 353 354 mutex_enter(&chmp->chm_lock_sizes); 355 356 chfs_change_size_free(chmp, 357 chmp->chm_nextblock, -CHFS_PAD(size)); 358 359 //dbg("vno: %llu nref lnr: %u offset: %u\n", 360 // dnode->vno, nref->nref_lnr, nref->nref_offset); 361 362 err = chfs_write_wbuf(chmp, vec, 2, nref->nref_offset, &retlen); 363 if (err || retlen != CHFS_PAD(size)) { 364 chfs_err("error while writing out flash data node to the media\n"); 365 chfs_err("err: %d | size: %zu | retlen : %zu\n", 366 err, size, retlen); 367 chfs_change_size_dirty(chmp, 368 chmp->chm_nextblock, CHFS_PAD(size)); 369 if (retries) { 370 err = EIO; 371 mutex_exit(&chmp->chm_lock_sizes); 372 goto out; 373 } 374 375 retries++; 376 mutex_exit(&chmp->chm_lock_sizes); 377 goto retry; 378 } 379 /* Everything went well */ 380 ip->write_size += fd->size; 381 chfs_change_size_used(chmp, 382 &chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size)); 383 mutex_exit(&chmp->chm_lock_sizes); 384 385 KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size); 386 fd->nref = nref; 387 chfs_add_node_to_list(chmp, ip->chvc, nref, &ip->chvc->dnode); 388out: 389 chfs_free_flash_dnode(dnode); 390 if (CHFS_PAD(size) - sizeof(*dnode)) { 391 kmem_free(tmpbuf, CHFS_PAD(size) - sizeof(*dnode)); 392 } 393 394 return err; 395} 396 397/** 398 * chfs_do_link - makes a copy from a node 399 * @old: old node 400 * @oldfd: dirent of old node 401 * @parent: parent of new node 402 * @name: name of new node 403 * @namelen: length of name 404 * This function writes the dirent of the new node to the media. 405 */ 406int 407chfs_do_link(struct chfs_inode *ip, struct chfs_inode *parent, const char *name, int namelen, enum vtype type) 408{ 409 int error = 0; 410 struct vnode *vp = ITOV(ip); 411 struct ufsmount *ump = VFSTOUFS(vp->v_mount); 412 struct chfs_mount *chmp = ump->um_chfs; 413 struct chfs_dirent *newfd = NULL; 414// struct chfs_dirent *fd = NULL; 415 416 //dbg("link vno: %llu\n", ip->ino); 417 418 newfd = chfs_alloc_dirent(namelen + 1); 419 420 newfd->vno = ip->ino; 421 newfd->type = type; 422 newfd->nsize = namelen; 423 memcpy(newfd->name, name, namelen); 424 newfd->name[newfd->nsize] = 0; 425// newfd->next = NULL; 426 427 ip->chvc->nlink++; 428 parent->chvc->nlink++; 429 ip->iflag |= IN_CHANGE; 430 chfs_update(vp, NULL, NULL, UPDATE_WAIT); 431 432 mutex_enter(&chmp->chm_lock_mountfields); 433 434 error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL); 435 if (error) 436 return error; 437 438 error = chfs_write_flash_dirent(chmp, 439 parent, ip, newfd, ip->ino, ALLOC_NORMAL); 440 /* TODO: what should we do if error isn't zero? */ 441 442 mutex_exit(&chmp->chm_lock_mountfields); 443 444 /* add fd to the fd list */ 445 TAILQ_INSERT_TAIL(&parent->dents, newfd, fds); 446#if 0 447 fd = parent->dents; 448 if (!fd) { 449 parent->dents = newfd; 450 } else { 451 while (fd->next) 452 fd = fd->next; 453 fd->next = newfd; 454 } 455#endif 456 457 return error; 458} 459 460 461/** 462 * chfs_do_unlink - delete a node 463 * @ip: node what we'd like to delete 464 * @parent: parent of the node 465 * @name: name of the node 466 * @namelen: length of name 467 * This function set the nlink and vno of the node zero and write its dirent to the media. 468 */ 469int 470chfs_do_unlink(struct chfs_inode *ip, 471 struct chfs_inode *parent, const char *name, int namelen) 472{ 473 struct chfs_dirent *fd, *tmpfd; 474 int error = 0; 475 struct vnode *vp = ITOV(ip); 476 struct ufsmount *ump = VFSTOUFS(vp->v_mount); 477 struct chfs_mount *chmp = ump->um_chfs; 478 struct chfs_node_ref *nref; 479 480 //dbg("unlink vno: %llu\n", ip->ino); 481 482 vflushbuf(vp, 0); 483 484 mutex_enter(&chmp->chm_lock_mountfields); 485 486 /* remove the full direntry from the parent dents list */ 487 TAILQ_FOREACH_SAFE(fd, &parent->dents, fds, tmpfd) { 488 if (fd->vno == ip->ino && 489 fd->nsize == namelen && 490 !memcmp(fd->name, name, fd->nsize)) { 491 if (fd->type == VDIR && ip->chvc->nlink == 2) 492 ip->chvc->nlink = 0; 493 else 494 ip->chvc->nlink--; 495 496 fd->type = VNON; 497 498 TAILQ_REMOVE(&parent->dents, fd, fds); 499 500 /* remove nref from dirents list */ 501 nref = parent->chvc->dirents; 502 if (nref == fd->nref) { 503 nref->nref_next = fd->nref->nref_next; 504 } else { 505 while (nref->nref_next && nref->nref_next != fd->nref) 506 nref = nref->nref_next; 507 if (nref->nref_next) 508 nref->nref_next = fd->nref->nref_next; 509 } 510 511 //dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n", 512 // fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset); 513 chfs_mark_node_obsolete(chmp, fd->nref); 514 515 error = chfs_write_flash_dirent(chmp, 516 parent, ip, fd, 0, ALLOC_DELETION); 517 518 //dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n", 519 // fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset); 520 chfs_mark_node_obsolete(chmp, fd->nref); 521 522 nref = ip->chvc->dnode; 523 while (nref != (struct chfs_node_ref *)ip->chvc) { 524 //dbg("DATA NREF\n"); 525 chfs_mark_node_obsolete(chmp, nref); 526 nref = nref->nref_next; 527 } 528 ip->chvc->dnode = (struct chfs_node_ref *)ip->chvc; 529 530 nref = ip->chvc->v; 531 while (nref != (struct chfs_node_ref *)ip->chvc) { 532 //dbg("V NREF\n"); 533 chfs_mark_node_obsolete(chmp, nref); 534 nref = nref->nref_next; 535 } 536 ip->chvc->v = ip->chvc->v->nref_next; 537 538 parent->chvc->nlink--; 539 //TODO: if error 540 } 541 } 542 mutex_exit(&chmp->chm_lock_mountfields); 543 544 return error; 545} 546