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
18RootInode::RootInode()
19	:
20	fInfoCacheExpire(0),
21	fName(NULL),
22	fIOSize(0)
23{
24	mutex_init(&fInfoCacheLock, NULL);
25}
26
27
28RootInode::~RootInode()
29{
30	free(const_cast<char*>(fName));
31	mutex_destroy(&fInfoCacheLock);
32}
33
34
35status_t
36RootInode::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
50status_t
51RootInode::_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
149bool
150RootInode::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
178status_t
179RootInode::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
220const char*
221RootInode::Name() const
222{
223	ASSERT(fName != NULL);
224	return fName;
225}
226
227