fsrvp: use fss server state storage back-end
authorDavid Disseldorp <ddiss@samba.org>
Fri, 28 Sep 2012 09:40:42 +0000 (11:40 +0200)
committerDavid Disseldorp <ddiss@samba.org>
Mon, 15 Apr 2013 16:15:20 +0000 (18:15 +0200)
MS-FSRVP outlines the requirement for persistent server state storage,
retrieved on startup. Store fss server state following snapshot
creation, deletion and exposure.

Storage and retrieval errors are logged but otherwise ignored. In such
a case, manual snapshot cleanup may be required if the server is
restarted with snapshots in existence.

smap sc_share_name was not set until exposure time, meaning there was
nothing available as a unique identifier. The sc_share_name is now set
immediately on sc/smap creation.

source3/rpc_server/fss/srv_fss_agent.c

index e63bd55c6c56ec1196f9865015320277ba14d6fa..28adb359c4cdc5ecbe252e52fbc6d8d68802f659 100644 (file)
@@ -194,6 +194,8 @@ void srv_fssa_cleanup(void)
 
 NTSTATUS srv_fssa_start(void)
 {
+       NTSTATUS status;
+
        fss_global.mem_ctx = talloc_named_const(NULL, 0,
                                                "parent fss rpc server ctx");
        if (fss_global.mem_ctx == NULL) {
@@ -203,9 +205,17 @@ NTSTATUS srv_fssa_start(void)
        fss_global.min_vers = FSRVP_RPC_VERSION_1;
        fss_global.max_vers = FSRVP_RPC_VERSION_1;
        /*
-        * TODO The server MUST populate the GlobalShadowCopySetTable with the
+        * The server MUST populate the GlobalShadowCopySetTable with the
         * ShadowCopySet entries read from the configuration store.
         */
+       become_root();
+       status = fss_state_retrieve(fss_global.mem_ctx, &fss_global.sc_sets,
+                                   &fss_global.sc_sets_count);
+       unbecome_root();
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("failed to retrieve fss server state: %s\n",
+                         nt_errstr(status)));
+       }
        return NT_STATUS_OK;
 }
 
@@ -345,9 +355,55 @@ uint32_t _fss_StartShadowCopySet(struct pipes_struct *p,
        return 0;
 }
 
+static uint32_t map_share_name(struct fss_sc_smap *sc_smap,
+                              const struct fss_sc *sc)
+{
+       bool hidden_base = false;
+
+       if (*(sc_smap->share_name + strlen(sc_smap->share_name) - 1) == '$') {
+               /*
+                * If MappedShare.ShareName ends with a $ character (meaning
+                * that the share is hidden), then the exposed share name will
+                * have the $ suffix appended.
+                * FIXME: turns out Windows doesn't do this, contrary to docs
+                */
+               hidden_base = true;
+       }
+
+       sc_smap->sc_share_name = talloc_asprintf(sc_smap, "%s@{%s}%s",
+                                               sc_smap->share_name,
+                                               sc->id_str,
+                                               hidden_base ? "$" : "");
+       if (sc_smap->sc_share_name == NULL) {
+               return E_OUTOFMEMORY;
+       }
+
+       return 0;
+}
+
+static uint32_t map_share_comment(struct fss_sc_smap *sc_smap,
+                                 const struct fss_sc *sc)
+{
+       char *time_str;
+
+       time_str = http_timestring(sc_smap, sc->create_ts);
+       if (time_str == NULL) {
+               return E_OUTOFMEMORY;
+       }
+
+       sc_smap->sc_share_comment = talloc_asprintf(sc_smap, "Shadow copy of %s taken %s",
+                                                  sc_smap->share_name, time_str);
+       if (sc_smap->sc_share_comment == NULL) {
+               return E_OUTOFMEMORY;
+       }
+
+       return 0;
+}
+
 uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
                                 struct fss_AddToShadowCopySet *r)
 {
+       uint32_t ret;
        struct fss_sc_set *sc_set;
        struct fss_sc *sc;
        struct fss_sc_smap *sc_smap;
@@ -458,6 +514,16 @@ uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
        talloc_steal(sc_smap, service);
        sc_smap->share_name = service;
        sc_smap->is_exposed = false;
+       /*
+        * generate the sc_smap share name now. It is a unique identifier for
+        * the smap used as a tdb key for state storage.
+        */
+       ret = map_share_name(sc_smap, sc);
+       if (ret) {
+               talloc_free(sc);
+               talloc_free(tmp_ctx);
+               return ret;
+       }
 
        /* add share map to shadow-copy */
        DLIST_ADD_END(sc->smaps, sc_smap, struct fss_sc_smap *);
@@ -604,12 +670,20 @@ static void fss_commit_vfs_done(struct tevent_req *subreq)
        }
 
        if (commit_state->recv_count != commit_state->dispatch_count) {
-               DEBUG(0, ("awaiting %u more snapshot completions\n",
+               DEBUG(4, ("awaiting %u more snapshot completions\n",
                    (commit_state->dispatch_count - commit_state->recv_count)));
                return;
        }
        if (NT_STATUS_IS_OK(commit_state->status)) {
                sc->sc_set->state = FSS_SC_COMMITED;
+               become_root();
+               status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
+                                        fss_global.sc_sets_count);
+               unbecome_root();
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(1, ("failed to store fss server state: %s\n",
+                                 nt_errstr(status)));
+               }
                tevent_req_done(req);
        } else {
                /* TODO cleanup */
@@ -636,44 +710,6 @@ uint32_t _fss_CommitShadowCopySet_recv(struct tevent_req *req)
        return 0;
 }
 
-static uint32_t map_share_name(struct fss_sc_smap *sc_smap,
-                              const struct fss_sc *sc)
-{
-       bool hidden_base = false;
-       char *time_str;
-
-       if (*(sc_smap->share_name + strlen(sc_smap->share_name) - 1) == '$') {
-               /*
-                * If MappedShare.ShareName ends with a $ character (meaning
-                * that the share is hidden), then the exposed share name will
-                * have the $ suffix appended.
-                * FIXME: turns out Windows doesn't do this, contrary to docs
-                */
-               hidden_base = true;
-       }
-
-       sc_smap->sc_share_name = talloc_asprintf(sc_smap, "%s@{%s}%s",
-                                               sc_smap->share_name,
-                                               sc->id_str,
-                                               hidden_base ? "$" : "");
-       if (sc_smap->sc_share_name == NULL) {
-               return E_OUTOFMEMORY;
-       }
-
-       time_str = http_timestring(sc_smap, sc->create_ts);
-       if (time_str == NULL) {
-               return E_OUTOFMEMORY;
-       }
-
-       sc_smap->sc_share_comment = talloc_asprintf(sc_smap, "Shadow copy of %s taken %s",
-                                                  sc_smap->share_name, time_str);
-       if (sc_smap->sc_share_comment == NULL) {
-               return E_OUTOFMEMORY;
-       }
-
-       return 0;
-}
-
 static sbcErr fss_conf_get_share_def(struct smbconf_ctx *fconf_ctx,
                                     struct smbconf_ctx *rconf_ctx,
                                     TALLOC_CTX *mem_ctx,
@@ -726,9 +762,10 @@ static uint32_t fss_sc_expose(struct smbconf_ctx *fconf_ctx,
                        break;
                }
 
-               err = map_share_name(sc_smap, sc);
+               /* smap share name already defined when added */
+               err = map_share_comment(sc_smap, sc);
                if (err) {
-                       DEBUG(0, ("failed to map share name\n"));
+                       DEBUG(0, ("failed to map share comment\n"));
                        break;
                }
 
@@ -780,6 +817,7 @@ static uint32_t fss_sc_expose(struct smbconf_ctx *fconf_ctx,
 uint32_t _fss_ExposeShadowCopySet(struct pipes_struct *p,
                                  struct fss_ExposeShadowCopySet *r)
 {
+       NTSTATUS status;
        struct fss_sc_set *sc_set;
        struct fss_sc *sc;
        uint32_t ret;
@@ -870,6 +908,14 @@ uint32_t _fss_ExposeShadowCopySet(struct pipes_struct *p,
                        sm->is_exposed = true;
        }
        sc_set->state = FSS_SC_EXPOSED;
+       become_root();
+       status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
+                                fss_global.sc_sets_count);
+       unbecome_root();
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("failed to store fss server state: %s\n",
+                         nt_errstr(status)));
+       }
        ret = 0;
 err_out:
        talloc_free(tmp_ctx);
@@ -884,6 +930,7 @@ err_cancel:
 uint32_t _fss_RecoveryCompleteShadowCopySet(struct pipes_struct *p,
                                struct fss_RecoveryCompleteShadowCopySet *r)
 {
+       NTSTATUS status;
        struct fss_sc_set *sc_set;
 
        if (!fss_permitted(p)) {
@@ -905,6 +952,14 @@ uint32_t _fss_RecoveryCompleteShadowCopySet(struct pipes_struct *p,
 
        sc_set->state = FSS_SC_RECOVERED;
        fss_global.cur_ctx = 0;
+       become_root();
+       status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
+                                fss_global.sc_sets_count);
+       unbecome_root();
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("failed to store fss server state: %s\n",
+                         nt_errstr(status)));
+       }
 
        return 0;
 }
@@ -1280,6 +1335,14 @@ static void fss_delete_vfs_done(struct tevent_req *subreq)
                }
        }
 
+       become_root();
+       status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
+                                fss_global.sc_sets_count);
+       unbecome_root();
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("failed to store fss server state: %s\n",
+                         nt_errstr(status)));
+       }
        tevent_req_done(req);
 }