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