Line data Source code
1 : /*
2 : Partitions ldb module - management of metadata.tdb for sequence number
3 :
4 : Copyright (C) Amitay Isaacs <amitay@samba.org> 2011
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "dsdb/samdb/ldb_modules/partition.h"
21 : #include "lib/ldb-samba/ldb_wrap.h"
22 : #include "system/filesys.h"
23 : #include "lib/util/smb_strtox.h"
24 :
25 : #define LDB_METADATA_SEQ_NUM "SEQ_NUM"
26 :
27 :
28 : /*
29 : * Read a key with uint64 value
30 : */
31 889956 : static int partition_metadata_get_uint64(struct ldb_module *module,
32 : const char *key, uint64_t *value,
33 : uint64_t default_value)
34 : {
35 : struct partition_private_data *data;
36 : struct tdb_context *tdb;
37 : TDB_DATA tdb_key, tdb_data;
38 : char *value_str;
39 : TALLOC_CTX *tmp_ctx;
40 889956 : int error = 0;
41 :
42 889956 : data = talloc_get_type_abort(ldb_module_get_private(module),
43 : struct partition_private_data);
44 :
45 889956 : if (!data || !data->metadata || !data->metadata->db) {
46 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
47 : "partition_metadata: metadata tdb not initialized");
48 : }
49 :
50 889956 : tmp_ctx = talloc_new(NULL);
51 889956 : if (tmp_ctx == NULL) {
52 0 : return ldb_module_oom(module);
53 : }
54 :
55 889956 : tdb = data->metadata->db->tdb;
56 :
57 889956 : tdb_key.dptr = (uint8_t *)discard_const_p(char, key);
58 889956 : tdb_key.dsize = strlen(key);
59 :
60 889956 : tdb_data = tdb_fetch(tdb, tdb_key);
61 889956 : if (!tdb_data.dptr) {
62 299 : if (tdb_error(tdb) == TDB_ERR_NOEXIST) {
63 299 : *value = default_value;
64 299 : return LDB_SUCCESS;
65 : } else {
66 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
67 : tdb_errorstr(tdb));
68 : }
69 : }
70 :
71 889657 : value_str = talloc_strndup(tmp_ctx, (char *)tdb_data.dptr, tdb_data.dsize);
72 889657 : if (value_str == NULL) {
73 0 : SAFE_FREE(tdb_data.dptr);
74 0 : talloc_free(tmp_ctx);
75 0 : return ldb_module_oom(module);
76 : }
77 :
78 889657 : *value = smb_strtoull(value_str, NULL, 10, &error, SMB_STR_STANDARD);
79 889657 : if (error != 0) {
80 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
81 : "partition_metadata: converision failed");
82 : }
83 :
84 889657 : SAFE_FREE(tdb_data.dptr);
85 889657 : talloc_free(tmp_ctx);
86 :
87 889657 : return LDB_SUCCESS;
88 : }
89 :
90 :
91 : /*
92 : * Write a key with uin64 value
93 : */
94 871349 : static int partition_metadata_set_uint64(struct ldb_module *module,
95 : const char *key, uint64_t value,
96 : bool insert)
97 : {
98 : struct partition_private_data *data;
99 : struct tdb_context *tdb;
100 : TDB_DATA tdb_key, tdb_data;
101 : int tdb_flag;
102 : char *value_str;
103 : TALLOC_CTX *tmp_ctx;
104 :
105 871349 : data = talloc_get_type_abort(ldb_module_get_private(module),
106 : struct partition_private_data);
107 :
108 871349 : if (!data || !data->metadata || !data->metadata->db) {
109 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
110 : "partition_metadata: metadata tdb not initialized");
111 : }
112 :
113 871349 : tmp_ctx = talloc_new(NULL);
114 871349 : if (tmp_ctx == NULL) {
115 0 : return ldb_module_oom(module);
116 : }
117 :
118 871349 : tdb = data->metadata->db->tdb;
119 :
120 871349 : value_str = talloc_asprintf(tmp_ctx, "%llu", (unsigned long long)value);
121 871349 : if (value_str == NULL) {
122 0 : talloc_free(tmp_ctx);
123 0 : return ldb_module_oom(module);
124 : }
125 :
126 871349 : tdb_key.dptr = (uint8_t *)discard_const_p(char, key);
127 871349 : tdb_key.dsize = strlen(key);
128 :
129 871349 : tdb_data.dptr = (uint8_t *)value_str;
130 871349 : tdb_data.dsize = strlen(value_str);
131 :
132 871349 : if (insert) {
133 299 : tdb_flag = TDB_INSERT;
134 : } else {
135 871050 : tdb_flag = TDB_MODIFY;
136 : }
137 :
138 871349 : if (tdb_store(tdb, tdb_key, tdb_data, tdb_flag) != 0) {
139 : int ret;
140 150 : char *error_string = talloc_asprintf(tmp_ctx, "%s: tdb_store of key %s failed: %s",
141 : tdb_name(tdb), key, tdb_errorstr(tdb));
142 150 : ret = ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
143 : error_string);
144 150 : talloc_free(tmp_ctx);
145 150 : return ret;
146 : }
147 :
148 871199 : talloc_free(tmp_ctx);
149 :
150 871199 : return LDB_SUCCESS;
151 : }
152 :
153 1922 : int partition_metadata_inc_schema_sequence(struct ldb_module *module)
154 : {
155 : struct partition_private_data *data;
156 : int ret;
157 1922 : uint64_t value = 0;
158 :
159 1922 : data = talloc_get_type_abort(ldb_module_get_private(module),
160 : struct partition_private_data);
161 1922 : if (!data || !data->metadata) {
162 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
163 : "partition_metadata: metadata not initialized");
164 : }
165 :
166 1922 : if (data->metadata->in_transaction == 0) {
167 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
168 : "partition_metadata: increment sequence number without transaction");
169 : }
170 1922 : ret = partition_metadata_get_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, &value, 0);
171 1922 : if (ret != LDB_SUCCESS) {
172 0 : return ret;
173 : }
174 :
175 1922 : value++;
176 1922 : ret = partition_metadata_set_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, value, false);
177 1922 : if (ret == LDB_ERR_OPERATIONS_ERROR) {
178 : /* Modify failed, let's try the add */
179 150 : ret = partition_metadata_set_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, value, true);
180 : }
181 1922 : return ret;
182 : }
183 :
184 :
185 :
186 : /*
187 : * Open sam.ldb.d/metadata.tdb.
188 : */
189 108163 : static int partition_metadata_open(struct ldb_module *module, bool create)
190 : {
191 108163 : struct ldb_context *ldb = ldb_module_get_ctx(module);
192 : TALLOC_CTX *tmp_ctx;
193 : struct partition_private_data *data;
194 : struct loadparm_context *lp_ctx;
195 : char *filename, *dirname;
196 : int open_flags, tdb_flags, ldb_flags;
197 : struct stat statbuf;
198 :
199 108163 : data = talloc_get_type_abort(ldb_module_get_private(module),
200 : struct partition_private_data);
201 108163 : if (!data || !data->metadata) {
202 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
203 : "partition_metadata: metadata not initialized");
204 : }
205 :
206 108163 : tmp_ctx = talloc_new(NULL);
207 108163 : if (tmp_ctx == NULL) {
208 0 : return ldb_module_oom(module);
209 : }
210 :
211 108163 : filename = ldb_relative_path(ldb,
212 : tmp_ctx,
213 : "sam.ldb.d/metadata.tdb");
214 :
215 108163 : if (!filename) {
216 0 : talloc_free(tmp_ctx);
217 0 : return ldb_oom(ldb);
218 : }
219 :
220 108163 : open_flags = O_RDWR;
221 108163 : if (create) {
222 150 : open_flags |= O_CREAT;
223 :
224 : /* While provisioning, sam.ldb.d directory may not exist,
225 : * so create it. Ignore errors, if it already exists. */
226 150 : dirname = ldb_relative_path(ldb,
227 : tmp_ctx,
228 : "sam.ldb.d");
229 150 : if (!dirname) {
230 0 : talloc_free(tmp_ctx);
231 0 : return ldb_oom(ldb);
232 : }
233 :
234 150 : mkdir(dirname, 0700);
235 150 : talloc_free(dirname);
236 : } else {
237 108013 : if (stat(filename, &statbuf) != 0) {
238 150 : talloc_free(tmp_ctx);
239 150 : return LDB_ERR_OPERATIONS_ERROR;
240 : }
241 : }
242 :
243 108013 : lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
244 : struct loadparm_context);
245 :
246 108013 : tdb_flags = lpcfg_tdb_flags(lp_ctx, TDB_DEFAULT|TDB_SEQNUM);
247 :
248 108013 : ldb_flags = ldb_module_flags(ldb);
249 :
250 108013 : if (ldb_flags & LDB_FLG_NOSYNC) {
251 107490 : tdb_flags |= TDB_NOSYNC;
252 : }
253 :
254 135056 : data->metadata->db = tdb_wrap_open(
255 108013 : data->metadata, filename, 10,
256 : tdb_flags, open_flags, 0660);
257 108013 : if (data->metadata->db == NULL) {
258 0 : talloc_free(tmp_ctx);
259 0 : if (create) {
260 0 : ldb_asprintf_errstring(ldb, "partition_metadata: Unable to create %s: %s",
261 0 : filename, strerror(errno));
262 : } else {
263 0 : ldb_asprintf_errstring(ldb, "partition_metadata: Unable to open %s: %s",
264 0 : filename, strerror(errno));
265 : }
266 0 : if (errno == EACCES || errno == EPERM) {
267 0 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
268 : }
269 0 : return LDB_ERR_OPERATIONS_ERROR;
270 : }
271 :
272 108013 : talloc_free(tmp_ctx);
273 108013 : return LDB_SUCCESS;
274 : }
275 :
276 :
277 : /*
278 : * Set the sequence number calculated from older logic (sum of primary sequence
279 : * numbers for each partition) as LDB_METADATA_SEQ_NUM key.
280 : */
281 149 : static int partition_metadata_set_sequence_number(struct ldb_module *module)
282 : {
283 : int ret;
284 : uint64_t seq_number;
285 :
286 149 : ret = partition_sequence_number_from_partitions(module, &seq_number);
287 149 : if (ret != LDB_SUCCESS) {
288 0 : return ret;
289 : }
290 :
291 149 : return partition_metadata_set_uint64(module, LDB_METADATA_SEQ_NUM, seq_number, true);
292 : }
293 :
294 :
295 : /*
296 : * Initialize metadata. Load metadata.tdb.
297 : * If missing, create it and fill in sequence number
298 : */
299 109689 : int partition_metadata_init(struct ldb_module *module)
300 : {
301 : struct partition_private_data *data;
302 : int ret;
303 :
304 109689 : data = talloc_get_type_abort(ldb_module_get_private(module),
305 : struct partition_private_data);
306 :
307 109689 : if (data->metadata != NULL && data->metadata->db != NULL) {
308 1676 : return LDB_SUCCESS;
309 : }
310 :
311 108013 : data->metadata = talloc_zero(data, struct partition_metadata);
312 108013 : if (data->metadata == NULL) {
313 0 : return ldb_module_oom(module);
314 : }
315 :
316 108013 : ret = partition_metadata_open(module, false);
317 108013 : if (ret == LDB_SUCCESS) {
318 : /* Great, we got the DB open */
319 107863 : return LDB_SUCCESS;
320 : }
321 :
322 : /* metadata.tdb does not exist, create it */
323 150 : DEBUG(2, ("partition_metadata: Migrating partition metadata: "
324 : "open of metadata.tdb gave: %s\n",
325 : ldb_errstring(ldb_module_get_ctx(module))));
326 150 : ret = partition_metadata_open(module, true);
327 150 : if (ret != LDB_SUCCESS) {
328 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
329 : "partition_metadata: "
330 : "Migrating partition metadata: "
331 : "create of metadata.tdb gave: %s\n",
332 : ldb_errstring(ldb_module_get_ctx(module)));
333 0 : TALLOC_FREE(data->metadata);
334 0 : return ret;
335 : }
336 :
337 150 : return ret;
338 : }
339 :
340 :
341 : /*
342 : * Read the sequence number, default to 0 if LDB_METADATA_SEQ_NUM key is missing
343 : */
344 18757 : int partition_metadata_sequence_number(struct ldb_module *module, uint64_t *value)
345 : {
346 :
347 : /* We have to lock all the databases as otherwise we can
348 : * return a sequence number that is higher than the DB values
349 : * that we can see, as those transactions close after the
350 : * metadata.tdb transaction closes */
351 18757 : int ret = partition_read_lock(module);
352 18757 : if (ret != LDB_SUCCESS) {
353 0 : return ret;
354 : }
355 :
356 : /*
357 : * This means we will give a 0 until the first write
358 : * transaction, which is actually pretty reasonable.
359 : *
360 : * All modern databases will have the metadata.tdb from
361 : * the time of the first transaction in provision anyway.
362 : */
363 18757 : ret = partition_metadata_get_uint64(module,
364 : LDB_METADATA_SEQ_NUM,
365 : value,
366 : 0);
367 18757 : if (ret == LDB_SUCCESS) {
368 18757 : ret = partition_read_unlock(module);
369 : } else {
370 : /* Don't overwrite the error code */
371 0 : partition_read_unlock(module);
372 : }
373 18757 : return ret;
374 :
375 : }
376 :
377 :
378 : /*
379 : * Increment the sequence number, returning the new sequence number
380 : */
381 869128 : int partition_metadata_sequence_number_increment(struct ldb_module *module, uint64_t *value)
382 : {
383 : struct partition_private_data *data;
384 : int ret;
385 :
386 869128 : data = talloc_get_type_abort(ldb_module_get_private(module),
387 : struct partition_private_data);
388 869128 : if (!data || !data->metadata) {
389 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
390 : "partition_metadata: metadata not initialized");
391 : }
392 :
393 869128 : if (data->metadata->in_transaction == 0) {
394 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
395 : "partition_metadata: increment sequence number without transaction");
396 : }
397 :
398 869128 : ret = partition_metadata_get_uint64(module, LDB_METADATA_SEQ_NUM, value, 0);
399 869128 : if (ret != LDB_SUCCESS) {
400 0 : return ret;
401 : }
402 :
403 869128 : if (*value == 0) {
404 : /*
405 : * We are in a transaction now, so we can get the
406 : * sequence number from the partitions.
407 : */
408 149 : ret = partition_metadata_set_sequence_number(module);
409 149 : if (ret != LDB_SUCCESS) {
410 0 : return ret;
411 : }
412 :
413 149 : ret = partition_metadata_get_uint64(module,
414 : LDB_METADATA_SEQ_NUM,
415 : value, 0);
416 149 : if (ret != LDB_SUCCESS) {
417 0 : return ret;
418 : }
419 : }
420 :
421 869128 : (*value)++;
422 869128 : ret = partition_metadata_set_uint64(module, LDB_METADATA_SEQ_NUM, *value, false);
423 869128 : return ret;
424 : }
425 : /*
426 : lock the database for read - use by partition_lock_read
427 : */
428 11288945 : int partition_metadata_read_lock(struct ldb_module *module)
429 : {
430 10109793 : struct partition_private_data *data
431 11288945 : = talloc_get_type_abort(ldb_module_get_private(module),
432 : struct partition_private_data);
433 11288945 : struct tdb_context *tdb = NULL;
434 11288945 : int tdb_ret = 0;
435 : int ret;
436 :
437 11288945 : if (!data || !data->metadata || !data->metadata->db) {
438 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
439 : "partition_metadata: metadata not initialized");
440 : }
441 11288945 : tdb = data->metadata->db->tdb;
442 :
443 17900747 : if (tdb_transaction_active(tdb) == false &&
444 7279408 : data->metadata->read_lock_count == 0) {
445 5745161 : tdb_ret = tdb_lockall_read(tdb);
446 : }
447 11288945 : if (tdb_ret == 0) {
448 11288945 : data->metadata->read_lock_count++;
449 11288945 : return LDB_SUCCESS;
450 : } else {
451 : /* Sadly we can't call ltdb_err_map(tdb_error(tdb)); */
452 0 : ret = LDB_ERR_BUSY;
453 : }
454 0 : ldb_debug_set(ldb_module_get_ctx(module),
455 : LDB_DEBUG_FATAL,
456 : "Failure during partition_metadata_read_lock(): %s",
457 : tdb_errorstr(tdb));
458 0 : return ret;
459 : }
460 :
461 : /*
462 : unlock the database after a partition_metadata_lock_read()
463 : */
464 11288945 : int partition_metadata_read_unlock(struct ldb_module *module)
465 : {
466 10109793 : struct partition_private_data *data
467 11288945 : = talloc_get_type_abort(ldb_module_get_private(module),
468 : struct partition_private_data);
469 11288945 : struct tdb_context *tdb = NULL;
470 :
471 11288945 : data = talloc_get_type_abort(ldb_module_get_private(module),
472 : struct partition_private_data);
473 11288945 : if (!data || !data->metadata || !data->metadata->db) {
474 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
475 : "partition_metadata: metadata not initialized");
476 : }
477 11288945 : tdb = data->metadata->db->tdb;
478 :
479 17900747 : if (!tdb_transaction_active(tdb) &&
480 7279408 : data->metadata->read_lock_count == 1) {
481 5745161 : tdb_unlockall_read(tdb);
482 5745161 : data->metadata->read_lock_count--;
483 5745161 : return 0;
484 : }
485 5543784 : data->metadata->read_lock_count--;
486 5543784 : return 0;
487 : }
488 :
489 :
490 : /*
491 : * Transaction start
492 : */
493 244616 : int partition_metadata_start_trans(struct ldb_module *module)
494 : {
495 : struct partition_private_data *data;
496 : struct tdb_context *tdb;
497 :
498 244616 : data = talloc_get_type_abort(ldb_module_get_private(module),
499 : struct partition_private_data);
500 244616 : if (!data || !data->metadata || !data->metadata->db) {
501 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
502 : "partition_metadata: metadata not initialized");
503 : }
504 244616 : tdb = data->metadata->db->tdb;
505 :
506 244616 : if (tdb_transaction_start(tdb) != 0) {
507 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
508 : tdb_errorstr(tdb));
509 : }
510 :
511 244616 : data->metadata->in_transaction++;
512 :
513 244616 : return LDB_SUCCESS;
514 : }
515 :
516 :
517 : /*
518 : * Transaction prepare commit
519 : */
520 212233 : int partition_metadata_prepare_commit(struct ldb_module *module)
521 : {
522 : struct partition_private_data *data;
523 : struct tdb_context *tdb;
524 :
525 212233 : data = talloc_get_type_abort(ldb_module_get_private(module),
526 : struct partition_private_data);
527 212233 : if (!data || !data->metadata || !data->metadata->db) {
528 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
529 : "partition_metadata: metadata not initialized");
530 : }
531 212233 : tdb = data->metadata->db->tdb;
532 :
533 212233 : if (data->metadata->in_transaction == 0) {
534 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
535 : "partition_metadata: not in transaction");
536 : }
537 :
538 212233 : if (tdb_transaction_prepare_commit(tdb) != 0) {
539 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
540 : tdb_errorstr(tdb));
541 : }
542 :
543 212233 : return LDB_SUCCESS;
544 : }
545 :
546 :
547 : /*
548 : * Transaction end
549 : */
550 212501 : int partition_metadata_end_trans(struct ldb_module *module)
551 : {
552 : struct partition_private_data *data;
553 : struct tdb_context *tdb;
554 :
555 212501 : data = talloc_get_type_abort(ldb_module_get_private(module),
556 : struct partition_private_data);
557 212501 : if (!data || !data->metadata || !data->metadata->db) {
558 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
559 : "partition_metadata: metadata not initialized");
560 : }
561 212501 : tdb = data->metadata->db->tdb;
562 :
563 212501 : if (data->metadata->in_transaction == 0) {
564 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
565 : "partition_metadata: not in transaction");
566 : }
567 :
568 212501 : data->metadata->in_transaction--;
569 :
570 212501 : if (tdb_transaction_commit(tdb) != 0) {
571 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
572 : tdb_errorstr(tdb));
573 : }
574 :
575 212501 : return LDB_SUCCESS;
576 : }
577 :
578 :
579 : /*
580 : * Transaction delete
581 : */
582 32114 : int partition_metadata_del_trans(struct ldb_module *module)
583 : {
584 : struct partition_private_data *data;
585 : struct tdb_context *tdb;
586 :
587 32114 : data = talloc_get_type_abort(ldb_module_get_private(module),
588 : struct partition_private_data);
589 32114 : if (!data || !data->metadata || !data->metadata->db) {
590 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
591 : "partition_metadata: metadata not initialized");
592 : }
593 32114 : tdb = data->metadata->db->tdb;
594 :
595 32114 : if (data->metadata->in_transaction == 0) {
596 0 : return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
597 : "partition_metadata: not in transaction");
598 : }
599 :
600 32114 : data->metadata->in_transaction--;
601 :
602 32114 : tdb_transaction_cancel(tdb);
603 :
604 32114 : return LDB_SUCCESS;
605 : }
|