xref: /haiku/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp (revision 0324283823c6b15f5bcc6455314c9a2ea28d4b30)
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