summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2012-01-10 17:07:29 +0100
committerJeremy Allison <jra@samba.org>2012-01-12 23:59:22 +0100
commit6da246bae1b000cb3191e114e978510ccacb7e90 (patch)
tree05bb1518abf7c2723efc049e99dd0713a5642d10
parent6f9442a705b7ca67c78137db537f556385aa8558 (diff)
downloadsamba-6da246bae1b000cb3191e114e978510ccacb7e90.tar.gz
samba-6da246bae1b000cb3191e114e978510ccacb7e90.tar.bz2
samba-6da246bae1b000cb3191e114e978510ccacb7e90.zip
s3: Fix nested get_share_mode_lock calls
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>
-rw-r--r--source3/locking/share_mode_lock.c62
1 files changed, 57 insertions, 5 deletions
diff --git a/source3/locking/share_mode_lock.c b/source3/locking/share_mode_lock.c
index 1fb96998d7..51f09ae2af 100644
--- a/source3/locking/share_mode_lock.c
+++ b/source3/locking/share_mode_lock.c
@@ -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)
{