Fix the "too many fcntl locks" scalability problem raised by tridge.
authorJeremy Allison <jra@samba.org>
Thu, 19 Feb 2004 01:55:21 +0000 (01:55 +0000)
committerJeremy Allison <jra@samba.org>
Thu, 19 Feb 2004 01:55:21 +0000 (01:55 +0000)
I've now tested this in daemon mode and also on xinetd and I'm pretty
sure it's working.
Jeremy.

source/smbd/server.c
source/smbd/session.c
source/tdb/tdb.c
source/tdb/tdbutil.c

index be59e92cd7bbcf2b9877021c3330fc5766625fcd..1de33739b24bd69c75d9a604890eb9bcd603f9b4 100644 (file)
@@ -405,10 +405,10 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
                                   done correctly in the process.  */
                                reset_globals_after_fork();
 
-                               /* tdb needs special fork handling */
+                               /* tdb needs special fork handling - remove CLEAR_IF_FIRST flags */
                                if (tdb_reopen_all() == -1) {
                                        DEBUG(0,("tdb_reopen_all failed.\n"));
-                                       return False;
+                                       smb_panic("tdb_reopen_all failed.");
                                }
 
                                return True; 
@@ -809,9 +809,27 @@ void build_options(BOOL screen);
        if (is_daemon)
                pidfile_create("smbd");
 
+       /* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */
        if (!message_init())
                exit(1);
 
+       if (!session_init())
+               exit(1);
+
+       if (conn_tdb_ctx() == NULL)
+               exit(1);
+
+       if (!locking_init(0))
+               exit(1);
+
+       if (!share_info_db_init())
+               exit(1);
+
+       namecache_enable();
+
+       if (!init_registry())
+               exit(1);
+
        if (!print_backend_init())
                exit(1);
 
@@ -832,17 +850,6 @@ void build_options(BOOL screen);
         * everything after this point is run after the fork()
         */ 
 
-       namecache_enable();
-
-       if (!locking_init(0))
-               exit(1);
-
-       if (!share_info_db_init())
-               exit(1);
-
-       if (!init_registry())
-               exit(1);
-
        /* Initialise the password backed before the global_sam_sid
           to ensure that we fetch from ldap before we make a domain sid up */
 
@@ -891,4 +898,3 @@ void build_options(BOOL screen);
        exit_server("normal exit");
        return(0);
 }
-
index a811a6e305a8aeb8eceba35e4dba16e95b47000e..61118f13dd9b2018f3c666cc851aade88ea7745c 100644 (file)
 #include "includes.h"
 
 static TDB_CONTEXT *tdb;
+
+BOOL session_init(void)
+{
+       if (tdb)
+               return True;
+
+       tdb = tdb_open_ex(lock_path("sessionid.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, 
+                      O_RDWR | O_CREAT, 0644, smbd_tdb_log);
+       if (!tdb) {
+               DEBUG(1,("session_init: failed to open sessionid tdb\n"));
+               return False;
+       }
+
+       return True;
+}
+
 /* called when a session is created */
 BOOL session_claim(user_struct *vuser)
 {
@@ -52,14 +68,8 @@ BOOL session_claim(user_struct *vuser)
                return True;
        }
 
-       if (!tdb) {
-               tdb = tdb_open_ex(lock_path("sessionid.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, 
-                              O_RDWR | O_CREAT, 0644, smbd_tdb_log);
-               if (!tdb) {
-                       DEBUG(1,("session_claim: failed to open sessionid tdb\n"));
-                       return False;
-               }
-       }
+       if (!session_init())
+               return False;
 
        ZERO_STRUCT(sessionid);
 
@@ -190,7 +200,7 @@ void session_yield(user_struct *vuser)
 
 static BOOL session_traverse(int (*fn)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *), void *state)
 {
-       if (!tdb) {
+       if (!session_init()) {
                DEBUG(3, ("No tdb opened\n"));
                return False;
        }
@@ -238,4 +248,3 @@ int list_sessions(struct sessionid **session_list)
        *session_list = sesslist.sessions;
        return sesslist.count;
 }
-               
index 7ad39175acb0fe8fa01baeee0ca103d5dc940413..7b10cfb3777fc7db46e627f36351ec9caffa2912 100644 (file)
@@ -1705,7 +1705,7 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
 {
        TDB_CONTEXT *tdb;
        struct stat st;
-       int rev = 0, locked;
+       int rev = 0, locked = 0;
        unsigned char *vp;
        u32 vertest;
 
@@ -1763,8 +1763,8 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
        }
 
        /* we need to zero database if we are the only one with it open */
-       if ((locked = (tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0) == 0))
-           && (tdb_flags & TDB_CLEAR_IF_FIRST)) {
+       if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
+               (locked = (tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0) == 0))) {
                open_flags |= O_CREAT;
                if (ftruncate(tdb->fd, 0) == -1) {
                        TDB_LOG((tdb, 0, "tdb_open_ex: "
@@ -1837,10 +1837,19 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
                                 name, strerror(errno)));
                        goto fail;
                }
+
        }
-       /* leave this lock in place to indicate it's in use */
-       if (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1)
-               goto fail;
+
+       /* We always need to do this if the CLEAR_IF_FIRST flag is set, even if
+          we didn't get the initial exclusive lock as we need to let all other
+          users know we're using it. */
+
+       if (tdb_flags & TDB_CLEAR_IF_FIRST) {
+               /* leave this lock in place to indicate it's in use */
+               if (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1)
+                       goto fail;
+       }
+
 
  internal:
        /* Internal (memory-only) databases skip all the code above to
@@ -2018,12 +2027,14 @@ void tdb_logging_function(TDB_CONTEXT *tdb, void (*fn)(TDB_CONTEXT *, int , cons
 }
 
 
-/* reopen a tdb - this is used after a fork to ensure that we have an independent
+/* reopen a tdb - this can be used after a fork to ensure that we have an independent
    seek pointer from our parent and to re-establish locks */
 int tdb_reopen(TDB_CONTEXT *tdb)
 {
        struct stat st;
 
+       if (tdb->flags & TDB_INTERNAL)
+               return 0; /* Nothing to do. */
        if (tdb_munmap(tdb) != 0) {
                TDB_LOG((tdb, 0, "tdb_reopen: munmap failed (%s)\n", strerror(errno)));
                goto fail;
@@ -2044,7 +2055,7 @@ int tdb_reopen(TDB_CONTEXT *tdb)
                goto fail;
        }
        tdb_mmap(tdb);
-       if (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1) {
+       if ((tdb->flags & TDB_CLEAR_IF_FIRST) && (tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1)) {
                TDB_LOG((tdb, 0, "tdb_reopen: failed to obtain active lock\n"));
                goto fail;
        }
@@ -2062,7 +2073,10 @@ int tdb_reopen_all(void)
        TDB_CONTEXT *tdb;
 
        for (tdb=tdbs; tdb; tdb = tdb->next) {
-               if (tdb_reopen(tdb) != 0) return -1;
+               /* Ensure no clear-if-first. */
+               tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+               if (tdb_reopen(tdb) != 0)
+                       return -1;
        }
 
        return 0;
index bae9a8b9d404fdc81ee1fa310bf7199ab5813741..304bf9c816d6b7788f55c2bbd7f772f07d1bd70a 100644 (file)
@@ -826,5 +826,3 @@ void tdb_search_list_free(TDB_LIST_NODE* node)
                node = next_node;
        };
 }
-
-