| Directory: | cvmfs/ |
|---|---|
| File: | cvmfs/nfs4/nfs4_server.cc |
| Date: | 2026-10-18 02:40:11 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 980 | 1390 | 70.5% |
| Branches: | 799 | 1651 | 48.4% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * This file is part of the CernVM File System. | ||
| 3 | */ | ||
| 4 | |||
| 5 | #include "nfs4/nfs4_server.h" | ||
| 6 | |||
| 7 | #include <errno.h> | ||
| 8 | #include <inttypes.h> | ||
| 9 | #include <sys/stat.h> | ||
| 10 | |||
| 11 | #include <chrono> | ||
| 12 | #include <cstdio> | ||
| 13 | #include <cstring> | ||
| 14 | #include <ctime> | ||
| 15 | |||
| 16 | #include "nfs4/logging.h" | ||
| 17 | |||
| 18 | #ifndef ENODATA | ||
| 19 | #define ENODATA ENOATTR | ||
| 20 | #endif | ||
| 21 | |||
| 22 | namespace nfs4 { | ||
| 23 | |||
| 24 | namespace { | ||
| 25 | |||
| 26 | const uint32_t kMaxName = 255; | ||
| 27 | const uint64_t kAttrDirFileIdBit = 1ull << 63; | ||
| 28 | const uint64_t kNamedAttrFileIdBit = 1ull << 62; | ||
| 29 | |||
| 30 | // Attributes this server can return, as bitmap words 0 and 1 | ||
| 31 | const unsigned kSupportedAttrs[] = {FATTR4_SUPPORTED_ATTRS, | ||
| 32 | FATTR4_TYPE, | ||
| 33 | FATTR4_FH_EXPIRE_TYPE, | ||
| 34 | FATTR4_CHANGE, | ||
| 35 | FATTR4_SIZE, | ||
| 36 | FATTR4_LINK_SUPPORT, | ||
| 37 | FATTR4_SYMLINK_SUPPORT, | ||
| 38 | FATTR4_NAMED_ATTR, | ||
| 39 | FATTR4_FSID, | ||
| 40 | FATTR4_UNIQUE_HANDLES, | ||
| 41 | FATTR4_LEASE_TIME, | ||
| 42 | FATTR4_RDATTR_ERROR, | ||
| 43 | FATTR4_ACLSUPPORT, | ||
| 44 | FATTR4_CANSETTIME, | ||
| 45 | FATTR4_CASE_INSENSITIVE, | ||
| 46 | FATTR4_CASE_PRESERVING, | ||
| 47 | FATTR4_CHOWN_RESTRICTED, | ||
| 48 | FATTR4_FILEHANDLE, | ||
| 49 | FATTR4_FILEID, | ||
| 50 | FATTR4_FILES_AVAIL, | ||
| 51 | FATTR4_FILES_FREE, | ||
| 52 | FATTR4_FILES_TOTAL, | ||
| 53 | FATTR4_HOMOGENEOUS, | ||
| 54 | FATTR4_MAXFILESIZE, | ||
| 55 | FATTR4_MAXLINK, | ||
| 56 | FATTR4_MAXNAME, | ||
| 57 | FATTR4_MAXREAD, | ||
| 58 | FATTR4_MAXWRITE, | ||
| 59 | FATTR4_MODE, | ||
| 60 | FATTR4_NO_TRUNC, | ||
| 61 | FATTR4_NUMLINKS, | ||
| 62 | FATTR4_OWNER, | ||
| 63 | FATTR4_OWNER_GROUP, | ||
| 64 | FATTR4_RAWDEV, | ||
| 65 | FATTR4_SPACE_AVAIL, | ||
| 66 | FATTR4_SPACE_FREE, | ||
| 67 | FATTR4_SPACE_TOTAL, | ||
| 68 | FATTR4_SPACE_USED, | ||
| 69 | FATTR4_TIME_ACCESS, | ||
| 70 | FATTR4_TIME_DELTA, | ||
| 71 | FATTR4_TIME_METADATA, | ||
| 72 | FATTR4_TIME_MODIFY, | ||
| 73 | FATTR4_MOUNTED_ON_FILEID}; | ||
| 74 | |||
| 75 | const unsigned kNumBitmapWords = 2; | ||
| 76 | |||
| 77 | 910 | void SupportedBitmap(uint32_t *words) { | |
| 78 | 910 | words[0] = words[1] = 0; | |
| 79 |
2/2✓ Branch 0 taken 39130 times.
✓ Branch 1 taken 910 times.
|
40040 | for (unsigned i = 0; i < sizeof(kSupportedAttrs) / sizeof(unsigned); ++i) |
| 80 | 39130 | words[kSupportedAttrs[i] / 32] |= 1u << (kSupportedAttrs[i] % 32); | |
| 81 | 910 | } | |
| 82 | |||
| 83 | 62049 | bool IsSet(const uint32_t *bitmap, unsigned len, unsigned attr) { | |
| 84 |
3/4✓ Branch 0 taken 62049 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 884 times.
✓ Branch 3 taken 61165 times.
|
62049 | return (attr / 32 < len) && (bitmap[attr / 32] & (1u << (attr % 32))); |
| 85 | } | ||
| 86 | |||
| 87 | 26 | void PutTime(const Timespec &t, XdrWriter *w) { | |
| 88 | 26 | w->PutI64(t.sec); | |
| 89 | 26 | w->PutU32(t.nsec); | |
| 90 | 26 | } | |
| 91 | |||
| 92 | 884 | void PutBitmap(const uint32_t *words, unsigned len, XdrWriter *w) { | |
| 93 | // Trailing zero words are dropped, as recommended by RFC 7530 | ||
| 94 |
4/4✓ Branch 0 taken 1742 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 897 times.
✓ Branch 3 taken 845 times.
|
1781 | while (len > 0 && words[len - 1] == 0) |
| 95 | 897 | len--; | |
| 96 | 884 | w->PutU32(len); | |
| 97 |
2/2✓ Branch 0 taken 871 times.
✓ Branch 1 taken 884 times.
|
1755 | for (unsigned i = 0; i < len; ++i) |
| 98 | 871 | w->PutU32(words[i]); | |
| 99 | 884 | } | |
| 100 | |||
| 101 | 780 | uint32_t FileType(const FileHandle &fh, mode_t mode) { | |
| 102 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 780 times.
|
780 | if (fh.kind == FileHandle::kAttrDir) |
| 103 | ✗ | return NF4ATTRDIR; | |
| 104 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 767 times.
|
780 | if (fh.kind == FileHandle::kNamedAttr) |
| 105 | 13 | return NF4NAMEDATTR; | |
| 106 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 767 times.
|
767 | if (S_ISDIR(mode)) |
| 107 | ✗ | return NF4DIR; | |
| 108 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 767 times.
|
767 | if (S_ISLNK(mode)) |
| 109 | ✗ | return NF4LNK; | |
| 110 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 767 times.
|
767 | if (S_ISCHR(mode)) |
| 111 | ✗ | return NF4CHR; | |
| 112 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 767 times.
|
767 | if (S_ISBLK(mode)) |
| 113 | ✗ | return NF4BLK; | |
| 114 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 767 times.
|
767 | if (S_ISFIFO(mode)) |
| 115 | ✗ | return NF4FIFO; | |
| 116 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 767 times.
|
767 | if (S_ISSOCK(mode)) |
| 117 | ✗ | return NF4SOCK; | |
| 118 | 767 | return NF4REG; | |
| 119 | } | ||
| 120 | |||
| 121 | 2600 | bool IsValidUtf8(const std::string &s) { | |
| 122 | 2600 | unsigned i = 0; | |
| 123 |
2/2✓ Branch 1 taken 15249 times.
✓ Branch 2 taken 2600 times.
|
17849 | while (i < s.size()) { |
| 124 | 15249 | const unsigned char c = s[i]; | |
| 125 | unsigned n; | ||
| 126 |
1/2✓ Branch 0 taken 15249 times.
✗ Branch 1 not taken.
|
15249 | if (c < 0x80) |
| 127 | 15249 | n = 0; | |
| 128 | ✗ | else if ((c & 0xE0) == 0xC0) | |
| 129 | ✗ | n = 1; | |
| 130 | ✗ | else if ((c & 0xF0) == 0xE0) | |
| 131 | ✗ | n = 2; | |
| 132 | ✗ | else if ((c & 0xF8) == 0xF0) | |
| 133 | ✗ | n = 3; | |
| 134 | else | ||
| 135 | ✗ | return false; | |
| 136 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 15249 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 15249 times.
|
15249 | if (i + n >= s.size() && n > 0) |
| 137 | ✗ | return false; | |
| 138 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15249 times.
|
15249 | for (unsigned j = 1; j <= n; ++j) { |
| 139 | ✗ | if ((static_cast<unsigned char>(s[i + j]) & 0xC0) != 0x80) | |
| 140 | ✗ | return false; | |
| 141 | } | ||
| 142 | 15249 | i += n + 1; | |
| 143 | } | ||
| 144 | 2600 | return true; | |
| 145 | } | ||
| 146 | |||
| 147 | 1820 | uint32_t CheckName(const std::string &name) { | |
| 148 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1820 times.
|
1820 | if (name.empty()) |
| 149 | ✗ | return NFS4ERR_INVAL; | |
| 150 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1820 times.
|
1820 | if (name.size() > kMaxName) |
| 151 | ✗ | return NFS4ERR_NAMETOOLONG; | |
| 152 |
6/8✓ Branch 1 taken 1820 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1807 times.
✓ Branch 5 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1807 times.
✓ Branch 9 taken 13 times.
✓ Branch 10 taken 1807 times.
|
1820 | if (name == "." || name == ".." || name.find('/') != std::string::npos) |
| 153 | 13 | return NFS4ERR_BADNAME; | |
| 154 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1807 times.
|
1807 | if (!IsValidUtf8(name)) |
| 155 | ✗ | return NFS4ERR_INVAL; | |
| 156 | 1807 | return NFS4_OK; | |
| 157 | } | ||
| 158 | |||
| 159 | ✗ | std::string NumericId(uint32_t id) { | |
| 160 | char buf[16]; | ||
| 161 | ✗ | snprintf(buf, sizeof(buf), "%u", id); | |
| 162 | ✗ | return buf; | |
| 163 | } | ||
| 164 | |||
| 165 | /** | ||
| 166 | * Permission check against the mode bits. Write access is never granted. | ||
| 167 | */ | ||
| 168 | 156 | uint32_t AccessFromMode(const Attr &attr, const Credentials &creds) { | |
| 169 | unsigned perms; | ||
| 170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
|
156 | if (creds.uid == 0) { |
| 171 | ✗ | perms = 04 | ((attr.mode & 0111) ? 01 : 0); | |
| 172 |
2/2✓ Branch 0 taken 130 times.
✓ Branch 1 taken 26 times.
|
156 | } else if (creds.uid == attr.uid) { |
| 173 | 130 | perms = (attr.mode >> 6) & 07; | |
| 174 | } else { | ||
| 175 | 26 | bool in_group = (creds.gid == attr.gid); | |
| 176 |
4/6✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 26 times.
|
26 | for (unsigned i = 0; !in_group && i < creds.gids.size(); ++i) |
| 177 | ✗ | in_group = (creds.gids[i] == attr.gid); | |
| 178 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
|
26 | perms = in_group ? (attr.mode >> 3) & 07 : attr.mode & 07; |
| 179 | } | ||
| 180 | |||
| 181 | 156 | uint32_t granted = 0; | |
| 182 |
2/2✓ Branch 0 taken 130 times.
✓ Branch 1 taken 26 times.
|
156 | if (perms & 04) |
| 183 | 130 | granted |= ACCESS4_READ; | |
| 184 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
|
156 | if (perms & 01) |
| 185 | ✗ | granted |= S_ISDIR(attr.mode) ? ACCESS4_LOOKUP : ACCESS4_EXECUTE; | |
| 186 | 156 | return granted; | |
| 187 | } | ||
| 188 | |||
| 189 | // Errors after which an open-owner's seqid is not advanced (RFC 7530 9.1.7) | ||
| 190 | 182 | bool SeqidAdvances(uint32_t status) { | |
| 191 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 182 times.
|
182 | switch (status) { |
| 192 | ✗ | case NFS4ERR_STALE_CLIENTID: | |
| 193 | case NFS4ERR_STALE_STATEID: | ||
| 194 | case NFS4ERR_BAD_STATEID: | ||
| 195 | case NFS4ERR_BAD_SEQID: | ||
| 196 | case NFS4ERR_BADXDR: | ||
| 197 | case NFS4ERR_RESOURCE: | ||
| 198 | case NFS4ERR_NOFILEHANDLE: | ||
| 199 | case NFS4ERR_MOVED: | ||
| 200 | ✗ | return false; | |
| 201 | 182 | default: | |
| 202 | 182 | return true; | |
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | } // anonymous namespace | ||
| 207 | |||
| 208 | |||
| 209 | 156 | uint32_t ErrnoToStatus(int err) { | |
| 210 |
2/18✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
156 | switch (err) { |
| 211 | 130 | case 0: | |
| 212 | 130 | return NFS4_OK; | |
| 213 | ✗ | case EPERM: | |
| 214 | ✗ | return NFS4ERR_PERM; | |
| 215 | 26 | case ENOENT: | |
| 216 | case ENODATA: | ||
| 217 | 26 | return NFS4ERR_NOENT; | |
| 218 | ✗ | case EACCES: | |
| 219 | ✗ | return NFS4ERR_ACCESS; | |
| 220 | ✗ | case ENOTDIR: | |
| 221 | ✗ | return NFS4ERR_NOTDIR; | |
| 222 | ✗ | case EISDIR: | |
| 223 | ✗ | return NFS4ERR_ISDIR; | |
| 224 | ✗ | case EINVAL: | |
| 225 | ✗ | return NFS4ERR_INVAL; | |
| 226 | ✗ | case ENAMETOOLONG: | |
| 227 | ✗ | return NFS4ERR_NAMETOOLONG; | |
| 228 | ✗ | case EROFS: | |
| 229 | ✗ | return NFS4ERR_ROFS; | |
| 230 | ✗ | case ESTALE: | |
| 231 | ✗ | return NFS4ERR_STALE; | |
| 232 | ✗ | case EAGAIN: | |
| 233 | case EBUSY: | ||
| 234 | ✗ | return NFS4ERR_DELAY; | |
| 235 | ✗ | case ENOSPC: | |
| 236 | ✗ | return NFS4ERR_NOSPC; | |
| 237 | ✗ | case EFBIG: | |
| 238 | ✗ | return NFS4ERR_FBIG; | |
| 239 | ✗ | case ERANGE: | |
| 240 | ✗ | return NFS4ERR_TOOSMALL; | |
| 241 | ✗ | case ELOOP: | |
| 242 | ✗ | return NFS4ERR_SYMLINK; | |
| 243 | ✗ | case EMFILE: | |
| 244 | case ENFILE: | ||
| 245 | ✗ | return NFS4ERR_DELAY; | |
| 246 | ✗ | case EIO: | |
| 247 | ✗ | return NFS4ERR_IO; | |
| 248 | ✗ | default: | |
| 249 | ✗ | Log(kLogLevelWarn, "mapping unexpected errno %d to NFS4ERR_IO", err); | |
| 250 | ✗ | return NFS4ERR_IO; | |
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | |||
| 255 | 234 | Nfs4Server::Nfs4Server(Backend *backend, const Options &options) | |
| 256 | 234 | : backend_(backend) | |
| 257 | 234 | , options_(options) | |
| 258 | 468 | , fsid_(backend->FsId()) | |
| 259 | 234 | , boot_(static_cast<uint32_t>(time(NULL))) | |
| 260 | 234 | , next_clientid_(1) | |
| 261 | 234 | , next_stateid_(1) | |
| 262 | 234 | , num_frozen_attrs_(0) | |
| 263 | 234 | , last_generation_(0) | |
| 264 | 234 | , monitor_stopping_(false) | |
| 265 |
2/4✓ Branch 2 taken 234 times.
✗ Branch 3 not taken.
✓ Branch 17 taken 234 times.
✗ Branch 18 not taken.
|
702 | , executors_stopping_(false) { } |
| 266 | |||
| 267 | |||
| 268 | 910 | Nfs4Server::~Nfs4Server() { | |
| 269 | { | ||
| 270 | 468 | std::lock_guard<std::mutex> const lock(state_lock_); | |
| 271 | 468 | monitor_stopping_ = true; | |
| 272 | } | ||
| 273 | 468 | monitor_cond_.notify_all(); | |
| 274 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 221 times.
|
468 | if (monitor_.joinable()) |
| 275 | 26 | monitor_.join(); | |
| 276 | { | ||
| 277 | 468 | std::lock_guard<std::mutex> const lock(executor_lock_); | |
| 278 | 468 | executors_stopping_ = true; | |
| 279 | } | ||
| 280 | 468 | executor_cond_.notify_all(); | |
| 281 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 234 times.
|
520 | for (unsigned i = 0; i < executors_.size(); ++i) |
| 282 | 52 | executors_[i].join(); | |
| 283 | 910 | } | |
| 284 | |||
| 285 | |||
| 286 | 52 | void Nfs4Server::ExecutorLoop() { | |
| 287 | while (true) { | ||
| 288 | 52 | TaskPtr task; | |
| 289 | { | ||
| 290 |
1/2✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
|
52 | std::unique_lock<std::mutex> lock(executor_lock_); |
| 291 | 52 | executor_cond_.wait( | |
| 292 |
4/4✓ Branch 0 taken 52 times.
✓ Branch 1 taken 26 times.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 26 times.
|
78 | lock, [this] { return executors_stopping_ || !tasks_.empty(); }); |
| 293 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 26 times.
|
52 | if (tasks_.empty()) |
| 294 | 52 | return; | |
| 295 | 26 | task = tasks_.front(); | |
| 296 | 26 | tasks_.pop_front(); | |
| 297 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 26 times.
|
52 | } |
| 298 | 26 | XdrReader args(reinterpret_cast<const unsigned char *>(task->args.data()), | |
| 299 | 52 | task->args.size()); | |
| 300 |
1/2✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
|
26 | ProcessCompound(task->call, &args, &task->res); |
| 301 | { | ||
| 302 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | std::lock_guard<std::mutex> const lock(executor_lock_); |
| 303 | 26 | task->done = true; | |
| 304 | 26 | } | |
| 305 | 26 | task->done_cond.notify_one(); | |
| 306 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 26 times.
|
78 | } |
| 307 | } | ||
| 308 | |||
| 309 | |||
| 310 | 26 | void Nfs4Server::RunWithDeadline(const RpcCall &call, XdrReader *args, | |
| 311 | XdrWriter *res) { | ||
| 312 |
2/4✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 26 times.
✗ Branch 6 not taken.
|
26 | TaskPtr task(new Task()); |
| 313 |
1/2✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
|
26 | task->call = call; |
| 314 |
1/2✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
|
26 | task->args.assign(reinterpret_cast<const char *>(args->cursor()), |
| 315 | args->remaining()); | ||
| 316 | 26 | task->call.args = NULL; | |
| 317 | 26 | task->call.args_size = 0; | |
| 318 | |||
| 319 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | std::unique_lock<std::mutex> lock(executor_lock_); |
| 320 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 13 times.
|
26 | if (executors_.empty()) { |
| 321 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 13 times.
|
39 | for (unsigned i = 0; i < options_.executor_threads; ++i) |
| 322 |
2/4✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
|
26 | executors_.push_back(std::thread(&Nfs4Server::ExecutorLoop, this)); |
| 323 | } | ||
| 324 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | tasks_.push_back(task); |
| 325 | 26 | executor_cond_.notify_one(); | |
| 326 |
1/2✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
|
52 | const bool done = task->done_cond.wait_for( |
| 327 | 26 | lock, std::chrono::milliseconds(options_.delay_after_ms), | |
| 328 | 52 | [&task] { return task->done; }); | |
| 329 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
|
26 | if (done) { |
| 330 |
1/2✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
|
13 | res->PutRaw(task->res.buffer().data(), task->res.size()); |
| 331 | 13 | return; | |
| 332 | } | ||
| 333 | |||
| 334 | // Still queued or running: the task completes on its own, and the client's | ||
| 335 | // retry benefits from the warmed cache (or the open-owner replay cache) | ||
| 336 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
|
13 | for (std::deque<TaskPtr>::iterator it = tasks_.begin(); it != tasks_.end(); |
| 337 | ✗ | ++it) { | |
| 338 | ✗ | if (*it == task) { | |
| 339 | ✗ | tasks_.erase(it); | |
| 340 | ✗ | break; | |
| 341 | } | ||
| 342 | } | ||
| 343 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | lock.unlock(); |
| 344 | |||
| 345 | 13 | XdrReader r(reinterpret_cast<const unsigned char *>(task->args.data()), | |
| 346 | 26 | task->args.size()); | |
| 347 | 13 | std::string tag; | |
| 348 | 13 | uint32_t minor_version = 0, num_ops = 0, first_op = 0; | |
| 349 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | r.GetOpaque(&tag, kNfs4OpaqueLimit); |
| 350 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | r.GetU32(&minor_version); |
| 351 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | r.GetU32(&num_ops); |
| 352 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | r.GetU32(&first_op); |
| 353 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | Log(kLogLevelDebug, "xid %u delayed", call.xid); |
| 354 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | res->PutU32(NFS4ERR_DELAY); |
| 355 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | res->PutOpaque(tag); |
| 356 |
3/6✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
|
13 | if (num_ops == 0 || !r.ok()) { |
| 357 | ✗ | res->PutU32(0); | |
| 358 | ✗ | return; | |
| 359 | } | ||
| 360 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | res->PutU32(1); |
| 361 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | res->PutU32(first_op); |
| 362 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | res->PutU32(NFS4ERR_DELAY); |
| 363 |
5/6✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 13 times.
✓ Branch 7 taken 13 times.
✓ Branch 8 taken 13 times.
|
39 | } |
| 364 | |||
| 365 | |||
| 366 | 1456 | AcceptStat Nfs4Server::Dispatch(const RpcCall &call, XdrReader *args, | |
| 367 | XdrWriter *res) { | ||
| 368 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
|
1456 | switch (call.procedure) { |
| 369 | ✗ | case kNfsProcNull: | |
| 370 | ✗ | return kAcceptSuccess; | |
| 371 | 1456 | case kNfsProcCompound: | |
| 372 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 1430 times.
|
1456 | if (options_.delay_after_ms > 0) |
| 373 | 26 | RunWithDeadline(call, args, res); | |
| 374 | else | ||
| 375 | 1430 | ProcessCompound(call, args, res); | |
| 376 | 1456 | return kAcceptSuccess; | |
| 377 | ✗ | default: | |
| 378 | ✗ | return kAcceptProcUnavail; | |
| 379 | } | ||
| 380 | } | ||
| 381 | |||
| 382 | |||
| 383 | 1456 | uint32_t Nfs4Server::ProcessCompound(const RpcCall &call, XdrReader *args, | |
| 384 | XdrWriter *res) { | ||
| 385 | 1456 | std::string tag; | |
| 386 | 1456 | uint32_t minor_version = 0, num_ops = 0; | |
| 387 |
1/2✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
|
1456 | args->GetOpaque(&tag, kNfs4OpaqueLimit); |
| 388 |
1/2✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
|
1456 | args->GetU32(&minor_version); |
| 389 |
1/2✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
|
1456 | args->GetU32(&num_ops); |
| 390 | |||
| 391 |
1/2✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
|
1456 | const size_t status_offset = res->ReserveU32(); |
| 392 |
1/2✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
|
1456 | res->PutOpaque(tag); |
| 393 |
1/2✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
|
1456 | const size_t count_offset = res->ReserveU32(); |
| 394 | |||
| 395 | 1456 | uint32_t status = NFS4_OK; | |
| 396 | 1456 | uint32_t num_results = 0; | |
| 397 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1456 times.
|
1456 | if (!args->ok()) { |
| 398 | ✗ | status = NFS4ERR_BADXDR; | |
| 399 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1443 times.
|
1456 | } else if (minor_version != 0) { |
| 400 | 13 | status = NFS4ERR_MINOR_VERS_MISMATCH; | |
| 401 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1443 times.
|
1443 | } else if (num_ops > options_.max_compound_ops) { |
| 402 | ✗ | status = NFS4ERR_RESOURCE; | |
| 403 | } else { | ||
| 404 | 1443 | Compound c; | |
| 405 | 1443 | c.call = &call; | |
| 406 |
2/2✓ Branch 0 taken 3601 times.
✓ Branch 1 taken 1105 times.
|
4706 | for (uint32_t i = 0; i < num_ops; ++i) { |
| 407 | uint32_t op; | ||
| 408 |
2/4✓ Branch 1 taken 3601 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3601 times.
|
3601 | if (!args->GetU32(&op)) { |
| 409 | ✗ | status = NFS4ERR_BADXDR; | |
| 410 | 338 | break; | |
| 411 | } | ||
| 412 | // The op's result is written in place; on failure it is cut off again | ||
| 413 |
1/2✓ Branch 1 taken 3601 times.
✗ Branch 2 not taken.
|
3601 | const size_t op_offset = res->ReserveU32(); |
| 414 |
1/2✓ Branch 1 taken 3601 times.
✗ Branch 2 not taken.
|
3601 | const size_t status_offset_op = res->ReserveU32(); |
| 415 | 3601 | const size_t body_offset = res->size(); | |
| 416 |
1/2✓ Branch 1 taken 3601 times.
✗ Branch 2 not taken.
|
3601 | status = ProcessOp(op, args, &c, res); |
| 417 |
4/6✓ Branch 0 taken 3263 times.
✓ Branch 1 taken 338 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3263 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3601 times.
|
3601 | if (status == NFS4_OK && !args->ok()) |
| 418 | ✗ | status = NFS4ERR_BADXDR; | |
| 419 |
1/2✓ Branch 1 taken 3601 times.
✗ Branch 2 not taken.
|
3601 | Log(kLogLevelDebug, "xid %u op %u -> %u", call.xid, op, status); |
| 420 | 3601 | const bool illegal = (status == NFS4ERR_OP_ILLEGAL); | |
| 421 |
3/4✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3588 times.
✓ Branch 3 taken 3601 times.
✗ Branch 4 not taken.
|
3601 | res->PatchU32(op_offset, illegal ? static_cast<uint32_t>(OP_ILLEGAL) : op); |
| 422 |
1/2✓ Branch 1 taken 3601 times.
✗ Branch 2 not taken.
|
3601 | res->PatchU32(status_offset_op, status); |
| 423 |
2/2✓ Branch 0 taken 338 times.
✓ Branch 1 taken 3263 times.
|
3601 | if (status != NFS4_OK) { |
| 424 |
1/2✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
|
338 | res->Truncate(body_offset); |
| 425 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 325 times.
|
338 | if (op == OP_SETATTR) |
| 426 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | res->PutU32(0); // attrsset is returned on failure, too |
| 427 | } | ||
| 428 | 3601 | num_results++; | |
| 429 |
2/2✓ Branch 0 taken 338 times.
✓ Branch 1 taken 3263 times.
|
3601 | if (status != NFS4_OK) |
| 430 | 338 | break; | |
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 434 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1443 times.
|
1456 | if (num_results == 0) { |
| 435 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | Log(kLogLevelDebug, "xid %u: compound of %u ops rejected -> %u", call.xid, |
| 436 | num_ops, status); | ||
| 437 | } | ||
| 438 |
1/2✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
|
1456 | res->PatchU32(status_offset, status); |
| 439 |
1/2✓ Branch 1 taken 1456 times.
✗ Branch 2 not taken.
|
1456 | res->PatchU32(count_offset, num_results); |
| 440 | 1456 | return status; | |
| 441 | 1456 | } | |
| 442 | |||
| 443 | |||
| 444 | 3601 | uint32_t Nfs4Server::ProcessOp(uint32_t op, XdrReader *args, Compound *c, | |
| 445 | XdrWriter *body) { | ||
| 446 |
21/28✓ Branch 0 taken 26 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 78 times.
✓ Branch 3 taken 533 times.
✓ Branch 4 taken 858 times.
✓ Branch 5 taken 65 times.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 13 times.
✓ Branch 8 taken 195 times.
✓ Branch 9 taken 39 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 689 times.
✓ Branch 13 taken 572 times.
✓ Branch 14 taken 91 times.
✓ Branch 15 taken 156 times.
✓ Branch 16 taken 13 times.
✓ Branch 17 taken 26 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 21 taken 65 times.
✓ Branch 22 taken 65 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 26 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 26 times.
✓ Branch 27 taken 13 times.
|
3601 | switch (op) { |
| 447 | 26 | case OP_ACCESS: | |
| 448 | 26 | return OpAccess(args, c, body); | |
| 449 | 39 | case OP_CLOSE: | |
| 450 | 39 | return OpClose(args, c, body); | |
| 451 | 78 | case OP_GETATTR: | |
| 452 | 78 | return OpGetattr(args, c, body); | |
| 453 | 533 | case OP_GETFH: | |
| 454 | 533 | return OpGetfh(c, body); | |
| 455 | 858 | case OP_LOOKUP: | |
| 456 | 858 | return OpLookup(args, c); | |
| 457 | 65 | case OP_LOOKUPP: | |
| 458 | 65 | return OpLookupp(c); | |
| 459 | 13 | case OP_NVERIFY: | |
| 460 | 13 | return OpVerify(args, c, true); | |
| 461 | 13 | case OP_VERIFY: | |
| 462 | 13 | return OpVerify(args, c, false); | |
| 463 | 195 | case OP_OPEN: | |
| 464 | 195 | return OpOpen(args, c, body); | |
| 465 | 39 | case OP_OPENATTR: | |
| 466 | 39 | return OpOpenattr(args, c); | |
| 467 | ✗ | case OP_OPEN_CONFIRM: | |
| 468 | ✗ | return OpOpenConfirm(args, c, body); | |
| 469 | ✗ | case OP_OPEN_DOWNGRADE: | |
| 470 | ✗ | return OpOpenDowngrade(args, c, body); | |
| 471 | 689 | case OP_PUTFH: | |
| 472 | 689 | return OpPutfh(args, c); | |
| 473 | 572 | case OP_PUTPUBFH: | |
| 474 | case OP_PUTROOTFH: | ||
| 475 | 572 | c->fh = FileHandle(FileHandle::kObject, fsid_, backend_->RootInode()); | |
| 476 | 572 | c->has_fh = true; | |
| 477 | 572 | return NFS4_OK; | |
| 478 | 91 | case OP_READ: | |
| 479 | 91 | return OpRead(args, c, body); | |
| 480 | 156 | case OP_READDIR: | |
| 481 | 156 | return OpReaddir(args, c, body); | |
| 482 | 13 | case OP_READLINK: | |
| 483 | 13 | return OpReadlink(c, body); | |
| 484 | 26 | case OP_RENEW: | |
| 485 | 26 | return OpRenew(args); | |
| 486 | ✗ | case OP_RESTOREFH: | |
| 487 | ✗ | if (!c->has_saved) | |
| 488 | ✗ | return NFS4ERR_RESTOREFH; | |
| 489 | ✗ | c->fh = c->saved; | |
| 490 | ✗ | c->has_fh = true; | |
| 491 | ✗ | return NFS4_OK; | |
| 492 | ✗ | case OP_SAVEFH: | |
| 493 | ✗ | if (!c->has_fh) | |
| 494 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 495 | ✗ | c->saved = c->fh; | |
| 496 | ✗ | c->has_saved = true; | |
| 497 | ✗ | return NFS4_OK; | |
| 498 | ✗ | case OP_SECINFO: | |
| 499 | ✗ | return OpSecinfo(args, c, body); | |
| 500 | 65 | case OP_SETCLIENTID: | |
| 501 | 65 | return OpSetclientid(args, body); | |
| 502 | 65 | case OP_SETCLIENTID_CONFIRM: | |
| 503 | 65 | return OpSetclientidConfirm(args); | |
| 504 | ✗ | case OP_RELEASE_LOCKOWNER: | |
| 505 | ✗ | return NFS4_OK; | |
| 506 | 26 | case OP_DELEGRETURN: | |
| 507 | 26 | return OpDelegreturn(args); | |
| 508 | ✗ | case OP_DELEGPURGE: | |
| 509 | case OP_LOCK: | ||
| 510 | case OP_LOCKT: | ||
| 511 | case OP_LOCKU: | ||
| 512 | ✗ | return NFS4ERR_NOTSUPP; | |
| 513 | 26 | case OP_COMMIT: | |
| 514 | case OP_CREATE: | ||
| 515 | case OP_LINK: | ||
| 516 | case OP_REMOVE: | ||
| 517 | case OP_RENAME: | ||
| 518 | case OP_SETATTR: | ||
| 519 | case OP_WRITE: | ||
| 520 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | return c->has_fh ? NFS4ERR_ROFS : NFS4ERR_NOFILEHANDLE; |
| 521 | 13 | default: | |
| 522 | 13 | return NFS4ERR_OP_ILLEGAL; | |
| 523 | } | ||
| 524 | } | ||
| 525 | |||
| 526 | |||
| 527 | //------------------------------------------------------------------------------ | ||
| 528 | // Object resolution | ||
| 529 | |||
| 530 | |||
| 531 | 65 | uint32_t Nfs4Server::ResolveXattrName(uint64_t ino, uint32_t hash, | |
| 532 | std::string *name) { | ||
| 533 | 65 | std::vector<std::string> names; | |
| 534 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | const int retval = backend_->ListXattr(ino, &names); |
| 535 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
|
65 | if (retval != 0) |
| 536 | ✗ | return ErrnoToStatus(retval); | |
| 537 |
1/2✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
|
117 | for (unsigned i = 0; i < names.size(); ++i) { |
| 538 |
3/4✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 65 times.
✓ Branch 5 taken 52 times.
|
117 | if (HashName(names[i]) == hash) { |
| 539 |
1/2✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
|
65 | *name = names[i]; |
| 540 | 65 | return NFS4_OK; | |
| 541 | } | ||
| 542 | } | ||
| 543 | ✗ | return NFS4ERR_STALE; | |
| 544 | 65 | } | |
| 545 | |||
| 546 | |||
| 547 | 1534 | uint32_t Nfs4Server::Resolve(const FileHandle &fh, const Credentials &creds, | |
| 548 | Object *obj) { | ||
| 549 | 1534 | obj->fh = fh; | |
| 550 | 1534 | int retval = backend_->GetAttr(fh.ino, &obj->attr); | |
| 551 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1521 times.
|
1534 | if (retval == ENOENT) |
| 552 | 13 | return NFS4ERR_STALE; | |
| 553 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1521 times.
|
1521 | if (retval != 0) |
| 554 | ✗ | return ErrnoToStatus(retval); | |
| 555 | |||
| 556 |
6/6✓ Branch 0 taken 1417 times.
✓ Branch 1 taken 104 times.
✓ Branch 3 taken 65 times.
✓ Branch 4 taken 1352 times.
✓ Branch 5 taken 65 times.
✓ Branch 6 taken 1456 times.
|
1521 | if (fh.kind == FileHandle::kObject && num_frozen_attrs_ > 0) { |
| 557 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | std::lock_guard<std::mutex> const lock(state_lock_); |
| 558 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | std::map<uint64_t, Attr>::const_iterator const it = frozen_attrs_.find(fh.ino); |
| 559 |
2/2✓ Branch 3 taken 13 times.
✓ Branch 4 taken 52 times.
|
65 | if (it != frozen_attrs_.end()) |
| 560 | 13 | obj->attr = it->second; | |
| 561 | 65 | } | |
| 562 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 1482 times.
|
1521 | if (fh.kind == FileHandle::kAttrDir) { |
| 563 | 39 | obj->attr.mode = S_IFDIR | 0555; | |
| 564 | 39 | obj->attr.nlink = 2; | |
| 565 | 39 | obj->attr.size = 0; | |
| 566 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 1417 times.
|
1482 | } else if (fh.kind == FileHandle::kNamedAttr) { |
| 567 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | const uint32_t status = ResolveXattrName(fh.ino, fh.aux, &obj->xattr_name); |
| 568 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
|
65 | if (status != NFS4_OK) |
| 569 | ✗ | return status; | |
| 570 | 65 | std::string value; | |
| 571 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | retval = backend_->GetXattr(fh.ino, obj->xattr_name, creds, &value); |
| 572 | // Unreadable values (e.g. privileged attributes) still get a handle; | ||
| 573 | // the error surfaces on READ | ||
| 574 |
1/2✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
|
65 | obj->attr.size = (retval == 0) ? value.size() : 0; |
| 575 | 65 | obj->attr.mode = S_IFREG | 0444; | |
| 576 | 65 | obj->attr.nlink = 1; | |
| 577 | 65 | } | |
| 578 | 1521 | return NFS4_OK; | |
| 579 | } | ||
| 580 | |||
| 581 | |||
| 582 | 1820 | uint32_t Nfs4Server::LookupChild(const Object &dir, const std::string &name, | |
| 583 | const Credentials &creds, Object *child) { | ||
| 584 | 1820 | uint32_t const status = CheckName(name); | |
| 585 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1807 times.
|
1820 | if (status != NFS4_OK) |
| 586 | 13 | return status; | |
| 587 | |||
| 588 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 1755 times.
|
1807 | if (dir.fh.kind == FileHandle::kAttrDir) { |
| 589 | 52 | std::vector<std::string> names; | |
| 590 |
1/2✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
|
52 | const int retval = backend_->ListXattr(dir.fh.ino, &names); |
| 591 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (retval != 0) |
| 592 | ✗ | return ErrnoToStatus(retval); | |
| 593 |
2/2✓ Branch 1 taken 91 times.
✓ Branch 2 taken 13 times.
|
104 | for (unsigned i = 0; i < names.size(); ++i) { |
| 594 |
2/2✓ Branch 2 taken 39 times.
✓ Branch 3 taken 52 times.
|
91 | if (names[i] == name) { |
| 595 |
2/4✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 39 times.
✗ Branch 6 not taken.
|
78 | return Resolve(FileHandle(FileHandle::kNamedAttr, fsid_, dir.fh.ino, |
| 596 | HashName(name)), | ||
| 597 | 39 | creds, child); | |
| 598 | } | ||
| 599 | } | ||
| 600 | 13 | return NFS4ERR_NOENT; | |
| 601 | 52 | } | |
| 602 | |||
| 603 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1755 times.
|
1755 | if (dir.fh.kind != FileHandle::kObject) |
| 604 | ✗ | return NFS4ERR_NOTDIR; | |
| 605 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1755 times.
|
1755 | if (S_ISLNK(dir.attr.mode)) |
| 606 | ✗ | return NFS4ERR_SYMLINK; | |
| 607 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1742 times.
|
1755 | if (!S_ISDIR(dir.attr.mode)) |
| 608 | 13 | return NFS4ERR_NOTDIR; | |
| 609 | |||
| 610 | 1742 | const int retval = backend_->Lookup(dir.fh.ino, name, &child->attr); | |
| 611 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 1716 times.
|
1742 | if (retval != 0) |
| 612 | 26 | return ErrnoToStatus(retval); | |
| 613 | 1716 | child->fh = FileHandle(FileHandle::kObject, fsid_, child->attr.ino); | |
| 614 | 1716 | child->xattr_name.clear(); | |
| 615 | 1716 | return NFS4_OK; | |
| 616 | } | ||
| 617 | |||
| 618 | |||
| 619 | 143 | uint32_t Nfs4Server::ListChildren(const Object &dir, | |
| 620 | std::vector<DirEntry> *entries) { | ||
| 621 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 130 times.
|
143 | if (dir.fh.kind == FileHandle::kAttrDir) { |
| 622 | 13 | std::vector<std::string> names; | |
| 623 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | const int retval = backend_->ListXattr(dir.fh.ino, &names); |
| 624 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (retval != 0) |
| 625 | ✗ | return ErrnoToStatus(retval); | |
| 626 | 13 | entries->clear(); | |
| 627 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 13 times.
|
39 | for (unsigned i = 0; i < names.size(); ++i) |
| 628 |
2/4✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 26 times.
✗ Branch 6 not taken.
|
26 | entries->push_back(DirEntry(names[i], dir.fh.ino)); |
| 629 | 13 | return NFS4_OK; | |
| 630 | 13 | } | |
| 631 |
2/4✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 130 times.
|
130 | if (dir.fh.kind != FileHandle::kObject || !S_ISDIR(dir.attr.mode)) |
| 632 | ✗ | return NFS4ERR_NOTDIR; | |
| 633 | 130 | return ErrnoToStatus(backend_->ReadDir(dir.fh.ino, entries)); | |
| 634 | } | ||
| 635 | |||
| 636 | |||
| 637 | 13 | uint64_t Nfs4Server::FileId(const Object &obj) const { | |
| 638 |
1/3✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
|
13 | switch (obj.fh.kind) { |
| 639 | ✗ | case FileHandle::kAttrDir: | |
| 640 | ✗ | return obj.fh.ino | kAttrDirFileIdBit; | |
| 641 | ✗ | case FileHandle::kNamedAttr: | |
| 642 | ✗ | return (obj.fh.ino ^ (static_cast<uint64_t>(obj.fh.aux) << 32)) | |
| 643 | ✗ | | kNamedAttrFileIdBit; | |
| 644 | 13 | default: | |
| 645 | 13 | return obj.fh.ino; | |
| 646 | } | ||
| 647 | } | ||
| 648 | |||
| 649 | |||
| 650 | //------------------------------------------------------------------------------ | ||
| 651 | // Attributes | ||
| 652 | |||
| 653 | |||
| 654 | 286 | bool Nfs4Server::DecodeBitmap(XdrReader *r, std::vector<uint32_t> *bitmap) { | |
| 655 | uint32_t len; | ||
| 656 |
4/8✓ Branch 1 taken 286 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 286 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 286 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 286 times.
|
286 | if (!r->GetU32(&len) || len > 8) |
| 657 | ✗ | return false; | |
| 658 |
1/2✓ Branch 1 taken 286 times.
✗ Branch 2 not taken.
|
286 | bitmap->resize(len); |
| 659 |
2/2✓ Branch 0 taken 364 times.
✓ Branch 1 taken 286 times.
|
650 | for (uint32_t i = 0; i < len; ++i) |
| 660 |
1/2✓ Branch 2 taken 364 times.
✗ Branch 3 not taken.
|
364 | r->GetU32(&(*bitmap)[i]); |
| 661 | 286 | return r->ok(); | |
| 662 | } | ||
| 663 | |||
| 664 | |||
| 665 | 884 | bool Nfs4Server::EncodeFattr(const Object &obj, const uint32_t *request, | |
| 666 | unsigned request_len, const Credentials &creds, | ||
| 667 | XdrWriter *out) { | ||
| 668 | uint32_t supported[kNumBitmapWords]; | ||
| 669 | 884 | SupportedBitmap(supported); | |
| 670 | 884 | uint32_t returned[kNumBitmapWords] = {0, 0}; | |
| 671 |
4/4✓ Branch 0 taken 1768 times.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 949 times.
✓ Branch 3 taken 819 times.
|
1833 | for (unsigned i = 0; i < kNumBitmapWords && i < request_len; ++i) |
| 672 | 949 | returned[i] = request[i] & supported[i]; | |
| 673 | // Errors are reported per op, not in the attributes of a single object | ||
| 674 | 884 | returned[0] &= ~(1u << FATTR4_RDATTR_ERROR); | |
| 675 | |||
| 676 | 884 | FsStat fs; | |
| 677 | 884 | const bool need_fs = IsSet(returned, 2, FATTR4_FILES_AVAIL) | |
| 678 |
1/2✓ Branch 1 taken 884 times.
✗ Branch 2 not taken.
|
884 | || IsSet(returned, 2, FATTR4_FILES_FREE) |
| 679 |
1/2✓ Branch 1 taken 884 times.
✗ Branch 2 not taken.
|
884 | || IsSet(returned, 2, FATTR4_FILES_TOTAL) |
| 680 |
1/2✓ Branch 1 taken 884 times.
✗ Branch 2 not taken.
|
884 | || IsSet(returned, 2, FATTR4_SPACE_AVAIL) |
| 681 |
1/2✓ Branch 1 taken 884 times.
✗ Branch 2 not taken.
|
884 | || IsSet(returned, 2, FATTR4_SPACE_FREE) |
| 682 |
2/4✓ Branch 0 taken 884 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 884 times.
|
1768 | || IsSet(returned, 2, FATTR4_SPACE_TOTAL); |
| 683 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 884 times.
|
884 | if (need_fs) |
| 684 | ✗ | backend_->StatFs(&fs); | |
| 685 | |||
| 686 | 884 | const Attr &a = obj.attr; | |
| 687 | 884 | XdrWriter v; | |
| 688 |
2/2✓ Branch 0 taken 56576 times.
✓ Branch 1 taken 884 times.
|
57460 | for (unsigned attr = 0; attr < 32 * kNumBitmapWords; ++attr) { |
| 689 |
2/2✓ Branch 1 taken 55692 times.
✓ Branch 2 taken 884 times.
|
56576 | if (!IsSet(returned, kNumBitmapWords, attr)) |
| 690 | 55692 | continue; | |
| 691 |
4/34✗ Branch 0 not taken.
✓ Branch 1 taken 780 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 65 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 13 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✓ Branch 32 taken 26 times.
✗ Branch 33 not taken.
|
884 | switch (attr) { |
| 692 | ✗ | case FATTR4_SUPPORTED_ATTRS: | |
| 693 | ✗ | PutBitmap(supported, kNumBitmapWords, &v); | |
| 694 | ✗ | break; | |
| 695 | 780 | case FATTR4_TYPE: | |
| 696 |
1/2✓ Branch 2 taken 780 times.
✗ Branch 3 not taken.
|
780 | v.PutU32(FileType(obj.fh, a.mode)); |
| 697 | 780 | break; | |
| 698 | ✗ | case FATTR4_FH_EXPIRE_TYPE: | |
| 699 | ✗ | v.PutU32(FH4_PERSISTENT); | |
| 700 | ✗ | break; | |
| 701 | ✗ | case FATTR4_CHANGE: | |
| 702 | ✗ | if (obj.fh.kind == FileHandle::kObject) { | |
| 703 | ✗ | v.PutU64((static_cast<uint64_t>(a.ctime.sec) << 30) ^ a.ctime.nsec); | |
| 704 | } else { | ||
| 705 | ✗ | v.PutU64(backend_->Generation()); | |
| 706 | } | ||
| 707 | ✗ | break; | |
| 708 | 65 | case FATTR4_SIZE: | |
| 709 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | v.PutU64(a.size); |
| 710 | 65 | break; | |
| 711 | ✗ | case FATTR4_LINK_SUPPORT: | |
| 712 | case FATTR4_SYMLINK_SUPPORT: | ||
| 713 | case FATTR4_UNIQUE_HANDLES: | ||
| 714 | case FATTR4_CASE_PRESERVING: | ||
| 715 | case FATTR4_CHOWN_RESTRICTED: | ||
| 716 | case FATTR4_HOMOGENEOUS: | ||
| 717 | case FATTR4_NO_TRUNC: | ||
| 718 | ✗ | v.PutBool(true); | |
| 719 | ✗ | break; | |
| 720 | ✗ | case FATTR4_NAMED_ATTR: | |
| 721 | ✗ | v.PutBool(obj.fh.kind == FileHandle::kObject); | |
| 722 | ✗ | break; | |
| 723 | ✗ | case FATTR4_FSID: | |
| 724 | ✗ | v.PutU64(fsid_); | |
| 725 | ✗ | v.PutU64(0); | |
| 726 | ✗ | break; | |
| 727 | ✗ | case FATTR4_LEASE_TIME: | |
| 728 | ✗ | v.PutU32(options_.lease_time); | |
| 729 | ✗ | break; | |
| 730 | ✗ | case FATTR4_ACLSUPPORT: | |
| 731 | ✗ | v.PutU32(0); | |
| 732 | ✗ | break; | |
| 733 | ✗ | case FATTR4_CANSETTIME: | |
| 734 | case FATTR4_CASE_INSENSITIVE: | ||
| 735 | ✗ | v.PutBool(false); | |
| 736 | ✗ | break; | |
| 737 | ✗ | case FATTR4_FILEHANDLE: | |
| 738 | ✗ | v.PutOpaque(obj.fh.Encode()); | |
| 739 | ✗ | break; | |
| 740 | 13 | case FATTR4_FILEID: | |
| 741 | case FATTR4_MOUNTED_ON_FILEID: | ||
| 742 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | v.PutU64(FileId(obj)); |
| 743 | 13 | break; | |
| 744 | ✗ | case FATTR4_FILES_AVAIL: | |
| 745 | ✗ | v.PutU64(fs.files_avail); | |
| 746 | ✗ | break; | |
| 747 | ✗ | case FATTR4_FILES_FREE: | |
| 748 | ✗ | v.PutU64(fs.files_free); | |
| 749 | ✗ | break; | |
| 750 | ✗ | case FATTR4_FILES_TOTAL: | |
| 751 | ✗ | v.PutU64(fs.files_total); | |
| 752 | ✗ | break; | |
| 753 | ✗ | case FATTR4_MAXFILESIZE: | |
| 754 | ✗ | v.PutU64(0x7fffffffffffffffull); | |
| 755 | ✗ | break; | |
| 756 | ✗ | case FATTR4_MAXLINK: | |
| 757 | ✗ | v.PutU32(32000); | |
| 758 | ✗ | break; | |
| 759 | ✗ | case FATTR4_MAXNAME: | |
| 760 | ✗ | v.PutU32(kMaxName); | |
| 761 | ✗ | break; | |
| 762 | ✗ | case FATTR4_MAXREAD: | |
| 763 | case FATTR4_MAXWRITE: | ||
| 764 | ✗ | v.PutU64(options_.max_read); | |
| 765 | ✗ | break; | |
| 766 | ✗ | case FATTR4_MODE: | |
| 767 | ✗ | v.PutU32(a.mode & 07777); | |
| 768 | ✗ | break; | |
| 769 | ✗ | case FATTR4_NUMLINKS: | |
| 770 | ✗ | v.PutU32(a.nlink); | |
| 771 | ✗ | break; | |
| 772 | ✗ | case FATTR4_OWNER: | |
| 773 | ✗ | v.PutString(NumericId(a.uid)); | |
| 774 | ✗ | break; | |
| 775 | ✗ | case FATTR4_OWNER_GROUP: | |
| 776 | ✗ | v.PutString(NumericId(a.gid)); | |
| 777 | ✗ | break; | |
| 778 | ✗ | case FATTR4_RAWDEV: | |
| 779 | ✗ | v.PutU32(static_cast<uint32_t>(a.rdev >> 32)); | |
| 780 | ✗ | v.PutU32(static_cast<uint32_t>(a.rdev)); | |
| 781 | ✗ | break; | |
| 782 | ✗ | case FATTR4_SPACE_AVAIL: | |
| 783 | ✗ | v.PutU64(fs.bytes_avail); | |
| 784 | ✗ | break; | |
| 785 | ✗ | case FATTR4_SPACE_FREE: | |
| 786 | ✗ | v.PutU64(fs.bytes_free); | |
| 787 | ✗ | break; | |
| 788 | ✗ | case FATTR4_SPACE_TOTAL: | |
| 789 | ✗ | v.PutU64(fs.bytes_total); | |
| 790 | ✗ | break; | |
| 791 | ✗ | case FATTR4_SPACE_USED: | |
| 792 | ✗ | v.PutU64(a.size); | |
| 793 | ✗ | break; | |
| 794 | ✗ | case FATTR4_TIME_ACCESS: | |
| 795 | ✗ | PutTime(a.atime, &v); | |
| 796 | ✗ | break; | |
| 797 | ✗ | case FATTR4_TIME_DELTA: { | |
| 798 | ✗ | Timespec delta; | |
| 799 | ✗ | delta.nsec = 1; | |
| 800 | ✗ | PutTime(delta, &v); | |
| 801 | ✗ | break; | |
| 802 | } | ||
| 803 | ✗ | case FATTR4_TIME_METADATA: | |
| 804 | ✗ | PutTime(a.ctime, &v); | |
| 805 | ✗ | break; | |
| 806 | 26 | case FATTR4_TIME_MODIFY: | |
| 807 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | PutTime(a.mtime, &v); |
| 808 | 26 | break; | |
| 809 | ✗ | default: | |
| 810 | ✗ | return false; | |
| 811 | } | ||
| 812 | } | ||
| 813 | |||
| 814 |
1/2✓ Branch 1 taken 884 times.
✗ Branch 2 not taken.
|
884 | PutBitmap(returned, kNumBitmapWords, out); |
| 815 |
1/2✓ Branch 2 taken 884 times.
✗ Branch 3 not taken.
|
884 | out->PutOpaque(v.buffer()); |
| 816 | (void)creds; | ||
| 817 | 884 | return true; | |
| 818 | 884 | } | |
| 819 | |||
| 820 | |||
| 821 | //------------------------------------------------------------------------------ | ||
| 822 | // Operations | ||
| 823 | |||
| 824 | |||
| 825 | 26 | uint32_t Nfs4Server::OpAccess(XdrReader *args, Compound *c, XdrWriter *body) { | |
| 826 | uint32_t requested; | ||
| 827 |
2/4✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
|
26 | if (!args->GetU32(&requested)) |
| 828 | ✗ | return NFS4ERR_BADXDR; | |
| 829 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if (!c->has_fh) |
| 830 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 831 | 26 | Object obj; | |
| 832 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | const uint32_t status = Resolve(c->fh, c->call->creds, &obj); |
| 833 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if (status != NFS4_OK) |
| 834 | ✗ | return status; | |
| 835 | |||
| 836 | 26 | const uint32_t supported = requested | |
| 837 | 26 | & (ACCESS4_READ | ACCESS4_LOOKUP | ACCESS4_MODIFY | |
| 838 | | ACCESS4_EXTEND | ACCESS4_DELETE | ||
| 839 | | ACCESS4_EXECUTE); | ||
| 840 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | body->PutU32(supported); |
| 841 |
1/2✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
|
26 | body->PutU32(AccessFromMode(obj.attr, c->call->creds) & supported); |
| 842 | 26 | return NFS4_OK; | |
| 843 | 26 | } | |
| 844 | |||
| 845 | |||
| 846 | 78 | uint32_t Nfs4Server::OpGetattr(XdrReader *args, Compound *c, XdrWriter *body) { | |
| 847 | 78 | std::vector<uint32_t> request; | |
| 848 |
2/4✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 78 times.
|
78 | if (!DecodeBitmap(args, &request)) |
| 849 | ✗ | return NFS4ERR_BADXDR; | |
| 850 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
|
78 | if (!c->has_fh) |
| 851 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 852 | 78 | Object obj; | |
| 853 |
1/2✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
|
78 | const uint32_t status = Resolve(c->fh, c->call->creds, &obj); |
| 854 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 65 times.
|
78 | if (status != NFS4_OK) |
| 855 | 13 | return status; | |
| 856 |
3/6✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
✓ Branch 5 taken 65 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 65 times.
|
65 | if (!EncodeFattr(obj, request.empty() ? NULL : &request[0], |
| 857 | 65 | static_cast<unsigned>(request.size()), c->call->creds, | |
| 858 | body)) { | ||
| 859 | ✗ | return NFS4ERR_SERVERFAULT; | |
| 860 | } | ||
| 861 | 65 | return NFS4_OK; | |
| 862 | 78 | } | |
| 863 | |||
| 864 | |||
| 865 | 533 | uint32_t Nfs4Server::OpGetfh(Compound *c, XdrWriter *body) { | |
| 866 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 520 times.
|
533 | if (!c->has_fh) |
| 867 | 13 | return NFS4ERR_NOFILEHANDLE; | |
| 868 |
1/2✓ Branch 2 taken 520 times.
✗ Branch 3 not taken.
|
520 | body->PutOpaque(c->fh.Encode()); |
| 869 | 520 | return NFS4_OK; | |
| 870 | } | ||
| 871 | |||
| 872 | |||
| 873 | 858 | uint32_t Nfs4Server::OpLookup(XdrReader *args, Compound *c) { | |
| 874 | 858 | std::string name; | |
| 875 |
2/4✓ Branch 1 taken 858 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 858 times.
|
858 | if (!args->GetString(&name, kNfs4OpaqueLimit)) |
| 876 | ✗ | return NFS4ERR_BADXDR; | |
| 877 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 858 times.
|
858 | if (!c->has_fh) |
| 878 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 879 | 858 | Object dir, child; | |
| 880 |
1/2✓ Branch 1 taken 858 times.
✗ Branch 2 not taken.
|
858 | uint32_t status = Resolve(c->fh, c->call->creds, &dir); |
| 881 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 858 times.
|
858 | if (status != NFS4_OK) |
| 882 | ✗ | return status; | |
| 883 |
1/2✓ Branch 1 taken 858 times.
✗ Branch 2 not taken.
|
858 | status = LookupChild(dir, name, c->call->creds, &child); |
| 884 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 806 times.
|
858 | if (status != NFS4_OK) |
| 885 | 52 | return status; | |
| 886 | 806 | c->fh = child.fh; | |
| 887 | 806 | return NFS4_OK; | |
| 888 | 858 | } | |
| 889 | |||
| 890 | |||
| 891 | 65 | uint32_t Nfs4Server::OpLookupp(Compound *c) { | |
| 892 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
|
65 | if (!c->has_fh) |
| 893 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 894 |
3/3✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 39 times.
|
65 | switch (c->fh.kind) { |
| 895 | 13 | case FileHandle::kAttrDir: | |
| 896 | 13 | c->fh.kind = FileHandle::kObject; | |
| 897 | 13 | return NFS4_OK; | |
| 898 | 13 | case FileHandle::kNamedAttr: | |
| 899 | 13 | c->fh.kind = FileHandle::kAttrDir; | |
| 900 | 13 | c->fh.aux = 0; | |
| 901 | 13 | return NFS4_OK; | |
| 902 | 39 | default: | |
| 903 | 39 | break; | |
| 904 | } | ||
| 905 | |||
| 906 | 78 | Object obj; | |
| 907 |
1/2✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
|
39 | const uint32_t status = Resolve(c->fh, c->call->creds, &obj); |
| 908 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
|
39 | if (status != NFS4_OK) |
| 909 | ✗ | return status; | |
| 910 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
|
39 | if (!S_ISDIR(obj.attr.mode)) |
| 911 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | return S_ISLNK(obj.attr.mode) ? NFS4ERR_SYMLINK : NFS4ERR_NOTDIR; |
| 912 |
3/4✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 13 times.
|
26 | if (c->fh.ino == backend_->RootInode()) |
| 913 | 13 | return NFS4ERR_NOENT; | |
| 914 | 13 | Attr parent; | |
| 915 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | const int retval = backend_->LookupParent(c->fh.ino, &parent); |
| 916 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (retval != 0) |
| 917 | ✗ | return ErrnoToStatus(retval); | |
| 918 | 13 | c->fh = FileHandle(FileHandle::kObject, fsid_, parent.ino); | |
| 919 | 13 | return NFS4_OK; | |
| 920 | } | ||
| 921 | |||
| 922 | |||
| 923 | 26 | uint32_t Nfs4Server::OpVerify(XdrReader *args, Compound *c, bool negate) { | |
| 924 | 26 | std::vector<uint32_t> request; | |
| 925 | 26 | std::string values; | |
| 926 |
5/10✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 26 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 26 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 26 times.
|
26 | if (!DecodeBitmap(args, &request) || !args->GetOpaque(&values)) |
| 927 | ✗ | return NFS4ERR_BADXDR; | |
| 928 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if (!c->has_fh) |
| 929 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 930 | |||
| 931 | uint32_t supported[kNumBitmapWords]; | ||
| 932 | 26 | SupportedBitmap(supported); | |
| 933 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 26 times.
|
52 | for (unsigned i = 0; i < request.size(); ++i) { |
| 934 |
2/4✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
|
26 | if (request[i] & ~(i < kNumBitmapWords ? supported[i] : 0)) |
| 935 | ✗ | return NFS4ERR_ATTRNOTSUPP; | |
| 936 | } | ||
| 937 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 26 times.
|
26 | if (IsSet(request.empty() ? NULL : &request[0], |
| 938 | 26 | static_cast<unsigned>(request.size()), FATTR4_RDATTR_ERROR)) { | |
| 939 | ✗ | return NFS4ERR_INVAL; | |
| 940 | } | ||
| 941 | |||
| 942 | 26 | Object obj; | |
| 943 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | const uint32_t status = Resolve(c->fh, c->call->creds, &obj); |
| 944 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if (status != NFS4_OK) |
| 945 | ✗ | return status; | |
| 946 | 26 | XdrWriter mine; | |
| 947 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 5 taken 26 times.
✗ Branch 6 not taken.
|
26 | EncodeFattr(obj, request.empty() ? NULL : &request[0], |
| 948 | 26 | static_cast<unsigned>(request.size()), c->call->creds, &mine); | |
| 949 | // Skip our bitmap and the opaque length to compare the raw values | ||
| 950 | 26 | XdrReader r(reinterpret_cast<const unsigned char *>(mine.buffer().data()), | |
| 951 | 52 | mine.size()); | |
| 952 | 26 | std::vector<uint32_t> ignored; | |
| 953 | 26 | std::string my_values; | |
| 954 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | DecodeBitmap(&r, &ignored); |
| 955 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | r.GetOpaque(&my_values); |
| 956 | |||
| 957 | 26 | const bool same = (my_values == values); | |
| 958 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
|
26 | if (negate) |
| 959 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | return same ? NFS4ERR_SAME : NFS4_OK; |
| 960 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | return same ? NFS4_OK : NFS4ERR_NOT_SAME; |
| 961 | 26 | } | |
| 962 | |||
| 963 | |||
| 964 | 39 | uint32_t Nfs4Server::OpOpenattr(XdrReader *args, Compound *c) { | |
| 965 | bool create_dir; | ||
| 966 |
2/4✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
|
39 | if (!args->GetBool(&create_dir)) |
| 967 | ✗ | return NFS4ERR_BADXDR; | |
| 968 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
|
39 | if (!c->has_fh) |
| 969 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 970 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
|
39 | if (c->fh.kind != FileHandle::kObject) |
| 971 | ✗ | return NFS4ERR_INVAL; | |
| 972 | 39 | Object obj; | |
| 973 |
1/2✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
|
39 | const uint32_t status = Resolve(c->fh, c->call->creds, &obj); |
| 974 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
|
39 | if (status != NFS4_OK) |
| 975 | ✗ | return status; | |
| 976 | 39 | c->fh.kind = FileHandle::kAttrDir; | |
| 977 | 39 | c->fh.aux = 0; | |
| 978 | 39 | return NFS4_OK; | |
| 979 | 39 | } | |
| 980 | |||
| 981 | |||
| 982 | 689 | uint32_t Nfs4Server::OpPutfh(XdrReader *args, Compound *c) { | |
| 983 | 689 | std::string raw; | |
| 984 |
2/4✓ Branch 1 taken 689 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 689 times.
|
689 | if (!args->GetOpaque(&raw, kNfs4FhSize)) |
| 985 | ✗ | return NFS4ERR_BADXDR; | |
| 986 | 689 | FileHandle fh; | |
| 987 |
3/4✓ Branch 1 taken 689 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 676 times.
|
689 | if (!FileHandle::Decode(raw, &fh)) |
| 988 | 13 | return NFS4ERR_BADHANDLE; | |
| 989 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 663 times.
|
676 | if (fh.fsid != fsid_) |
| 990 | 13 | return NFS4ERR_STALE; | |
| 991 | 663 | c->fh = fh; | |
| 992 | 663 | c->has_fh = true; | |
| 993 | 663 | return NFS4_OK; | |
| 994 | 689 | } | |
| 995 | |||
| 996 | |||
| 997 | 91 | uint32_t Nfs4Server::OpRead(XdrReader *args, Compound *c, XdrWriter *body) { | |
| 998 | 91 | Stateid stateid; | |
| 999 | uint64_t offset; | ||
| 1000 | uint32_t count; | ||
| 1001 |
3/6✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 91 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 91 times.
✗ Branch 7 not taken.
|
182 | if (!GetStateid(args, &stateid) || !args->GetU64(&offset) |
| 1002 |
4/8✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 91 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 91 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 91 times.
|
182 | || !args->GetU32(&count)) { |
| 1003 | ✗ | return NFS4ERR_BADXDR; | |
| 1004 | } | ||
| 1005 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
|
91 | if (!c->has_fh) |
| 1006 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 1007 | |||
| 1008 | 91 | Object obj; | |
| 1009 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | uint32_t status = Resolve(c->fh, c->call->creds, &obj); |
| 1010 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
|
91 | if (status != NFS4_OK) |
| 1011 | ✗ | return status; | |
| 1012 |
2/4✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 91 times.
|
91 | if (obj.fh.kind == FileHandle::kAttrDir || S_ISDIR(obj.attr.mode)) |
| 1013 | ✗ | return NFS4ERR_ISDIR; | |
| 1014 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
|
91 | if (!S_ISREG(obj.attr.mode)) |
| 1015 | ✗ | return NFS4ERR_INVAL; | |
| 1016 | { | ||
| 1017 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | std::lock_guard<std::mutex> const lock(state_lock_); |
| 1018 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | status = CheckReadStateid(stateid, c->fh); |
| 1019 | 91 | } | |
| 1020 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 78 times.
|
91 | if (status != NFS4_OK) |
| 1021 | 13 | return status; | |
| 1022 | |||
| 1023 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
|
78 | if (count > options_.max_read) |
| 1024 | ✗ | count = options_.max_read; | |
| 1025 | 78 | std::string data; | |
| 1026 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 65 times.
|
78 | if (obj.fh.kind == FileHandle::kNamedAttr) { |
| 1027 | 13 | std::string value; | |
| 1028 | 26 | const int retval = backend_->GetXattr(obj.fh.ino, obj.xattr_name, | |
| 1029 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | c->call->creds, &value); |
| 1030 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (retval != 0) |
| 1031 | ✗ | return ErrnoToStatus(retval); | |
| 1032 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | if (offset < value.size()) |
| 1033 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | data = value.substr(offset, count); |
| 1034 |
1/2✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
13 | body->PutBool(offset + data.size() >= value.size()); |
| 1035 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | body->PutOpaque(data); |
| 1036 | 13 | return NFS4_OK; | |
| 1037 | 13 | } | |
| 1038 | |||
| 1039 |
1/2✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
|
65 | if (count > 0) { |
| 1040 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | const int retval = backend_->Read(obj.fh.ino, offset, count, &data); |
| 1041 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
|
65 | if (retval != 0) |
| 1042 | ✗ | return ErrnoToStatus(retval); | |
| 1043 | } | ||
| 1044 | 65 | const bool eof = (data.size() < count) | |
| 1045 |
3/4✓ Branch 0 taken 52 times.
✓ Branch 1 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 52 times.
|
65 | || (offset + data.size() >= obj.attr.size); |
| 1046 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | body->PutBool(eof); |
| 1047 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | body->PutOpaque(data); |
| 1048 | 65 | return NFS4_OK; | |
| 1049 | 91 | } | |
| 1050 | |||
| 1051 | |||
| 1052 | 156 | uint32_t Nfs4Server::OpReaddir(XdrReader *args, Compound *c, XdrWriter *body) { | |
| 1053 | uint64_t cookie; | ||
| 1054 | unsigned char verifier[kNfs4VerifierSize]; | ||
| 1055 | uint32_t dircount, maxcount; | ||
| 1056 | 156 | std::vector<uint32_t> request; | |
| 1057 |
1/2✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
|
156 | if (!args->GetU64(&cookie) |
| 1058 |
2/4✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
✗ Branch 4 not taken.
|
156 | || !args->GetFixedOpaque(verifier, kNfs4VerifierSize) |
| 1059 |
4/8✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 156 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 156 times.
✗ Branch 9 not taken.
|
156 | || !args->GetU32(&dircount) || !args->GetU32(&maxcount) |
| 1060 |
4/8✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 156 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 156 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 156 times.
|
312 | || !DecodeBitmap(args, &request)) { |
| 1061 | ✗ | return NFS4ERR_BADXDR; | |
| 1062 | } | ||
| 1063 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
|
156 | if (!c->has_fh) |
| 1064 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 1065 | |||
| 1066 | 156 | Object dir; | |
| 1067 |
1/2✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
|
156 | uint32_t status = Resolve(c->fh, c->call->creds, &dir); |
| 1068 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
|
156 | if (status != NFS4_OK) |
| 1069 | ✗ | return status; | |
| 1070 |
2/4✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
|
156 | if (dir.fh.kind == FileHandle::kNamedAttr || !S_ISDIR(dir.attr.mode)) |
| 1071 | ✗ | return NFS4ERR_NOTDIR; | |
| 1072 | |||
| 1073 | 156 | XdrWriter my_verifier_w; | |
| 1074 |
2/4✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 156 times.
✗ Branch 5 not taken.
|
156 | my_verifier_w.PutU64(backend_->Generation()); |
| 1075 | 156 | const std::string &my_verifier = my_verifier_w.buffer(); | |
| 1076 |
2/4✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
|
156 | if (cookie == 1 || cookie == 2) |
| 1077 | ✗ | return NFS4ERR_BAD_COOKIE; | |
| 1078 | 312 | if (cookie != 0 | |
| 1079 |
6/6✓ Branch 0 taken 117 times.
✓ Branch 1 taken 39 times.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 104 times.
✓ Branch 5 taken 13 times.
✓ Branch 6 taken 143 times.
|
156 | && memcmp(verifier, my_verifier.data(), kNfs4VerifierSize) != 0) { |
| 1080 | 13 | return NFS4ERR_NOT_SAME; | |
| 1081 | } | ||
| 1082 | |||
| 1083 | 143 | std::vector<DirEntry> entries; | |
| 1084 |
1/2✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
|
143 | status = ListChildren(dir, &entries); |
| 1085 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 143 times.
|
143 | if (status != NFS4_OK) |
| 1086 | ✗ | return status; | |
| 1087 | |||
| 1088 | // Cookies 0, 1 and 2 are reserved; entry i has cookie i + 3 | ||
| 1089 |
2/2✓ Branch 0 taken 104 times.
✓ Branch 1 taken 39 times.
|
143 | size_t index = (cookie == 0) ? 0 : static_cast<size_t>(cookie - 2); |
| 1090 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 143 times.
|
143 | if (index > entries.size()) |
| 1091 | ✗ | return NFS4ERR_BAD_COOKIE; | |
| 1092 | |||
| 1093 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 143 times.
|
143 | const bool want_rdattr_error = IsSet(request.empty() ? NULL : &request[0], |
| 1094 | 143 | static_cast<unsigned>(request.size()), | |
| 1095 | FATTR4_RDATTR_ERROR); | ||
| 1096 | |||
| 1097 |
1/2✓ Branch 2 taken 143 times.
✗ Branch 3 not taken.
|
143 | body->PutFixedOpaque(my_verifier.data(), kNfs4VerifierSize); |
| 1098 | // Fixed part: verifier, end-of-list marker, eof flag | ||
| 1099 | 143 | const size_t fixed_size = kNfs4VerifierSize + 4 + 4; | |
| 1100 | 143 | unsigned num_encoded = 0; | |
| 1101 |
2/2✓ Branch 1 taken 793 times.
✓ Branch 2 taken 26 times.
|
819 | for (; index < entries.size(); ++index) { |
| 1102 | 793 | const DirEntry &e = entries[index]; | |
| 1103 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 793 times.
|
793 | if (!IsValidUtf8(e.name)) { |
| 1104 | ✗ | Log(kLogLevelDebug, "skipping non-UTF-8 name in listing"); | |
| 1105 | ✗ | continue; | |
| 1106 | } | ||
| 1107 | |||
| 1108 | 793 | XdrWriter entry; | |
| 1109 |
1/2✓ Branch 1 taken 793 times.
✗ Branch 2 not taken.
|
793 | entry.PutBool(true); |
| 1110 |
1/2✓ Branch 1 taken 793 times.
✗ Branch 2 not taken.
|
793 | entry.PutU64(index + 3); |
| 1111 |
1/2✓ Branch 1 taken 793 times.
✗ Branch 2 not taken.
|
793 | entry.PutString(e.name); |
| 1112 | 793 | Object child; | |
| 1113 |
1/2✓ Branch 1 taken 793 times.
✗ Branch 2 not taken.
|
793 | const uint32_t child_status = LookupChild(dir, e.name, c->call->creds, |
| 1114 | &child); | ||
| 1115 |
1/2✓ Branch 0 taken 793 times.
✗ Branch 1 not taken.
|
793 | if (child_status == NFS4_OK) { |
| 1116 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 793 times.
✓ Branch 5 taken 793 times.
✗ Branch 6 not taken.
|
793 | EncodeFattr(child, request.empty() ? NULL : &request[0], |
| 1117 | 793 | static_cast<unsigned>(request.size()), c->call->creds, | |
| 1118 | &entry); | ||
| 1119 | ✗ | } else if (want_rdattr_error) { | |
| 1120 | ✗ | uint32_t words[1] = {1u << FATTR4_RDATTR_ERROR}; | |
| 1121 | ✗ | PutBitmap(words, 1, &entry); | |
| 1122 | ✗ | XdrWriter value; | |
| 1123 | ✗ | value.PutU32(child_status); | |
| 1124 | ✗ | entry.PutOpaque(value.buffer()); | |
| 1125 | ✗ | } else { | |
| 1126 | // Vanished between listing and lookup; skip it | ||
| 1127 | ✗ | continue; | |
| 1128 | } | ||
| 1129 | |||
| 1130 | 793 | if (body->size() + entry.size() + fixed_size - kNfs4VerifierSize | |
| 1131 |
2/2✓ Branch 0 taken 117 times.
✓ Branch 1 taken 676 times.
|
793 | > maxcount) { |
| 1132 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 104 times.
|
117 | if (num_encoded == 0) |
| 1133 | 13 | return NFS4ERR_TOOSMALL; | |
| 1134 | 104 | break; | |
| 1135 | } | ||
| 1136 |
1/2✓ Branch 4 taken 676 times.
✗ Branch 5 not taken.
|
676 | body->PutRaw(entry.buffer().data(), entry.size()); |
| 1137 | 676 | num_encoded++; | |
| 1138 |
6/8✓ Branch 1 taken 676 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 104 times.
✓ Branch 6 taken 676 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
✓ Branch 9 taken 104 times.
|
910 | } |
| 1139 |
1/2✓ Branch 1 taken 130 times.
✗ Branch 2 not taken.
|
130 | body->PutBool(false); |
| 1140 |
1/2✓ Branch 2 taken 130 times.
✗ Branch 3 not taken.
|
130 | body->PutBool(index >= entries.size()); |
| 1141 | 130 | return NFS4_OK; | |
| 1142 | 156 | } | |
| 1143 | |||
| 1144 | |||
| 1145 | 13 | uint32_t Nfs4Server::OpReadlink(Compound *c, XdrWriter *body) { | |
| 1146 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (!c->has_fh) |
| 1147 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 1148 | 13 | Object obj; | |
| 1149 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | const uint32_t status = Resolve(c->fh, c->call->creds, &obj); |
| 1150 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (status != NFS4_OK) |
| 1151 | ✗ | return status; | |
| 1152 |
2/4✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
|
13 | if (obj.fh.kind != FileHandle::kObject || !S_ISLNK(obj.attr.mode)) |
| 1153 | ✗ | return S_ISDIR(obj.attr.mode) ? NFS4ERR_ISDIR : NFS4ERR_INVAL; | |
| 1154 | 13 | std::string target; | |
| 1155 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | const int retval = backend_->ReadLink(obj.fh.ino, &target); |
| 1156 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (retval != 0) |
| 1157 | ✗ | return ErrnoToStatus(retval); | |
| 1158 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | body->PutString(target); |
| 1159 | 13 | return NFS4_OK; | |
| 1160 | 13 | } | |
| 1161 | |||
| 1162 | |||
| 1163 | ✗ | uint32_t Nfs4Server::OpSecinfo(XdrReader *args, Compound *c, XdrWriter *body) { | |
| 1164 | ✗ | std::string name; | |
| 1165 | ✗ | if (!args->GetString(&name, kNfs4OpaqueLimit)) | |
| 1166 | ✗ | return NFS4ERR_BADXDR; | |
| 1167 | ✗ | if (!c->has_fh) | |
| 1168 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 1169 | ✗ | Object dir, child; | |
| 1170 | ✗ | uint32_t status = Resolve(c->fh, c->call->creds, &dir); | |
| 1171 | ✗ | if (status != NFS4_OK) | |
| 1172 | ✗ | return status; | |
| 1173 | ✗ | status = LookupChild(dir, name, c->call->creds, &child); | |
| 1174 | ✗ | if (status != NFS4_OK) | |
| 1175 | ✗ | return status; | |
| 1176 | // RFC 7530 16.31.4: SECINFO consumes the current file handle | ||
| 1177 | ✗ | c->has_fh = false; | |
| 1178 | ✗ | body->PutU32(1); | |
| 1179 | ✗ | body->PutU32(kAuthSys); | |
| 1180 | ✗ | return NFS4_OK; | |
| 1181 | } | ||
| 1182 | |||
| 1183 | |||
| 1184 | //------------------------------------------------------------------------------ | ||
| 1185 | // Client and open state | ||
| 1186 | |||
| 1187 | |||
| 1188 | 143 | void Nfs4Server::PutStateid(const Stateid &stateid, XdrWriter *w) { | |
| 1189 | 143 | w->PutU32(stateid.seqid); | |
| 1190 | 143 | w->PutFixedOpaque(stateid.other.data(), kStateidOtherSize); | |
| 1191 | 143 | } | |
| 1192 | |||
| 1193 | |||
| 1194 | 156 | bool Nfs4Server::GetStateid(XdrReader *r, Stateid *stateid) { | |
| 1195 | unsigned char other[kStateidOtherSize]; | ||
| 1196 |
1/2✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
|
156 | if (!r->GetU32(&stateid->seqid) |
| 1197 |
4/8✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 156 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 156 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 156 times.
|
156 | || !r->GetFixedOpaque(other, kStateidOtherSize)) { |
| 1198 | ✗ | return false; | |
| 1199 | } | ||
| 1200 |
1/2✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
|
156 | stateid->other.assign(reinterpret_cast<char *>(other), kStateidOtherSize); |
| 1201 | 156 | return true; | |
| 1202 | } | ||
| 1203 | |||
| 1204 | |||
| 1205 | 52 | std::string Nfs4Server::NewStateidOther() { | |
| 1206 | 52 | XdrWriter w; | |
| 1207 |
1/2✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
|
52 | w.PutU32(boot_); |
| 1208 |
1/2✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
|
52 | w.PutU64(next_stateid_++); |
| 1209 |
1/2✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
|
104 | return w.buffer(); |
| 1210 | 52 | } | |
| 1211 | |||
| 1212 | |||
| 1213 | 221 | uint32_t Nfs4Server::CheckClient(uint64_t clientid) { | |
| 1214 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 208 times.
|
221 | if (static_cast<uint32_t>(clientid >> 32) != boot_) |
| 1215 | 13 | return NFS4ERR_STALE_CLIENTID; | |
| 1216 |
1/2✓ Branch 1 taken 208 times.
✗ Branch 2 not taken.
|
208 | std::map<uint64_t, Client>::const_iterator const it = clients_.find(clientid); |
| 1217 |
5/6✓ Branch 3 taken 195 times.
✓ Branch 4 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 195 times.
✓ Branch 8 taken 13 times.
✓ Branch 9 taken 195 times.
|
208 | if (it == clients_.end() || !it->second.confirmed) |
| 1218 | 13 | return NFS4ERR_STALE_CLIENTID; | |
| 1219 | 195 | return NFS4_OK; | |
| 1220 | } | ||
| 1221 | |||
| 1222 | |||
| 1223 | 195 | Nfs4Server::SeqidCheck Nfs4Server::CheckSeqid(const OwnerKey &owner, | |
| 1224 | uint32_t seqid, uint32_t op, | ||
| 1225 | bool create_owner, | ||
| 1226 | uint32_t *status, | ||
| 1227 | std::string *body) { | ||
| 1228 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | std::map<OwnerKey, OpenOwner>::iterator const it = owners_.find(owner); |
| 1229 |
2/2✓ Branch 2 taken 52 times.
✓ Branch 3 taken 143 times.
|
195 | if (it == owners_.end()) { |
| 1230 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (!create_owner) { |
| 1231 | ✗ | *status = NFS4ERR_BAD_SEQID; | |
| 1232 | ✗ | return kSeqidBad; | |
| 1233 | } | ||
| 1234 | 52 | return kSeqidProcess; | |
| 1235 | } | ||
| 1236 |
2/2✓ Branch 1 taken 130 times.
✓ Branch 2 taken 13 times.
|
143 | if (seqid == it->second.seqid + 1) |
| 1237 | 130 | return kSeqidProcess; | |
| 1238 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
|
13 | if (seqid == it->second.seqid && it->second.last_op == op) { |
| 1239 | ✗ | *status = it->second.last_status; | |
| 1240 | ✗ | *body = it->second.last_body; | |
| 1241 | ✗ | return kSeqidReplay; | |
| 1242 | } | ||
| 1243 | 13 | *status = NFS4ERR_BAD_SEQID; | |
| 1244 | 13 | return kSeqidBad; | |
| 1245 | } | ||
| 1246 | |||
| 1247 | |||
| 1248 | 182 | void Nfs4Server::RecordSeqid(const OwnerKey &owner, uint32_t seqid, uint32_t op, | |
| 1249 | uint32_t status, const std::string &body) { | ||
| 1250 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 182 times.
|
182 | if (!SeqidAdvances(status)) |
| 1251 | ✗ | return; | |
| 1252 | 182 | OpenOwner &o = owners_[owner]; | |
| 1253 | 182 | o.seqid = seqid; | |
| 1254 | 182 | o.last_op = op; | |
| 1255 | 182 | o.last_status = status; | |
| 1256 | 182 | o.last_body = body; | |
| 1257 | } | ||
| 1258 | |||
| 1259 | |||
| 1260 | 78 | uint32_t Nfs4Server::FindOpenState( | |
| 1261 | const Stateid &stateid, bool exact_seqid, | ||
| 1262 | std::map<std::string, OpenState>::iterator *it) { | ||
| 1263 | 78 | XdrReader r(reinterpret_cast<const unsigned char *>(stateid.other.data()), | |
| 1264 | 156 | stateid.other.size()); | |
| 1265 | uint32_t boot; | ||
| 1266 |
1/2✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
|
78 | r.GetU32(&boot); |
| 1267 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
|
78 | if (boot != boot_) |
| 1268 | ✗ | return NFS4ERR_STALE_STATEID; | |
| 1269 |
1/2✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
|
78 | *it = open_states_.find(stateid.other); |
| 1270 |
2/2✓ Branch 2 taken 26 times.
✓ Branch 3 taken 52 times.
|
78 | if (*it == open_states_.end()) |
| 1271 | 26 | return NFS4ERR_BAD_STATEID; | |
| 1272 | 52 | const uint32_t current = (*it)->second.seqid; | |
| 1273 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (stateid.seqid > current) |
| 1274 | ✗ | return NFS4ERR_BAD_STATEID; | |
| 1275 |
4/4✓ Branch 0 taken 26 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 13 times.
|
52 | if (exact_seqid && stateid.seqid < current) |
| 1276 | 13 | return NFS4ERR_OLD_STATEID; | |
| 1277 | 39 | return NFS4_OK; | |
| 1278 | } | ||
| 1279 | |||
| 1280 | |||
| 1281 | 91 | uint32_t Nfs4Server::CheckReadStateid(const Stateid &stateid, | |
| 1282 | const FileHandle &fh) { | ||
| 1283 |
1/2✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
|
91 | const std::string zeros(kStateidOtherSize, '\0'); |
| 1284 |
1/2✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
|
91 | const std::string ones(kStateidOtherSize, '\xff'); |
| 1285 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
|
52 | if ((stateid.seqid == 0 && stateid.other == zeros) |
| 1286 |
5/8✓ Branch 0 taken 52 times.
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 52 times.
✓ Branch 8 taken 39 times.
|
143 | || (stateid.seqid == 0xffffffffu && stateid.other == ones)) { |
| 1287 | 52 | return NFS4_OK; | |
| 1288 | } | ||
| 1289 | 39 | std::map<std::string, OpenState>::iterator it; | |
| 1290 |
1/2✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
|
39 | const uint32_t status = FindOpenState(stateid, false, &it); |
| 1291 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
|
39 | if (status == NFS4ERR_BAD_STATEID) { |
| 1292 | std::map<std::string, Delegation>::const_iterator const d = | ||
| 1293 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | delegations_.find(stateid.other); |
| 1294 |
3/6✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 13 times.
✗ Branch 10 not taken.
|
13 | if (d != delegations_.end() && d->second.fh == fh) |
| 1295 | 13 | return NFS4_OK; | |
| 1296 | } | ||
| 1297 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if (status != NFS4_OK) |
| 1298 | ✗ | return status; | |
| 1299 |
2/2✓ Branch 2 taken 13 times.
✓ Branch 3 taken 13 times.
|
26 | if (!(it->second.fh == fh)) |
| 1300 | 13 | return NFS4ERR_BAD_STATEID; | |
| 1301 | 13 | return NFS4_OK; | |
| 1302 | 91 | } | |
| 1303 | |||
| 1304 | |||
| 1305 | 13 | void Nfs4Server::DropClient(uint64_t clientid) { | |
| 1306 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | clients_.erase(clientid); |
| 1307 | struct Refreeze { | ||
| 1308 | 13 | explicit Refreeze(Nfs4Server *s) : server(s) { } | |
| 1309 | 13 | ~Refreeze() { server->UpdateFrozenAttrs(); } | |
| 1310 | Nfs4Server *server; | ||
| 1311 | 13 | } const refreeze(this); | |
| 1312 | 13 | for (std::set<std::pair<uint64_t, uint64_t> >::iterator it = | |
| 1313 | 13 | recalled_files_.begin(); | |
| 1314 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
|
13 | it != recalled_files_.end();) { |
| 1315 | ✗ | if (it->first == clientid) | |
| 1316 | ✗ | recalled_files_.erase(it++); | |
| 1317 | else | ||
| 1318 | ✗ | ++it; | |
| 1319 | } | ||
| 1320 | 13 | for (std::map<std::string, Delegation>::iterator it = delegations_.begin(); | |
| 1321 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
|
13 | it != delegations_.end();) { |
| 1322 | ✗ | if (it->second.clientid == clientid) | |
| 1323 | ✗ | delegations_.erase(it++); | |
| 1324 | else | ||
| 1325 | ✗ | ++it; | |
| 1326 | } | ||
| 1327 | 13 | for (std::map<std::string, OpenState>::iterator it = open_states_.begin(); | |
| 1328 |
2/2✓ Branch 2 taken 13 times.
✓ Branch 3 taken 13 times.
|
26 | it != open_states_.end();) { |
| 1329 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | if (it->second.owner.first == clientid) |
| 1330 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | open_states_.erase(it++); |
| 1331 | else | ||
| 1332 | ✗ | ++it; | |
| 1333 | } | ||
| 1334 | 13 | for (std::map<OwnerKey, OpenOwner>::iterator it = owners_.begin(); | |
| 1335 |
2/2✓ Branch 2 taken 13 times.
✓ Branch 3 taken 13 times.
|
26 | it != owners_.end();) { |
| 1336 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | if (it->first.first == clientid) |
| 1337 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | owners_.erase(it++); |
| 1338 | else | ||
| 1339 | ✗ | ++it; | |
| 1340 | } | ||
| 1341 | 13 | } | |
| 1342 | |||
| 1343 | |||
| 1344 | 65 | void Nfs4Server::UpdateFrozenAttrs() { | |
| 1345 | 65 | frozen_attrs_.clear(); | |
| 1346 | 65 | for (std::map<std::string, Delegation>::const_iterator it = | |
| 1347 | 65 | delegations_.begin(); | |
| 1348 |
2/2✓ Branch 3 taken 26 times.
✓ Branch 4 taken 65 times.
|
91 | it != delegations_.end(); |
| 1349 | 26 | ++it) { | |
| 1350 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | if (it->second.recalled != 0) |
| 1351 |
1/2✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
|
26 | frozen_attrs_[it->second.fh.ino] = it->second.attr; |
| 1352 | } | ||
| 1353 | 65 | num_frozen_attrs_ = frozen_attrs_.size(); | |
| 1354 | 65 | } | |
| 1355 | |||
| 1356 | |||
| 1357 | 117 | void Nfs4Server::PutDelegation(uint64_t clientid, const FileHandle &fh, | |
| 1358 | const Attr &attr, XdrWriter *w) { | ||
| 1359 |
1/2✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
|
117 | std::map<uint64_t, Client>::const_iterator const client = clients_.find(clientid); |
| 1360 |
1/2✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
|
78 | bool grant = options_.delegations && fh.kind == FileHandle::kObject |
| 1361 |
5/6✓ Branch 0 taken 78 times.
✓ Branch 1 taken 39 times.
✓ Branch 5 taken 78 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 13 times.
✓ Branch 9 taken 65 times.
|
195 | && client != clients_.end() && client->second.callback_ok; |
| 1362 | 117 | for (std::map<std::string, Delegation>::const_iterator it = | |
| 1363 | 117 | delegations_.begin(); | |
| 1364 |
4/6✓ Branch 0 taken 13 times.
✓ Branch 1 taken 104 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 117 times.
|
117 | grant && it != delegations_.end(); |
| 1365 | ✗ | ++it) { | |
| 1366 | // One delegation per client and file; none while a recall is going on | ||
| 1367 | ✗ | if ((it->second.clientid == clientid && it->second.fh == fh) | |
| 1368 | ✗ | || it->second.recalled != 0) { | |
| 1369 | ✗ | grant = false; | |
| 1370 | } | ||
| 1371 | } | ||
| 1372 |
6/10✓ Branch 0 taken 13 times.
✓ Branch 1 taken 104 times.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 13 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 117 times.
|
117 | if (grant && recalled_files_.erase(std::make_pair(clientid, fh.ino)) > 0) |
| 1373 | ✗ | grant = false; | |
| 1374 |
5/6✓ Branch 0 taken 13 times.
✓ Branch 1 taken 104 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 104 times.
✓ Branch 6 taken 13 times.
|
117 | if (!grant || delegations_.size() >= options_.max_stateids) { |
| 1375 |
1/2✓ Branch 1 taken 104 times.
✗ Branch 2 not taken.
|
104 | w->PutU32(OPEN_DELEGATE_NONE); |
| 1376 | 104 | return; | |
| 1377 | } | ||
| 1378 | |||
| 1379 | 13 | Stateid stateid; | |
| 1380 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | stateid.other = NewStateidOther(); |
| 1381 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | Delegation &delegation = delegations_[stateid.other]; |
| 1382 | 13 | delegation.clientid = clientid; | |
| 1383 | 13 | delegation.fh = fh; | |
| 1384 | 13 | delegation.attr = attr; | |
| 1385 | 13 | stateid.seqid = delegation.seqid; | |
| 1386 | |||
| 1387 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | w->PutU32(OPEN_DELEGATE_READ); |
| 1388 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | PutStateid(stateid, w); |
| 1389 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | w->PutBool(false); // recall |
| 1390 | // permissions: none granted in advance, the client still asks ACCESS | ||
| 1391 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | w->PutU32(0); // ACE4_ACCESS_ALLOWED_ACE_TYPE |
| 1392 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | w->PutU32(0); // flags |
| 1393 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | w->PutU32(0); // access mask |
| 1394 |
2/4✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
|
13 | w->PutString("EVERYONE@"); |
| 1395 | 13 | } | |
| 1396 | |||
| 1397 | |||
| 1398 | 26 | uint32_t Nfs4Server::OpDelegreturn(XdrReader *args) { | |
| 1399 | 26 | Stateid stateid; | |
| 1400 |
2/4✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
|
26 | if (!GetStateid(args, &stateid)) |
| 1401 | ✗ | return NFS4ERR_BADXDR; | |
| 1402 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | std::lock_guard<std::mutex> const lock(state_lock_); |
| 1403 | 26 | XdrReader r(reinterpret_cast<const unsigned char *>(stateid.other.data()), | |
| 1404 | 52 | stateid.other.size()); | |
| 1405 | uint32_t boot; | ||
| 1406 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | r.GetU32(&boot); |
| 1407 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if (boot != boot_) |
| 1408 | ✗ | return NFS4ERR_STALE_STATEID; | |
| 1409 |
3/4✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 13 times.
|
26 | if (delegations_.erase(stateid.other) == 0) |
| 1410 | 13 | return NFS4ERR_BAD_STATEID; | |
| 1411 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | if (num_frozen_attrs_ > 0) |
| 1412 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | UpdateFrozenAttrs(); |
| 1413 | 13 | return NFS4_OK; | |
| 1414 | 26 | } | |
| 1415 | |||
| 1416 | |||
| 1417 | 13 | void Nfs4Server::StartMonitor() { | |
| 1418 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | if (!monitor_.joinable()) |
| 1419 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | monitor_ = std::thread(&Nfs4Server::MonitorLoop, this); |
| 1420 | 13 | } | |
| 1421 | |||
| 1422 | |||
| 1423 | 13 | void Nfs4Server::MonitorLoop() { | |
| 1424 | 13 | const unsigned kCallbackTimeoutMs = 5000; | |
| 1425 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | std::unique_lock<std::mutex> lock(state_lock_); |
| 1426 |
1/2✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
|
39 | while (!monitor_stopping_) { |
| 1427 |
1/2✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
|
39 | monitor_cond_.wait_for(lock, std::chrono::seconds(1)); |
| 1428 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
|
39 | if (monitor_stopping_) |
| 1429 | 13 | break; | |
| 1430 | |||
| 1431 | // Probe new callback paths | ||
| 1432 | 26 | std::vector<uint64_t> probes; | |
| 1433 | 26 | probes.swap(pending_probes_); | |
| 1434 | 26 | std::vector<std::pair<uint64_t, std::shared_ptr<CallbackClient> > > cbs; | |
| 1435 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 26 times.
|
39 | for (unsigned i = 0; i < probes.size(); ++i) { |
| 1436 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | std::map<uint64_t, Client>::iterator const c = clients_.find(probes[i]); |
| 1437 |
3/6✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
|
13 | if (c != clients_.end() && c->second.callback) |
| 1438 |
2/4✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
|
13 | cbs.push_back(std::make_pair(probes[i], c->second.callback)); |
| 1439 | } | ||
| 1440 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | lock.unlock(); |
| 1441 | 26 | std::vector<bool> probe_ok; | |
| 1442 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 26 times.
|
39 | for (unsigned i = 0; i < cbs.size(); ++i) |
| 1443 |
2/4✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
|
13 | probe_ok.push_back(cbs[i].second->Null(kCallbackTimeoutMs)); |
| 1444 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | const uint64_t generation = backend_->Generation(); |
| 1445 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | lock.lock(); |
| 1446 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 26 times.
|
39 | for (unsigned i = 0; i < cbs.size(); ++i) { |
| 1447 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | std::map<uint64_t, Client>::iterator const c = clients_.find(cbs[i].first); |
| 1448 |
3/6✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 13 times.
✗ Branch 10 not taken.
|
13 | if (c != clients_.end() && c->second.callback == cbs[i].second) { |
| 1449 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | c->second.callback_ok = probe_ok[i]; |
| 1450 |
2/4✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
26 | Log(kLogLevelDebug, "callback path of client %" PRIx64 " %s", |
| 1451 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
39 | cbs[i].first, probe_ok[i] ? "works" : "is down"); |
| 1452 | } | ||
| 1453 | } | ||
| 1454 | |||
| 1455 | // Recall everything when the exported tree changed; revoke what was not | ||
| 1456 | // returned within a lease period | ||
| 1457 | 26 | const time_t now = time(NULL); | |
| 1458 | 52 | const bool changed = (last_generation_ != 0) | |
| 1459 |
3/4✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
26 | && (generation != last_generation_); |
| 1460 | 26 | last_generation_ = generation; | |
| 1461 | struct Recall { | ||
| 1462 | std::string other; | ||
| 1463 | uint32_t seqid; | ||
| 1464 | std::string fh; | ||
| 1465 | std::shared_ptr<CallbackClient> callback; | ||
| 1466 | }; | ||
| 1467 | 26 | std::vector<Recall> recalls; | |
| 1468 | 26 | for (std::map<std::string, Delegation>::iterator it = delegations_.begin(); | |
| 1469 |
2/2✓ Branch 2 taken 13 times.
✓ Branch 3 taken 26 times.
|
39 | it != delegations_.end();) { |
| 1470 | 13 | Delegation &d = it->second; | |
| 1471 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
13 | if (d.recalled != 0 && now - d.recalled > options_.lease_time) { |
| 1472 | ✗ | Log(kLogLevelWarn, "revoking unreturned delegation"); | |
| 1473 | ✗ | delegations_.erase(it++); | |
| 1474 | ✗ | continue; | |
| 1475 | } | ||
| 1476 |
2/4✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | if (changed && d.recalled == 0) { |
| 1477 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | std::map<uint64_t, Client>::iterator const c = clients_.find(d.clientid); |
| 1478 |
3/6✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 13 times.
|
13 | if (c == clients_.end() || !c->second.callback) { |
| 1479 | ✗ | delegations_.erase(it++); | |
| 1480 | ✗ | continue; | |
| 1481 | } | ||
| 1482 | 13 | d.recalled = now; | |
| 1483 |
2/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
|
13 | recalled_files_.insert(std::make_pair(d.clientid, d.fh.ino)); |
| 1484 | 13 | Recall recall; | |
| 1485 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | recall.other = it->first; |
| 1486 | 13 | recall.seqid = d.seqid; | |
| 1487 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | recall.fh = d.fh.Encode(); |
| 1488 | 13 | recall.callback = c->second.callback; | |
| 1489 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | recalls.push_back(recall); |
| 1490 | 13 | } | |
| 1491 | 13 | ++it; | |
| 1492 | } | ||
| 1493 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | UpdateFrozenAttrs(); |
| 1494 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 13 times.
|
26 | if (recalls.empty()) |
| 1495 | 13 | continue; | |
| 1496 | |||
| 1497 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | lock.unlock(); |
| 1498 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | Log(kLogLevelInfo, "recalling %zu delegations", recalls.size()); |
| 1499 | 13 | std::vector<std::string> failed; | |
| 1500 | 13 | const time_t recall_start = time(NULL); | |
| 1501 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 13 times.
|
26 | for (unsigned i = 0; i < recalls.size(); ++i) { |
| 1502 |
1/2✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
26 | const int result = recalls[i].callback->Recall( |
| 1503 | 13 | recalls[i].seqid, recalls[i].other, recalls[i].fh, | |
| 1504 | kCallbackTimeoutMs); | ||
| 1505 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (result != NFS4_OK) { |
| 1506 | ✗ | Log(kLogLevelWarn, "delegation recall failed (%d)", result); | |
| 1507 | ✗ | failed.push_back(recalls[i].other); | |
| 1508 | } | ||
| 1509 | } | ||
| 1510 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
26 | Log(kLogLevelInfo, "sent %zu recalls in %lds, %zu failed", recalls.size(), |
| 1511 | 13 | static_cast<long>(time(NULL) - recall_start), failed.size()); // NOLINT | |
| 1512 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | lock.lock(); |
| 1513 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
|
13 | for (unsigned i = 0; i < failed.size(); ++i) |
| 1514 | ✗ | delegations_.erase(failed[i]); | |
| 1515 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | UpdateFrozenAttrs(); |
| 1516 |
8/8✓ Branch 2 taken 13 times.
✓ Branch 3 taken 13 times.
✓ Branch 5 taken 13 times.
✓ Branch 6 taken 13 times.
✓ Branch 8 taken 13 times.
✓ Branch 9 taken 13 times.
✓ Branch 11 taken 13 times.
✓ Branch 12 taken 13 times.
|
65 | } |
| 1517 | 13 | } | |
| 1518 | |||
| 1519 | |||
| 1520 | 26 | size_t Nfs4Server::NumDelegations() { | |
| 1521 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | std::lock_guard<std::mutex> const lock(state_lock_); |
| 1522 | 52 | return delegations_.size(); | |
| 1523 | 26 | } | |
| 1524 | |||
| 1525 | |||
| 1526 | 78 | size_t Nfs4Server::NumOpenStates() { | |
| 1527 |
1/2✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
|
78 | std::lock_guard<std::mutex> const lock(state_lock_); |
| 1528 | 156 | return open_states_.size(); | |
| 1529 | 78 | } | |
| 1530 | |||
| 1531 | |||
| 1532 | 65 | uint32_t Nfs4Server::OpSetclientid(XdrReader *args, XdrWriter *body) { | |
| 1533 | unsigned char verifier[kNfs4VerifierSize]; | ||
| 1534 | 65 | std::string name, netid, addr; | |
| 1535 | uint32_t cb_program, cb_ident; | ||
| 1536 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | args->GetFixedOpaque(verifier, kNfs4VerifierSize); |
| 1537 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | args->GetOpaque(&name, kNfs4OpaqueLimit); |
| 1538 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | args->GetU32(&cb_program); |
| 1539 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | args->GetString(&netid); |
| 1540 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | args->GetString(&addr); |
| 1541 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | args->GetU32(&cb_ident); |
| 1542 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
|
65 | if (!args->ok()) |
| 1543 | ✗ | return NFS4ERR_BADXDR; | |
| 1544 |
1/2✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
|
65 | const std::string verf(reinterpret_cast<char *>(verifier), kNfs4VerifierSize); |
| 1545 | |||
| 1546 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | std::lock_guard<std::mutex> const lock(state_lock_); |
| 1547 | 65 | uint64_t clientid = 0; | |
| 1548 | 65 | for (std::map<uint64_t, Client>::iterator it = clients_.begin(); | |
| 1549 |
2/2✓ Branch 2 taken 13 times.
✓ Branch 3 taken 65 times.
|
78 | it != clients_.end(); |
| 1550 | 13 | ++it) { | |
| 1551 |
1/2✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
26 | if (it->second.name == name && it->second.confirmed |
| 1552 |
3/6✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
|
26 | && it->second.verifier == verf) { |
| 1553 | // Same client instance, e.g. callback update: keep the client id | ||
| 1554 | ✗ | clientid = it->first; | |
| 1555 | ✗ | break; | |
| 1556 | } | ||
| 1557 | } | ||
| 1558 |
1/2✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
|
65 | if (clientid == 0) { |
| 1559 | 65 | for (std::map<uint64_t, Client>::iterator it = clients_.begin(); | |
| 1560 |
2/2✓ Branch 2 taken 13 times.
✓ Branch 3 taken 65 times.
|
78 | it != clients_.end();) { |
| 1561 |
3/6✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
|
13 | if (it->second.name == name && !it->second.confirmed) |
| 1562 | ✗ | clients_.erase(it++); | |
| 1563 | else | ||
| 1564 | 13 | ++it; | |
| 1565 | } | ||
| 1566 | 65 | clientid = (static_cast<uint64_t>(boot_) << 32) | next_clientid_++; | |
| 1567 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | Client &client = clients_[clientid]; |
| 1568 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | client.name = name; |
| 1569 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | client.verifier = verf; |
| 1570 | } | ||
| 1571 | |||
| 1572 | 65 | XdrWriter confirm; | |
| 1573 | 130 | confirm.PutU64((static_cast<uint64_t>(next_clientid_++) << 32) | |
| 1574 |
1/2✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
|
65 | ^ static_cast<uint64_t>(time(NULL))); |
| 1575 |
2/4✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 65 times.
✗ Branch 6 not taken.
|
65 | clients_[clientid].confirm = confirm.buffer(); |
| 1576 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 52 times.
|
65 | if (options_.delegations) { |
| 1577 |
2/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
|
26 | clients_[clientid].callback.reset( |
| 1578 |
2/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
|
13 | new CallbackClient(cb_program, cb_ident, netid, addr)); |
| 1579 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | clients_[clientid].callback_ok = false; |
| 1580 | } | ||
| 1581 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | body->PutU64(clientid); |
| 1582 |
1/2✓ Branch 3 taken 65 times.
✗ Branch 4 not taken.
|
65 | body->PutFixedOpaque(confirm.buffer().data(), kNfs4VerifierSize); |
| 1583 | 65 | return NFS4_OK; | |
| 1584 | 65 | } | |
| 1585 | |||
| 1586 | |||
| 1587 | 65 | uint32_t Nfs4Server::OpSetclientidConfirm(XdrReader *args) { | |
| 1588 | uint64_t clientid; | ||
| 1589 | unsigned char confirm[kNfs4VerifierSize]; | ||
| 1590 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | if (!args->GetU64(&clientid) |
| 1591 |
4/8✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 65 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 65 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 65 times.
|
65 | || !args->GetFixedOpaque(confirm, kNfs4VerifierSize)) { |
| 1592 | ✗ | return NFS4ERR_BADXDR; | |
| 1593 | } | ||
| 1594 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | std::lock_guard<std::mutex> const lock(state_lock_); |
| 1595 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | std::map<uint64_t, Client>::iterator const it = clients_.find(clientid); |
| 1596 | 65 | if (it == clients_.end() | |
| 1597 |
2/4✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 65 times.
|
260 | || it->second.confirm |
| 1598 |
4/12✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 65 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 65 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 65 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
195 | != std::string(reinterpret_cast<char *>(confirm), |
| 1599 | kNfs4VerifierSize)) { | ||
| 1600 | ✗ | return NFS4ERR_STALE_CLIENTID; | |
| 1601 | } | ||
| 1602 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | if (options_.delegations && it->second.callback |
| 1603 |
5/6✓ Branch 0 taken 13 times.
✓ Branch 1 taken 52 times.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
✓ Branch 8 taken 52 times.
|
78 | && it->second.callback->valid()) { |
| 1604 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | pending_probes_.push_back(clientid); |
| 1605 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | StartMonitor(); |
| 1606 | 13 | monitor_cond_.notify_all(); | |
| 1607 | } | ||
| 1608 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
|
65 | if (it->second.confirmed) |
| 1609 | ✗ | return NFS4_OK; | |
| 1610 | |||
| 1611 | 65 | it->second.confirmed = true; | |
| 1612 |
1/2✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
|
65 | const std::string name = it->second.name; |
| 1613 | // A rebooted client replaces its previous incarnation and its state | ||
| 1614 | 65 | std::vector<uint64_t> previous; | |
| 1615 | 65 | for (std::map<uint64_t, Client>::iterator i = clients_.begin(); | |
| 1616 |
2/2✓ Branch 2 taken 78 times.
✓ Branch 3 taken 65 times.
|
143 | i != clients_.end(); |
| 1617 | 78 | ++i) { | |
| 1618 |
5/6✓ Branch 1 taken 13 times.
✓ Branch 2 taken 65 times.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
✓ Branch 8 taken 65 times.
|
78 | if (i->first != clientid && i->second.name == name) |
| 1619 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | previous.push_back(i->first); |
| 1620 | } | ||
| 1621 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 65 times.
|
78 | for (unsigned i = 0; i < previous.size(); ++i) |
| 1622 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | DropClient(previous[i]); |
| 1623 | 65 | return NFS4_OK; | |
| 1624 | 65 | } | |
| 1625 | |||
| 1626 | |||
| 1627 | 26 | uint32_t Nfs4Server::OpRenew(XdrReader *args) { | |
| 1628 | uint64_t clientid; | ||
| 1629 |
2/4✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
|
26 | if (!args->GetU64(&clientid)) |
| 1630 | ✗ | return NFS4ERR_BADXDR; | |
| 1631 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | std::lock_guard<std::mutex> const lock(state_lock_); |
| 1632 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | return CheckClient(clientid); |
| 1633 | 26 | } | |
| 1634 | |||
| 1635 | |||
| 1636 | 195 | uint32_t Nfs4Server::OpOpen(XdrReader *args, Compound *c, XdrWriter *body) { | |
| 1637 | uint32_t seqid, share_access, share_deny, open_type, claim_type; | ||
| 1638 | uint64_t clientid; | ||
| 1639 | 195 | std::string owner, name; | |
| 1640 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | args->GetU32(&seqid); |
| 1641 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | args->GetU32(&share_access); |
| 1642 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | args->GetU32(&share_deny); |
| 1643 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | args->GetU64(&clientid); |
| 1644 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | args->GetOpaque(&owner, kNfs4OpaqueLimit); |
| 1645 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | args->GetU32(&open_type); |
| 1646 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 195 times.
|
195 | if (!args->ok()) |
| 1647 | ✗ | return NFS4ERR_BADXDR; | |
| 1648 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
|
195 | if (open_type == OPEN4_CREATE) { |
| 1649 | // The create arguments are not needed: the file system is read-only | ||
| 1650 | ✗ | return c->has_fh ? NFS4ERR_ROFS : NFS4ERR_NOFILEHANDLE; | |
| 1651 | } | ||
| 1652 |
2/4✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 195 times.
|
195 | if (!args->GetU32(&claim_type)) |
| 1653 | ✗ | return NFS4ERR_BADXDR; | |
| 1654 |
1/4✓ Branch 0 taken 195 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
195 | switch (claim_type) { |
| 1655 | 195 | case CLAIM_NULL: | |
| 1656 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | args->GetString(&name, kNfs4OpaqueLimit); |
| 1657 | 195 | break; | |
| 1658 | ✗ | case CLAIM_PREVIOUS: { | |
| 1659 | uint32_t delegation_type; | ||
| 1660 | ✗ | args->GetU32(&delegation_type); | |
| 1661 | ✗ | break; | |
| 1662 | } | ||
| 1663 | ✗ | case CLAIM_DELEGATE_CUR: { | |
| 1664 | // The client converts local opens before returning a delegation | ||
| 1665 | ✗ | Stateid delegation; | |
| 1666 | ✗ | GetStateid(args, &delegation); | |
| 1667 | ✗ | args->GetString(&name, kNfs4OpaqueLimit); | |
| 1668 | ✗ | break; | |
| 1669 | } | ||
| 1670 | ✗ | default: | |
| 1671 | // State of a previous server instance is not kept | ||
| 1672 | ✗ | return NFS4ERR_RECLAIM_BAD; | |
| 1673 | } | ||
| 1674 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 195 times.
|
195 | if (!args->ok()) |
| 1675 | ✗ | return NFS4ERR_BADXDR; | |
| 1676 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
|
195 | if (!c->has_fh) |
| 1677 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 1678 | |||
| 1679 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
390 | const OwnerKey owner_key(clientid, owner); |
| 1680 | 390 | std::string replay_body; | |
| 1681 | uint32_t status; | ||
| 1682 | { | ||
| 1683 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | std::lock_guard<std::mutex> const lock(state_lock_); |
| 1684 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | status = CheckClient(clientid); |
| 1685 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 182 times.
|
195 | if (status != NFS4_OK) |
| 1686 | 13 | return status; | |
| 1687 |
1/2✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
|
182 | const SeqidCheck check = CheckSeqid(owner_key, seqid, OP_OPEN, true, |
| 1688 | &status, &replay_body); | ||
| 1689 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 169 times.
|
182 | if (check == kSeqidBad) |
| 1690 | 13 | return status; | |
| 1691 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 169 times.
|
169 | if (check == kSeqidReplay) { |
| 1692 | ✗ | body->PutRaw(replay_body.data(), replay_body.size()); | |
| 1693 | ✗ | return status; | |
| 1694 | } | ||
| 1695 |
2/2✓ Branch 1 taken 169 times.
✓ Branch 2 taken 26 times.
|
195 | } |
| 1696 | |||
| 1697 | 338 | Object target; | |
| 1698 | 338 | Object dir; | |
| 1699 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
169 | if (claim_type == CLAIM_NULL || claim_type == CLAIM_DELEGATE_CUR) { |
| 1700 |
1/2✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
|
169 | status = Resolve(c->fh, c->call->creds, &dir); |
| 1701 |
1/2✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
|
169 | if (status == NFS4_OK) |
| 1702 |
1/2✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
|
169 | status = LookupChild(dir, name, c->call->creds, &target); |
| 1703 | } else { | ||
| 1704 | ✗ | status = Resolve(c->fh, c->call->creds, &target); | |
| 1705 | } | ||
| 1706 |
2/2✓ Branch 0 taken 156 times.
✓ Branch 1 taken 13 times.
|
169 | if (status == NFS4_OK) { |
| 1707 |
2/2✓ Branch 0 taken 143 times.
✓ Branch 1 taken 13 times.
|
156 | if ((share_access & OPEN4_SHARE_ACCESS_WRITE) |
| 1708 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 143 times.
|
143 | || !(share_access & OPEN4_SHARE_ACCESS_READ)) { |
| 1709 | 13 | status = NFS4ERR_ROFS; | |
| 1710 |
1/2✓ Branch 0 taken 143 times.
✗ Branch 1 not taken.
|
143 | } else if (target.fh.kind == FileHandle::kAttrDir |
| 1711 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 143 times.
|
143 | || S_ISDIR(target.attr.mode)) { |
| 1712 | ✗ | status = NFS4ERR_ISDIR; | |
| 1713 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 130 times.
|
143 | } else if (S_ISLNK(target.attr.mode)) { |
| 1714 | 13 | status = NFS4ERR_SYMLINK; | |
| 1715 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 130 times.
|
130 | } else if (!S_ISREG(target.attr.mode)) { |
| 1716 | ✗ | status = NFS4ERR_INVAL; | |
| 1717 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 117 times.
|
130 | } else if (!(AccessFromMode(target.attr, c->call->creds) & ACCESS4_READ)) { |
| 1718 | 13 | status = NFS4ERR_ACCESS; | |
| 1719 | } | ||
| 1720 | } | ||
| 1721 | |||
| 1722 | 338 | XdrWriter result; | |
| 1723 |
1/2✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
|
338 | std::lock_guard<std::mutex> const lock(state_lock_); |
| 1724 |
2/2✓ Branch 0 taken 117 times.
✓ Branch 1 taken 52 times.
|
169 | if (status == NFS4_OK) { |
| 1725 | // Repeated opens of a file by the same owner share one stateid | ||
| 1726 | 117 | std::map<std::string, OpenState>::iterator it = open_states_.begin(); | |
| 1727 |
2/2✓ Branch 3 taken 78 times.
✓ Branch 4 taken 39 times.
|
117 | for (; it != open_states_.end(); ++it) { |
| 1728 |
3/6✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 78 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 78 times.
✗ Branch 9 not taken.
|
78 | if (it->second.owner == owner_key && it->second.fh == target.fh) |
| 1729 | 78 | break; | |
| 1730 | } | ||
| 1731 |
2/2✓ Branch 2 taken 39 times.
✓ Branch 3 taken 78 times.
|
117 | if (it == open_states_.end()) { |
| 1732 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
|
39 | if (open_states_.size() >= options_.max_stateids) { |
| 1733 | ✗ | Log(kLogLevelWarn, "too many open NFS stateids (%u)", options_.max_stateids); | |
| 1734 | ✗ | return NFS4ERR_RESOURCE; | |
| 1735 | } | ||
| 1736 |
1/2✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
|
39 | const std::string other = NewStateidOther(); |
| 1737 |
3/6✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
|
39 | it = open_states_.insert(std::make_pair(other, OpenState())).first; |
| 1738 |
1/2✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
|
39 | it->second.owner = owner_key; |
| 1739 | 39 | it->second.fh = target.fh; | |
| 1740 | 39 | } | |
| 1741 | 117 | it->second.seqid++; | |
| 1742 | 117 | it->second.access |= share_access; | |
| 1743 | |||
| 1744 | 117 | Stateid stateid; | |
| 1745 | 117 | stateid.seqid = it->second.seqid; | |
| 1746 |
1/2✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
|
117 | stateid.other = it->first; |
| 1747 |
1/2✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
|
117 | PutStateid(stateid, &result); |
| 1748 | // change_info4: nothing changes in a read-only directory | ||
| 1749 |
1/2✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
|
117 | result.PutBool(true); |
| 1750 |
1/2✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
|
117 | result.PutU64(0); |
| 1751 |
1/2✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
|
117 | result.PutU64(0); |
| 1752 | // No OPEN4_RESULT_CONFIRM: a confirm round trip buys nothing here | ||
| 1753 |
1/2✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
|
117 | result.PutU32(OPEN4_RESULT_LOCKTYPE_POSIX); |
| 1754 |
1/2✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
|
117 | result.PutU32(0); // attrset |
| 1755 |
1/2✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
|
117 | if (claim_type == CLAIM_NULL) |
| 1756 |
1/2✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
|
117 | PutDelegation(clientid, target.fh, target.attr, &result); |
| 1757 | else | ||
| 1758 | ✗ | result.PutU32(OPEN_DELEGATE_NONE); | |
| 1759 | 117 | c->fh = target.fh; | |
| 1760 | 117 | } | |
| 1761 |
1/2✓ Branch 2 taken 169 times.
✗ Branch 3 not taken.
|
169 | RecordSeqid(owner_key, seqid, OP_OPEN, status, result.buffer()); |
| 1762 |
2/2✓ Branch 0 taken 117 times.
✓ Branch 1 taken 52 times.
|
169 | if (status == NFS4_OK) |
| 1763 |
1/2✓ Branch 4 taken 117 times.
✗ Branch 5 not taken.
|
117 | body->PutRaw(result.buffer().data(), result.size()); |
| 1764 | 169 | return status; | |
| 1765 | 195 | } | |
| 1766 | |||
| 1767 | |||
| 1768 | ✗ | uint32_t Nfs4Server::OpOpenConfirm(XdrReader *args, Compound *c, | |
| 1769 | XdrWriter *body) { | ||
| 1770 | ✗ | Stateid stateid; | |
| 1771 | uint32_t seqid; | ||
| 1772 | ✗ | if (!GetStateid(args, &stateid) || !args->GetU32(&seqid)) | |
| 1773 | ✗ | return NFS4ERR_BADXDR; | |
| 1774 | ✗ | if (!c->has_fh) | |
| 1775 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 1776 | |||
| 1777 | ✗ | std::lock_guard<std::mutex> const lock(state_lock_); | |
| 1778 | ✗ | std::map<std::string, OpenState>::iterator it; | |
| 1779 | ✗ | uint32_t status = FindOpenState(stateid, true, &it); | |
| 1780 | ✗ | if (status != NFS4_OK) | |
| 1781 | ✗ | return status; | |
| 1782 | ✗ | const OwnerKey owner = it->second.owner; | |
| 1783 | ✗ | std::string replay_body; | |
| 1784 | ✗ | const SeqidCheck check = CheckSeqid(owner, seqid, OP_OPEN_CONFIRM, false, | |
| 1785 | &status, &replay_body); | ||
| 1786 | ✗ | if (check == kSeqidBad) | |
| 1787 | ✗ | return status; | |
| 1788 | ✗ | if (check == kSeqidReplay) { | |
| 1789 | ✗ | body->PutRaw(replay_body.data(), replay_body.size()); | |
| 1790 | ✗ | return status; | |
| 1791 | } | ||
| 1792 | |||
| 1793 | ✗ | it->second.seqid++; | |
| 1794 | ✗ | Stateid result; | |
| 1795 | ✗ | result.seqid = it->second.seqid; | |
| 1796 | ✗ | result.other = it->first; | |
| 1797 | ✗ | XdrWriter w; | |
| 1798 | ✗ | PutStateid(result, &w); | |
| 1799 | ✗ | RecordSeqid(owner, seqid, OP_OPEN_CONFIRM, NFS4_OK, w.buffer()); | |
| 1800 | ✗ | body->PutRaw(w.buffer().data(), w.size()); | |
| 1801 | ✗ | return NFS4_OK; | |
| 1802 | } | ||
| 1803 | |||
| 1804 | |||
| 1805 | ✗ | uint32_t Nfs4Server::OpOpenDowngrade(XdrReader *args, Compound *c, | |
| 1806 | XdrWriter *body) { | ||
| 1807 | ✗ | Stateid stateid; | |
| 1808 | uint32_t seqid, share_access, share_deny; | ||
| 1809 | ✗ | if (!GetStateid(args, &stateid) || !args->GetU32(&seqid) | |
| 1810 | ✗ | || !args->GetU32(&share_access) || !args->GetU32(&share_deny)) { | |
| 1811 | ✗ | return NFS4ERR_BADXDR; | |
| 1812 | } | ||
| 1813 | ✗ | if (!c->has_fh) | |
| 1814 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 1815 | |||
| 1816 | ✗ | std::lock_guard<std::mutex> const lock(state_lock_); | |
| 1817 | ✗ | std::map<std::string, OpenState>::iterator it; | |
| 1818 | ✗ | uint32_t status = FindOpenState(stateid, true, &it); | |
| 1819 | ✗ | if (status != NFS4_OK) | |
| 1820 | ✗ | return status; | |
| 1821 | ✗ | const OwnerKey owner = it->second.owner; | |
| 1822 | ✗ | std::string replay_body; | |
| 1823 | ✗ | const SeqidCheck check = CheckSeqid(owner, seqid, OP_OPEN_DOWNGRADE, false, | |
| 1824 | &status, &replay_body); | ||
| 1825 | ✗ | if (check == kSeqidBad) | |
| 1826 | ✗ | return status; | |
| 1827 | ✗ | if (check == kSeqidReplay) { | |
| 1828 | ✗ | body->PutRaw(replay_body.data(), replay_body.size()); | |
| 1829 | ✗ | return status; | |
| 1830 | } | ||
| 1831 | |||
| 1832 | ✗ | XdrWriter w; | |
| 1833 | ✗ | if ((share_access & ~it->second.access) != 0) { | |
| 1834 | ✗ | status = NFS4ERR_INVAL; | |
| 1835 | } else { | ||
| 1836 | ✗ | it->second.access = share_access; | |
| 1837 | ✗ | it->second.seqid++; | |
| 1838 | ✗ | Stateid result; | |
| 1839 | ✗ | result.seqid = it->second.seqid; | |
| 1840 | ✗ | result.other = it->first; | |
| 1841 | ✗ | PutStateid(result, &w); | |
| 1842 | ✗ | status = NFS4_OK; | |
| 1843 | } | ||
| 1844 | ✗ | RecordSeqid(owner, seqid, OP_OPEN_DOWNGRADE, status, w.buffer()); | |
| 1845 | ✗ | body->PutRaw(w.buffer().data(), w.size()); | |
| 1846 | ✗ | return status; | |
| 1847 | } | ||
| 1848 | |||
| 1849 | |||
| 1850 | 39 | uint32_t Nfs4Server::OpClose(XdrReader *args, Compound *c, XdrWriter *body) { | |
| 1851 | uint32_t seqid; | ||
| 1852 | 39 | Stateid stateid; | |
| 1853 |
5/10✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 39 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 39 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 39 times.
|
39 | if (!args->GetU32(&seqid) || !GetStateid(args, &stateid)) |
| 1854 | ✗ | return NFS4ERR_BADXDR; | |
| 1855 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
|
39 | if (!c->has_fh) |
| 1856 | ✗ | return NFS4ERR_NOFILEHANDLE; | |
| 1857 | |||
| 1858 | 39 | uint64_t forget_ino = 0; | |
| 1859 | { | ||
| 1860 |
1/2✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
|
39 | std::lock_guard<std::mutex> const lock(state_lock_); |
| 1861 | 39 | std::map<std::string, OpenState>::iterator it; | |
| 1862 |
1/2✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
|
39 | uint32_t status = FindOpenState(stateid, true, &it); |
| 1863 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
|
39 | if (status == NFS4ERR_BAD_STATEID) { |
| 1864 | // The stateid is gone after a CLOSE, so a retransmitted CLOSE is only | ||
| 1865 | // recognizable by the owner's cached reply | ||
| 1866 | 13 | for (std::map<OwnerKey, OpenOwner>::const_iterator o = owners_.begin(); | |
| 1867 |
1/2✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
13 | o != owners_.end(); |
| 1868 | ✗ | ++o) { | |
| 1869 | 13 | const OpenOwner &owner = o->second; | |
| 1870 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | if (owner.last_op == OP_CLOSE && owner.seqid == seqid |
| 1871 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | && owner.last_body.size() == 4 + kStateidOtherSize |
| 1872 |
4/8✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
|
26 | && owner.last_body.compare(4, kStateidOtherSize, stateid.other) |
| 1873 | == 0) { | ||
| 1874 |
1/2✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
13 | body->PutRaw(owner.last_body.data(), owner.last_body.size()); |
| 1875 | 13 | return owner.last_status; | |
| 1876 | } | ||
| 1877 | } | ||
| 1878 | } | ||
| 1879 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
|
26 | if (status != NFS4_OK) |
| 1880 | 13 | return status; | |
| 1881 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | const OwnerKey owner = it->second.owner; |
| 1882 | 13 | std::string replay_body; | |
| 1883 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | const SeqidCheck check = CheckSeqid(owner, seqid, OP_CLOSE, false, &status, |
| 1884 | &replay_body); | ||
| 1885 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (check == kSeqidBad) |
| 1886 | ✗ | return status; | |
| 1887 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (check == kSeqidReplay) { |
| 1888 | ✗ | body->PutRaw(replay_body.data(), replay_body.size()); | |
| 1889 | ✗ | return status; | |
| 1890 | } | ||
| 1891 | |||
| 1892 | 13 | Stateid result; | |
| 1893 | 13 | result.seqid = it->second.seqid + 1; | |
| 1894 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | result.other = it->first; |
| 1895 | 13 | const FileHandle fh = it->second.fh; | |
| 1896 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | open_states_.erase(it); |
| 1897 | 13 | bool still_open = false; | |
| 1898 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 13 times.
|
13 | for (it = open_states_.begin(); it != open_states_.end(); ++it) { |
| 1899 | ✗ | if (it->second.fh.ino == fh.ino) { | |
| 1900 | ✗ | still_open = true; | |
| 1901 | ✗ | break; | |
| 1902 | } | ||
| 1903 | } | ||
| 1904 |
2/4✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | if (!still_open && fh.kind == FileHandle::kObject) |
| 1905 | 13 | forget_ino = fh.ino; | |
| 1906 | |||
| 1907 | 13 | XdrWriter w; | |
| 1908 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | PutStateid(result, &w); |
| 1909 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | RecordSeqid(owner, seqid, OP_CLOSE, NFS4_OK, w.buffer()); |
| 1910 |
1/2✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
|
13 | body->PutRaw(w.buffer().data(), w.size()); |
| 1911 |
4/6✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 13 times.
✓ Branch 10 taken 26 times.
|
39 | } |
| 1912 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | if (forget_ino != 0) |
| 1913 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | backend_->Forget(forget_ino); |
| 1914 | 13 | return NFS4_OK; | |
| 1915 | 39 | } | |
| 1916 | |||
| 1917 | } // namespace nfs4 | ||
| 1918 |