xref: /haiku/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp (revision e5d65858f2361fe0552495b61620c84dcee6bc00)
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 
18 RootInode::RootInode()
19 	:
20 	fInfoCacheExpire(0),
21 	fName(NULL),
22 	fIOSize(0)
23 {
24 	mutex_init(&fInfoCacheLock, NULL);
25 }
26 
27 
28 RootInode::~RootInode()
29 {
30 	free(const_cast<char*>(fName));
31 	mutex_destroy(&fInfoCacheLock);
32 }
33 
34 
35 status_t
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
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 		fInfoCache.io_size = ioSize;
114 		fInfoCache.block_size = ioSize;
115 		fIOSize = ioSize;
116 
117 		if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) {
118 			fInfoCache.free_blocks = values[next].fData.fValue64 / ioSize;
119 			next++;
120 		}
121 
122 		if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) {
123 			fInfoCache.total_blocks = values[next].fData.fValue64 / ioSize;
124 			next++;
125 		}
126 
127 		delete[] values;
128 
129 		break;
130 	} while (true);
131 
132 	fInfoCache.flags = 	B_FS_IS_PERSISTENT | B_FS_IS_SHARED
133 		| B_FS_SUPPORTS_NODE_MONITORING;
134 
135 	if (fFileSystem->NamedAttrs()
136 		|| fFileSystem->GetConfiguration().fEmulateNamedAttrs)
137 		fInfoCache.flags |= B_FS_HAS_MIME | B_FS_HAS_ATTR;
138 
139 	strlcpy(fInfoCache.volume_name, fName, sizeof(fInfoCache.volume_name));
140 
141 	fInfoCacheExpire = time(NULL) + MetadataCache::kExpirationTime;
142 
143 	return B_OK;
144 }
145 
146 
147 bool
148 RootInode::ProbeMigration()
149 {
150 	uint32 attempt = 0;
151 	do {
152 		RPC::Server* server = fFileSystem->Server();
153 		Request request(server, fFileSystem);
154 		RequestBuilder& req = request.Builder();
155 
156 		req.PutFH(fInfo.fHandle);
157 		req.Access();
158 
159 		status_t result = request.Send();
160 		if (result != B_OK)
161 			continue;
162 
163 		ReplyInterpreter& reply = request.Reply();
164 
165 		if (reply.NFS4Error() == NFS4ERR_MOVED)
166 			return true;
167 
168 		if (HandleErrors(attempt, reply.NFS4Error(), server))
169 			continue;
170 
171 		return false;
172 	} while (true);
173 }
174 
175 
176 status_t
177 RootInode::GetLocations(AttrValue** attrv)
178 {
179 	ASSERT(attrv != NULL);
180 
181 	uint32 attempt = 0;
182 	do {
183 		RPC::Server* server = fFileSystem->Server();
184 		Request request(server, fFileSystem);
185 		RequestBuilder& req = request.Builder();
186 
187 		req.PutFH(fInfo.fHandle);
188 		Attribute attr[] = { FATTR4_FS_LOCATIONS };
189 		req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
190 
191 		status_t result = request.Send();
192 		if (result != B_OK)
193 			return result;
194 
195 		ReplyInterpreter& reply = request.Reply();
196 
197 		if (HandleErrors(attempt, reply.NFS4Error(), server))
198 			continue;
199 
200 		reply.PutFH();
201 
202 		uint32 count;
203 		result = reply.GetAttr(attrv, &count);
204 		if (result != B_OK)
205 			return result;
206 		if (count < 1)
207 			return B_ERROR;
208 		return B_OK;
209 
210 	} while (true);
211 
212 	return B_OK;
213 }
214 
215 
216 const char*
217 RootInode::Name() const
218 {
219 	ASSERT(fName != NULL);
220 	return fName;
221 }
222 
223