1 /*
2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Paweł Dziepak, pdziepak@quarnos.org
7 */
8
9
10 #include "RootInode.h"
11
12 #include <string.h>
13
14 #include "MetadataCache.h"
15 #include "Request.h"
16
17
RootInode()18 RootInode::RootInode()
19 :
20 fInfoCacheExpire(0),
21 fName(NULL),
22 fIOSize(0)
23 {
24 mutex_init(&fInfoCacheLock, NULL);
25 }
26
27
~RootInode()28 RootInode::~RootInode()
29 {
30 free(const_cast<char*>(fName));
31 mutex_destroy(&fInfoCacheLock);
32 }
33
34
35 status_t
ReadInfo(struct fs_info * info)36 RootInode::ReadInfo(struct fs_info* info)
37 {
38 ASSERT(info != NULL);
39
40 status_t result = _UpdateInfo();
41 if (result != B_OK)
42 return result;
43
44 memcpy(info, &fInfoCache, sizeof(struct fs_info));
45
46 return B_OK;
47 }
48
49
50 status_t
_UpdateInfo(bool force)51 RootInode::_UpdateInfo(bool force)
52 {
53 if (!force && fInfoCacheExpire > time(NULL))
54 return B_OK;
55
56 MutexLocker _(fInfoCacheLock);
57
58 if (fInfoCacheExpire > time(NULL))
59 return B_OK;
60
61 uint32 attempt = 0;
62 do {
63 RPC::Server* server = fFileSystem->Server();
64 Request request(server, fFileSystem);
65 RequestBuilder& req = request.Builder();
66
67 req.PutFH(fInfo.fHandle);
68 Attribute attr[] = { FATTR4_FILES_FREE, FATTR4_FILES_TOTAL,
69 FATTR4_MAXREAD, FATTR4_MAXWRITE, FATTR4_SPACE_FREE,
70 FATTR4_SPACE_TOTAL };
71 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
72
73 status_t result = request.Send();
74 if (result != B_OK)
75 return result;
76
77 ReplyInterpreter& reply = request.Reply();
78
79 if (HandleErrors(attempt, reply.NFS4Error(), server))
80 continue;
81
82 reply.PutFH();
83
84 AttrValue* values;
85 uint32 count, next = 0;
86 result = reply.GetAttr(&values, &count);
87 if (result != B_OK)
88 return result;
89
90 if (count >= next && values[next].fAttribute == FATTR4_FILES_FREE) {
91 fInfoCache.free_nodes = values[next].fData.fValue64;
92 next++;
93 }
94
95 if (count >= next && values[next].fAttribute == FATTR4_FILES_TOTAL) {
96 fInfoCache.total_nodes = values[next].fData.fValue64;
97 next++;
98 }
99
100 uint64 ioSize = LONGLONG_MAX;
101 if (count >= next && values[next].fAttribute == FATTR4_MAXREAD) {
102 ioSize = min_c(ioSize, values[next].fData.fValue64);
103 next++;
104 }
105
106 if (count >= next && values[next].fAttribute == FATTR4_MAXWRITE) {
107 ioSize = min_c(ioSize, values[next].fData.fValue64);
108 next++;
109 }
110
111 if (ioSize == LONGLONG_MAX)
112 ioSize = 32768;
113 if (ioSize == 0)
114 ioSize = 4096;
115 fInfoCache.io_size = ioSize;
116 fInfoCache.block_size = ioSize;
117 fIOSize = ioSize;
118
119 if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) {
120 fInfoCache.free_blocks = values[next].fData.fValue64 / ioSize;
121 next++;
122 }
123
124 if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) {
125 fInfoCache.total_blocks = values[next].fData.fValue64 / ioSize;
126 next++;
127 }
128
129 delete[] values;
130
131 break;
132 } while (true);
133
134 fInfoCache.flags = B_FS_IS_PERSISTENT | B_FS_IS_SHARED
135 | B_FS_SUPPORTS_NODE_MONITORING;
136
137 if (fFileSystem->NamedAttrs()
138 || fFileSystem->GetConfiguration().fEmulateNamedAttrs)
139 fInfoCache.flags |= B_FS_HAS_MIME | B_FS_HAS_ATTR;
140
141 strlcpy(fInfoCache.volume_name, fName, sizeof(fInfoCache.volume_name));
142
143 fInfoCacheExpire = time(NULL) + MetadataCache::kExpirationTime;
144
145 return B_OK;
146 }
147
148
149 bool
ProbeMigration()150 RootInode::ProbeMigration()
151 {
152 uint32 attempt = 0;
153 do {
154 RPC::Server* server = fFileSystem->Server();
155 Request request(server, fFileSystem);
156 RequestBuilder& req = request.Builder();
157
158 req.PutFH(fInfo.fHandle);
159 req.Access();
160
161 status_t result = request.Send();
162 if (result != B_OK)
163 continue;
164
165 ReplyInterpreter& reply = request.Reply();
166
167 if (reply.NFS4Error() == NFS4ERR_MOVED)
168 return true;
169
170 if (HandleErrors(attempt, reply.NFS4Error(), server))
171 continue;
172
173 return false;
174 } while (true);
175 }
176
177
178 status_t
GetLocations(AttrValue ** attrv)179 RootInode::GetLocations(AttrValue** attrv)
180 {
181 ASSERT(attrv != NULL);
182
183 uint32 attempt = 0;
184 do {
185 RPC::Server* server = fFileSystem->Server();
186 Request request(server, fFileSystem);
187 RequestBuilder& req = request.Builder();
188
189 req.PutFH(fInfo.fHandle);
190 Attribute attr[] = { FATTR4_FS_LOCATIONS };
191 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
192
193 status_t result = request.Send();
194 if (result != B_OK)
195 return result;
196
197 ReplyInterpreter& reply = request.Reply();
198
199 if (HandleErrors(attempt, reply.NFS4Error(), server))
200 continue;
201
202 reply.PutFH();
203
204 uint32 count;
205 result = reply.GetAttr(attrv, &count);
206 if (result != B_OK)
207 return result;
208 if (count < 1) {
209 delete[] *attrv;
210 return B_ERROR;
211 }
212
213 return B_OK;
214 } while (true);
215
216 return B_OK;
217 }
218
219
220 const char*
Name() const221 RootInode::Name() const
222 {
223 ASSERT(fName != NULL);
224 return fName;
225 }
226
227