Skip to content

Add a fault-injection with fs freeze #110

@ligurio

Description

@ligurio

fsfreeze(8):

fsfreeze suspends or resumes access to a filesystem.

fsfreeze halts any new access to the filesystem and creates a
stable image on disk. fsfreeze is intended to be used with
hardware RAID devices that support the creation of snapshots.

Filesystem freeze and unfreeze allows backup systems to snapshot a consistent state.

Behavior:

  • Suspend writes
    • Including all vfs I/O submission APIs and mmap I/O (the latter only since Linux 3.0)
    • We need to get the metadata and journal out, so there are several special cases for them
  • Sync filesystem
  • Call filesystem specific freeze function
  • Used to be a xfs specific ioctl but is now a VFS interface

VFS API

  • Freeze: ioctl(fd, FIFREEZE, 0)
  • Thaw: ioctl(fd, FITHAW, 0)

New filesystem freeze API

  • FIISFROZEN: vfs ioctl to check freeze state
  • BLKISFROZEN: add block device ioctl to check freeze state
  • Useful to thaw unmounted frozen filesystems
  • Might get rid of this if returning EBUSY when trying to unmount a frozen filesystem is acceptable
  • FIGETFREEZEFD: freezes the indicated filesystem and returns a file descriptor; as long as that file descriptor is held open, the filesystem remains open
  • Since the filesytem is automatically thawed when the file descriptor is closed, if the agent goes away the filesystem will be automagically thawed by kernel
  • Filesystem freeze fs ioctls: FS_FREEZE_FD, FS_THAW_FD, FS_ISFROZEN_FD
  • Added new parameter to FIGETFREEZEFD ioctl to indicate whether the filesystem should be frozen on fd open
  • Useful when you are trying to restart the agent

See New Filesystem Freeze API (PDF)

https://github.com/util-linux/util-linux/blob/ef7d50a0cc59d3b55587c8ea5fa45db45b888aee/sys-utils/fsfreeze.c#L118-L140

	if (fstat(fd, &sb) == -1) {
		warn(_("stat of %s failed"), path);
		goto done;
	}

	if (!S_ISDIR(sb.st_mode)) {
		warnx(_("%s: is not a directory"), path);
		goto done;
	}

	switch (action) {
	case FREEZE:
		if (ioctl(fd, FIFREEZE, 0)) {
			warn(_("%s: freeze failed"), path);
			goto done;
		}
		break;
	case UNFREEZE:
		if (ioctl(fd, FITHAW, 0)) {
			warn(_("%s: unfreeze failed"), path);
			goto done;
		}
		break;

https://github.com/qemu/qemu/blob/master/qga/commands-posix.c

        /* we try to cull filesystems we know won't work in advance, but other
         * filesystems may not implement fsfreeze for less obvious reasons.
         * these will report EOPNOTSUPP. we simply ignore these when tallying
         * the number of frozen filesystems.
         * if a filesystem is mounted more than once (aka bind mount) a
         * consecutive attempt to freeze an already frozen filesystem will
         * return EBUSY.
         *
         * any other error means a failure to freeze a filesystem we
         * expect to be freezable, so return an error in those cases
         * and return system to thawed state.
         */
        ret = ioctl(fd, FIFREEZE);
        if (ret == -1) {
            if (errno != EOPNOTSUPP && errno != EBUSY) {
                error_setg_errno(errp, errno, "failed to freeze %s",
                                 mount->dirname);
                close(fd);
                goto error;
            }
        } else {
            i++;
        }
        close(fd);

...

        /* we have no way of knowing whether a filesystem was actually unfrozen
         * as a result of a successful call to FITHAW, only that if an error
         * was returned the filesystem was *not* unfrozen by that particular
         * call.
         *
         * since multiple preceding FIFREEZEs require multiple calls to FITHAW
         * to unfreeze, continuing issuing FITHAW until an error is returned,
         * in which case either the filesystem is in an unfreezable state, or,
         * more likely, it was thawed previously (and remains so afterward).
         *
         * also, since the most recent successful call is the one that did
         * the actual unfreeze, we can use this to provide an accurate count
         * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
         * may * be useful for determining whether a filesystem was unfrozen
         * during the freeze/thaw phase by a process other than qemu-ga.
         */
        do {
            ret = ioctl(fd, FITHAW);
            if (ret == 0 && !logged) {
                i++;
                logged = true;
            }
        } while (ret == 0);
        close(fd);

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions