runtimejs / runtime

[not maintained] Lightweight JavaScript library operating system for the cloud
http://runtimejs.org
Apache License 2.0
1.93k stars 128 forks source link

Disk driver! #133

Closed facekapow closed 7 years ago

facekapow commented 7 years ago

Disk support for runtime.js! runtime.disk.disks contains all the registered disk interfaces.

Disk interfaces can optionally be initialized with the underlying methods through a second init argument, like read, write, formatInfo, etc. To read and write, provide a sector and a Uint8Array (I believe the array should be a multiple of the disk's sectorSize). Getting isOnline will call the underlying ongetonline method to check if the disk is connected and therefore usable. Getting formatInfo returns information about the disk from ongetformatinfo.

The default virtio-blk driver registers a single disk, called hda. An example of using it with fatfs:

// custom fs.js
'use strict';

const fatfs = require('fatfs');
const disk = runtime.disk.disks.hda;

module.exports = fatfs.createFileSystem({
  sectorSize: disk.formatInfo.sectorSize,
  numSectors: disk.formatInfo.totalSectorCount,
  readSectors(i, dest, cb) {
    disk
      .read(i, dest)
      .then(cb.bind(null, null))
      .catch(cb);
  },
  writeSectors(i, data, cb) {
    disk
      .write(i, data)
      .then(cb.bind(null, null))
      .catch(cb);
  }
});
piranna commented 7 years ago

Wiiii!!! That's awesome! :-D

module.exports = fatfs.createFileSystem({

Is this formatting it? How to use an already existent one? I though fatfs accepted a blockDevice object...

.then(cb.bind(null, null)) .catch(cb);

This could lead to being cb() called twice in case cb() itself generates an error, is better to use the second argument of .then() instead of .catch().

facekapow commented 7 years ago

Is this formatting it? How to use an already existent one? I though fatfs accepted a blockDevice object..

No it's not formatting it, it's using the existing one, createFileSystem just creates a new instance of an fs object, it's just a confusing function name :smile:. And what it accepts is a driver object to access the disk.

This could lead to being cb() called twice in case cb() itself generates an error, is better to use the second argument of .then() instead of .catch().

You're right, I'm just used to doing it the other way. It's probably better to pass it in as a second argument like you say. Either way, it's just an example of using the API, you can change it any way you like.

iefserge commented 7 years ago

@facekapow Very nice, added some comments! What's the best way to setup a disk for qemu?

facekapow commented 7 years ago

@iefserge The way I do it is using -drive, like -drive file=disk.img,if=virtio,media=disk,format=raw.

iefserge commented 7 years ago

@facekapow how do you create a disk image for it?

I'm using this command (on MacOS), but it will not format it

qemu-img create -f raw -o size=10M disk.img

Code I'm trying to run:

'use strict';

const fatfs = require('fatfs');
const disk = runtime.block.devices[0];

var fs = fatfs.createFileSystem({
  sectorSize: disk.formatInfo.sectorSize,
  numSectors: disk.formatInfo.totalSectorCount,
  readSectors(i, dest, cb) {
    disk
      .read(i, dest)
      .then(cb.bind(null, null))
      .catch(cb);
  },
  writeSectors(i, data, cb) {
    disk
      .write(i, data)
      .then(cb.bind(null, null))
      .catch(cb);
  }
});

fs.readFile('/1.txt', 'utf8', (err, data) => {
  console.log(err, data);
});

doesn't print any data or error

Edit: added

fs.on('ready', () => {
  console.log('ready');
});

fs.on('error', err => {
  console.log(err);
});

now it prints [Error: Invalid volume signature!], I think I need to format it first

facekapow commented 7 years ago

@iefserge Yeah, you need to format it as a FAT filesystem first. On macOS, you can use Disk Utility to format a partition for it.

But if you want to do it purely from the command line you have to:

hdiutil attach disk.img -nomount
# it'll print where it's attached
diskutil eraseVolume fat32 "RUNTIMEJS" /dev/disk1 # replace /dev/disk1 with wherever it says it's attached
hdiutil detach /dev/disk1 # same here

Also, I've found that the GUI version of Disk Utility will handle any size you throw at it, but the command line version is very picky about the size of the disk you give it for the format you give it. The only safe sizes I've found are GiBs, so with qemu-img, that'd be G.

iefserge commented 7 years ago

@facekapow Ok thanks, that worked. I was able to create a new file, but readFile fails with an error

fs.on('ready', () => {
  fs.readFile('/1.txt', 'utf8', (err, data) => {
    console.log(err, data);
  });
});
Uncaught exception: /node_modules/fatfs/helpers.js:37: TypeError: Cannot read property '0' of undefined
TypeError: Cannot read property '0' of undefined
    at Object.exports.parseFlags (/node_modules/fatfs/helpers.js:37:14)
    at /node_modules/fatfs/index.js:130:19
    at setImmediate (/node_modules/runtimejs/js/modules/process.js:86:53)
piranna commented 7 years ago

Do you have a file in the filesystem so it could be read?

El 3/9/2016 16:59, "Serge" notifications@github.com escribió:

@facekapow https://github.com/facekapow Ok thanks, that worked. I was able to create a new file, but readFile fails with an error

fs.on('ready', () => { fs.readFile('/1.txt', 'utf8', (err, data) => { console.log(err, data); }); });

Uncaught exception: /node_modules/fatfs/helpers.js:37: TypeError: Cannot read property '0' of undefined TypeError: Cannot read property '0' of undefined at Object.exports.parseFlags (/node_modules/fatfs/helpers.js:37:14) at /node_modules/fatfs/index.js:130:19 at setImmediate (/node_modules/runtimejs/js/modules/process.js:86:53)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/runtimejs/runtime/pull/133#issuecomment-244551138, or mute the thread https://github.com/notifications/unsubscribe-auth/AAgfvol1TziLX7ke8Ct2QQZKRlQVPPaBks5qmYtXgaJpZM4Jur73 .

facekapow commented 7 years ago

@iefserge From what I can see in the source code, I think the problem is that fatfs doesn't seem to support passing a string for opts. Try { encoding: 'utf8' } instead and see if it works.

iefserge commented 7 years ago

@facekapow wow, that worked! thanks! @piranna yeah, filesystem works and I can mount it in OSX.

iefserge commented 7 years ago

@facekapow works great, LGTM 🚀

facekapow commented 7 years ago

I'm gonna merge this, but in order to be able to use this, runtime-cli is gonna need to be updated to allow files to be passed in for disk images. What about adding a subcommand to runtime-cli for easy creation of FAT disk images?

iefserge commented 7 years ago

Sounds good. How would subcommand work though? Using OS tools or js code?

facekapow commented 7 years ago

I'd think using OS tools, since there are no modules that I know of that can format an image to FAT, although I'd be happy to be wrong :smile:.

piranna commented 7 years ago

I'd think using OS tools, since there are no modules that I know of that can format an image to FAT, although I'd be happy to be wrong 😄.

Search for "nos-init" ;-)

facekapow commented 7 years ago

@piranna Do you mean this? It looks like all it does is create an initrd for NodeOS, not an empty FAT disk. And searching on npm gives zero results, so :confused:...

piranna commented 7 years ago

Sorry, node-mkfat from the same author.

El 3/9/2016 22:15, "facekapow" notifications@github.com escribió:

@piranna https://github.com/piranna Do you mean this https://github.com/sbuller/nos-init? It looks like all it does is create an initrd for NodeOS, not an empty FAT disk. And searching on npm gives zero results https://www.npmjs.com/search?q=nos-init, so 😕...

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/runtimejs/runtime/pull/133#issuecomment-244567539, or mute the thread https://github.com/notifications/unsubscribe-auth/AAgfvkLEAK4pH9syjZ_cvtDSC0nOo67aks5qmdVfgaJpZM4Jur73 .

facekapow commented 7 years ago

@piranna If I'm not mistaken, it limits you to 1 GiB disk size?

piranna commented 7 years ago

Well, it's something... For experimental purposses on this initial stage is just enought, later it could be improved.

El 3/9/2016 22:46, "facekapow" notifications@github.com escribió:

@piranna https://github.com/piranna If I'm not mistaken, it limits you to 1 GiB disk size?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/runtimejs/runtime/pull/133#issuecomment-244568892, or mute the thread https://github.com/notifications/unsubscribe-auth/AAgfvtQAO2fIT1iAcWEWJl2nDqZzh0xEks5qmdyIgaJpZM4Jur73 .

facekapow commented 7 years ago

Well, I'm going to merge this and the subcommand can be further discussed in the runtime-cli repo.

austinfrey commented 7 years ago

Noob question. Would this be equivalent to mounting a volume in something like docker? Trying to follow along but I'm not that technical

facekapow commented 7 years ago

@aafrey Actually, not a bad comparison. Pretty close, this would be what you use to read and write to the disk; mounting a volume would use this. Everything the system does with the disk uses this.

austinfrey commented 7 years ago

I guess the difference would be docker would mount to the host file system, this creates a completely separate disk?

facekapow commented 7 years ago

Well, it depends. I believe there's a way for QEMU to use a host disk. But the way that we're doing it in runtime.js is to create a separate disk, yes.

austinfrey commented 7 years ago

Nice. Thanks for the explanation