--- 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);
+        }
     });
 };
 
