Working with file systems

The BlackBerry 10 OS provides a variety of file systems, so that you can easily access DOS, Linux, as well as native (Power-Safe) disks. File systems in System architecture describes their classes and features.

Under BlackBerry 10 OS:

  • You can dynamically start and stop file systems.
  • Multiple file systems may run concurrently.
  • Applications are presented with a single unified pathname space and interface, regardless of the configuration and number of underlying file systems.

Setting up, starting, and stopping a block file system

When you boot your machine, the system detects partitions on the block I/O devices and automatically starts the appropriate file system for each partition. You aren't likely ever to need to stop or restart a block file system; if you change any of the file system's options, you can use the -e or -u option to the mount command to update the file system.

If you need to change any of the options associated with the block I/O device, you can slay the appropriate devb-* driver (being careful not to pull the carpet from under your feet) and restart it, but you need to explicitly mount any of the file systems on it.

To determine how much free space you have on a file system, use the df command. For more information, see Utilities.

Some file systems have the concept of being marked as dirty. This can be used to skip an intensive file system-check the next time it starts up. By default, when you mount a file system as read-write, that flag is set; when you cleanly unmount the file system, the flag is cleared. In between, the file system is dirty and may need to be checked (if it never gets cleanly unmounted). The Power-Safe file system has no such flag; it just rolls back to the last clean snapshot. You can use the blk marking=none option to turn off this marking; see the entry for io-blk.so in Utilities.

Mounting and unmounting file systems

The following utilities work with file systems:

mount
Mount a block-special device or remote file system.
umount
Unmount a device or file system.

By default, file systems are mounted as read-write if the physical media permit it. You can use the -r option for mount to mount the file system as read-only. The io-blk.so library also supports an ro option for mounting block I/O file systems as read-only.

You can also use the -u option for the mount utility to temporarily change the way the file system is mounted. For example, if a file system is usually mounted as read-only, and you need to remount it as read-write, you can update the mounting by specifying -uw. For example:

mount -uw /

To return to read-only mode, use the -ur options:

mount -ur /

You should use umount to unmount a read-write file system before removing or ejecting removable media.

See Utilities for details on usage and syntax.

/dev/shmem RAM file system

The BlackBerry 10 OS provides a simple RAM-based file system that allows read/write files to be placed under /dev/shmem.

Note that /dev/shmem isn't actually a file system. It's a window onto the shared memory names that happens to have some file system-like characteristics.

The files in the /dev/shmem directory are advertised as name-special files (S_IFNAM), which fools many utilities—such as more—that expect regular files (S_IFREG). For this reason, many utilities might not work for the RAM file system.

This file system is mainly used by the shared memory system of procnto . In special situations (for example, when no file system is available), you can use the RAM file system to store file data. There's nothing to stop a file from consuming all free RAM; if this happens, other processes might have problems.

You can use the RAM file system mostly in tiny embedded systems where you need a small, fast, temporary-storage file system, but you don't need persistent storage across reboots.

The file system comes for free with procnto and doesn't require any setup or device driver. You can simply create files under /dev/shmem and grow them to any size (depending on RAM resources).

Although the RAM file system itself doesn't support hard or soft links or directories, you can create a link to it by using process-manager links. For example, you could create a link to a RAM-based /tmp directory:

ln -sP /dev/shmem /tmp

This tells procnto to create a process-manager link to /dev/shmem known as /tmp. Most application programs can then open files under /tmp as if it were a normal file system.

To minimize the size of the RAM file system code inside the process manager, this file system specifically doesn't include big file system features such as:

  • File locking
  • Directories
  • . and .. entries for the current and parent directories
  • Hard or soft linksPprotection from overwriting running executables. A real file system gives an error of EBUSY if you try this; in /dev/shmem, the running executable will likely crash. This is because being able to write to a shared memory object while somebody else has it open is the whole point of shared memory.

Power-Safe file system

The Power-Safe file system, supported by the fs-qnx6.so shared object, is a reliable disk file system that can withstand power failures without losing or corrupting data. Its features include the following:

  • 510-byte (UTF-8) filenames
  • Copy-on-write (COW) updates that prevent the file system from becoming corrupted by a power failure while writing
  • A snapshot that captures a consistent view of the file system

For information about the structure of this file system, see Power-Safe file system in System architecture.

If the drive doesn't support synchronizing, fs-qnx6.so can't guarantee that the file system is Power-Safe. Before using this file system on devices—such as USB/Flash devices—other than traditional rotating hard disk drive media, check to make sure that your device meets the file system's requirements. For more information, see Required properties of the device in the entry for fs-qnx6.so in Utilities.

To create a Power-Safe file system, use the mkqnx6fs utility. For example:

mkqnx6fs /dev/hd0t76

You can use the mkqnx6fs options to specify the logical blocksize, endian layout, number of logical blocks, and so on.

Once you've formatted the file system, simply mount it. For example:

mount -t qnx6 /dev/hd0t76 /mnt/psfs

For more information about the options for the Power-Safe file system, see fs-qnx6.so in Utilities.

Booting

The current boot support is for x86 PC partition-table-based (the same base system as current booting) with a BIOS that supports INT13X (LBA). The mkqnx6fs utility creates a .boot directory in the root of the new file system. This is always present, and always has an inode of 2 (the root directory itself is inode 1). The mkqnx6fs utility also installs a new secondary boot loader in the first 8 KB of the partition (and patches it with the location and offset of the file system).

