I'm currently designing a new locking system (using a tdb database!)
authorAndrew Tridgell <tridge@samba.org>
Mon, 10 Jan 2000 14:41:20 +0000 (14:41 +0000)
committerAndrew Tridgell <tridge@samba.org>
Mon, 10 Jan 2000 14:41:20 +0000 (14:41 +0000)
that will make us match NT semantics exactly and do away with the
horrible fd multiplexing in smbd.

this is some diag stuff to get me started.

- added the ability to do read or write locks in clientgen.c

- added a LOCK4 test to smbtorture. This produces a report on the server
and its locking capabilities. For example, NT4 gives this:

the same process cannot set overlapping write locks
the same process can set overlapping read locks
a different connection cannot set overlapping write locks
a different connection can set overlapping read locks
a different pid cannot set overlapping write locks
a different pid can set overlapping read locks
the same process can set the same read lock twice
the same process cannot set the same write lock twice
the same process cannot override a read lock with a write lock
the same process can override a write lock with a read lock
a different pid cannot override a write lock with a read lock
the same process cannot coalesce read locks
this server does strict write locking
this server does strict read locking

whereas Samba currently gives this:

the same process can set overlapping write locks
the same process can set overlapping read locks
a different connection cannot set overlapping write locks
a different connection can set overlapping read locks
a different pid can set overlapping write locks
a different pid can set overlapping read locks
the same process can set the same read lock twice
the same process can set the same write lock twice
the same process can override a read lock with a write lock
the same process can override a write lock with a read lock
a different pid can override a write lock with a read lock
the same process can coalesce read locks
this server does strict write locking
this server does strict read locking

win95 gives this - I don't understand why!

the same process cannot set overlapping write locks
the same process cannot set overlapping read locks
a different connection cannot set overlapping write locks
a different connection cannot set overlapping read locks
a different pid cannot set overlapping write locks
a different pid cannot set overlapping read locks
the same process cannot set the same read lock twice
the same process cannot set the same write lock twice
the same process cannot override a read lock with a write lock
the same process cannot override a write lock with a read lock
a different pid cannot override a write lock with a read lock
the same process cannot coalesce read locks
this server does strict write locking
this server does strict read locking

source/include/proto.h
source/libsmb/clientgen.c
source/utils/torture.c

index 0388ef6911326b74bbf6317652d0a2f1a1e3fce7..2db1f3ed027fce0c8052c99c601cf273b829ef47 100644 (file)
@@ -587,8 +587,10 @@ BOOL cli_rmdir(struct cli_state *cli, char *dname);
 int cli_nt_create(struct cli_state *cli, char *fname);
 int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode);
 BOOL cli_close(struct cli_state *cli, int fnum);
-BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout);
-BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout);
+BOOL cli_lock(struct cli_state *cli, int fnum, 
+             uint32 offset, uint32 len, int timeout, int locktype);
+BOOL cli_unlock(struct cli_state *cli, int fnum, 
+               uint32 offset, uint32 len, int timeout, int locktype);
 size_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size);
 ssize_t cli_write(struct cli_state *cli,
                  int fnum, uint16 write_mode,
@@ -2972,6 +2974,7 @@ int smbw_stat(const char *fname, struct stat *st);
 
 /*The following definitions come from  tdb/tdb.c  */
 
+char *tdb_error(TDB_CONTEXT *tdb);
 int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf);
 TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
 int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
index 3b6403fe733397d0ea5174fbb29768e93c72ead6..bf610a7ff7c75287b8c276388db1363cfd235bbd 100644 (file)
@@ -1344,7 +1344,8 @@ BOOL cli_close(struct cli_state *cli, int fnum)
 /****************************************************************************
   lock a file
 ****************************************************************************/
-BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
+BOOL cli_lock(struct cli_state *cli, int fnum, 
+             uint32 offset, uint32 len, int timeout, int locktype)
 {
        char *p;
         int saved_timeout = cli->timeout;
@@ -1360,7 +1361,7 @@ BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int ti
 
        CVAL(cli->outbuf,smb_vwv0) = 0xFF;
        SSVAL(cli->outbuf,smb_vwv2,fnum);
-       CVAL(cli->outbuf,smb_vwv3) = 0;
+       CVAL(cli->outbuf,smb_vwv3) = (locktype == F_RDLCK? 1 : 0);
        SIVALS(cli->outbuf, smb_vwv4, timeout);
        SSVAL(cli->outbuf,smb_vwv6,0);
        SSVAL(cli->outbuf,smb_vwv7,1);
@@ -1390,7 +1391,8 @@ BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int ti
 /****************************************************************************
   unlock a file
 ****************************************************************************/
-BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
+BOOL cli_unlock(struct cli_state *cli, int fnum, 
+               uint32 offset, uint32 len, int timeout, int locktype)
 {
        char *p;
 
@@ -1405,7 +1407,7 @@ BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int
 
        CVAL(cli->outbuf,smb_vwv0) = 0xFF;
        SSVAL(cli->outbuf,smb_vwv2,fnum);
-       CVAL(cli->outbuf,smb_vwv3) = 0;
+       CVAL(cli->outbuf,smb_vwv3) = (locktype == F_RDLCK? 1 : 0);
        SIVALS(cli->outbuf, smb_vwv4, timeout);
        SSVAL(cli->outbuf,smb_vwv6,1);
        SSVAL(cli->outbuf,smb_vwv7,0);
index 4375cbe231f3d8e4dea6c050f64a945acd31f7f9..b9f0d76581d449c6ca3a5454fe4526eb3261adb8 100644 (file)
@@ -168,7 +168,7 @@ static BOOL check_error(struct cli_state *c,
 
 static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
 {
-       while (!cli_lock(c, fnum, offset, len, -1)) {
+       while (!cli_lock(c, fnum, offset, len, -1, F_WRLCK)) {
                if (!check_error(c, ERRDOS, ERRlock, 0)) return False;
        }
        return True;
@@ -242,7 +242,7 @@ static BOOL rw_torture(struct cli_state *c)
                        printf("unlink failed (%s)\n", cli_errstr(c));
                }
 
-               if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
+               if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1, F_WRLCK)) {
                        printf("unlock failed (%s)\n", cli_errstr(c));
                }
        }
@@ -436,13 +436,13 @@ static void run_locktest1(int dummy)
                return;
        }
 
-       if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
+       if (!cli_lock(&cli1, fnum1, 0, 4, 0, F_WRLCK)) {
                printf("lock1 failed (%s)\n", cli_errstr(&cli1));
                return;
        }
 
 
