Filesystem: Refactor inodedata accesses to async methods

The "// jshint ignore:line" comments are pretty messy, so squint your eyes.
They're systematically placed, so we can regex it out when jshint's
new version finally arrives.

Using async/await instead of callbacks due to callback hell, and it also
helps minimising the diff)
This commit is contained in:
Ernest Wong 2018-09-19 22:10:13 +12:00 committed by Fabian
parent 1a6f3cfef3
commit 595d6dca55
3 changed files with 97 additions and 70 deletions

View file

@ -250,7 +250,7 @@ Virtio9p.prototype.SendReply = function (bufchain) {
this.virtqueue.flush_replies(); this.virtqueue.flush_replies();
}; };
Virtio9p.prototype.ReceiveRequest = function (bufchain) { Virtio9p.prototype.ReceiveRequest = async function (bufchain) { // jshint ignore:line
// TODO: split into header + data blobs to avoid unnecessary copying. // TODO: split into header + data blobs to avoid unnecessary copying.
const buffer = new Uint8Array(bufchain.length_readable); const buffer = new Uint8Array(bufchain.length_readable);
bufchain.get_next_blob(buffer); bufchain.get_next_blob(buffer);
@ -552,7 +552,7 @@ Virtio9p.prototype.ReceiveRequest = function (bufchain) {
inode.mtime = req[8]; inode.mtime = req[8];
} }
if (req[1] & P9_SETATTR_SIZE) { if (req[1] & P9_SETATTR_SIZE) {
this.fs.ChangeSize(this.fids[fid].inodeid, req[5]); await this.fs.ChangeSize(this.fids[fid].inodeid, req[5]); // jshint ignore:line
} }
this.BuildReply(id, tag, 0); this.BuildReply(id, tag, 0);
this.SendReply(bufchain); this.SendReply(bufchain);
@ -593,7 +593,7 @@ Virtio9p.prototype.ReceiveRequest = function (bufchain) {
this.fs.OpenInode(this.fids[fid].inodeid, undefined); this.fs.OpenInode(this.fids[fid].inodeid, undefined);
this.fs.AddEvent(this.fids[fid].inodeid, this.fs.AddEvent(this.fids[fid].inodeid,
function() { async function() { // jshint ignore:line
this.bus.send("9p-read-end", [this.fids[fid].dbg_name, count]); this.bus.send("9p-read-end", [this.fids[fid].dbg_name, count]);
const inodeid = this.fids[fid].inodeid; const inodeid = this.fids[fid].inodeid;
@ -610,15 +610,15 @@ Virtio9p.prototype.ReceiveRequest = function (bufchain) {
// See http://ericvh.github.io/9p-rfc/rfc9p2000.html#anchor30 // See http://ericvh.github.io/9p-rfc/rfc9p2000.html#anchor30
count = 0; count = 0;
} }
const data = this.fs.Read(inodeid, offset, count); const data = await this.fs.Read(inodeid, offset, count); // jshint ignore:line
if(data) { if(data) {
this.replybuffer.set(data, 7 + 4); this.replybuffer.set(data, 7 + 4);
} }
marshall.Marshall(["w"], [count], this.replybuffer, 7); marshall.Marshall(["w"], [count], this.replybuffer, 7);
this.BuildReply(id, tag, 4 + count); this.BuildReply(id, tag, 4 + count);
this.SendReply(bufchain); this.SendReply(bufchain);
}.bind(this) }.bind(this) // jshint ignore:line
); ); // jshint ignore:line
} }
break; break;
@ -640,7 +640,7 @@ Virtio9p.prototype.ReceiveRequest = function (bufchain) {
else else
{ {
// XXX: Size of the subarray is unchecked // XXX: Size of the subarray is unchecked
this.fs.Write(this.fids[fid].inodeid, offset, count, buffer.subarray(state.offset)); await this.fs.Write(this.fids[fid].inodeid, offset, count, buffer.subarray(state.offset)); // jshint ignore:line
} }
this.bus.send("9p-write-end", [filename, count]); this.bus.send("9p-write-end", [filename, count]);
@ -657,7 +657,7 @@ Virtio9p.prototype.ReceiveRequest = function (bufchain) {
var newdirfid = req[2]; var newdirfid = req[2];
var newname = req[3]; var newname = req[3];
message.Debug("[renameat]: oldname=" + oldname + " newname=" + newname); message.Debug("[renameat]: oldname=" + oldname + " newname=" + newname);
var ret = this.fs.Rename(this.fids[olddirfid].inodeid, oldname, this.fids[newdirfid].inodeid, newname); var ret = await this.fs.Rename(this.fids[olddirfid].inodeid, oldname, this.fids[newdirfid].inodeid, newname); // jshint ignore:line
if (ret < 0) { if (ret < 0) {
let error_message = ""; let error_message = "";
if(ret === -ENOENT) error_message = "No such file or directory"; if(ret === -ENOENT) error_message = "No such file or directory";
@ -790,7 +790,7 @@ Virtio9p.prototype.ReceiveRequest = function (bufchain) {
var req = marshall.Unmarshall(["w"], buffer, state); var req = marshall.Unmarshall(["w"], buffer, state);
message.Debug("[clunk]: fid=" + req[0]); message.Debug("[clunk]: fid=" + req[0]);
if (this.fids[req[0]] && this.fids[req[0]].inodeid >= 0) { if (this.fids[req[0]] && this.fids[req[0]].inodeid >= 0) {
this.fs.CloseInode(this.fids[req[0]].inodeid); await this.fs.CloseInode(this.fids[req[0]].inodeid); // jshint ignore:line
this.fids[req[0]].inodeid = -1; this.fids[req[0]].inodeid = -1;
this.fids[req[0]].type = FID_NONE; this.fids[req[0]].type = FID_NONE;
} }
@ -844,4 +844,4 @@ Virtio9p.prototype.ReceiveRequest = function (bufchain) {
//consistency checks if there are problems with the filesystem //consistency checks if there are problems with the filesystem
//this.fs.Check(); //this.fs.Check();
}; }; // jshint ignore:line

View file

@ -303,15 +303,16 @@ FS.prototype.LoadFile = function(idx) {
if(this.baseurl) if(this.baseurl)
{ {
LoadBinaryResource(this.baseurl + inode.sha256sum, LoadBinaryResource(this.baseurl + inode.sha256sum,
function(buffer){ async function(buffer){ // jshint ignore:line
var data = this.inodedata[idx] = new Uint8Array(buffer); const data = new Uint8Array(buffer);
await this.set_data(idx, data); // jshint ignore:line
inode.size = data.length; // correct size if the previous was wrong. inode.size = data.length; // correct size if the previous was wrong.
inode.status = STATUS_OK; inode.status = STATUS_OK;
this.filesinloadingqueue--; this.filesinloadingqueue--;
this.HandleEvent(idx); this.HandleEvent(idx);
}.bind(this), }.bind(this), // jshint ignore:line
function(error){throw error;}); function(error){throw error;}); // jshint ignore:line
} }
else else
{ {
@ -710,7 +711,7 @@ FS.prototype.CreateSymlink = function(filename, parentid, symlink) {
return this.inodes.length-1; return this.inodes.length-1;
}; };
FS.prototype.CreateTextFile = function(filename, parentid, str) { FS.prototype.CreateTextFile = async function(filename, parentid, str) { // jshint ignore:line
const parent_inode = this.inodes[parentid]; const parent_inode = this.inodes[parentid];
if(this.is_forwarder(parent_inode)) if(this.is_forwarder(parent_inode))
{ {
@ -721,19 +722,20 @@ FS.prototype.CreateTextFile = function(filename, parentid, str) {
} }
var id = this.CreateFile(filename, parentid); var id = this.CreateFile(filename, parentid);
var x = this.inodes[id]; var x = this.inodes[id];
var data = this.inodedata[id] = new Uint8Array(str.length); var data = new Uint8Array(str.length);
x.dirty = true; x.dirty = true;
x.size = str.length; x.size = str.length;
for (var j = 0; j < str.length; j++) { for (var j = 0; j < str.length; j++) {
data[j] = str.charCodeAt(j); data[j] = str.charCodeAt(j);
} }
await this.set_data(id, data); // jshint ignore:line
return id; return id;
}; }; // jshint ignore:line
/** /**
* @param {Uint8Array} buffer * @param {Uint8Array} buffer
*/ */
FS.prototype.CreateBinaryFile = function(filename, parentid, buffer) { FS.prototype.CreateBinaryFile = async function(filename, parentid, buffer) { // jshint ignore:line
const parent_inode = this.inodes[parentid]; const parent_inode = this.inodes[parentid];
if(this.is_forwarder(parent_inode)) if(this.is_forwarder(parent_inode))
{ {
@ -744,12 +746,13 @@ FS.prototype.CreateBinaryFile = function(filename, parentid, buffer) {
} }
var id = this.CreateFile(filename, parentid); var id = this.CreateFile(filename, parentid);
var x = this.inodes[id]; var x = this.inodes[id];
var data = this.inodedata[id] = new Uint8Array(buffer.length); var data = new Uint8Array(buffer.length);
x.dirty = true; x.dirty = true;
data.set(buffer); data.set(buffer);
await this.set_data(id, data); // jshint ignore:line
x.size = buffer.length; x.size = buffer.length;
return id; return id;
}; }; // jshint ignore:line
FS.prototype.OpenInode = function(id, mode) { FS.prototype.OpenInode = function(id, mode) {
@ -778,7 +781,7 @@ FS.prototype.OpenInode = function(id, mode) {
return true; return true;
}; };
FS.prototype.CloseInode = function(id) { FS.prototype.CloseInode = async function(id) { // jshint ignore:line
//message.Debug("close: " + this.GetFullPath(id)); //message.Debug("close: " + this.GetFullPath(id));
var inode = this.inodes[id]; var inode = this.inodes[id];
if(this.is_forwarder(inode)) if(this.is_forwarder(inode))
@ -788,15 +791,14 @@ FS.prototype.CloseInode = function(id) {
if (inode.status == STATUS_UNLINKED) { if (inode.status == STATUS_UNLINKED) {
//message.Debug("Filesystem: Delete unlinked file"); //message.Debug("Filesystem: Delete unlinked file");
inode.status = STATUS_INVALID; inode.status = STATUS_INVALID;
delete this.inodedata[id]; await this.DeleteData(id); // jshint ignore:line
inode.size = 0;
} }
}; }; // jshint ignore:line
/** /**
* @return {number} 0 if success, or -errno if failured. * @return {number} 0 if success, or -errno if failured.
*/ */
FS.prototype.Rename = function(olddirid, oldname, newdirid, newname) { FS.prototype.Rename = async function(olddirid, oldname, newdirid, newname) { // jshint ignore:line
// message.Debug("Rename " + oldname + " to " + newname); // message.Debug("Rename " + oldname + " to " + newname);
if ((olddirid == newdirid) && (oldname == newname)) { if ((olddirid == newdirid) && (oldname == newname)) {
return 0; return 0;
@ -834,8 +836,8 @@ FS.prototype.Rename = function(olddirid, oldname, newdirid, newname) {
{ {
// Move inode within the same child filesystem. // Move inode within the same child filesystem.
const ret = this.follow_fs(olddir) const ret = await // jshint ignore:line
.Rename(olddir.foreign_id, oldname, newdir.foreign_id, newname); this.follow_fs(olddir).Rename(olddir.foreign_id, oldname, newdir.foreign_id, newname);
if(ret < 0) return ret; if(ret < 0) return ret;
} }
@ -862,7 +864,7 @@ FS.prototype.Rename = function(olddirid, oldname, newdirid, newname) {
const diverted_old_idx = this.divert(olddirid, oldname); const diverted_old_idx = this.divert(olddirid, oldname);
const old_real_inode = this.GetInode(idx); const old_real_inode = this.GetInode(idx);
const data = this.Read(diverted_old_idx, 0, old_real_inode.size); const data = await this.Read(diverted_old_idx, 0, old_real_inode.size); // jshint ignore:line
if(this.is_forwarder(newdir)) if(this.is_forwarder(newdir))
{ {
@ -889,10 +891,10 @@ FS.prototype.Rename = function(olddirid, oldname, newdirid, newname) {
} }
// Rewrite data to newly created destination. // Rewrite data to newly created destination.
this.ChangeSize(idx, old_real_inode.size); await this.ChangeSize(idx, old_real_inode.size); // jshint ignore:line
if(data && data.length) if(data && data.length)
{ {
this.Write(idx, 0, data.length, data); await this.Write(idx, 0, data.length, data); // jshint ignore:line
} }
// Move children to newly created destination. // Move children to newly created destination.
@ -900,13 +902,13 @@ FS.prototype.Rename = function(olddirid, oldname, newdirid, newname) {
{ {
for(const child_filename of this.GetChildren(diverted_old_idx)) for(const child_filename of this.GetChildren(diverted_old_idx))
{ {
const ret = this.Rename(diverted_old_idx, child_filename, idx, child_filename); const ret = await this.Rename(diverted_old_idx, child_filename, idx, child_filename); // jshint ignore:line
if(ret < 0) return ret; if(ret < 0) return ret;
} }
} }
// Perform destructive changes only after migration succeeded. // Perform destructive changes only after migration succeeded.
this.DeleteData(diverted_old_idx); await this.DeleteData(diverted_old_idx); // jshint ignore:line
const ret = this.Unlink(olddirid, oldname); const ret = this.Unlink(olddirid, oldname);
if(ret < 0) return ret; if(ret < 0) return ret;
} }
@ -914,26 +916,26 @@ FS.prototype.Rename = function(olddirid, oldname, newdirid, newname) {
this.NotifyListeners(idx, "rename", {oldpath: oldpath}); this.NotifyListeners(idx, "rename", {oldpath: oldpath});
return 0; return 0;
}; }; // jshint ignore:line
FS.prototype.Write = function(id, offset, count, buffer) { FS.prototype.Write = async function(id, offset, count, buffer) { // jshint ignore:line
this.NotifyListeners(id, 'write'); this.NotifyListeners(id, 'write');
var inode = this.inodes[id]; var inode = this.inodes[id];
if(this.is_forwarder(inode)) if(this.is_forwarder(inode))
{ {
const foreign_id = inode.foreign_id; const foreign_id = inode.foreign_id;
this.follow_fs(inode).Write(foreign_id, offset, count, buffer); await this.follow_fs(inode).Write(foreign_id, offset, count, buffer); // jshint ignore:line
return; return;
} }
inode.dirty = true; inode.dirty = true;
var data = this.inodedata[id]; var data = await this.get_data(id); // jshint ignore:line
if (!data || data.length < (offset+count)) { if (!data || data.length < (offset+count)) {
this.ChangeSize(id, Math.floor(((offset+count)*3)/2) ); await this.ChangeSize(id, Math.floor(((offset+count)*3)/2)); // jshint ignore:line
inode.size = offset + count; inode.size = offset + count;
data = this.inodedata[id]; data = await this.get_data(id); // jshint ignore:line
} else } else
if (inode.size < (offset+count)) { if (inode.size < (offset+count)) {
inode.size = offset + count; inode.size = offset + count;
@ -942,25 +944,28 @@ FS.prototype.Write = function(id, offset, count, buffer) {
{ {
data.set(buffer.subarray(0, count), offset); data.set(buffer.subarray(0, count), offset);
} }
}; await this.set_data(id, data); // jshint ignore:line
}; // jshint ignore:line
FS.prototype.Read = function(inodeid, offset, count) FS.prototype.Read = async function(inodeid, offset, count) // jshint ignore:line
{ {
const inode = this.inodes[inodeid]; const inode = this.inodes[inodeid];
if(this.is_forwarder(inode)) if(this.is_forwarder(inode))
{ {
const foreign_id = inode.foreign_id; const foreign_id = inode.foreign_id;
return this.follow_fs(inode).Read(foreign_id, offset, count); return await this.follow_fs(inode).Read(foreign_id, offset, count); // jshint ignore:line
} }
else if(!this.inodedata[inodeid])
const data = await this.get_data(inodeid); // jshint ignore:line
if(!data)
{ {
return null; return null;
} }
else else
{ {
return this.inodedata[inodeid].subarray(offset, offset + count); return data.subarray(offset, offset + count);
} }
}; }; // jshint ignore:line
FS.prototype.Search = function(parentid, name) { FS.prototype.Search = function(parentid, name) {
const parent_inode = this.inodes[parentid]; const parent_inode = this.inodes[parentid];
@ -1136,7 +1141,7 @@ FS.prototype.Unlink = function(parentid, name) {
return 0; return 0;
}; };
FS.prototype.DeleteData = function(idx) FS.prototype.DeleteData = async function(idx) // jshint ignore:line
{ {
const inode = this.inodes[idx]; const inode = this.inodes[idx];
if(this.is_forwarder(inode)) if(this.is_forwarder(inode))
@ -1146,7 +1151,32 @@ FS.prototype.DeleteData = function(idx)
} }
inode.size = 0; inode.size = 0;
delete this.inodedata[idx]; delete this.inodedata[idx];
}; }; // jshint ignore:line
/**
* @private
* @param {number} idx
* @return {Uint8Array}
*/
FS.prototype.get_data = async function(idx) // jshint ignore:line
{
const inode = this.inodes[idx];
dbg_assert(inode, `Filesystem get_data: idx ${idx} does not point to an inode`);
if(this.inodedata[idx]) return this.inodedata[idx];
return null;
}; // jshint ignore:line
/**
* @private
* @param {number} idx
* @param {Uint8Array} buffer
*/
FS.prototype.set_data = async function(idx, buffer) // jshint ignore:line
{
// Current scheme: Save all modified buffers into local inodedata.
this.inodedata[idx] = buffer;
}; // jshint ignore:line
/** /**
* @param {number} idx * @param {number} idx
@ -1166,19 +1196,20 @@ FS.prototype.GetInode = function(idx)
return inode; return inode;
}; };
FS.prototype.ChangeSize = function(idx, newsize) FS.prototype.ChangeSize = async function(idx, newsize) // jshint ignore:line
{ {
var inode = this.GetInode(idx); var inode = this.GetInode(idx);
var temp = this.inodedata[idx]; var temp = await this.get_data(idx); // jshint ignore:line
inode.dirty = true; inode.dirty = true;
//message.Debug("change size to: " + newsize); //message.Debug("change size to: " + newsize);
if (newsize == inode.size) return; if (newsize == inode.size) return;
var data = this.inodedata[idx] = new Uint8Array(newsize); var data = new Uint8Array(newsize);
await this.set_data(idx, data); // jshint ignore:line
inode.size = newsize; inode.size = newsize;
if(!temp) return; if(!temp) return;
var size = Math.min(temp.length, inode.size); var size = Math.min(temp.length, inode.size);
data.set(temp.subarray(0, size), 0); data.set(temp.subarray(0, size), 0);
}; }; // jshint ignore:line
FS.prototype.SearchPath = function(path) { FS.prototype.SearchPath = function(path) {
//path = path.replace(/\/\//g, "/"); //path = path.replace(/\/\//g, "/");

View file

@ -1149,6 +1149,8 @@ V86Starter.prototype.mount_fs = function(path, baseurl, basefs, callback)
*/ */
V86Starter.prototype.create_file = function(file, data, callback) V86Starter.prototype.create_file = function(file, data, callback)
{ {
callback = callback || function() {};
var fs = this.fs9p; var fs = this.fs9p;
if(!fs) if(!fs)
@ -1165,21 +1167,14 @@ V86Starter.prototype.create_file = function(file, data, callback)
if(!not_found) if(!not_found)
{ {
fs.CreateBinaryFile(filename, parent_id, data); fs.CreateBinaryFile(filename, parent_id, data)
.then(() => callback(null));
} }
else
if(callback)
{ {
setTimeout(function() setTimeout(function()
{ {
if(not_found) callback(new FileNotFoundError());
{
callback(new FileNotFoundError());
}
else
{
callback(null);
}
}, 0); }, 0);
} }
}; };
@ -1216,16 +1211,17 @@ V86Starter.prototype.read_file = function(file, callback)
function() function()
{ {
const size = fs.GetInode(id).size; const size = fs.GetInode(id).size;
const data = fs.Read(id, 0, size); fs.Read(id, 0, size).then(data =>
if(data)
{ {
callback(null, data); if(data)
} {
else callback(null, data);
{ }
callback(new FileNotFoundError(), null); else
} {
callback(new FileNotFoundError(), null);
}
});
} }
); );
} }