00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <types.h>
00036 #include <kern/errno.h>
00037 #include <kern/fcntl.h>
00038 #include <stat.h>
00039 #include <lib.h>
00040 #include <array.h>
00041 #include <bitmap.h>
00042 #include <uio.h>
00043 #include <synch.h>
00044 #include <vfs.h>
00045 #include <device.h>
00046 #include <sfs.h>
00047
00048
00049 static int sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int type,
00050 struct sfs_vnode **ret);
00051
00052
00053
00054
00055
00056
00057 static
00058 int
00059 sfs_clearblock(struct sfs_fs *sfs, uint32_t block)
00060 {
00061
00062 static char zeros[SFS_BLOCKSIZE];
00063 return sfs_wblock(sfs, zeros, block);
00064 }
00065
00066
00067 static
00068 int
00069 sfs_sync_inode(struct sfs_vnode *sv)
00070 {
00071 if (sv->sv_dirty) {
00072 struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
00073 int result = sfs_wblock(sfs, &sv->sv_i, sv->sv_ino);
00074 if (result) {
00075 return result;
00076 }
00077 sv->sv_dirty = false;
00078 }
00079 return 0;
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00089 static
00090 int
00091 sfs_balloc(struct sfs_fs *sfs, uint32_t *diskblock)
00092 {
00093 int result;
00094
00095 result = bitmap_alloc(sfs->sfs_freemap, diskblock);
00096 if (result) {
00097 return result;
00098 }
00099 sfs->sfs_freemapdirty = true;
00100
00101 if (*diskblock >= sfs->sfs_super.sp_nblocks) {
00102 panic("sfs: balloc: invalid block %u\n", *diskblock);
00103 }
00104
00105
00106 return sfs_clearblock(sfs, *diskblock);
00107 }
00108
00109
00110
00111
00112 static
00113 void
00114 sfs_bfree(struct sfs_fs *sfs, uint32_t diskblock)
00115 {
00116 bitmap_unmark(sfs->sfs_freemap, diskblock);
00117 sfs->sfs_freemapdirty = true;
00118 }
00119
00120
00121
00122
00123 static
00124 int
00125 sfs_bused(struct sfs_fs *sfs, uint32_t diskblock)
00126 {
00127 if (diskblock >= sfs->sfs_super.sp_nblocks) {
00128 panic("sfs: sfs_bused called on out of range block %u\n",
00129 diskblock);
00130 }
00131 return bitmap_isset(sfs->sfs_freemap, diskblock);
00132 }
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 static
00145 int
00146 sfs_bmap(struct sfs_vnode *sv, uint32_t fileblock, int doalloc,
00147 uint32_t *diskblock)
00148 {
00149
00150
00151
00152
00153
00154
00155
00156 static uint32_t idbuf[SFS_DBPERIDB];
00157
00158 struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
00159 uint32_t block;
00160 uint32_t idblock;
00161 uint32_t idnum, idoff;
00162 int result;
00163
00164 KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE);
00165
00166
00167
00168
00169 if (fileblock < SFS_NDIRECT) {
00170
00171
00172
00173 block = sv->sv_i.sfi_direct[fileblock];
00174
00175
00176
00177
00178 if (block==0 && doalloc) {
00179 result = sfs_balloc(sfs, &block);
00180 if (result) {
00181 return result;
00182 }
00183
00184
00185 sv->sv_i.sfi_direct[fileblock] = block;
00186 sv->sv_dirty = true;
00187 }
00188
00189
00190
00191
00192 if (block != 0 && !sfs_bused(sfs, block)) {
00193 panic("sfs: Data block %u (block %u of file %u) "
00194 "marked free\n", block, fileblock, sv->sv_ino);
00195 }
00196 *diskblock = block;
00197 return 0;
00198 }
00199
00200
00201
00202
00203
00204
00205
00206 fileblock -= SFS_NDIRECT;
00207
00208
00209 idnum = fileblock / SFS_DBPERIDB;
00210 idoff = fileblock % SFS_DBPERIDB;
00211
00212
00213
00214
00215
00216 if (idnum > 0) {
00217 return EFBIG;
00218 }
00219
00220
00221 idblock = sv->sv_i.sfi_indirect;
00222
00223 if (idblock==0 && !doalloc) {
00224
00225
00226
00227
00228
00229 *diskblock = 0;
00230 return 0;
00231 }
00232 else if (idblock==0) {
00233
00234
00235
00236
00237
00238
00239 result = sfs_balloc(sfs, &idblock);
00240 if (result) {
00241 return result;
00242 }
00243
00244
00245 sv->sv_i.sfi_indirect = idblock;
00246
00247
00248 sv->sv_dirty = true;
00249
00250
00251 bzero(idbuf, sizeof(idbuf));
00252 }
00253 else {
00254
00255
00256
00257 result = sfs_rblock(sfs, idbuf, idblock);
00258 if (result) {
00259 return result;
00260 }
00261 }
00262
00263
00264 block = idbuf[idoff];
00265
00266
00267 if (block==0 && doalloc) {
00268 result = sfs_balloc(sfs, &block);
00269 if (result) {
00270 return result;
00271 }
00272
00273
00274 idbuf[idoff] = block;
00275
00276
00277 result = sfs_wblock(sfs, idbuf, idblock);
00278 if (result) {
00279 return result;
00280 }
00281 }
00282
00283
00284 if (block != 0 && !sfs_bused(sfs, block)) {
00285 panic("sfs: Data block %u (block %u of file %u) marked free\n",
00286 block, fileblock, sv->sv_ino);
00287 }
00288 *diskblock = block;
00289 return 0;
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306 static
00307 int
00308 sfs_partialio(struct sfs_vnode *sv, struct uio *uio,
00309 uint32_t skipstart, uint32_t len)
00310 {
00311
00312
00313
00314
00315
00316
00317
00318 static char iobuf[SFS_BLOCKSIZE];
00319
00320 struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
00321 uint32_t diskblock;
00322 uint32_t fileblock;
00323 int result;
00324
00325
00326 int doalloc = (uio->uio_rw==UIO_WRITE);
00327
00328 KASSERT(skipstart + len <= SFS_BLOCKSIZE);
00329
00330
00331 fileblock = uio->uio_offset / SFS_BLOCKSIZE;
00332
00333
00334 result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
00335 if (result) {
00336 return result;
00337 }
00338
00339 if (diskblock == 0) {
00340
00341
00342
00343
00344 KASSERT(uio->uio_rw == UIO_READ);
00345 bzero(iobuf, sizeof(iobuf));
00346 }
00347 else {
00348
00349
00350
00351 result = sfs_rblock(sfs, iobuf, diskblock);
00352 if (result) {
00353 return result;
00354 }
00355 }
00356
00357
00358
00359
00360 result = uiomove(iobuf+skipstart, len, uio);
00361 if (result) {
00362 return result;
00363 }
00364
00365
00366
00367
00368 if (uio->uio_rw == UIO_WRITE) {
00369 result = sfs_wblock(sfs, iobuf, diskblock);
00370 if (result) {
00371 return result;
00372 }
00373 }
00374
00375 return 0;
00376 }
00377
00378
00379
00380
00381 static
00382 int
00383 sfs_blockio(struct sfs_vnode *sv, struct uio *uio)
00384 {
00385 struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
00386 uint32_t diskblock;
00387 uint32_t fileblock;
00388 int result;
00389 int doalloc = (uio->uio_rw==UIO_WRITE);
00390 off_t saveoff;
00391 off_t diskoff;
00392 off_t saveres;
00393 off_t diskres;
00394
00395
00396 fileblock = uio->uio_offset / SFS_BLOCKSIZE;
00397
00398
00399 result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
00400 if (result) {
00401 return result;
00402 }
00403
00404 if (diskblock == 0) {
00405
00406
00407
00408
00409
00410
00411 KASSERT(uio->uio_rw == UIO_READ);
00412 return uiomovezeros(SFS_BLOCKSIZE, uio);
00413 }
00414
00415
00416
00417
00418
00419 saveoff = uio->uio_offset;
00420 diskoff = diskblock * SFS_BLOCKSIZE;
00421 uio->uio_offset = diskoff;
00422
00423
00424
00425
00426 KASSERT(uio->uio_resid >= SFS_BLOCKSIZE);
00427 saveres = uio->uio_resid;
00428 diskres = SFS_BLOCKSIZE;
00429 uio->uio_resid = diskres;
00430
00431 result = sfs_rwblock(sfs, uio);
00432
00433
00434
00435
00436
00437 uio->uio_offset = (uio->uio_offset - diskoff) + saveoff;
00438 uio->uio_resid = (uio->uio_resid - diskres) + saveres;
00439
00440 return result;
00441 }
00442
00443
00444
00445
00446 static
00447 int
00448 sfs_io(struct sfs_vnode *sv, struct uio *uio)
00449 {
00450 uint32_t blkoff;
00451 uint32_t nblocks, i;
00452 int result = 0;
00453 uint32_t extraresid = 0;
00454
00455
00456
00457
00458
00459
00460 if (uio->uio_rw == UIO_READ) {
00461 off_t size = sv->sv_i.sfi_size;
00462 off_t endpos = uio->uio_offset + uio->uio_resid;
00463
00464 if (uio->uio_offset >= size) {
00465
00466 return 0;
00467 }
00468
00469 if (endpos > size) {
00470 extraresid = endpos - size;
00471 KASSERT(uio->uio_resid > extraresid);
00472 uio->uio_resid -= extraresid;
00473 }
00474 }
00475
00476
00477
00478
00479 blkoff = uio->uio_offset % SFS_BLOCKSIZE;
00480 if (blkoff != 0) {
00481
00482 uint32_t skip = blkoff;
00483
00484
00485 uint32_t len = SFS_BLOCKSIZE - blkoff;
00486
00487
00488 if (len > uio->uio_resid) {
00489 len = uio->uio_resid;
00490 }
00491
00492
00493 result = sfs_partialio(sv, uio, skip, len);
00494 if (result) {
00495 goto out;
00496 }
00497 }
00498
00499
00500 if (uio->uio_resid==0) {
00501 goto out;
00502 }
00503
00504
00505
00506
00507 KASSERT(uio->uio_offset % SFS_BLOCKSIZE == 0);
00508 nblocks = uio->uio_resid / SFS_BLOCKSIZE;
00509 for (i=0; i<nblocks; i++) {
00510 result = sfs_blockio(sv, uio);
00511 if (result) {
00512 goto out;
00513 }
00514 }
00515
00516
00517
00518
00519 KASSERT(uio->uio_resid < SFS_BLOCKSIZE);
00520
00521 if (uio->uio_resid > 0) {
00522 result = sfs_partialio(sv, uio, 0, uio->uio_resid);
00523 if (result) {
00524 goto out;
00525 }
00526 }
00527
00528 out:
00529
00530
00531 if (uio->uio_rw == UIO_WRITE &&
00532 uio->uio_offset > (off_t)sv->sv_i.sfi_size) {
00533 sv->sv_i.sfi_size = uio->uio_offset;
00534 sv->sv_dirty = true;
00535 }
00536
00537
00538 uio->uio_resid += extraresid;
00539
00540
00541 return result;
00542 }
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552 static
00553 int
00554 sfs_readdir(struct sfs_vnode *sv, struct sfs_dir *sd, int slot)
00555 {
00556 struct iovec iov;
00557 struct uio ku;
00558 off_t actualpos;
00559 int result;
00560
00561
00562 actualpos = slot * sizeof(struct sfs_dir);
00563
00564
00565 uio_kinit(&iov, &ku, sd, sizeof(struct sfs_dir), actualpos, UIO_READ);
00566
00567
00568 result = sfs_io(sv, &ku);
00569 if (result) {
00570 return result;
00571 }
00572
00573
00574 if (ku.uio_resid > 0) {
00575 panic("sfs: readdir: Short entry (inode %u)\n", sv->sv_ino);
00576 }
00577
00578
00579 return 0;
00580 }
00581
00582
00583
00584
00585
00586 static
00587 int
00588 sfs_writedir(struct sfs_vnode *sv, struct sfs_dir *sd, int slot)
00589 {
00590 struct iovec iov;
00591 struct uio ku;
00592 off_t actualpos;
00593 int result;
00594
00595
00596 KASSERT(slot>=0);
00597 actualpos = slot * sizeof(struct sfs_dir);
00598
00599
00600 uio_kinit(&iov, &ku, sd, sizeof(struct sfs_dir), actualpos, UIO_WRITE);
00601
00602
00603 result = sfs_io(sv, &ku);
00604 if (result) {
00605 return result;
00606 }
00607
00608
00609 if (ku.uio_resid > 0) {
00610 panic("sfs: writedir: Short write (ino %u)\n", sv->sv_ino);
00611 }
00612
00613
00614 return 0;
00615 }
00616
00617
00618
00619
00620
00621
00622 static
00623 int
00624 sfs_dir_nentries(struct sfs_vnode *sv)
00625 {
00626 off_t size;
00627
00628 KASSERT(sv->sv_i.sfi_type == SFS_TYPE_DIR);
00629
00630 size = sv->sv_i.sfi_size;
00631 if (size % sizeof(struct sfs_dir) != 0) {
00632 panic("sfs: directory %u: Invalid size %llu\n",
00633 sv->sv_ino, size);
00634 }
00635
00636 return size / sizeof(struct sfs_dir);
00637 }
00638
00639
00640
00641
00642
00643
00644
00645 static
00646 int
00647 sfs_dir_findname(struct sfs_vnode *sv, const char *name,
00648 uint32_t *ino, int *slot, int *emptyslot)
00649 {
00650 struct sfs_dir tsd;
00651 int found = 0;
00652 int nentries = sfs_dir_nentries(sv);
00653 int i, result;
00654
00655
00656 for (i=0; i<nentries; i++) {
00657
00658
00659 result = sfs_readdir(sv, &tsd, i);
00660 if (result) {
00661 return result;
00662 }
00663 if (tsd.sfd_ino == SFS_NOINO) {
00664
00665 if (emptyslot != NULL) {
00666 *emptyslot = i;
00667 }
00668 }
00669 else {
00670
00671 tsd.sfd_name[sizeof(tsd.sfd_name)-1] = 0;
00672 if (!strcmp(tsd.sfd_name, name)) {
00673
00674
00675 KASSERT(found==0);
00676
00677 found = 1;
00678 if (slot != NULL) {
00679 *slot = i;
00680 }
00681 if (ino != NULL) {
00682 *ino = tsd.sfd_ino;
00683 }
00684 }
00685 }
00686 }
00687
00688 return found ? 0 : ENOENT;
00689 }
00690
00691
00692
00693
00694
00695 static
00696 int
00697 sfs_dir_link(struct sfs_vnode *sv, const char *name, uint32_t ino, int *slot)
00698 {
00699 int emptyslot = -1;
00700 int result;
00701 struct sfs_dir sd;
00702
00703
00704 result = sfs_dir_findname(sv, name, NULL, NULL, &emptyslot);
00705 if (result!=0 && result!=ENOENT) {
00706 return result;
00707 }
00708 if (result==0) {
00709 return EEXIST;
00710 }
00711
00712 if (strlen(name)+1 > sizeof(sd.sfd_name)) {
00713 return ENAMETOOLONG;
00714 }
00715
00716
00717 if (emptyslot < 0) {
00718 emptyslot = sfs_dir_nentries(sv);
00719 }
00720
00721
00722 bzero(&sd, sizeof(sd));
00723 sd.sfd_ino = ino;
00724 strcpy(sd.sfd_name, name);
00725
00726
00727 if (slot) {
00728 *slot = emptyslot;
00729 }
00730
00731
00732 return sfs_writedir(sv, &sd, emptyslot);
00733
00734 }
00735
00736
00737
00738
00739 static
00740 int
00741 sfs_dir_unlink(struct sfs_vnode *sv, int slot)
00742 {
00743 struct sfs_dir sd;
00744
00745
00746 bzero(&sd, sizeof(sd));
00747 sd.sfd_ino = SFS_NOINO;
00748
00749
00750 return sfs_writedir(sv, &sd, slot);
00751 }
00752
00753
00754
00755
00756
00757 static
00758 int
00759 sfs_lookonce(struct sfs_vnode *sv, const char *name,
00760 struct sfs_vnode **ret,
00761 int *slot)
00762 {
00763 struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
00764 uint32_t ino;
00765 int result;
00766
00767 result = sfs_dir_findname(sv, name, &ino, slot, NULL);
00768 if (result) {
00769 return result;
00770 }
00771
00772 result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, ret);
00773 if (result) {
00774 return result;
00775 }
00776
00777 if ((*ret)->sv_i.sfi_linkcount == 0) {
00778 panic("sfs: Link count of file %u found in dir %u is 0\n",
00779 (*ret)->sv_ino, sv->sv_ino);
00780 }
00781
00782 return 0;
00783 }
00784
00785
00786
00787
00788
00789
00790
00791
00792 static
00793 int
00794 sfs_makeobj(struct sfs_fs *sfs, int type, struct sfs_vnode **ret)
00795 {
00796 uint32_t ino;
00797 int result;
00798
00799
00800
00801
00802
00803
00804 result = sfs_balloc(sfs, &ino);
00805 if (result) {
00806 return result;
00807 }
00808
00809
00810
00811
00812
00813 return sfs_loadvnode(sfs, ino, type, ret);
00814 }
00815
00816
00817
00818
00819
00820
00821
00822
00823 static
00824 int
00825 sfs_open(struct vnode *v, int openflags)
00826 {
00827
00828
00829
00830
00831
00832
00833
00834
00835 if (openflags & O_APPEND) {
00836 return EUNIMP;
00837 }
00838
00839 (void)v;
00840
00841 return 0;
00842 }
00843
00844
00845
00846
00847
00848 static
00849 int
00850 sfs_opendir(struct vnode *v, int openflags)
00851 {
00852 switch (openflags & O_ACCMODE) {
00853 case O_RDONLY:
00854 break;
00855 case O_WRONLY:
00856 case O_RDWR:
00857 default:
00858 return EISDIR;
00859 }
00860 if (openflags & O_APPEND) {
00861 return EISDIR;
00862 }
00863
00864 (void)v;
00865 return 0;
00866 }
00867
00868
00869
00870
00871
00872
00873
00874 static
00875 int
00876 sfs_close(struct vnode *v)
00877 {
00878
00879 return VOP_FSYNC(v);
00880 }
00881
00882
00883
00884
00885
00886
00887 static
00888 int
00889 sfs_reclaim(struct vnode *v)
00890 {
00891 struct sfs_vnode *sv = v->vn_data;
00892 struct sfs_fs *sfs = v->vn_fs->fs_data;
00893 unsigned ix, i, num;
00894 int result;
00895
00896 vfs_biglock_acquire();
00897
00898
00899
00900
00901
00902
00903 if (v->vn_refcount != 1) {
00904
00905
00906 KASSERT(v->vn_refcount>1);
00907 v->vn_refcount--;
00908
00909 vfs_biglock_release();
00910 return EBUSY;
00911 }
00912
00913
00914 if (sv->sv_i.sfi_linkcount==0) {
00915 result = VOP_TRUNCATE(&sv->sv_v, 0);
00916 if (result) {
00917 vfs_biglock_release();
00918 return result;
00919 }
00920 }
00921
00922
00923 result = sfs_sync_inode(sv);
00924 if (result) {
00925 vfs_biglock_release();
00926 return result;
00927 }
00928
00929
00930 if (sv->sv_i.sfi_linkcount==0) {
00931 sfs_bfree(sfs, sv->sv_ino);
00932 }
00933
00934
00935 num = vnodearray_num(sfs->sfs_vnodes);
00936 ix = num;
00937 for (i=0; i<num; i++) {
00938 struct vnode *v2 = vnodearray_get(sfs->sfs_vnodes, i);
00939 struct sfs_vnode *sv2 = v2->vn_data;
00940 if (sv2 == sv) {
00941 ix = i;
00942 break;
00943 }
00944 }
00945 if (ix == num) {
00946 panic("sfs: reclaim vnode %u not in vnode pool\n",
00947 sv->sv_ino);
00948 }
00949 vnodearray_remove(sfs->sfs_vnodes, ix);
00950
00951 VOP_CLEANUP(&sv->sv_v);
00952
00953 vfs_biglock_release();
00954
00955
00956 kfree(sv);
00957
00958
00959 return 0;
00960 }
00961
00962
00963
00964
00965 static
00966 int
00967 sfs_read(struct vnode *v, struct uio *uio)
00968 {
00969 struct sfs_vnode *sv = v->vn_data;
00970 int result;
00971
00972 KASSERT(uio->uio_rw==UIO_READ);
00973
00974 vfs_biglock_acquire();
00975 result = sfs_io(sv, uio);
00976 vfs_biglock_release();
00977
00978 return result;
00979 }
00980
00981
00982
00983
00984 static
00985 int
00986 sfs_write(struct vnode *v, struct uio *uio)
00987 {
00988 struct sfs_vnode *sv = v->vn_data;
00989 int result;
00990
00991 KASSERT(uio->uio_rw==UIO_WRITE);
00992
00993 vfs_biglock_acquire();
00994 result = sfs_io(sv, uio);
00995 vfs_biglock_release();
00996
00997 return result;
00998 }
00999
01000
01001
01002
01003 static
01004 int
01005 sfs_ioctl(struct vnode *v, int op, userptr_t data)
01006 {
01007
01008
01009
01010
01011 (void)v;
01012 (void)op;
01013 (void)data;
01014
01015 return EINVAL;
01016 }
01017
01018
01019
01020
01021 static
01022 int
01023 sfs_stat(struct vnode *v, struct stat *statbuf)
01024 {
01025 struct sfs_vnode *sv = v->vn_data;
01026 int result;
01027
01028
01029 bzero(statbuf, sizeof(struct stat));
01030
01031 result = VOP_GETTYPE(v, &statbuf->st_mode);
01032 if (result) {
01033 return result;
01034 }
01035
01036 statbuf->st_size = sv->sv_i.sfi_size;
01037
01038
01039 statbuf->st_nlink = 0;
01040 statbuf->st_blocks = 0;
01041
01042
01043
01044 return 0;
01045 }
01046
01047
01048
01049
01050 static
01051 int
01052 sfs_gettype(struct vnode *v, uint32_t *ret)
01053 {
01054 struct sfs_vnode *sv = v->vn_data;
01055
01056 vfs_biglock_acquire();
01057
01058 switch (sv->sv_i.sfi_type) {
01059 case SFS_TYPE_FILE:
01060 *ret = S_IFREG;
01061 vfs_biglock_release();
01062 return 0;
01063 case SFS_TYPE_DIR:
01064 *ret = S_IFDIR;
01065 vfs_biglock_release();
01066 return 0;
01067 }
01068 panic("sfs: gettype: Invalid inode type (inode %u, type %u)\n",
01069 sv->sv_ino, sv->sv_i.sfi_type);
01070 return EINVAL;
01071 }
01072
01073
01074
01075
01076
01077
01078
01079
01080 static
01081 int
01082 sfs_tryseek(struct vnode *v, off_t pos)
01083 {
01084 if (pos<0) {
01085 return EINVAL;
01086 }
01087
01088
01089 (void)v;
01090
01091 return 0;
01092 }
01093
01094
01095
01096
01097
01098 static
01099 int
01100 sfs_fsync(struct vnode *v)
01101 {
01102 struct sfs_vnode *sv = v->vn_data;
01103 int result;
01104
01105 vfs_biglock_acquire();
01106 result = sfs_sync_inode(sv);
01107 vfs_biglock_release();
01108
01109 return result;
01110 }
01111
01112
01113
01114
01115 static
01116 int
01117 sfs_mmap(struct vnode *v )
01118 {
01119 (void)v;
01120 return EUNIMP;
01121 }
01122
01123
01124
01125
01126 static
01127 int
01128 sfs_truncate(struct vnode *v, off_t len)
01129 {
01130
01131
01132
01133
01134
01135
01136
01137 static uint32_t idbuf[SFS_DBPERIDB];
01138
01139 struct sfs_vnode *sv = v->vn_data;
01140 struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data;
01141
01142
01143 uint32_t blocklen = DIVROUNDUP(len, SFS_BLOCKSIZE);
01144
01145 uint32_t i, j, block;
01146 uint32_t idblock, baseblock, highblock;
01147 int result;
01148 int hasnonzero, iddirty;
01149
01150 KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE);
01151
01152 vfs_biglock_acquire();
01153
01154
01155
01156
01157
01158 for (i=0; i<SFS_NDIRECT; i++) {
01159 block = sv->sv_i.sfi_direct[i];
01160 if (i >= blocklen && block != 0) {
01161 sfs_bfree(sfs, block);
01162 sv->sv_i.sfi_direct[i] = 0;
01163 sv->sv_dirty = true;
01164 }
01165 }
01166
01167
01168 idblock = sv->sv_i.sfi_indirect;
01169
01170
01171 baseblock = SFS_NDIRECT;
01172
01173
01174 highblock = baseblock + SFS_DBPERIDB - 1;
01175
01176 if (blocklen < highblock && idblock != 0) {
01177
01178
01179
01180 result = sfs_rblock(sfs, idbuf, idblock);
01181 if (result) {
01182 vfs_biglock_release();
01183 return result;
01184 }
01185
01186 hasnonzero = 0;
01187 iddirty = 0;
01188 for (j=0; j<SFS_DBPERIDB; j++) {
01189
01190 if (blocklen < baseblock+j && idbuf[j] != 0) {
01191 sfs_bfree(sfs, idbuf[j]);
01192 idbuf[j] = 0;
01193 iddirty = 1;
01194 }
01195
01196 if (idbuf[j]!=0) {
01197 hasnonzero=1;
01198 }
01199 }
01200
01201 if (!hasnonzero) {
01202
01203 sfs_bfree(sfs, idblock);
01204 sv->sv_i.sfi_indirect = 0;
01205 sv->sv_dirty = true;
01206 }
01207 else if (iddirty) {
01208
01209 result = sfs_wblock(sfs, idbuf, idblock);
01210 if (result) {
01211 vfs_biglock_release();
01212 return result;
01213 }
01214 }
01215 }
01216
01217
01218 sv->sv_i.sfi_size = len;
01219
01220
01221 sv->sv_dirty = true;
01222
01223 vfs_biglock_release();
01224 return 0;
01225 }
01226
01227
01228
01229
01230
01231
01232
01233 static
01234 int
01235 sfs_namefile(struct vnode *vv, struct uio *uio)
01236 {
01237 struct sfs_vnode *sv = vv->vn_data;
01238 KASSERT(sv->sv_ino == SFS_ROOT_LOCATION);
01239
01240
01241
01242 (void)uio;
01243
01244 return 0;
01245 }
01246
01247
01248
01249
01250
01251 static
01252 int
01253 sfs_creat(struct vnode *v, const char *name, bool excl, mode_t mode,
01254 struct vnode **ret)
01255 {
01256 struct sfs_fs *sfs = v->vn_fs->fs_data;
01257 struct sfs_vnode *sv = v->vn_data;
01258 struct sfs_vnode *newguy;
01259 uint32_t ino;
01260 int result;
01261
01262 vfs_biglock_acquire();
01263
01264
01265 result = sfs_dir_findname(sv, name, &ino, NULL, NULL);
01266 if (result!=0 && result!=ENOENT) {
01267 vfs_biglock_release();
01268 return result;
01269 }
01270
01271
01272 if (result==0 && excl) {
01273 vfs_biglock_release();
01274 return EEXIST;
01275 }
01276
01277 if (result==0) {
01278
01279 result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy);
01280 if (result) {
01281 vfs_biglock_release();
01282 return result;
01283 }
01284 *ret = &newguy->sv_v;
01285 vfs_biglock_release();
01286 return 0;
01287 }
01288
01289
01290 result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy);
01291 if (result) {
01292 vfs_biglock_release();
01293 return result;
01294 }
01295
01296
01297 (void)mode;
01298
01299
01300 result = sfs_dir_link(sv, name, newguy->sv_ino, NULL);
01301 if (result) {
01302 VOP_DECREF(&newguy->sv_v);
01303 vfs_biglock_release();
01304 return result;
01305 }
01306
01307
01308 newguy->sv_i.sfi_linkcount++;
01309
01310
01311 newguy->sv_dirty = true;
01312
01313 *ret = &newguy->sv_v;
01314
01315 vfs_biglock_release();
01316 return 0;
01317 }
01318
01319
01320
01321
01322
01323
01324 static
01325 int
01326 sfs_link(struct vnode *dir, const char *name, struct vnode *file)
01327 {
01328 struct sfs_vnode *sv = dir->vn_data;
01329 struct sfs_vnode *f = file->vn_data;
01330 int result;
01331
01332 KASSERT(file->vn_fs == dir->vn_fs);
01333
01334 vfs_biglock_acquire();
01335
01336
01337 result = sfs_dir_link(sv, name, f->sv_ino, NULL);
01338 if (result) {
01339 vfs_biglock_release();
01340 return result;
01341 }
01342
01343
01344 f->sv_i.sfi_linkcount++;
01345 f->sv_dirty = true;
01346
01347 vfs_biglock_release();
01348 return 0;
01349 }
01350
01351
01352
01353
01354 static
01355 int
01356 sfs_remove(struct vnode *dir, const char *name)
01357 {
01358 struct sfs_vnode *sv = dir->vn_data;
01359 struct sfs_vnode *victim;
01360 int slot;
01361 int result;
01362
01363 vfs_biglock_acquire();
01364
01365
01366 result = sfs_lookonce(sv, name, &victim, &slot);
01367 if (result) {
01368 vfs_biglock_release();
01369 return result;
01370 }
01371
01372
01373 result = sfs_dir_unlink(sv, slot);
01374 if (result==0) {
01375
01376 KASSERT(victim->sv_i.sfi_linkcount > 0);
01377 victim->sv_i.sfi_linkcount--;
01378 victim->sv_dirty = true;
01379 }
01380
01381
01382 VOP_DECREF(&victim->sv_v);
01383
01384 vfs_biglock_release();
01385 return result;
01386 }
01387
01388
01389
01390
01391
01392
01393
01394 static
01395 int
01396 sfs_rename(struct vnode *d1, const char *n1,
01397 struct vnode *d2, const char *n2)
01398 {
01399 struct sfs_vnode *sv = d1->vn_data;
01400 struct sfs_vnode *g1;
01401 int slot1, slot2;
01402 int result, result2;
01403
01404 vfs_biglock_acquire();
01405
01406 KASSERT(d1==d2);
01407 KASSERT(sv->sv_ino == SFS_ROOT_LOCATION);
01408
01409
01410 result = sfs_lookonce(sv, n1, &g1, &slot1);
01411 if (result) {
01412 vfs_biglock_release();
01413 return result;
01414 }
01415
01416
01417 KASSERT(g1->sv_i.sfi_type == SFS_TYPE_FILE);
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427 result = sfs_dir_link(sv, n2, g1->sv_ino, &slot2);
01428 if (result) {
01429 goto puke;
01430 }
01431
01432
01433 g1->sv_i.sfi_linkcount++;
01434 g1->sv_dirty = true;
01435
01436
01437 result = sfs_dir_unlink(sv, slot1);
01438 if (result) {
01439 goto puke_harder;
01440 }
01441
01442
01443
01444
01445
01446 KASSERT(g1->sv_i.sfi_linkcount>0);
01447 g1->sv_i.sfi_linkcount--;
01448 g1->sv_dirty = true;
01449
01450
01451 VOP_DECREF(&g1->sv_v);
01452
01453 vfs_biglock_release();
01454 return 0;
01455
01456 puke_harder:
01457
01458
01459
01460 result2 = sfs_dir_unlink(sv, slot2);
01461 if (result2) {
01462 kprintf("sfs: rename: %s\n", strerror(result));
01463 kprintf("sfs: rename: while cleaning up: %s\n",
01464 strerror(result2));
01465 panic("sfs: rename: Cannot recover\n");
01466 }
01467 g1->sv_i.sfi_linkcount--;
01468 puke:
01469
01470 VOP_DECREF(&g1->sv_v);
01471 vfs_biglock_release();
01472 return result;
01473 }
01474
01475
01476
01477
01478
01479
01480
01481
01482 static
01483 int
01484 sfs_lookparent(struct vnode *v, char *path, struct vnode **ret,
01485 char *buf, size_t buflen)
01486 {
01487 struct sfs_vnode *sv = v->vn_data;
01488
01489 vfs_biglock_acquire();
01490
01491 if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
01492 vfs_biglock_release();
01493 return ENOTDIR;
01494 }
01495
01496 if (strlen(path)+1 > buflen) {
01497 vfs_biglock_release();
01498 return ENAMETOOLONG;
01499 }
01500 strcpy(buf, path);
01501
01502 VOP_INCREF(&sv->sv_v);
01503 *ret = &sv->sv_v;
01504
01505 vfs_biglock_release();
01506 return 0;
01507 }
01508
01509
01510
01511
01512
01513
01514
01515 static
01516 int
01517 sfs_lookup(struct vnode *v, char *path, struct vnode **ret)
01518 {
01519 struct sfs_vnode *sv = v->vn_data;
01520 struct sfs_vnode *final;
01521 int result;
01522
01523 vfs_biglock_acquire();
01524
01525 if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
01526 vfs_biglock_release();
01527 return ENOTDIR;
01528 }
01529
01530 result = sfs_lookonce(sv, path, &final, NULL);
01531 if (result) {
01532 vfs_biglock_release();
01533 return result;
01534 }
01535
01536 *ret = &final->sv_v;
01537
01538 vfs_biglock_release();
01539 return 0;
01540 }
01541
01542
01543
01544 static
01545 int
01546 sfs_notdir(void)
01547 {
01548 return ENOTDIR;
01549 }
01550
01551 static
01552 int
01553 sfs_isdir(void)
01554 {
01555 return EISDIR;
01556 }
01557
01558 static
01559 int
01560 sfs_unimp(void)
01561 {
01562 return EUNIMP;
01563 }
01564
01565
01566
01567
01568
01569
01570
01571 #define ISDIR ((void *)sfs_isdir)
01572 #define NOTDIR ((void *)sfs_notdir)
01573 #define UNIMP ((void *)sfs_unimp)
01574
01575
01576
01577
01578 static const struct vnode_ops sfs_fileops = {
01579 VOP_MAGIC,
01580
01581 sfs_open,
01582 sfs_close,
01583 sfs_reclaim,
01584
01585 sfs_read,
01586 NOTDIR,
01587 NOTDIR,
01588 sfs_write,
01589 sfs_ioctl,
01590 sfs_stat,
01591 sfs_gettype,
01592 sfs_tryseek,
01593 sfs_fsync,
01594 sfs_mmap,
01595 sfs_truncate,
01596 NOTDIR,
01597
01598 NOTDIR,
01599 NOTDIR,
01600 NOTDIR,
01601 NOTDIR,
01602 NOTDIR,
01603 NOTDIR,
01604 NOTDIR,
01605
01606 NOTDIR,
01607 NOTDIR,
01608 };
01609
01610
01611
01612
01613 static const struct vnode_ops sfs_dirops = {
01614 VOP_MAGIC,
01615
01616 sfs_opendir,
01617 sfs_close,
01618 sfs_reclaim,
01619
01620 ISDIR,
01621 ISDIR,
01622 UNIMP,
01623 ISDIR,
01624 sfs_ioctl,
01625 sfs_stat,
01626 sfs_gettype,
01627 UNIMP,
01628 sfs_fsync,
01629 ISDIR,
01630 ISDIR,
01631 sfs_namefile,
01632
01633 sfs_creat,
01634 UNIMP,
01635 UNIMP,
01636 sfs_link,
01637 sfs_remove,
01638 UNIMP,
01639 sfs_rename,
01640
01641 sfs_lookup,
01642 sfs_lookparent,
01643 };
01644
01645
01646
01647
01648
01649 static
01650 int
01651 sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int forcetype,
01652 struct sfs_vnode **ret)
01653 {
01654 struct vnode *v;
01655 struct sfs_vnode *sv;
01656 const struct vnode_ops *ops = NULL;
01657 unsigned i, num;
01658 int result;
01659
01660
01661 num = vnodearray_num(sfs->sfs_vnodes);
01662
01663
01664 for (i=0; i<num; i++) {
01665 v = vnodearray_get(sfs->sfs_vnodes, i);
01666 sv = v->vn_data;
01667
01668
01669 if (!sfs_bused(sfs, sv->sv_ino)) {
01670 panic("sfs: Found inode %u in unallocated block\n",
01671 sv->sv_ino);
01672 }
01673
01674 if (sv->sv_ino==ino) {
01675
01676
01677
01678 KASSERT(forcetype==SFS_TYPE_INVAL);
01679
01680 VOP_INCREF(&sv->sv_v);
01681 *ret = sv;
01682 return 0;
01683 }
01684 }
01685
01686
01687
01688 sv = kmalloc(sizeof(struct sfs_vnode));
01689 if (sv==NULL) {
01690 return ENOMEM;
01691 }
01692
01693
01694 if (!sfs_bused(sfs, ino)) {
01695 panic("sfs: Tried to load inode %u from unallocated block\n",
01696 ino);
01697 }
01698
01699
01700 result = sfs_rblock(sfs, &sv->sv_i, ino);
01701 if (result) {
01702 kfree(sv);
01703 return result;
01704 }
01705
01706
01707 sv->sv_dirty = false;
01708
01709
01710
01711
01712
01713
01714 if (forcetype != SFS_TYPE_INVAL) {
01715 KASSERT(sv->sv_i.sfi_type == SFS_TYPE_INVAL);
01716 sv->sv_i.sfi_type = forcetype;
01717 sv->sv_dirty = true;
01718 }
01719
01720
01721
01722
01723 switch (sv->sv_i.sfi_type) {
01724 case SFS_TYPE_FILE:
01725 ops = &sfs_fileops;
01726 break;
01727 case SFS_TYPE_DIR:
01728 ops = &sfs_dirops;
01729 break;
01730 default:
01731 panic("sfs: loadvnode: Invalid inode type "
01732 "(inode %u, type %u)\n",
01733 ino, sv->sv_i.sfi_type);
01734 }
01735
01736
01737 result = VOP_INIT(&sv->sv_v, ops, &sfs->sfs_absfs, sv);
01738 if (result) {
01739 kfree(sv);
01740 return result;
01741 }
01742
01743
01744 sv->sv_ino = ino;
01745
01746
01747 result = vnodearray_add(sfs->sfs_vnodes, &sv->sv_v, NULL);
01748 if (result) {
01749 VOP_CLEANUP(&sv->sv_v);
01750 kfree(sv);
01751 return result;
01752 }
01753
01754
01755 *ret = sv;
01756 return 0;
01757 }
01758
01759
01760
01761
01762
01763 struct vnode *
01764 sfs_getroot(struct fs *fs)
01765 {
01766 struct sfs_fs *sfs = fs->fs_data;
01767 struct sfs_vnode *sv;
01768 int result;
01769
01770 vfs_biglock_acquire();
01771
01772 result = sfs_loadvnode(sfs, SFS_ROOT_LOCATION, SFS_TYPE_INVAL, &sv);
01773 if (result) {
01774 panic("sfs: getroot: Cannot load root vnode\n");
01775 }
01776
01777 vfs_biglock_release();
01778
01779 return &sv->sv_v;
01780 }