--- old/src/vm/node_modules/VM.js	2013-10-29 04:23:36.163160637 +0000
+++ new/src/vm/node_modules/VM.js	2013-10-29 04:23:36.177230802 +0000
@@ -67,6 +67,7 @@
 var bunyan = require('/usr/node/node_modules/bunyan');
 var cp = require('child_process');
 var dladm = require('/usr/vm/node_modules/dladm');
+var lock = require('/usr/vm/node_modules/locker').lock;
 var EventEmitter = require('events').EventEmitter;
 var exec = cp.exec;
 var execFile = cp.execFile;
@@ -4225,6 +4226,33 @@
     });
 }
 
+function writeAndRename(log, name, destfile, file_data, callback)
+{
+    var tempfile = destfile + '.new';
+
+    log.debug('writing ' + name + ' to ' + tempfile);
+
+    fs.writeFile(tempfile, file_data, function (err) {
+        if (err) {
+            callback(err);
+            return;
+        }
+
+        log.debug('wrote ' + name + ' to ' + tempfile);
+        log.debug('renaming from ' + tempfile + ' to ' + destfile);
+
+        fs.rename(tempfile, destfile, function (_err) {
+            if (_err) {
+                callback(_err);
+                return;
+            }
+
+            log.debug('renamed from ' + tempfile + ' to ' + destfile);
+            callback();
+        });
+    });
+}
+
 // writes a Zone's metadata JSON to /zones/<uuid>/config/metadata.json
 // and /zones/<uuid>/config/tags.json.
 function updateMetadata(vmobj, payload, log, callback)
@@ -4314,25 +4342,17 @@
     }
 
     mdata = {'customer_metadata': cmdata, 'internal_metadata': imdata};
-    fs.writeFile(mdata_filename, JSON.stringify(mdata, null, 2),
-        function (err) {
-            if (err) {
-                callback(err);
-            } else {
-                log.debug('wrote metadata to ' + mdata_filename);
-                fs.writeFile(tags_filename, JSON.stringify(tags, null, 2),
-                    function (e) {
-                        if (e) {
-                            callback(e);
-                        } else {
-                            log.debug('wrote tags to' + tags_filename);
-                            callback();
-                        }
-                    }
-                );
-            }
+
+    async.series([
+        function (next) {
+            writeAndRename(log, 'metadata', mdata_filename,
+                JSON.stringify(mdata, null, 2), next);
+        },
+        function (next) {
+            writeAndRename(log, 'tags', tags_filename,
+                JSON.stringify(tags, null, 2), next);
         }
-    );
+    ], callback);
 }
 
 function saveMetadata(payload, log, callback)
@@ -12005,6 +12025,8 @@
     var log;
     var new_vmobj;
     var vmobj;
+    var unlock;
+    var lockpath;
 
     // options parameter is optional
     if (arguments.length === 3) {
@@ -12024,6 +12046,19 @@
 
     async.series([
         function (cb) {
+            lockpath = '/var/run/vm.' + uuid + '.config.lockfile';
+            log.debug('acquiring lock on ' + lockpath);
+            lock(lockpath, function (err, _unlock) {
+                log.debug('acquired lock on ' + lockpath);
+                if (err) {
+                    cb(err);
+                    return;
+                }
+                unlock = _unlock;
+                cb();
+            });
+        },
+        function (cb) {
             // for update we currently always load the whole vmobj since the
             // update functions may need to look at bits from the existing VM.
             VM.load(uuid, {log: log}, function (err, obj) {
@@ -12161,7 +12196,22 @@
             });
         }
     ], function (e) {
-        callback(e);
+        // If we were able to hold the lockfile, and thus have an unlock
+        // callback, we must call it before returning, whether or not
+        // there was an error.
+        if (unlock) {
+            log.debug('releasing lock on ' + lockpath);
+            unlock(function (unlock_err) {
+                if (unlock_err) {
+                    log.error(err, 'unlock error! (path ' + lockpath + ')');
+                } else {
+                    log.debug('released lock on ' + lockpath);
+                }
+                callback(e);
+            });
+        } else {
+            callback(e);
+        }
     });
 };
 
