Skip to content

feat(shell): add sync command to flush filesystem buffers to disk #606

Description

@LSantha

Summary

Add a sync shell command that flushes dirty filesystem buffers to disk. With no arguments, flushes all mounted filesystems. With an optional path argument, flushes only the filesystem mounted at that path.

Motivation

With write-back caching (7baa16d), data written to disk may sit in the drive's volatile cache until unmount or power loss. There is currently no user-facing way to force a flush. A sync command fills this gap — standard on all Unix-like systems.

Implementation

Command class

package org.jnode.fs.command;

public class SyncCommand extends AbstractCommand {

    private final FileArgument argPath =
        new FileArgument("path", Argument.OPTIONAL,
            "flush only the filesystem mounted at this path");

    public SyncCommand() {
        super("Flush filesystem buffers to disk");
        registerArguments(argPath);
    }

    public static void main(String[] args) throws Exception {
        new SyncCommand().execute(args);
    }

    @Override
    public void execute() throws Exception {
        FileSystemService fss = InitialNaming.lookup(FileSystemService.NAME);
        PrintWriter out = getOutput().getPrintWriter();
        PrintWriter err = getError().getPrintWriter();

        if (argPath.isSet()) {
            // Find which filesystem is mounted at or under this path
            String path = argPath.getValue().getCanonicalPath();
            FileSystem<?> target = null;
            String mountPoint = null;
            for (Map.Entry<String, FileSystem<?>> e : fss.getMountPoints().entrySet()) {
                if (path.equals(e.getKey()) || path.startsWith(e.getKey() + File.separator)) {
                    target = e.getValue();
                    mountPoint = e.getKey();
                }
            }
            if (target == null) {
                err.println("No filesystem mounted at " + path);
                exit(1);
            }
            target.flush();
            out.println("synced " + mountPoint);
        } else {
            int errors = 0;
            for (Map.Entry<String, FileSystem<?>> e : fss.getMountPoints().entrySet()) {
                try {
                    e.getValue().flush();
                    out.println("synced " + e.getKey());
                } catch (IOException ex) {
                    err.println("sync failed on " + e.getKey() + ": " + ex.getMessage());
                    errors++;
                }
            }
            if (errors > 0) exit(1);
        }
    }
}

Plugin XML

Add to fs/descriptors/org.jnode.fs.command.xml (existing file):

<extension point="org.jnode.shell.aliases">
    <alias name="sync" class="org.jnode.fs.command.SyncCommand"/>
</extension>

<extension point="org.jnode.shell.syntaxes">
    <syntax alias="sync">
        <empty description="Flush all mounted filesystems to disk"/>
        <sequence description="Flush the filesystem at a specific path">
            <argument argLabel="path"/>
        </sequence>
    </syntax>
</extension>

Files to create/modify

  • Create: fs/src/commands/org/jnode/fs/command/SyncCommand.java
  • Modify: fs/descriptors/org.jnode.fs.command.xml — add alias and syntax entries

Testing / Validation

Test 1: Sync all mounted filesystems

  1. Boot JNode, mount a FAT filesystem: mount /dev/ide0-auto /mnt
  2. Write a file: echo test > /mnt/test.txt
  3. Run sync
  4. Expected output: synced /mnt
  5. Kill VM without save, reboot — file should be intact

Test 2: Sync specific path

  1. Mount FAT at /mnt
  2. Write a file
  3. Run sync /mnt
  4. Expected: synced /mnt
  5. Verify only that filesystem was flushed (check serial log for FLUSH CACHE)

Test 3: Sync non-mounted path

  1. Run sync /nonexistent
  2. Expected: error message No filesystem mounted at /nonexistent, exit code 1

Test 4: Multiple mount points

  1. Mount two filesystems: mount /dev/ide0-auto /mnt1 and mount /dev/ide1-auto /mnt2
  2. Run sync
  3. Expected: synced /mnt1 and synced /mnt2
  4. Verify both FLUSH CACHE commands in serial log

Test 5: Read-only filesystem

  1. Mount a read-only filesystem (e.g., ISO9660)
  2. Run sync
  3. Expected: synced /cdrom (flush is no-op for read-only, no error)

Test 6: No filesystems mounted

  1. Boot with no mounts
  2. Run sync
  3. Expected: no output, clean exit (empty loop)

Acceptance Criteria

  • sync with no args flushes all mounted filesystems
  • sync /path flushes only the filesystem at that path
  • Non-mounted path prints error and exits with code 1
  • Partial failures (one FS fails) report errors but continue flushing others
  • Exit code 0 on full success, 1 on any failure
  • Command appears in shell tab-completion

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent/doneThe agent finished successfully; PR opened or comment posted.enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions