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 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 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 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* 221 RootInode::Name() const 222 { 223 ASSERT(fName != NULL); 224 return fName; 225 } 226 227