--- /dev/null	2013-10-29 04:23:36.000000000 +0000
+++ new/src/vm/node_modules/locker.js	2013-10-29 04:23:36.759457635 +0000
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+// vim: set sts=4 sw=4 et:
+
+// Ensure we're using the platform's node
+require('/usr/node/node_modules/platform_node_version').assert();
+
+var mod_path = require('path');
+var mod_fs = require('fs');
+var mod_assert = require('assert');
+
+var mod_lockfd = require('/usr/node/0.8/node_modules/lockfd');
+
+// If we fail to lock (i.e. the call to fcntl() in node-lockfd), and
+// the errno is in this list, then we should back off for some delay
+// and retry.  Note that an EDEADLK, in particular, is not necessarilly
+// a permanent failure in a program using multiple lock files through
+// multiple threads of control.
+var RETRY_CODES = [
+    'EAGAIN',
+    'ENOLCK',
+    'EDEADLK'
+];
+var RETRY_DELAY = 250; // ms
+
+var LOCKFILE_MODE = 0644;
+
+var LOCKFILES = [];
+var NEXT_HOLDER_ID = 1;
+
+function lockfile_create(path) {
+    path = mod_path.normalize(path);
+
+    mod_assert.strictEqual(lockfile_lookup(path), null);
+
+    var lf = {
+        lf_path: path,
+        lf_state: 'UNLOCKED',
+        lf_cbq: [],
+        lf_fd: -1,
+        lf_holder_id: -1
+    };
+
+    LOCKFILES.push(lf);
+
+    return (lf);
+}
+
+function lockfile_lookup(path) {
+    path = mod_path.normalize(path);
+
+    for (var i = 0; i < LOCKFILES.length; i++) {
+        var lf = LOCKFILES[i];
+
+        if (lf.lf_path === path)
+            return (lf);
+    }
+
+    return (null);
+}
+
+// Make an unlock callback for this lockfile to hand to the waiter for whom
+// we acquired the lock:
+function lockfile_make_unlock(lf) {
+    var holder_id;
+
+    mod_assert.strictEqual(lf.lf_holder_id, -1);
+
+    lf.lf_holder_id = holder_id = ++NEXT_HOLDER_ID;
+
+    return (function __unlock(ulcb) {
+        mod_assert.strictEqual(lf.lf_holder_id, holder_id,
+            'mismatched lock holder or already unlocked');
+        lf.lf_holder_id = -1;
+
+        mod_assert.strictEqual(lf.lf_state, 'LOCKED');
+        mod_assert.notStrictEqual(lf.lf_fd, -1);
+
+        lf.lf_state = 'UNLOCKING';
+
+        mod_fs.close(lf.lf_fd, function (err) {
+            lf.lf_state = 'UNLOCKED';
+            lf.lf_fd = -1;
+
+            ulcb(err);
+
+            lockfile_dispatch(lf);
+        });
+    });
+}
+
+function lockfile_dispatch(lf) {
+    if (lf.lf_state !== 'UNLOCKED')
+        return;
+
+    if (lf.lf_cbq.length === 0) {
+        // No more waiters to service for now.
+        return;
+    }
+
+    lockfile_to_locking(lf);
+}
+
+function lockfile_to_locking(lf) {
+    mod_assert.strictEqual(lf.lf_state, 'UNLOCKED');
+    mod_assert.strictEqual(lf.lf_fd, -1);
+
+    lf.lf_state = 'LOCKING';
+
+    // Open the lock file, creating it if it does not exist:
+    mod_fs.open(lf.lf_path, 'w+', LOCKFILE_MODE, function __opencb(err, fd) {
+        mod_assert.strictEqual(lf.lf_state, 'LOCKING');
+        mod_assert.strictEqual(lf.lf_fd, -1);
+
+        if (err) {
+            lf.lf_state = 'UNLOCKED';
+
+            // Dispatch error to the first waiter
+            lf.lf_cbq.shift()(err);
+            lockfile_dispatch(lf);
+            return;
+        }
+
+        lf.lf_fd = fd;
+
+        // Attempt to get an exclusive lock on the file via our file
+        // descriptor:
+        mod_lockfd.lockfd(lf.lf_fd, function __lockfdcb(_err) {
+            mod_assert.strictEqual(lf.lf_state, 'LOCKING');
+
+            if (_err) {
+                var do_retry = (RETRY_CODES.indexOf(_err.code) !== -1);
+
+                // We could not lock the file, so we should close our fd now:
+                mod_fs.close(lf.lf_fd, function __closecb(__err) {
+                    // It would be most unfortunate to fail here:
+                    mod_assert.ifError(__err);
+
+                    lf.lf_fd = -1;
+                    lf.lf_state = 'UNLOCKED';
+
+                    if (do_retry) {
+                        // Back off and try again.
+                        setTimeout(function __tocb() {
+                            lockfile_dispatch(lf);
+                        }, RETRY_DELAY);
+                        return;
+                    }
+
+                    // Report the condition to the first waiter:
+                    lf.lf_cbq.shift()(_err);
+
+                    lockfile_dispatch(lf);
+                });
+                return;
+            }
+
+            lf.lf_state = 'LOCKED';
+
+            // Dispatch locking success to first waiter, with unlock callback:
+            lf.lf_cbq.shift()(null, lockfile_make_unlock(lf));
+        });
+    });
+}
+
+exports.lock = function (path, callback) {
+    var lf = lockfile_lookup(path);
+    if (!lf) {
+        lf = lockfile_create(path);
+    }
+
+    lf.lf_cbq.push(callback);
+
+    lockfile_dispatch(lf);
+
+};
