Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fill / persist all iovecs in FileDisk.request. #20

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions lib/binding.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function getCallback(req) {
}

function addNullTerminationIfNeeded(s) {
// If the s is a Buffer, we need to add a NULL termination byte.
// If s is a Buffer, we need to add a NULL termination byte.
if (Buffer.isBuffer(s)) {
const nullTerminated = Buffer.allocUnsafe(s.length + 1);
s.copy(nullTerminated);
Expand Down Expand Up @@ -193,8 +193,21 @@ exports.writeBuffer = function(fd, buffer, offset, length, position, req) {
}
}

exports.writeBuffers = function() {
throw new Error('Unimplemented');
exports.writeBuffers = function(fd, buffers, position, req) {
const callback = getCallback(req);
const iovecs = bindings.buffersToIoVecs(buffers);
if (typeof position === 'number' && position !== -1) {
return syscall.pwritev(
fd,
iovecs,
buffers.length,
position & 0xffffffff, // 32 lower bits
Math.floor(position / Math.pow(2, 32)), // high bits
callback
);
} else {
return syscall.writev(fd, iovecs, buffers.length, callback);
}
}

exports.writeString = function() {
Expand Down
34 changes: 32 additions & 2 deletions lib/disk.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ const filedisk = require('resin-file-disk');

const constants = require('./constants');

function sum(arr) {
return arr.reduce(function(a, b) {return a + b});
}

class FileDisk extends filedisk.FileDisk {
constructor(path) {
super(
Expand All @@ -20,8 +24,34 @@ class FileDisk extends filedisk.FileDisk {
};

request(type, offset, iovecs, callback) {
// FIXME: we have to fill / persist all the iovecs, not just the first
super.request(type, offset, iovecs[0].length, iovecs[0], callback);
if (iovecs.length > 1) {
// special case for read / write requests with more than one iovec
const length = sum(iovecs.map(function(b) {return b.length}));
if (type === constants.LKL_DEV_BLK_TYPE_READ) {
const buf = Buffer.allocUnsafe(length);
const cb = function(err, bytesRead, buf) {
if (err) {
callback(err);
return;
}
let off = 0;
// copy from result buffer to iovecs:
for (let vec of iovecs) {
buf.copy(vec, 0, off, off + vec.length);
off += vec.length;
}
callback(null);
};
super.request(type, offset, length, buf, cb);
} else if (type === constants.LKL_DEV_BLK_TYPE_WRITE) {
// transform all iovecs to a single buffer:
const length = sum(iovecs.map(function(b) {return b.length}));
const buf = Buffer.concat(iovecs, length);
super.request(type, offset, length, buf, callback);
}
} else {
super.request(type, offset, iovecs[0].length, iovecs[0], callback);
}
};
}

Expand Down
4 changes: 3 additions & 1 deletion lib/syscall.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ module.exports = {
openat: syscall.bind(null, constants.SYS_openat),
pread64: syscall.bind(null, constants.SYS_pread64),
pwrite64: syscall.bind(null, constants.SYS_pwrite64),
pwritev: syscall.bind(null, constants.SYS_pwritev),
read: syscall.bind(null, constants.SYS_read),
readlinkat: syscall.bind(null, constants.SYS_readlinkat),
removexattr: syscall.bind(null, constants.SYS_removexattr),
Expand All @@ -56,7 +57,8 @@ module.exports = {
sync: syscall.bind(null, constants.SYS_sync),
truncate: syscall.bind(null, constants.SYS_truncate),
unlinkat: syscall.bind(null, constants.SYS_unlinkat),
write: syscall.bind(null, constants.SYS_write)
write: syscall.bind(null, constants.SYS_write),
writev: syscall.bind(null, constants.SYS_writev)
};

// Unimplemented syscalls
Expand Down
1 change: 1 addition & 0 deletions src/bindings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ NAN_MODULE_INIT(InitAll) {
NAN_EXPORT(target, sizeOfStructLklStat);
NAN_EXPORT(target, parseLklStat);
NAN_EXPORT(target, millisecondsToTimespec);
NAN_EXPORT(target, buffersToIoVecs);
}

NODE_MODULE(bindings, InitAll)
16 changes: 16 additions & 0 deletions src/node_lkl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,19 @@ NAN_METHOD(millisecondsToTimespec) {
).ToLocalChecked();
info.GetReturnValue().Set(result);
}

NAN_METHOD(buffersToIoVecs) {
auto arr = info[0].As<v8::Array>();
auto len = arr->Length();
auto *iovecs = new struct iovec[len];
for (unsigned int i = 0; i < len; i++) {
auto buf = arr->Get(i);
iovecs[i].iov_base = reinterpret_cast<char*>(node::Buffer::Data(buf));
iovecs[i].iov_len = node::Buffer::Length(buf);
}
auto result = Nan::NewBuffer(
reinterpret_cast<char*>(iovecs),
sizeof *iovecs
).ToLocalChecked();
info.GetReturnValue().Set(result);
}
1 change: 1 addition & 0 deletions src/node_lkl.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ NAN_METHOD(parseDirent64);
NAN_METHOD(sizeOfStructLklStat);
NAN_METHOD(parseLklStat);
NAN_METHOD(millisecondsToTimespec);
NAN_METHOD(buffersToIoVecs);
26 changes: 26 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -432,5 +432,31 @@ describe('node-lkl', function() {
.then(done);
});
});

describe('writev', function() {
it('should write all buffers to file', function(done) {
const fpath = path.join(this.mountpoint, 'filename');
const stream = lkl.fs.WriteStream(fpath);
const chunks = [
{chunk: Buffer.from('1')},
{chunk: Buffer.from('2')},
{chunk: Buffer.from('3')},
]
// testing writev syscall
stream._writev(chunks, function(err) {
// testing pwritev syscall
stream.pos = 1;
stream._writev(chunks, function(err) {
stream.close(function(err){
lkl.fs.readFileAsync(fpath, 'utf8')
.then(function(content) {
assert.strictEqual(content, '1123', 'should read what it has written');
done();
})
})
});
});
});
});
});
});