-
Notifications
You must be signed in to change notification settings - Fork 57
/
k-chkfsiter.cc
144 lines (124 loc) · 3.98 KB
/
k-chkfsiter.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include "k-chkfsiter.hh"
// MAIN CHICKADEEFS ITERATOR FUNCTIONS
chkfs_fileiter& chkfs_fileiter::find(off_t off) {
// if moving backwards, rewind to start
off_ = off;
if (!eptr_ || off_ < eoff_) {
eoff_ = 0;
eidx_ = 0;
eptr_ = &ino_->direct[0];
if (indirect_entry_) {
indirect_entry_->put();
indirect_entry_ = nullptr;
}
}
// walk extents to relevant position
while (off_ >= eoff_ + eptr_->count * blocksize) {
if (eptr_->count == 0) {
goto not_found;
}
eoff_ += eptr_->count * blocksize;
++eidx_;
++eptr_;
if (eidx_ < chkfs::ndirect) {
// do nothing
} else if ((eidx_ - chkfs::ndirect) % chkfs::extentsperblock == 0) {
if (indirect_entry_) {
indirect_entry_->put();
indirect_entry_ = nullptr;
}
unsigned ibi = (eidx_ - chkfs::ndirect) / chkfs::extentsperblock;
if (ino_->indirect.count <= ibi) {
goto not_found;
}
auto& bc = bufcache::get();
indirect_entry_ = bc.get_disk_entry(ino_->indirect.first + ibi);
if (!indirect_entry_) {
goto not_found;
}
eptr_ = reinterpret_cast<chkfs::extent*>(indirect_entry_->buf_);
}
}
return *this;
not_found:
eptr_ = nullptr;
return *this;
}
void chkfs_fileiter::next() {
if (eptr_ && eptr_->count != 0) {
do {
find(round_up(off_ + 1, blocksize));
} while (eptr_ && eptr_->first == 0 && eptr_->count != 0);
}
}
int chkfs_fileiter::insert(blocknum_t first, unsigned count) {
assert(ino_->has_write_lock());
assert(count != 0);
assert(!eptr_ || !eptr_->count);
assert((eoff_ % blocksize) == 0);
auto& bc = bufcache::get();
auto ino_entry = inode()->entry();
// grow previous direct extent if possible
if (eidx_ > 0 && eidx_ <= chkfs::ndirect) {
chkfs::extent* peptr = &ino_->direct[eidx_ - 1];
if (peptr->first + peptr->count == first) {
ino_entry->get_write();
eptr_ = peptr;
--eidx_;
eoff_ -= eptr_->count * blocksize;
eptr_->count += count;
ino_entry->put_write();
return 0;
}
}
// allocate & initialize indirect extent if necessary
if (eidx_ == chkfs::ndirect && !ino_->indirect.count) {
auto& chkfs = chkfsstate::get();
assert(!indirect_entry_);
blocknum_t indirect_bn = chkfs.allocate_extent(1);
if (indirect_bn >= blocknum_t(E_MINERROR)) {
return int(indirect_bn);
}
indirect_entry_ = bc.get_disk_entry(indirect_bn);
if (!indirect_entry_) {
return E_NOMEM;
}
indirect_entry_->get_write();
memset(indirect_entry_->buf_, 0, blocksize);
indirect_entry_->put_write();
ino_entry->get_write();
ino_->indirect.first = indirect_bn;
ino_->indirect.count = 1;
ino_entry->put_write();
}
// fail if required to grow indirect extent
if (eidx_ >= chkfs::ndirect && !indirect_entry_) {
return E_FBIG;
}
// add new extent
bcentry* entry;
if (eidx_ < chkfs::ndirect) {
entry = ino_entry;
eptr_ = &ino_->direct[eidx_];
} else {
entry = indirect_entry_;
eptr_ = reinterpret_cast<chkfs::extent*>(indirect_entry_->buf_)
+ (eidx_ - chkfs::ndirect) % chkfs::extentsperblock;
}
entry->get_write();
if (eidx_ >= chkfs::ndirect
&& (eidx_ - chkfs::ndirect) % chkfs::extentsperblock != 0
&& eptr_[-1].first + eptr_[-1].count == first) {
// grow previous extent
--eptr_;
--eidx_;
eoff_ -= eptr_->count * blocksize;
eptr_->count += count;
} else {
// add new extent
eptr_->first = first;
eptr_->count = count;
}
entry->put_write();
return 0;
}