io.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. /*
  2. Unix SMB/CIFS implementation.
  3. trivial database library
  4. Copyright (C) Andrew Tridgell 1999-2005
  5. Copyright (C) Paul `Rusty' Russell 2000
  6. Copyright (C) Jeremy Allison 2000-2003
  7. Copyright (C) Rusty Russell 2010
  8. ** NOTE! The following LGPL license applies to the ntdb
  9. ** library. This does NOT imply that all of Samba is released
  10. ** under the LGPL
  11. This library is free software; you can redistribute it and/or
  12. modify it under the terms of the GNU Lesser General Public
  13. License as published by the Free Software Foundation; either
  14. version 3 of the License, or (at your option) any later version.
  15. This library is distributed in the hope that it will be useful,
  16. but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. Lesser General Public License for more details.
  19. You should have received a copy of the GNU Lesser General Public
  20. License along with this library; if not, see <http://www.gnu.org/licenses/>.
  21. */
  22. #include "private.h"
  23. #include <ccan/likely/likely.h>
  24. static void free_old_mmaps(struct ntdb_context *ntdb)
  25. {
  26. struct ntdb_old_mmap *i;
  27. assert(ntdb->file->direct_count == 0);
  28. while ((i = ntdb->file->old_mmaps) != NULL) {
  29. ntdb->file->old_mmaps = i->next;
  30. if (ntdb->flags & NTDB_INTERNAL) {
  31. ntdb->free_fn(i->map_ptr, ntdb->alloc_data);
  32. } else {
  33. munmap(i->map_ptr, i->map_size);
  34. }
  35. ntdb->free_fn(i, ntdb->alloc_data);
  36. }
  37. }
  38. static enum NTDB_ERROR save_old_map(struct ntdb_context *ntdb)
  39. {
  40. struct ntdb_old_mmap *old;
  41. assert(ntdb->file->direct_count);
  42. old = ntdb->alloc_fn(ntdb->file, sizeof(*old), ntdb->alloc_data);
  43. if (!old) {
  44. return ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
  45. "save_old_map alloc failed");
  46. }
  47. old->next = ntdb->file->old_mmaps;
  48. old->map_ptr = ntdb->file->map_ptr;
  49. old->map_size = ntdb->file->map_size;
  50. ntdb->file->old_mmaps = old;
  51. return NTDB_SUCCESS;
  52. }
  53. enum NTDB_ERROR ntdb_munmap(struct ntdb_context *ntdb)
  54. {
  55. if (ntdb->file->fd == -1) {
  56. return NTDB_SUCCESS;
  57. }
  58. if (!ntdb->file->map_ptr) {
  59. return NTDB_SUCCESS;
  60. }
  61. /* We can't unmap now if there are accessors. */
  62. if (ntdb->file->direct_count) {
  63. return save_old_map(ntdb);
  64. } else {
  65. munmap(ntdb->file->map_ptr, ntdb->file->map_size);
  66. ntdb->file->map_ptr = NULL;
  67. }
  68. return NTDB_SUCCESS;
  69. }
  70. enum NTDB_ERROR ntdb_mmap(struct ntdb_context *ntdb)
  71. {
  72. int mmap_flags;
  73. if (ntdb->flags & NTDB_INTERNAL)
  74. return NTDB_SUCCESS;
  75. #ifndef HAVE_INCOHERENT_MMAP
  76. if (ntdb->flags & NTDB_NOMMAP)
  77. return NTDB_SUCCESS;
  78. #endif
  79. if ((ntdb->open_flags & O_ACCMODE) == O_RDONLY)
  80. mmap_flags = PROT_READ;
  81. else
  82. mmap_flags = PROT_READ | PROT_WRITE;
  83. /* size_t can be smaller than off_t. */
  84. if ((size_t)ntdb->file->map_size == ntdb->file->map_size) {
  85. ntdb->file->map_ptr = mmap(NULL, ntdb->file->map_size,
  86. mmap_flags,
  87. MAP_SHARED, ntdb->file->fd, 0);
  88. } else
  89. ntdb->file->map_ptr = MAP_FAILED;
  90. /*
  91. * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
  92. */
  93. if (ntdb->file->map_ptr == MAP_FAILED) {
  94. ntdb->file->map_ptr = NULL;
  95. #ifdef HAVE_INCOHERENT_MMAP
  96. /* Incoherent mmap means everyone must mmap! */
  97. return ntdb_logerr(ntdb, NTDB_ERR_IO, NTDB_LOG_ERROR,
  98. "ntdb_mmap failed for size %lld (%s)",
  99. (long long)ntdb->file->map_size,
  100. strerror(errno));
  101. #else
  102. ntdb_logerr(ntdb, NTDB_SUCCESS, NTDB_LOG_WARNING,
  103. "ntdb_mmap failed for size %lld (%s)",
  104. (long long)ntdb->file->map_size, strerror(errno));
  105. #endif
  106. }
  107. return NTDB_SUCCESS;
  108. }
  109. /* check for an out of bounds access - if it is out of bounds then
  110. see if the database has been expanded by someone else and expand
  111. if necessary
  112. note that "len" is the minimum length needed for the db.
  113. If probe is true, len being too large isn't a failure.
  114. */
  115. static enum NTDB_ERROR ntdb_normal_oob(struct ntdb_context *ntdb,
  116. ntdb_off_t off, ntdb_len_t len,
  117. bool probe)
  118. {
  119. struct stat st;
  120. enum NTDB_ERROR ecode;
  121. if (len + off < len) {
  122. if (probe)
  123. return NTDB_SUCCESS;
  124. return ntdb_logerr(ntdb, NTDB_ERR_IO, NTDB_LOG_ERROR,
  125. "ntdb_oob off %llu len %llu wrap\n",
  126. (long long)off, (long long)len);
  127. }
  128. if (ntdb->flags & NTDB_INTERNAL) {
  129. if (probe)
  130. return NTDB_SUCCESS;
  131. ntdb_logerr(ntdb, NTDB_ERR_IO, NTDB_LOG_ERROR,
  132. "ntdb_oob len %lld beyond internal"
  133. " alloc size %lld",
  134. (long long)(off + len),
  135. (long long)ntdb->file->map_size);
  136. return NTDB_ERR_IO;
  137. }
  138. ecode = ntdb_lock_expand(ntdb, F_RDLCK);
  139. if (ecode != NTDB_SUCCESS) {
  140. return ecode;
  141. }
  142. if (fstat(ntdb->file->fd, &st) != 0) {
  143. ntdb_logerr(ntdb, NTDB_ERR_IO, NTDB_LOG_ERROR,
  144. "Failed to fstat file: %s", strerror(errno));
  145. ntdb_unlock_expand(ntdb, F_RDLCK);
  146. return NTDB_ERR_IO;
  147. }
  148. ntdb_unlock_expand(ntdb, F_RDLCK);
  149. if (st.st_size < off + len) {
  150. if (probe)
  151. return NTDB_SUCCESS;
  152. ntdb_logerr(ntdb, NTDB_ERR_IO, NTDB_LOG_ERROR,
  153. "ntdb_oob len %llu beyond eof at %llu",
  154. (long long)(off + len), (long long)st.st_size);
  155. return NTDB_ERR_IO;
  156. }
  157. /* Unmap, update size, remap */
  158. ecode = ntdb_munmap(ntdb);
  159. if (ecode) {
  160. return ecode;
  161. }
  162. ntdb->file->map_size = st.st_size;
  163. return ntdb_mmap(ntdb);
  164. }
  165. /* Endian conversion: we only ever deal with 8 byte quantities */
  166. void *ntdb_convert(const struct ntdb_context *ntdb, void *buf, ntdb_len_t size)
  167. {
  168. assert(size % 8 == 0);
  169. if (unlikely((ntdb->flags & NTDB_CONVERT)) && buf) {
  170. uint64_t i, *p = (uint64_t *)buf;
  171. for (i = 0; i < size / 8; i++)
  172. p[i] = bswap_64(p[i]);
  173. }
  174. return buf;
  175. }
  176. /* Return first non-zero offset in offset array, or end, or -ve error. */
  177. /* FIXME: Return the off? */
  178. uint64_t ntdb_find_nonzero_off(struct ntdb_context *ntdb,
  179. ntdb_off_t base, uint64_t start, uint64_t end)
  180. {
  181. uint64_t i;
  182. const uint64_t *val;
  183. /* Zero vs non-zero is the same unconverted: minor optimization. */
  184. val = ntdb_access_read(ntdb, base + start * sizeof(ntdb_off_t),
  185. (end - start) * sizeof(ntdb_off_t), false);
  186. if (NTDB_PTR_IS_ERR(val)) {
  187. return NTDB_ERR_TO_OFF(NTDB_PTR_ERR(val));
  188. }
  189. for (i = 0; i < (end - start); i++) {
  190. if (val[i])
  191. break;
  192. }
  193. ntdb_access_release(ntdb, val);
  194. return start + i;
  195. }
  196. /* Return first zero offset in num offset array, or num, or -ve error. */
  197. uint64_t ntdb_find_zero_off(struct ntdb_context *ntdb, ntdb_off_t off,
  198. uint64_t num)
  199. {
  200. uint64_t i;
  201. const uint64_t *val;
  202. /* Zero vs non-zero is the same unconverted: minor optimization. */
  203. val = ntdb_access_read(ntdb, off, num * sizeof(ntdb_off_t), false);
  204. if (NTDB_PTR_IS_ERR(val)) {
  205. return NTDB_ERR_TO_OFF(NTDB_PTR_ERR(val));
  206. }
  207. for (i = 0; i < num; i++) {
  208. if (!val[i])
  209. break;
  210. }
  211. ntdb_access_release(ntdb, val);
  212. return i;
  213. }
  214. enum NTDB_ERROR zero_out(struct ntdb_context *ntdb, ntdb_off_t off, ntdb_len_t len)
  215. {
  216. char buf[8192] = { 0 };
  217. void *p = ntdb->io->direct(ntdb, off, len, true);
  218. enum NTDB_ERROR ecode = NTDB_SUCCESS;
  219. assert(!(ntdb->flags & NTDB_RDONLY));
  220. if (NTDB_PTR_IS_ERR(p)) {
  221. return NTDB_PTR_ERR(p);
  222. }
  223. if (p) {
  224. memset(p, 0, len);
  225. return ecode;
  226. }
  227. while (len) {
  228. unsigned todo = len < sizeof(buf) ? len : sizeof(buf);
  229. ecode = ntdb->io->twrite(ntdb, off, buf, todo);
  230. if (ecode != NTDB_SUCCESS) {
  231. break;
  232. }
  233. len -= todo;
  234. off += todo;
  235. }
  236. return ecode;
  237. }
  238. /* write a lump of data at a specified offset */
  239. static enum NTDB_ERROR ntdb_write(struct ntdb_context *ntdb, ntdb_off_t off,
  240. const void *buf, ntdb_len_t len)
  241. {
  242. enum NTDB_ERROR ecode;
  243. if (ntdb->flags & NTDB_RDONLY) {
  244. return ntdb_logerr(ntdb, NTDB_ERR_RDONLY, NTDB_LOG_USE_ERROR,
  245. "Write to read-only database");
  246. }
  247. ecode = ntdb_oob(ntdb, off, len, false);
  248. if (ecode != NTDB_SUCCESS) {
  249. return ecode;
  250. }
  251. if (ntdb->file->map_ptr) {
  252. memcpy(off + (char *)ntdb->file->map_ptr, buf, len);
  253. } else {
  254. #ifdef HAVE_INCOHERENT_MMAP
  255. return NTDB_ERR_IO;
  256. #else
  257. ssize_t ret;
  258. ret = pwrite(ntdb->file->fd, buf, len, off);
  259. if (ret != len) {
  260. /* This shouldn't happen: we avoid sparse files. */
  261. if (ret >= 0)
  262. errno = ENOSPC;
  263. return ntdb_logerr(ntdb, NTDB_ERR_IO, NTDB_LOG_ERROR,
  264. "ntdb_write: %zi at %zu len=%zu (%s)",
  265. ret, (size_t)off, (size_t)len,
  266. strerror(errno));
  267. }
  268. #endif
  269. }
  270. return NTDB_SUCCESS;
  271. }
  272. /* read a lump of data at a specified offset */
  273. static enum NTDB_ERROR ntdb_read(struct ntdb_context *ntdb, ntdb_off_t off,
  274. void *buf, ntdb_len_t len)
  275. {
  276. enum NTDB_ERROR ecode;
  277. ecode = ntdb_oob(ntdb, off, len, false);
  278. if (ecode != NTDB_SUCCESS) {
  279. return ecode;
  280. }
  281. if (ntdb->file->map_ptr) {
  282. memcpy(buf, off + (char *)ntdb->file->map_ptr, len);
  283. } else {
  284. #ifdef HAVE_INCOHERENT_MMAP
  285. return NTDB_ERR_IO;
  286. #else
  287. ssize_t r = pread(ntdb->file->fd, buf, len, off);
  288. if (r != len) {
  289. return ntdb_logerr(ntdb, NTDB_ERR_IO, NTDB_LOG_ERROR,
  290. "ntdb_read failed with %zi at %zu "
  291. "len=%zu (%s) map_size=%zu",
  292. r, (size_t)off, (size_t)len,
  293. strerror(errno),
  294. (size_t)ntdb->file->map_size);
  295. }
  296. #endif
  297. }
  298. return NTDB_SUCCESS;
  299. }
  300. enum NTDB_ERROR ntdb_write_convert(struct ntdb_context *ntdb, ntdb_off_t off,
  301. const void *rec, size_t len)
  302. {
  303. enum NTDB_ERROR ecode;
  304. if (unlikely((ntdb->flags & NTDB_CONVERT))) {
  305. void *conv = ntdb->alloc_fn(ntdb, len, ntdb->alloc_data);
  306. if (!conv) {
  307. return ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
  308. "ntdb_write: no memory converting"
  309. " %zu bytes", len);
  310. }
  311. memcpy(conv, rec, len);
  312. ecode = ntdb->io->twrite(ntdb, off,
  313. ntdb_convert(ntdb, conv, len), len);
  314. ntdb->free_fn(conv, ntdb->alloc_data);
  315. } else {
  316. ecode = ntdb->io->twrite(ntdb, off, rec, len);
  317. }
  318. return ecode;
  319. }
  320. enum NTDB_ERROR ntdb_read_convert(struct ntdb_context *ntdb, ntdb_off_t off,
  321. void *rec, size_t len)
  322. {
  323. enum NTDB_ERROR ecode = ntdb->io->tread(ntdb, off, rec, len);
  324. ntdb_convert(ntdb, rec, len);
  325. return ecode;
  326. }
  327. static void *_ntdb_alloc_read(struct ntdb_context *ntdb, ntdb_off_t offset,
  328. ntdb_len_t len, unsigned int prefix)
  329. {
  330. unsigned char *buf;
  331. enum NTDB_ERROR ecode;
  332. /* some systems don't like zero length malloc */
  333. buf = ntdb->alloc_fn(ntdb, prefix + len ? prefix + len : 1,
  334. ntdb->alloc_data);
  335. if (!buf) {
  336. ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
  337. "ntdb_alloc_read alloc failed len=%zu",
  338. (size_t)(prefix + len));
  339. return NTDB_ERR_PTR(NTDB_ERR_OOM);
  340. } else {
  341. ecode = ntdb->io->tread(ntdb, offset, buf+prefix, len);
  342. if (unlikely(ecode != NTDB_SUCCESS)) {
  343. ntdb->free_fn(buf, ntdb->alloc_data);
  344. return NTDB_ERR_PTR(ecode);
  345. }
  346. }
  347. return buf;
  348. }
  349. /* read a lump of data, allocating the space for it */
  350. void *ntdb_alloc_read(struct ntdb_context *ntdb, ntdb_off_t offset, ntdb_len_t len)
  351. {
  352. return _ntdb_alloc_read(ntdb, offset, len, 0);
  353. }
  354. static enum NTDB_ERROR fill(struct ntdb_context *ntdb,
  355. const void *buf, size_t size,
  356. ntdb_off_t off, ntdb_len_t len)
  357. {
  358. while (len) {
  359. size_t n = len > size ? size : len;
  360. ssize_t ret = pwrite(ntdb->file->fd, buf, n, off);
  361. if (ret != n) {
  362. if (ret >= 0)
  363. errno = ENOSPC;
  364. return ntdb_logerr(ntdb, NTDB_ERR_IO, NTDB_LOG_ERROR,
  365. "fill failed:"
  366. " %zi at %zu len=%zu (%s)",
  367. ret, (size_t)off, (size_t)len,
  368. strerror(errno));
  369. }
  370. len -= n;
  371. off += n;
  372. }
  373. return NTDB_SUCCESS;
  374. }
  375. /* expand a file. we prefer to use ftruncate, as that is what posix
  376. says to use for mmap expansion */
  377. static enum NTDB_ERROR ntdb_expand_file(struct ntdb_context *ntdb,
  378. ntdb_len_t addition)
  379. {
  380. char buf[8192];
  381. enum NTDB_ERROR ecode;
  382. assert((ntdb->file->map_size + addition) % NTDB_PGSIZE == 0);
  383. if (ntdb->flags & NTDB_RDONLY) {
  384. return ntdb_logerr(ntdb, NTDB_ERR_RDONLY, NTDB_LOG_USE_ERROR,
  385. "Expand on read-only database");
  386. }
  387. if (ntdb->flags & NTDB_INTERNAL) {
  388. char *new;
  389. /* Can't free it if we have direct accesses. */
  390. if (ntdb->file->direct_count) {
  391. ecode = save_old_map(ntdb);
  392. if (ecode) {
  393. return ecode;
  394. }
  395. new = ntdb->alloc_fn(ntdb->file,
  396. ntdb->file->map_size + addition,
  397. ntdb->alloc_data);
  398. if (new) {
  399. memcpy(new, ntdb->file->map_ptr,
  400. ntdb->file->map_size);
  401. }
  402. } else {
  403. new = ntdb->expand_fn(ntdb->file->map_ptr,
  404. ntdb->file->map_size + addition,
  405. ntdb->alloc_data);
  406. }
  407. if (!new) {
  408. return ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
  409. "No memory to expand database");
  410. }
  411. ntdb->file->map_ptr = new;
  412. ntdb->file->map_size += addition;
  413. return NTDB_SUCCESS;
  414. } else {
  415. /* Unmap before trying to write; old NTDB claimed OpenBSD had
  416. * problem with this otherwise. */
  417. ecode = ntdb_munmap(ntdb);
  418. if (ecode) {
  419. return ecode;
  420. }
  421. /* If this fails, we try to fill anyway. */
  422. if (ftruncate(ntdb->file->fd, ntdb->file->map_size + addition))
  423. ;
  424. /* now fill the file with something. This ensures that the
  425. file isn't sparse, which would be very bad if we ran out of
  426. disk. This must be done with write, not via mmap */
  427. memset(buf, 0x43, sizeof(buf));
  428. ecode = fill(ntdb, buf, sizeof(buf), ntdb->file->map_size,
  429. addition);
  430. if (ecode != NTDB_SUCCESS)
  431. return ecode;
  432. ntdb->file->map_size += addition;
  433. return ntdb_mmap(ntdb);
  434. }
  435. }
  436. const void *ntdb_access_read(struct ntdb_context *ntdb,
  437. ntdb_off_t off, ntdb_len_t len, bool convert)
  438. {
  439. void *ret = NULL;
  440. if (likely(!(ntdb->flags & NTDB_CONVERT))) {
  441. ret = ntdb->io->direct(ntdb, off, len, false);
  442. if (NTDB_PTR_IS_ERR(ret)) {
  443. return ret;
  444. }
  445. }
  446. if (!ret) {
  447. struct ntdb_access_hdr *hdr;
  448. hdr = _ntdb_alloc_read(ntdb, off, len, sizeof(*hdr));
  449. if (NTDB_PTR_IS_ERR(hdr)) {
  450. return hdr;
  451. }
  452. hdr->next = ntdb->access;
  453. ntdb->access = hdr;
  454. ret = hdr + 1;
  455. if (convert) {
  456. ntdb_convert(ntdb, (void *)ret, len);
  457. }
  458. } else {
  459. ntdb->file->direct_count++;
  460. }
  461. return ret;
  462. }
  463. void *ntdb_access_write(struct ntdb_context *ntdb,
  464. ntdb_off_t off, ntdb_len_t len, bool convert)
  465. {
  466. void *ret = NULL;
  467. if (ntdb->flags & NTDB_RDONLY) {
  468. ntdb_logerr(ntdb, NTDB_ERR_RDONLY, NTDB_LOG_USE_ERROR,
  469. "Write to read-only database");
  470. return NTDB_ERR_PTR(NTDB_ERR_RDONLY);
  471. }
  472. if (likely(!(ntdb->flags & NTDB_CONVERT))) {
  473. ret = ntdb->io->direct(ntdb, off, len, true);
  474. if (NTDB_PTR_IS_ERR(ret)) {
  475. return ret;
  476. }
  477. }
  478. if (!ret) {
  479. struct ntdb_access_hdr *hdr;
  480. hdr = _ntdb_alloc_read(ntdb, off, len, sizeof(*hdr));
  481. if (NTDB_PTR_IS_ERR(hdr)) {
  482. return hdr;
  483. }
  484. hdr->next = ntdb->access;
  485. ntdb->access = hdr;
  486. hdr->off = off;
  487. hdr->len = len;
  488. hdr->convert = convert;
  489. ret = hdr + 1;
  490. if (convert)
  491. ntdb_convert(ntdb, (void *)ret, len);
  492. } else {
  493. ntdb->file->direct_count++;
  494. }
  495. return ret;
  496. }
  497. static struct ntdb_access_hdr **find_hdr(struct ntdb_context *ntdb, const void *p)
  498. {
  499. struct ntdb_access_hdr **hp;
  500. for (hp = &ntdb->access; *hp; hp = &(*hp)->next) {
  501. if (*hp + 1 == p)
  502. return hp;
  503. }
  504. return NULL;
  505. }
  506. void ntdb_access_release(struct ntdb_context *ntdb, const void *p)
  507. {
  508. struct ntdb_access_hdr *hdr, **hp = find_hdr(ntdb, p);
  509. if (hp) {
  510. hdr = *hp;
  511. *hp = hdr->next;
  512. ntdb->free_fn(hdr, ntdb->alloc_data);
  513. } else {
  514. if (--ntdb->file->direct_count == 0) {
  515. free_old_mmaps(ntdb);
  516. }
  517. }
  518. }
  519. enum NTDB_ERROR ntdb_access_commit(struct ntdb_context *ntdb, void *p)
  520. {
  521. struct ntdb_access_hdr *hdr, **hp = find_hdr(ntdb, p);
  522. enum NTDB_ERROR ecode;
  523. if (hp) {
  524. hdr = *hp;
  525. if (hdr->convert)
  526. ecode = ntdb_write_convert(ntdb, hdr->off, p, hdr->len);
  527. else
  528. ecode = ntdb_write(ntdb, hdr->off, p, hdr->len);
  529. *hp = hdr->next;
  530. ntdb->free_fn(hdr, ntdb->alloc_data);
  531. } else {
  532. if (--ntdb->file->direct_count == 0) {
  533. free_old_mmaps(ntdb);
  534. }
  535. ecode = NTDB_SUCCESS;
  536. }
  537. return ecode;
  538. }
  539. static void *ntdb_direct(struct ntdb_context *ntdb, ntdb_off_t off, size_t len,
  540. bool write_mode)
  541. {
  542. enum NTDB_ERROR ecode;
  543. if (unlikely(!ntdb->file->map_ptr))
  544. return NULL;
  545. ecode = ntdb_oob(ntdb, off, len, false);
  546. if (unlikely(ecode != NTDB_SUCCESS))
  547. return NTDB_ERR_PTR(ecode);
  548. return (char *)ntdb->file->map_ptr + off;
  549. }
  550. static ntdb_off_t ntdb_read_normal_off(struct ntdb_context *ntdb,
  551. ntdb_off_t off)
  552. {
  553. ntdb_off_t ret;
  554. enum NTDB_ERROR ecode;
  555. ntdb_off_t *p;
  556. p = ntdb_direct(ntdb, off, sizeof(*p), false);
  557. if (NTDB_PTR_IS_ERR(p)) {
  558. return NTDB_ERR_TO_OFF(NTDB_PTR_ERR(p));
  559. }
  560. if (likely(p)) {
  561. return *p;
  562. }
  563. ecode = ntdb_read(ntdb, off, &ret, sizeof(ret));
  564. if (ecode != NTDB_SUCCESS) {
  565. return NTDB_ERR_TO_OFF(ecode);
  566. }
  567. return ret;
  568. }
  569. static ntdb_off_t ntdb_read_convert_off(struct ntdb_context *ntdb,
  570. ntdb_off_t off)
  571. {
  572. ntdb_off_t ret;
  573. enum NTDB_ERROR ecode;
  574. ecode = ntdb_read_convert(ntdb, off, &ret, sizeof(ret));
  575. if (ecode != NTDB_SUCCESS) {
  576. return NTDB_ERR_TO_OFF(ecode);
  577. }
  578. return ret;
  579. }
  580. static enum NTDB_ERROR ntdb_write_normal_off(struct ntdb_context *ntdb,
  581. ntdb_off_t off, ntdb_off_t val)
  582. {
  583. ntdb_off_t *p;
  584. p = ntdb_direct(ntdb, off, sizeof(*p), true);
  585. if (NTDB_PTR_IS_ERR(p)) {
  586. return NTDB_PTR_ERR(p);
  587. }
  588. if (likely(p)) {
  589. *p = val;
  590. return NTDB_SUCCESS;
  591. }
  592. return ntdb_write(ntdb, off, &val, sizeof(val));
  593. }
  594. static enum NTDB_ERROR ntdb_write_convert_off(struct ntdb_context *ntdb,
  595. ntdb_off_t off, ntdb_off_t val)
  596. {
  597. return ntdb_write_convert(ntdb, off, &val, sizeof(val));
  598. }
  599. void ntdb_inc_seqnum(struct ntdb_context *ntdb)
  600. {
  601. ntdb_off_t seq;
  602. if (likely(!(ntdb->flags & NTDB_CONVERT))) {
  603. int64_t *direct;
  604. direct = ntdb->io->direct(ntdb,
  605. offsetof(struct ntdb_header, seqnum),
  606. sizeof(*direct), true);
  607. if (likely(direct)) {
  608. /* Don't let it go negative, even briefly */
  609. if (unlikely((*direct) + 1) < 0)
  610. *direct = 0;
  611. (*direct)++;
  612. return;
  613. }
  614. }
  615. seq = ntdb_read_off(ntdb, offsetof(struct ntdb_header, seqnum));
  616. if (!NTDB_OFF_IS_ERR(seq)) {
  617. seq++;
  618. if (unlikely((int64_t)seq < 0))
  619. seq = 0;
  620. ntdb_write_off(ntdb, offsetof(struct ntdb_header, seqnum), seq);
  621. }
  622. }
  623. static const struct ntdb_methods io_methods = {
  624. ntdb_read,
  625. ntdb_write,
  626. ntdb_normal_oob,
  627. ntdb_expand_file,
  628. ntdb_direct,
  629. ntdb_read_normal_off,
  630. ntdb_write_normal_off,
  631. };
  632. static const struct ntdb_methods io_convert_methods = {
  633. ntdb_read,
  634. ntdb_write,
  635. ntdb_normal_oob,
  636. ntdb_expand_file,
  637. ntdb_direct,
  638. ntdb_read_convert_off,
  639. ntdb_write_convert_off,
  640. };
  641. /*
  642. initialise the default methods table
  643. */
  644. void ntdb_io_init(struct ntdb_context *ntdb)
  645. {
  646. if (ntdb->flags & NTDB_CONVERT)
  647. ntdb->io = &io_convert_methods;
  648. else
  649. ntdb->io = &io_methods;
  650. }