s3: Fix nested get_share_mode_lock calls
authorVolker Lendecke <vl@samba.org>
Tue, 10 Jan 2012 16:07:29 +0000 (17:07 +0100)
committerJeremy Allison <jra@samba.org>
Thu, 12 Jan 2012 22:59:22 +0000 (23:59 +0100)
This forces us to only do one real get_share_mode_lock call and
share the data between the nested get_share_mode_lock calls.

Signed-off-by: Jeremy Allison <jra@samba.org>
source3/locking/share_mode_lock.c

index 1fb96998d704c0c62371573ca63ecb4557b329b1..51f09ae2af9b2cde46977d821353c647a1d4ee0a 100644 (file)
@@ -306,11 +306,10 @@ fail:
        return NULL;
 }
 
-struct share_mode_lock *get_share_mode_lock_fresh(TALLOC_CTX *mem_ctx,
-                                                 const struct file_id id,
-                                                 const char *servicepath,
-                                                 const struct smb_filename *smb_fname,
-                                                 const struct timespec *old_write_time)
+static struct share_mode_lock *get_share_mode_lock_internal(
+       TALLOC_CTX *mem_ctx, const struct file_id id,
+       const char *servicepath, const struct smb_filename *smb_fname,
+       const struct timespec *old_write_time)
 {
        struct share_mode_lock *lck;
        struct share_mode_data *d;
@@ -353,6 +352,59 @@ struct share_mode_lock *get_share_mode_lock_fresh(TALLOC_CTX *mem_ctx,
        return lck;
 }
 
+/*
+ * We can only ever have one share mode locked. Users of
+ * get_share_mode_lock never see this, it will be refcounted by
+ * talloc_reference.
+ */
+static struct share_mode_lock *the_lock;
+
+static int the_lock_destructor(struct share_mode_lock *l)
+{
+       the_lock = NULL;
+       return 0;
+}
+
+struct share_mode_lock *get_share_mode_lock_fresh(
+       TALLOC_CTX *mem_ctx,
+       const struct file_id id,
+       const char *servicepath,
+       const struct smb_filename *smb_fname,
+       const struct timespec *old_write_time)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+
+       struct share_mode_lock *lck;
+
+       if (the_lock == NULL) {
+               the_lock = get_share_mode_lock_internal(
+                       frame, id, servicepath, smb_fname, old_write_time);
+               if (the_lock == NULL) {
+                       goto fail;
+               }
+               talloc_set_destructor(the_lock, the_lock_destructor);
+       }
+       if (!file_id_equal(&the_lock->data->id, &id)) {
+               DEBUG(1, ("Can not lock two share modes simultaneously\n"));
+               goto fail;
+       }
+       lck = talloc(mem_ctx, struct share_mode_lock);
+       if (lck == NULL) {
+               DEBUG(1, ("talloc failed\n"));
+               goto fail;
+       }
+       if (talloc_reference(lck, the_lock) == NULL) {
+               DEBUG(1, ("talloc_reference failed\n"));
+               goto fail;
+       }
+       lck->data = the_lock->data;
+       TALLOC_FREE(frame);
+       return lck;
+fail:
+       TALLOC_FREE(frame);
+       return NULL;
+}
+
 struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx,
                                                  const struct file_id id)
 {