LCOV - code coverage report
Current view: top level - lib/tdb/test - run-rdlock-upgrade.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 73 75 97.3 %
Date: 2024-04-13 12:30:31 Functions: 4 4 100.0 %

          Line data    Source code
       1             : #include "../common/io.c"
       2             : #include "../common/tdb.c"
       3             : #include "../common/lock.c"
       4             : #include "../common/freelist.c"
       5             : #include "../common/traverse.c"
       6             : #include "../common/transaction.c"
       7             : #include "../common/error.c"
       8             : #include "../common/open.c"
       9             : #include "../common/check.c"
      10             : #include "../common/hash.c"
      11             : #include "../common/mutex.c"
      12             : #include "tap-interface.h"
      13             : #include <stdlib.h>
      14             : #include <sys/types.h>
      15             : #include <sys/wait.h>
      16             : #include <stdarg.h>
      17             : #include "logging.h"
      18             : 
      19             : static TDB_DATA key, data;
      20             : 
      21           1 : static void do_chainlock(const char *name, int tdb_flags, int up, int down)
      22             : {
      23             :         struct tdb_context *tdb;
      24             :         int ret;
      25             :         ssize_t nread, nwritten;
      26           1 :         char c = 0;
      27             : 
      28           1 :         tdb = tdb_open_ex(name, 3, tdb_flags,
      29             :                           O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
      30           1 :         ok(tdb, "tdb_open_ex should succeed");
      31             : 
      32           1 :         ret = tdb_chainlock_read(tdb, key);
      33           1 :         ok(ret == 0, "tdb_chainlock_read should succeed");
      34             : 
      35           1 :         nwritten = write(up, &c, sizeof(c));
      36           1 :         ok(nwritten == sizeof(c), "write should succeed");
      37             : 
      38           1 :         nread = read(down, &c, sizeof(c));
      39           1 :         ok(nread == 0, "read should succeed");
      40             : 
      41           1 :         exit(0);
      42             : }
      43             : 
      44           1 : static void do_trylock(const char *name, int tdb_flags, int up, int down)
      45             : {
      46             :         struct tdb_context *tdb;
      47             :         int ret;
      48             :         ssize_t nread, nwritten;
      49           1 :         char c = 0;
      50             : 
      51           1 :         tdb = tdb_open_ex(name, 3, tdb_flags,
      52             :                           O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
      53           1 :         ok(tdb, "tdb_open_ex should succeed");
      54             : 
      55             :         /*
      56             :          * tdb used to have a bug where with fcntl locks an upgrade
      57             :          * from a readlock to writelock did not check for the
      58             :          * underlying fcntl lock. Mutexes don't distinguish between
      59             :          * readlocks and writelocks, so that bug does not apply here.
      60             :          */
      61             : 
      62           1 :         ret = tdb_chainlock_read(tdb, key);
      63           1 :         ok(ret == 0, "tdb_chainlock_read should succeed");
      64             : 
      65           1 :         ret = tdb_chainlock_nonblock(tdb, key);
      66           1 :         ok(ret == -1, "tdb_chainlock_nonblock should fail");
      67             : 
      68           1 :         nwritten = write(up, &c, sizeof(c));
      69           1 :         ok(nwritten == sizeof(c), "write should succeed");
      70             : 
      71           1 :         nread = read(down, &c, sizeof(c));
      72           1 :         ok(nread == 0, "read should succeed");
      73             : 
      74           1 :         exit(0);
      75             : }
      76             : 
      77           1 : static int do_tests(const char *name, int tdb_flags)
      78             : {
      79             :         int ret;
      80             :         pid_t chainlock_child, store_child;
      81             :         int chainlock_down[2];
      82             :         int chainlock_up[2];
      83             :         int store_down[2];
      84             :         int store_up[2];
      85             :         char c;
      86             :         ssize_t nread;
      87             : 
      88           1 :         key.dsize = strlen("hi");
      89           1 :         key.dptr = discard_const_p(uint8_t, "hi");
      90           1 :         data.dsize = strlen("world");
      91           1 :         data.dptr = discard_const_p(uint8_t, "world");
      92             : 
      93           1 :         ret = pipe(chainlock_down);
      94           1 :         ok(ret == 0, "pipe should succeed");
      95             : 
      96           1 :         ret = pipe(chainlock_up);
      97           1 :         ok(ret == 0, "pipe should succeed");
      98             : 
      99           1 :         ret = pipe(store_down);
     100           1 :         ok(ret == 0, "pipe should succeed");
     101             : 
     102           1 :         ret = pipe(store_up);
     103           1 :         ok(ret == 0, "pipe should succeed");
     104             : 
     105           1 :         chainlock_child = fork();
     106           2 :         ok(chainlock_child != -1, "fork should succeed");
     107             : 
     108           2 :         if (chainlock_child == 0) {
     109           1 :                 close(chainlock_up[0]);
     110           1 :                 close(chainlock_down[1]);
     111           1 :                 close(store_up[0]);
     112           1 :                 close(store_up[1]);
     113           1 :                 close(store_down[0]);
     114           1 :                 close(store_down[1]);
     115           1 :                 do_chainlock(name, tdb_flags,
     116             :                              chainlock_up[1], chainlock_down[0]);
     117           0 :                 exit(0);
     118             :         }
     119           1 :         close(chainlock_up[1]);
     120           1 :         close(chainlock_down[0]);
     121             : 
     122           1 :         nread = read(chainlock_up[0], &c, sizeof(c));
     123           1 :         ok(nread == sizeof(c), "read should succeed");
     124             : 
     125             :         /*
     126             :          * Now we have a process holding a chain read lock. Start
     127             :          * another process trying to write lock. This should fail.
     128             :          */
     129             : 
     130           1 :         store_child = fork();
     131           2 :         ok(store_child != -1, "fork should succeed");
     132             : 
     133           2 :         if (store_child == 0) {
     134           1 :                 close(chainlock_up[0]);
     135           1 :                 close(chainlock_down[1]);
     136           1 :                 close(store_up[0]);
     137           1 :                 close(store_down[1]);
     138           1 :                 do_trylock(name, tdb_flags,
     139             :                            store_up[1], store_down[0]);
     140           0 :                 exit(0);
     141             :         }
     142           1 :         close(store_up[1]);
     143           1 :         close(store_down[0]);
     144             : 
     145           1 :         nread = read(store_up[0], &c, sizeof(c));
     146           1 :         ok(nread == sizeof(c), "read should succeed");
     147             : 
     148           1 :         close(chainlock_up[0]);
     149           1 :         close(chainlock_down[1]);
     150           1 :         close(store_up[0]);
     151           1 :         close(store_down[1]);
     152           1 :         diag("%s tests done", name);
     153           1 :         return exit_status();
     154             : }
     155             : 
     156           1 : int main(int argc, char *argv[])
     157             : {
     158             :         int ret;
     159             : 
     160           1 :         ret = do_tests("rdlock-upgrade.tdb",
     161             :                        TDB_CLEAR_IF_FIRST |
     162             :                        TDB_INCOMPATIBLE_HASH);
     163           1 :         ok(ret == 0, "rdlock-upgrade.tdb tests should succeed");
     164             : 
     165           1 :         return exit_status();
     166             : }

Generated by: LCOV version 1.14