sync

Introduce

sync, linux command, using to write any data buffer in memory out to disk.

It do nothing, but exercise the ‘sync’ system call

So, if we want to study what the ‘sync’ really do, go in the kernel.

sync command

File: coreutils-8.9/src/sync.c

int
main (int argc, char **argv)
{
  initialize_main (&argc, &argv);
  set_program_name (argv[0]);
  setlocale (LC_ALL, "");
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);

  atexit (close_stdout);

  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, Version,
                      usage, AUTHORS, (char const *) NULL);
  if (getopt_long (argc, argv, "", NULL, NULL) != -1)
    usage (EXIT_FAILURE);

  if (optind < argc)
    error (0, 0, _("ignoring all arguments"));

  sync ();
  exit (EXIT_SUCCESS);
}

Do nothing, but do system call sync()

sync architecture in kernel

system call sync() is defined in fs/sync.c

/*
 * sync everything.  Start out by waking pdflush, because that writes back
 * all queues in parallel.
 */
SYSCALL_DEFINE0(sync)
{
    wakeup_flusher_threads(0);
    sync_filesystems(0);
    sync_filesystems(1);
    if (unlikely(laptop_mode))
        laptop_sync_completion();
    return 0;
}

sync call sync_filesystems

static void sync_filesystems(int wait)
{
    struct super_block *sb;
    static DEFINE_MUTEX(mutex);

    mutex_lock(&mutex);        /* Could be down_interruptible */
    spin_lock(&sb_lock);
    list_for_each_entry(sb, &super_blocks, s_list)
        sb->s_need_sync = 1;

restart:
    list_for_each_entry(sb, &super_blocks, s_list) {
        if (!sb->s_need_sync)
            continue;
        sb->s_need_sync = 0;
        sb->s_count++;
        spin_unlock(&sb_lock);

        down_read(&sb->s_umount);
        if (!(sb->s_flags & MS_RDONLY) && sb->s_root && sb->s_bdi)
            __sync_filesystem(sb, wait);
        up_read(&sb->s_umount);

        /* restart only when sb is no longer on the list */
        spin_lock(&sb_lock);
        if (__put_super_and_need_restart(sb))
            goto restart;
    }
    spin_unlock(&sb_lock);
    mutex_unlock(&mutex);
}

sync_filesystems call __sync_filesystem

static int __sync_filesystem(struct super_block *sb, int wait)
{
    /*
     * This should be safe, as we require bdi backing to actually
     * write out data in the first place
     */
    if (!sb->s_bdi)
        return 0;

    /* Avoid doing twice syncing and cache pruning for quota sync */
    if (!wait) {
        writeout_quota_sb(sb, -1);
        writeback_inodes_sb(sb);
    } else {
        sync_quota_sb(sb, -1);
        sync_inodes_sb(sb);
    }
    if (sb->s_op->sync_fs)
        sb->s_op->sync_fs(sb, wait);
    return __sync_blockdev(sb->s_bdev, wait);
}

__sync_filesystem call sb->s_op->sync_fs(sb, wait), each filesystem should
implement the sync_fs()

when to use

  1. before shutdown computer, using sync more than twice
  2. after write big file to disk, such as using command cp
  3. to be continue

sync,fsync,fdatasync

  • sync, add the modified buffer to write_queue, then return immediately, not wait
    for the reality disk writed.
  • fsync, used for single file with specify file description,and wait the disk write finish.
  • fdatasync, similar to fsync, but just do effect to the data part. fsync make
    effect to data and file property.

special application

  1. How if I want to sync from serval Virtual Disks, and ignore serval VDs
  2. To be continue

Reference