The fs-qnx6.so file system protects this directory at runtime; in particular it can't be removed or renamed, nor can it exceed 4096 bytes (128 entries). Files placed into the .boot directory are assumed to be boot images created with mkifs . The name of the file should describe the boot image (for example, 6.3.2SP3, 6.4.0_with_diskboot, or SafeMode_1CPU).

The directory can contain up to 126 entries. You can create other types of object in this directory (for example, directories or symbolic links) but the boot loader ignores them. The boot loader also ignores certain-sized regular files (for example, 0 or larger than 2 GB), as well as those with names longer than 27 characters.

The file system implicitly suspends snapshots when a boot image is open for writing; this guarantees that the boot loader will never see a partially-written image. You typically build the images elsewhere and then copy them into the directory, and so are open for only a brief time; however this scheme also works if you send the output from mkifs directly to the final boot file.

To prevent this from being used as a DOS attack, the default permissions for the boot directory are root:root rwx------. You can change the permissions with chmod and chown , but beware that if you allow everyone to write in this directory, then anyone can install custom boot images or delete existing ones.

Snapshots

A snapshot is a committed stable view of a Power-Safe file system. Each mounted file system has one stable snapshot and one working view (in which copy-on-write modifications to the stable snapshot are being made). Whenever a new snapshot is made, file system activity is suspended (to give a stable system), the bitmaps are updated, all dirty blocks are forced to disk, and the alternate file system superblock is written (with a higher sequence number). Then file system activity is resumed, and another working view is constructed on the old superblock. When a file system is remounted after an unclean power failure, it restores the last stable snapshot.

Snapshots are made:

  • Explicitly, when a global sync() of all file systems is performed
  • Explicitly, when fsync() is called for any file in the Power-Safe file system
  • Explicitly, when switching to read-only mode with mount -ur
  • Periodically, from the timer specified to the snapshot= option to the mount command (the default is 10 seconds).

You can disable snapshots on a file system at a global or local level. When disabled, a new superblock isn't written, and an attempt to make a snapshot fails with an errno of EAGAIN (or silently, for the sync() or timer cases). If snapshots are still disabled when the file system is unmounted (implicitly or at a power failure), any pending modifications are discarded (lost).

Snapshots are also permanently disabled automatically after an unrecoverable error that results in an inconsistent file system. An example is running out of memory for caching bitmap modifications, or a disk I/O error while writing a snapshot. In this case, the file system is forced to be read-only, and the current and all future snapshot processing is omitted; the aim being to ensure that the last stable snapshot remains undisturbed and available for reloading at the next mount/startup (that is, the file system always has a guaranteed stable state, even if slightly stale). This is only for certain serious error situations, and generally shouldn't happen.

Manually disabling snapshots can be used to encapsulate a higher-level sequence of operations that must either all succeed or none occur (for example, should power be lost during this sequence). Possible applications include software updates or file system defragmentation.

To disable snapshots at the global level, clear the FS_FLAGS_COMMITTING flag on the file system, using the DCMD_FSYS_FILE_FLAGS command to devctl():

struct fs_fileflags  flags;
 
memset( &flags, 0, sizeof(struct fs_fileflags));
flags.mask[FS_FLAGS_GENERIC] = FS_FLAGS_COMMITTING;
flags.bits[FS_FLAGS_GENERIC] = disable ? 0 : FS_FLAGS_COMMITTING;
devctl( fd, DCMD_FSYS_FILE_FLAGS, &flags,
        sizeof(struct fs_fileflags), NULL);

This is a single flag for the entire file system, and can be set or cleared by any superuser client; thus applications must coordinate the use of this flag among themselves.

To disable snapshots at a local level, adjust the QNX6FS_SNAPSHOT_HOLD count on a per-file-descriptor basis, again using the DCMD_FSYS_FILE_FLAGS command to devctl(). Each open file has its own hold count, and the sum of all local hold counts is a global hold count that disables snapshots if nonzero. Thus if any client sets a hold count, snapshots are disabled until all clients clear their hold counts.

The hold count is a 32-bit value, and can be incremented more than once (and must be balanced by the appropriate number of decrements). If a file descriptor is closed, or the process terminates, then any local holds it contributed are automatically undone. The advantage of this scheme is that it requires no special coordination between clients; each can encapsulate its own sequence of atomic operations using its independent hold count:

struct fs_fileflags  flags;
 
memset( &flags, 0, sizeof(struct fs_fileflags));
flags.mask[FS_FLAGS_FSYS] = QNX6FS_SNAPSHOT_HOLD;
flags.bits[FS_FLAGS_FSYS] = QNX6FS_SNAPSHOT_HOLD;
devctl( fd, DCMD_FSYS_FILE_FLAGS, &flags,
        sizeof(struct fs_fileflags), NULL);
...
memset( &flags, 0, sizeof(struct fs_fileflags));
flags.mask[FS_FLAGS_FSYS] = QNX6FS_SNAPSHOT_HOLD;
flags.bits[FS_FLAGS_FSYS] = 0;
devctl( fd, DCMD_FSYS_FILE_FLAGS, &flags,
        sizeof(struct fs_fileflags), NULL);

Enabling snapshots doesn't in itself cause a snapshot to be made; you should do this with an explicit fsync() if required. It's often a good idea to fsync() both before disabling and after enabling snapshots.

Last modified: 2014-11-17



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus