Merge DMAPI fixes from Tridge
authorAlexander Bokovoy <ab@samba.org>
Tue, 29 Jan 2008 14:43:49 +0000 (17:43 +0300)
committerAlexander Bokovoy <ab@samba.org>
Tue, 29 Jan 2008 14:43:49 +0000 (17:43 +0300)
Support cases when existing DMAPI session is stale. In this case we are creating another one.
The code differs from 3-0_ctdb branch in that we fail when it is not possible to create more
sessions and pretend that file is offline. This allows to escape endless loop in vfs_tsmsm.c.
(This used to be commit 5efb57d904e25e68b09a567e260292439ad9c095)

source3/modules/vfs_tsmsm.c
source3/smbd/dmapi.c

index 40b8c3adad8d7d724486ed23a75cc3fd8ba07c40..3badaa3923f9a3d89cb17b2fc05982795771cc4b 100644 (file)
@@ -141,8 +141,9 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
        size_t dmhandle_len = 0;
        size_t rlen;
        dm_attrname_t dmname;
-       int ret;
+       int ret, lerrno;
        bool offline;
+       char buf[1];
 
         /* if the file has more than FILE_IS_ONLINE_RATIO of blocks available,
           then assume it is not offline (it may not be 100%, as it could be sparse) */
@@ -179,8 +180,26 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
        memset(&dmname, 0, sizeof(dmname));
        strlcpy((char *)&dmname.an_chars[0], tsmd->attrib_name, sizeof(dmname.an_chars));
 
-       ret = dm_get_dmattr(*dmsession_id, dmhandle, dmhandle_len, 
-                           DM_NO_TOKEN, &dmname, 0, NULL, &rlen);
+       lerrno = 0;
+
+       do {
+               ret = dm_get_dmattr(*dmsession_id, dmhandle, dmhandle_len, 
+                                   DM_NO_TOKEN, &dmname, sizeof(buf), buf, &rlen);
+               if (ret == -1 && errno == EINVAL) {
+                       DEBUG(0, ("Stale DMAPI session, re-creating it.\n"));
+                       lerrno = EINVAL;
+                       if (dmapi_new_session()) {
+                               sessionp = dmapi_get_current_session();
+                       } else {
+                               DEBUG(0, 
+                                     ("Unable to re-create DMAPI session, assuming offline (%s) - %s\n", 
+                                      path, strerror(errno)));
+                               offline = true;
+                               dm_handle_free(dmhandle, dmhandle_len);
+                               goto done;
+                       }
+               }
+       } while (ret == -1 && lerrno == EINVAL);
 
        /* its offline if the specified DMAPI attribute exists */
        offline = (ret == 0 || (ret == -1 && errno == E2BIG));
index a410748ccfd0db7d8046769273db36b39915833f..8d43e0a9d1e9f51aa23c6a3a60560f3f7b6c1227 100644 (file)
@@ -47,7 +47,7 @@ const void * dmapi_get_current_session(void) { return NULL; }
 #define DMAPI_TRACE 10
 
 static dm_sessid_t samba_dmapi_session = DM_NO_SESSION;
-
+static unsigned session_num;
 
 /* 
    Initialise DMAPI session. The session is persistant kernel state, 
@@ -61,23 +61,41 @@ static int dmapi_init_session(void)
        uint        nsessions = 5;
        dm_sessid_t *sessions = NULL;
        char    *version;
+       char    *session_name;
+       TALLOC_CTX *tmp_ctx = talloc_new(NULL);
 
        int i, err;
 
+       if (session_num == 0) {
+               session_name = DMAPI_SESSION_NAME;
+       } else {
+               session_name = talloc_asprintf(tmp_ctx, "%s%u", DMAPI_SESSION_NAME,
+                                              session_num);
+       }
+
+       if (session_name == NULL) {
+               DEBUG(0,("Out of memory in dmapi_init_session\n"));
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+
        if (dm_init_service(&version) < 0) {
                DEBUG(0, ("dm_init_service failed - disabling DMAPI\n"));
+               talloc_free(tmp_ctx);
                return -1;
        }
 
        ZERO_STRUCT(buf);
 
+       /* Fetch kernel DMAPI sessions until we get any of them */
        do {
                dm_sessid_t *new_sessions;
                nsessions *= 2;
-               new_sessions = TALLOC_REALLOC_ARRAY(NULL, sessions, 
+               new_sessions = TALLOC_REALLOC_ARRAY(tmp_ctx, sessions, 
                                                    dm_sessid_t, nsessions);
                if (new_sessions == NULL) {
-                       talloc_free(sessions);
+                       talloc_free(tmp_ctx);
                        return -1;
                }
 
@@ -89,14 +107,15 @@ static int dmapi_init_session(void)
                DEBUGADD(DMAPI_TRACE,
                        ("failed to retrieve DMAPI sessions: %s\n",
                        strerror(errno)));
-               talloc_free(sessions);
+               talloc_free(tmp_ctx);
                return -1;
        }
 
+       /* Look through existing kernel DMAPI sessions to find out ours */
        for (i = 0; i < nsessions; ++i) {
                err = dm_query_session(sessions[i], sizeof(buf), buf, &buflen);
                buf[sizeof(buf) - 1] = '\0';
-               if (err == 0 && strcmp(DMAPI_SESSION_NAME, buf) == 0) {
+               if (err == 0 && strcmp(session_name, buf) == 0) {
                        samba_dmapi_session = sessions[i];
                        DEBUGADD(DMAPI_TRACE,
                                ("attached to existing DMAPI session "
@@ -105,23 +124,22 @@ static int dmapi_init_session(void)
                }
        }
 
-       talloc_free(sessions);
-
        /* No session already defined. */
        if (samba_dmapi_session == DM_NO_SESSION) {
                err = dm_create_session(DM_NO_SESSION, 
-                                       CONST_DISCARD(char *, DMAPI_SESSION_NAME),
+                                       session_name,
                                        &samba_dmapi_session);
                if (err < 0) {
                        DEBUGADD(DMAPI_TRACE,
                                ("failed to create new DMAPI session: %s\n",
                                strerror(errno)));
                        samba_dmapi_session = DM_NO_SESSION;
+                       talloc_free(tmp_ctx);
                        return -1;
                }
 
                DEBUG(0, ("created new DMAPI session named '%s' for %s\n",
-                         DMAPI_SESSION_NAME, version));
+                         session_name, version));
        }
 
        if (samba_dmapi_session != DM_NO_SESSION) {
@@ -132,8 +150,12 @@ static int dmapi_init_session(void)
           Note that we never end the DMAPI session. It gets re-used if possiblie. 
           DMAPI session is a kernel resource that is usually lives until server reboot
           and doesn't get destroed when an application finishes.
+
+          However, we free list of references to DMAPI sessions we've got from the kernel
+          as it is not needed anymore once we have found (or created) our session.
         */
 
+       talloc_free(tmp_ctx);
        return 0;
 }
 
@@ -171,6 +193,25 @@ bool dmapi_have_session(void)
        return samba_dmapi_session != DM_NO_SESSION;
 }
 
+/*
+  only call this when you get back an EINVAL error indicating that the
+  session you are using is invalid. This destroys the existing session
+  and creates a new one.
+ */
+BOOL dmapi_new_session(void)
+{
+       if (dmapi_have_session()) {
+               /* try to destroy the old one - this may not succeed */
+               dm_destroy_session(samba_dmapi_session);
+       }
+       samba_dmapi_session = DM_NO_SESSION;
+       become_root();
+       session_num++;
+       dmapi_init_session();
+       unbecome_root();
+       return samba_dmapi_session != DM_NO_SESSION;    
+}
+
 /* 
    This is default implementation of dmapi_file_flags() that is 
    called from VFS is_offline() call to know whether file is offline.
@@ -185,12 +226,12 @@ uint32 dmapi_file_flags(const char * const path)
        dm_eventset_t   events = {0};
        uint            nevents;
 
-       dm_sessid_t dmapi_session;
-       void    *dmapi_session_ptr;
-       void    *dm_handle = NULL;
-       size_t  dm_handle_len = 0;
+       dm_sessid_t     dmapi_session;
+       const void      *dmapi_session_ptr;
+       void            *dm_handle = NULL;
+       size_t          dm_handle_len = 0;
 
-       uint32  flags = 0;
+       uint32          flags = 0;
 
        dmapi_session_ptr = dmapi_get_current_session();
        if (dmapi_session_ptr == NULL) {
@@ -251,8 +292,7 @@ uint32 dmapi_file_flags(const char * const path)
         * interested in trapping read events is that part of the file is
         * offline.
         */
-       DEBUG(DMAPI_TRACE, ("DMAPI event list for %s is %#llx\n",
-                   path, events));
+       DEBUG(DMAPI_TRACE, ("DMAPI event list for %s\n", path));
        if (DMEV_ISSET(DM_EVENT_READ, events)) {
                flags = FILE_ATTRIBUTE_OFFLINE;
        }