-       if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
+       if (cli_lock(&cli2, fnum3, 0, 4, 0, F_WRLCK)) {
                printf("lock2 succeeded! This is a locking bug\n");
                return;
        } else {
@@ -452,7 +452,7 @@ static void run_locktest1(int dummy)
 
        printf("Testing lock timeouts\n");
        t1 = time(NULL);
-       if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
+       if (cli_lock(&cli2, fnum3, 0, 4, 10*1000, F_WRLCK)) {
                printf("lock3 succeeded! This is a locking bug\n");
                return;
        } else {
@@ -469,7 +469,7 @@ static void run_locktest1(int dummy)
                return;
        }
 
-       if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
+       if (cli_lock(&cli2, fnum3, 0, 4, 0, F_WRLCK)) {
                printf("lock4 succeeded! This is a locking bug\n");
                return;
        } else {
@@ -550,12 +550,12 @@ static void run_locktest2(int dummy)
 
        cli_setpid(&cli, 1);
 
-       if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
+       if (!cli_lock(&cli, fnum1, 0, 4, 0, F_WRLCK)) {
                printf("lock1 failed (%s)\n", cli_errstr(&cli));
                return;
        }
 
-       if (cli_lock(&cli, fnum2, 0, 4, 0)) {
+       if (cli_lock(&cli, fnum2, 0, 4, 0, F_WRLCK)) {
                printf("lock2 succeeded! This is a locking bug\n");
        } else {
                if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
@@ -563,11 +563,11 @@ static void run_locktest2(int dummy)
 
        cli_setpid(&cli, 2);
 
-       if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
+       if (cli_unlock(&cli, fnum1, 0, 4, 0, F_WRLCK)) {
                printf("unlock1 succeeded! This is a locking bug\n");
        }
 
-       if (cli_lock(&cli, fnum3, 0, 4, 0)) {
+       if (cli_lock(&cli, fnum3, 0, 4, 0, F_WRLCK)) {
                printf("lock3 succeeded! This is a locking bug\n");
        } else {
                if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
@@ -633,14 +633,14 @@ static void run_locktest3(int dummy)
 
        for (offset=i=0;i<numops;i++) {
                NEXT_OFFSET;
-               if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
+               if (!cli_lock(&cli1, fnum1, offset-1, 1, 0, F_WRLCK)) {
                        printf("lock1 %d failed (%s)\n", 
                               i,
                               cli_errstr(&cli1));
                        return;
                }
 
-               if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
+               if (!cli_lock(&cli2, fnum2, offset-2, 1, 0, F_WRLCK)) {
                        printf("lock2 %d failed (%s)\n", 
                               i,
                               cli_errstr(&cli1));
@@ -651,22 +651,22 @@ static void run_locktest3(int dummy)
        for (offset=i=0;i<numops;i++) {
                NEXT_OFFSET;
 
-               if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
+               if (cli_lock(&cli1, fnum1, offset-2, 1, 0, F_WRLCK)) {
                        printf("error: lock1 %d succeeded!\n", i);
                        return;
                }
 
-               if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
+               if (cli_lock(&cli2, fnum2, offset-1, 1, 0, F_WRLCK)) {
                        printf("error: lock2 %d succeeded!\n", i);
                        return;
                }
 
-               if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
+               if (cli_lock(&cli1, fnum1, offset-1, 1, 0, F_WRLCK)) {
                        printf("error: lock3 %d succeeded!\n", i);
                        return;
                }
 
-               if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
+               if (cli_lock(&cli2, fnum2, offset-2, 1, 0, F_WRLCK)) {
                        printf("error: lock4 %d succeeded!\n", i);
                        return;
                }
@@ -675,14 +675,14 @@ static void run_locktest3(int dummy)
        for (offset=i=0;i<numops;i++) {
                NEXT_OFFSET;
 
-               if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
+               if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0, F_WRLCK)) {
                        printf("unlock1 %d failed (%s)\n", 
                               i,
                               cli_errstr(&cli1));
                        return;
                }
 
-               if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
+               if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0, F_WRLCK)) {
                        printf("unlock2 %d failed (%s)\n", 
                               i,
                               cli_errstr(&cli1));
@@ -710,6 +710,114 @@ static void run_locktest3(int dummy)
 }
 
 
+/*
+  looks at overlapping locks
+*/
+static void run_locktest4(int dummy)
+{
+       static struct cli_state cli1, cli2;
+       char *fname = "\\lockt4.lck";
+       int fnum1, fnum2;
+       BOOL ret;
+       char buf[1000];
+
+       if (!open_connection(&cli1) || !open_connection(&cli2)) {
+               return;
+       }
+       cli_sockopt(&cli1, sockops);
+       cli_sockopt(&cli2, sockops);
+
+       printf("starting locktest4\n");
+
+       cli_unlink(&cli1, fname);
+
+       fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+       fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+
+       memset(buf, 0, sizeof(buf));
+
+       if (cli_write(&cli1, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
+               printf("Failed to create file\n");
+               goto fail;
+       }
+
+             cli_lock(&cli1, fnum1, 0, 4, 0, F_WRLCK);
+       ret = cli_lock(&cli1, fnum1, 2, 4, 0, F_WRLCK);
+       printf("the same process %s set overlapping write locks\n", ret?"can":"cannot");
+           
+             cli_lock(&cli1, fnum1, 10, 4, 0, F_RDLCK);
+       ret = cli_lock(&cli1, fnum1, 12, 4, 0, F_RDLCK);
+       printf("the same process %s set overlapping read locks\n", ret?"can":"cannot");
+
+             cli_lock(&cli1, fnum1, 20, 4, 0, F_WRLCK);
+       ret = cli_lock(&cli2, fnum2, 22, 4, 0, F_WRLCK);
+       printf("a different connection %s set overlapping write locks\n", ret?"can":"cannot");
+           
+             cli_lock(&cli1, fnum1, 30, 4, 0, F_RDLCK);
+       ret = cli_lock(&cli2, fnum2, 32, 4, 0, F_RDLCK);
+       printf("a different connection %s set overlapping read locks\n", ret?"can":"cannot");
+       
+       cli_setpid(&cli1, 1);
+             cli_lock(&cli1, fnum1, 40, 4, 0, F_WRLCK);
+       cli_setpid(&cli1, 2);
+       ret = cli_lock(&cli1, fnum1, 42, 4, 0, F_WRLCK);
+       printf("a different pid %s set overlapping write locks\n", ret?"can":"cannot");
+           
+       cli_setpid(&cli1, 1);
+             cli_lock(&cli1, fnum1, 50, 4, 0, F_RDLCK);
+       cli_setpid(&cli1, 2);
+       ret = cli_lock(&cli1, fnum1, 52, 4, 0, F_RDLCK);
+       printf("a different pid %s set overlapping read locks\n", ret?"can":"cannot");
+
+             cli_lock(&cli1, fnum1, 60, 4, 0, F_RDLCK);
+       ret = cli_lock(&cli1, fnum1, 60, 4, 0, F_RDLCK);
+       printf("the same process %s set the same read lock twice\n", ret?"can":"cannot");
+
+             cli_lock(&cli1, fnum1, 70, 4, 0, F_WRLCK);
+       ret = cli_lock(&cli1, fnum1, 70, 4, 0, F_WRLCK);
+       printf("the same process %s set the same write lock twice\n", ret?"can":"cannot");
+
+             cli_lock(&cli1, fnum1, 80, 4, 0, F_RDLCK);
+       ret = cli_lock(&cli1, fnum1, 80, 4, 0, F_WRLCK);
+       printf("the same process %s override a read lock with a write lock\n", ret?"can":"cannot");
+
+             cli_lock(&cli1, fnum1, 90, 4, 0, F_WRLCK);
+       ret = cli_lock(&cli1, fnum1, 90, 4, 0, F_RDLCK);
+       printf("the same process %s override a write lock with a read lock\n", ret?"can":"cannot");
+
+       cli_setpid(&cli1, 1);
+             cli_lock(&cli1, fnum1, 100, 4, 0, F_WRLCK);
+       cli_setpid(&cli1, 2);
+       ret = cli_lock(&cli1, fnum1, 100, 4, 0, F_RDLCK);
+       printf("a different pid %s override a write lock with a read lock\n", ret?"can":"cannot");
+
+             cli_lock(&cli1, fnum1, 110, 4, 0, F_RDLCK);
+             cli_lock(&cli1, fnum1, 112, 4, 0, F_RDLCK);
+        ret = cli_unlock(&cli1, fnum1, 110, 6, 0, F_RDLCK);
+       printf("the same process %s coalesce read locks\n", ret?"can":"cannot");
+
+
+       cli_lock(&cli1, fnum1, 120, 4, 0, F_WRLCK);
+        ret = (cli_read(&cli2, fnum2, buf, 120, 4) == 4);
+       printf("this server %s strict write locking\n", ret?"doesn't do":"does");
+
+       cli_lock(&cli1, fnum1, 130, 4, 0, F_RDLCK);
+        ret = (cli_write(&cli2, fnum2, 0, buf, 130, 4) == 4);
+       printf("this server %s strict read locking\n", ret?"doesn't do":"does");
+
+
+
+ fail:
+       cli_close(&cli1, fnum1);
+       cli_close(&cli1, fnum2);
+       cli_unlink(&cli1, fname);
+       close_connection(&cli1);
+       close_connection(&cli2);
+
+       printf("finished locktest4\n");
+}
+
+
 /*
   this produces a matrix of deny mode behaviour
  */
@@ -1190,10 +1298,9 @@ static void run_trans2test(int dummy)
  */
 static void run_oplock(int dummy)
 {
-       static struct cli_state cli1, cli2;
+       static struct cli_state cli1;
        char *fname = "\\lockt1.lck";
-       char *fname2 = "\\lockt2.lck";
-       int fnum1, fnum2;
+       int fnum1;
 
        printf("starting oplock test\n");
 
@@ -1380,6 +1487,7 @@ static struct {
        {"LOCK1",  run_locktest1,  0},
        {"LOCK2",  run_locktest2,  0},
        {"LOCK3",  run_locktest3,  0},
+       {"LOCK4",  run_locktest4,  0},
        {"UNLINK", run_unlinktest, 0},
        {"BROWSE", run_browsetest, 0},
        {"ATTR",   run_attrtest,   0},