Linux内核进程详解之一:sync_supers

先说下环境,CentOS 6.0/Linux kernel 2.6.38.8/X86-64,后面提到的代码也都来之kernel 2.6.38.8。这个环节下的进程列表具体如下所示,后续将有一系列的文章分析各个进程(主要是内核进程)的功能:

[root@localhost ~]# cat /etc/issue
CentOS Linux release 6.0 (Final)
Kernel \r on an \m

[root@localhost ~]# uname -a
Linux localhost.localdomain 2.6.38.8 #4 SMP Mon Oct 31 20:49:48 CST 2011 x86_64 x86_64 x86_64 GNU/Linux
[root@localhost ~]# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1  19284  1368 ?        Ss   Feb06   0:02 /sbin/init
root         2  0.0  0.0      0     0 ?        S    Feb06   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        S    Feb06   0:00 [ksoftirqd/0]
root         5  0.0  0.0      0     0 ?        S    Feb06   0:20 [kworker/u:0]
root         6  0.0  0.0      0     0 ?        S    Feb06   0:00 [migration/0]
root         7  0.0  0.0      0     0 ?        S    Feb06   0:00 [migration/1]
root         9  0.0  0.0      0     0 ?        S    Feb06   0:00 [ksoftirqd/1]
root        11  0.0  0.0      0     0 ?        S<   Feb06   0:00 [cpuset]
root        12  0.0  0.0      0     0 ?        S<   Feb06   0:00 [khelper]
root        13  0.0  0.0      0     0 ?        S<   Feb06   0:00 [netns]
root        14  0.0  0.0      0     0 ?        S    Feb06   0:01 [sync_supers]
root        15  0.0  0.0      0     0 ?        S    Feb06   0:00 [bdi-default]
root        16  0.0  0.0      0     0 ?        S<   Feb06   0:00 [kintegrityd]
root        17  0.0  0.0      0     0 ?        S<   Feb06   0:00 [kblockd]
root        18  0.0  0.0      0     0 ?        S<   Feb06   0:00 [kacpid]
root        19  0.0  0.0      0     0 ?        S<   Feb06   0:00 [kacpi_notify]
root        20  0.0  0.0      0     0 ?        S<   Feb06   0:00 [kacpi_hotplug]
root        21  0.0  0.0      0     0 ?        S<   Feb06   0:00 [ata_sff]
root        22  0.0  0.0      0     0 ?        S    Feb06   0:00 [khubd]
root        23  0.0  0.0      0     0 ?        S<   Feb06   0:00 [md]
root        24  0.0  0.0      0     0 ?        S    Feb06   0:00 [khungtaskd]
root        25  0.0  0.0      0     0 ?        S    Feb06   0:05 [kswapd0]
root        26  0.0  0.0      0     0 ?        SN   Feb06   0:00 [ksmd]
root        27  0.0  0.0      0     0 ?        SN   Feb06   0:02 [khugepaged]
root        28  0.0  0.0      0     0 ?        S    Feb06   0:00 [fsnotify_mark]
root        29  0.0  0.0      0     0 ?        S<   Feb06   0:00 [aio]
root        30  0.0  0.0      0     0 ?        S<   Feb06   0:00 [crypto]
root        35  0.0  0.0      0     0 ?        S    Feb06   0:20 [kworker/u:1]
root        37  0.0  0.0      0     0 ?        S<   Feb06   0:00 [kpsmoused]
root       175  0.0  0.0      0     0 ?        S    Feb06   0:00 [scsi_eh_0]
root       176  0.0  0.0      0     0 ?        S    Feb06   0:42 [scsi_eh_1]
root       182  0.0  0.0      0     0 ?        S<   Feb06   0:00 [mpt_poll_0]
root       183  0.0  0.0      0     0 ?        S<   Feb06   0:00 [mpt/0]
root       184  0.0  0.0      0     0 ?        S    Feb06   0:00 [scsi_eh_2]
root       240  0.0  0.0      0     0 ?        S<   Feb06   0:00 [kdmflush]
root       247  0.0  0.0      0     0 ?        S<   Feb06   0:00 [kdmflush]
root       259  0.0  0.0      0     0 ?        S    Feb06   0:19 [jbd2/dm-0-8]
root       260  0.0  0.0      0     0 ?        S<   Feb06   0:00 [ext4-dio-unwrit]
root       297  0.0  0.0      0     0 ?        S    Feb06   0:01 [kauditd]
root       346  0.0  0.1  11700  1820 ?        S<s  Feb06   0:00 /sbin/udevd -d
root       565  0.0  0.0      0     0 ?        S    Feb06   0:05 [flush-253:0]
root       681  0.0  0.0      0     0 ?        S<   Feb06   0:00 [vmmemctl]
root       757  0.0  0.0      0     0 ?        S<   Feb06   0:00 [kdmflush]
root       801  0.0  0.0      0     0 ?        S    Feb06   0:00 [jbd2/sda1-8]
root       802  0.0  0.0      0     0 ?        S<   Feb06   0:00 [ext4-dio-unwrit]
root       803  0.0  0.0      0     0 ?        S    Feb06   0:00 [jbd2/dm-2-8]
root       804  0.0  0.0      0     0 ?        S<   Feb06   0:00 [ext4-dio-unwrit]
root       912  0.0  0.3  12880  3108 ?        S<   Feb06   0:00 /sbin/udevd -d
root       924  0.0  0.2  12356  2648 ?        S<   Feb06   0:00 /sbin/udevd -d
root      1114  0.0  0.1 242492  1540 ?        Sl   Feb06   0:05 /sbin/rsyslogd -c 4
root      1143  0.0  0.0   9104   428 ?        Ss   Feb06   1:04 irqbalance
rpc       1162  0.0  0.0  18920   816 ?        Ss   Feb06   0:01 rpcbind
root      1176  0.0  0.0   6604   260 ?        Ss   Feb06   0:00 mdadm --monitor --scan -f --pid-file=/var/run/mdadm/mdadm.pid
dbus      1185  0.0  0.1  29964  1448 ?        Ssl  Feb06   0:00 dbus-daemon --system
root      1196  0.0  0.3  95412  3468 ?        Ssl  Feb06   0:00 NetworkManager --pid-file=/var/run/NetworkManager/NetworkManager.pid
root      1202  0.0  0.1  55792  2000 ?        S    Feb06   0:00 /usr/sbin/modem-manager
avahi     1212  0.0  0.1  27820  1392 ?        S    Feb06   0:00 avahi-daemon: running [linux.local]
avahi     1213  0.0  0.0  27696   188 ?        Ss   Feb06   0:00 avahi-daemon: chroot helper
root      1221  0.0  0.1   9064  1360 ?        S    Feb06   0:04 /sbin/dhclient -d -4 -sf /usr/libexec/nm-dhcp-client.action -pf /var/run/dhclient-eth3.pid -lf /var/lib/dhclient/dhclient-aacaa3a9-81be-441d-ba72-cec0c023b1f8-eth3.lease -cf /var/run/nm-dhclient-eth3.conf eth3
root      1235  0.0  0.0  39232   388 ?        Ss   Feb06   0:00 /usr/sbin/wpa_supplicant -c /etc/wpa_supplicant/wpa_supplicant.conf -B -u -f /var/log/wpa_supplicant.log -P /var/run/wpa_supplicant.pid
rpcuser   1236  0.0  0.1  23088  1124 ?        Ss   Feb06   0:00 rpc.statd
root      1251  0.0  0.0   4020   508 tty1     Ss+  Feb11   0:00 /sbin/mingetty /dev/tty1
root      1280  0.0  0.0      0     0 ?        S<   Feb06   0:00 [rpciod]
root      1287  0.0  0.0  27336   396 ?        Ss   Feb06   0:00 rpc.idmapd
root      1297  0.0  0.2 178584  2840 ?        Ss   Feb06   0:00 cupsd -C /etc/cups/cupsd.conf
root      1322  0.0  0.0   4036   604 ?        Ss   Feb06   0:00 /usr/sbin/acpid
68        1331  0.0  0.3  26184  3252 ?        Ss   Feb06   0:03 hald
root      1332  0.0  0.1  18068  1136 ?        S    Feb06   0:00 hald-runner
root      1375  0.0  0.0  20184   832 ?        S    Feb06   0:00 hald-addon-input: Listening on /dev/input/event0 /dev/input/event1
root      1376  0.0  0.0  20180   856 ?        S    Feb06   0:18 hald-addon-storage: no polling on /dev/fd0 because it is explicitly disabled
68        1377  0.0  0.0  17760   988 ?        S    Feb06   0:00 hald-addon-acpi: listening on acpid socket /var/run/acpid.socket
root      1380  0.0  0.0  20180   856 ?        S    Feb06   1:29 hald-addon-storage: polling /dev/sr0 (every 2 sec)
root      1397  0.0  0.1  89180  1420 ?        Ssl  Feb06   0:00 pcscd
root      1418  0.0  0.3 381500  3368 ?        Ssl  Feb06   0:38 automount --pid-file /var/run/autofs.pid
root      1452  0.0  0.1  63804  1316 ?        Ss   Feb06   0:00 /usr/sbin/sshd
root      1478  0.0  0.0  22020   880 ?        Ss   Feb06   0:00 xinetd -stayalive -pidfile /var/run/xinetd.pid
root      1579  0.0  0.2  62020  2716 ?        Ss   Feb06   0:03 /usr/libexec/postfix/master
postfix   1586  0.0  0.2  62168  2436 ?        S    Feb06   0:00 qmgr -l -t fifo -u
root      1590  0.0  0.8 263516  8848 ?        Ss   Feb06   1:25 /usr/sbin/abrtd
root      1604  0.0  0.0 108292   944 ?        S    Feb06   0:47 /bin/bash /usr/sbin/ksmtuned
qpidd     1616  0.0  0.2 314868  3052 ?        Ssl  Feb06   0:27 /usr/sbin/qpidd --data-dir /var/lib/qpidd --daemon
root      1646  0.0  0.1 117072  1324 ?        Ss   Feb06   0:06 crond
root      1657  0.0  0.0  21360   156 ?        Ss   Feb06   0:00 /usr/sbin/atd
root      1668  0.0  1.0 268400 10880 ?        Sl   Feb06   0:01 libvirtd --daemon
root      1733  0.0  0.0   4020   504 tty2     Ss+  Feb06   0:00 /sbin/mingetty /dev/tty2
root      1737  0.0  0.0   4020   508 tty3     Ss+  Feb06   0:00 /sbin/mingetty /dev/tty3
root      1740  0.0  0.0   4020   504 tty4     Ss+  Feb06   0:00 /sbin/mingetty /dev/tty4
root      1742  0.0  0.0   4020   504 tty5     Ss+  Feb06   0:00 /sbin/mingetty /dev/tty5
root      1745  0.0  0.0   4020   500 tty6     Ss+  Feb06   0:00 /sbin/mingetty /dev/tty6
nobody    1761  0.0  0.0  12840   564 ?        S    Feb06   0:00 /usr/sbin/dnsmasq --strict-order --bind-interfaces --pid-file=/var/run/libvirt/network/default.pid --conf-file=  --listen-address 192.168.122.1 --except-interface lo --dhcp-range 192.168.122.2,192.168.122.254 --dhcp-lease-max=253 --dhcp-no-override
root      1780  0.0  0.2 4111744 2592 ?        Sl   Feb06   0:00 /usr/sbin/console-kit-daemon --no-daemon
root      1886  0.0  0.0  25536   704 ?        S<sl Feb06   0:01 auditd
root     14757  0.0  0.3  97484  3636 ?        Ss   14:57   0:00 sshd: root@pts/0
root     14761  0.0  0.1 108296  1832 pts/0    Ss   14:57   0:00 -bash
root     14858  0.0  0.3  97484  3640 ?        Ss   15:01   0:00 sshd: root@pts/1
root     14862  0.0  0.1 108424  1868 pts/1    Ss+  15:01   0:00 -bash
root     14987  0.0  0.3  97484  3636 ?        Ss   15:04   0:00 sshd: root@pts/2
root     14991  0.0  0.1 108296  1680 pts/2    Ss+  15:04   0:00 -bash
root     15049  0.0  0.0      0     0 ?        S    15:08   0:00 [kworker/1:0]
postfix  15321  0.0  0.2  62100  2656 ?        S    15:31   0:00 pickup -l -t fifo -u
root     15401  0.1  0.0      0     0 ?        S    15:38   0:01 [kworker/0:1]
root     15518  0.0  0.0      0     0 ?        S    15:48   0:00 [kworker/0:0]
root     15556  0.0  0.0      0     0 ?        S    15:50   0:00 [kworker/1:2]
root     15582  0.0  0.0      0     0 ?        S    15:53   0:00 [kworker/0:2]
root     15727  0.0  0.0      0     0 ?        S    16:03   0:00 [kworker/1:1]
root     15791  0.0  0.0 100864   456 ?        S    16:07   0:00 sleep 60
root     15793  0.0  0.1 107968  1052 pts/0    R+   16:07   0:00 ps aux
root     25845  0.0  0.0      0     0 ?        S    Feb07   0:00 [jbd2/sdb1-8]
root     25846  0.0  0.0      0     0 ?        S<   Feb07   0:00 [ext4-dio-unwrit]

sync_supers内核线程功能专一,用来同步操作系统当前挂载的各个文件系统的超级块数据,由于超级块对于文件系统的特殊性,所以这对保证文件系统的完整性至关重要。
在源文件mm/backing-dev.c内可以看到sync_supers内核线程的创建:

static int __init default_bdi_init(void)
{
	int err;

	sync_supers_tsk = kthread_run(bdi_sync_supers, NULL, "sync_supers");
	BUG_ON(IS_ERR(sync_supers_tsk));

	setup_timer(&sync_supers_timer, sync_supers_timer_fn, 0);
	bdi_arm_supers_timer();

	err = bdi_init(&default_backing_dev_info);
	if (!err)
		bdi_register(&default_backing_dev_info, NULL, "default");
	err = bdi_init(&noop_backing_dev_info);

	return err;
}
subsys_initcall(default_bdi_init);

void bdi_arm_supers_timer(void)
{
	unsigned long next;

	if (!dirty_writeback_interval)
		return;

	next = msecs_to_jiffies(dirty_writeback_interval * 10) + jiffies;
	mod_timer(&sync_supers_timer, round_jiffies_up(next));
}

/*
 * The interval between `kupdate'-style writebacks
 */
unsigned int dirty_writeback_interval = 5 * 100; /* centiseconds */

通过函数bdi_arm_supers_timer()设置定时器,默认每隔5秒唤醒sync_supers内核线程执行具体的操作函数sync_supers():

/*
 * kupdated() used to do this. We cannot do it from the bdi_forker_thread()
 * or we risk deadlocking on ->s_umount. The longer term solution would be
 * to implement sync_supers_bdi() or similar and simply do it from the
 * bdi writeback thread individually.
 */
static int bdi_sync_supers(void *unused)
{
	set_user_nice(current, 0);

	while (!kthread_should_stop()) {
		set_current_state(TASK_INTERRUPTIBLE);
		schedule();

		/*
		 * Do this periodically, like kupdated() did before.
		 */
		sync_supers();
	}

	return 0;
}

/**
 * sync_supers - helper for periodic superblock writeback
 *
 * Call the write_super method if present on all dirty superblocks in
 * the system.  This is for the periodic writeback used by most older
 * filesystems.  For data integrity superblock writeback use
 * sync_filesystems() instead.
 *
 * Note: check the dirty flag before waiting, so we don't
 * hold up the sync while mounting a device. (The newly
 * mounted device won't need syncing.)
 */
void sync_supers(void)
{
	struct super_block *sb, *p = NULL;

	spin_lock(&sb_lock);
	list_for_each_entry(sb, &super_blocks, s_list) {
		if (list_empty(&sb->s_instances))
			continue;
		if (sb->s_op->write_super && sb->s_dirt) {
			sb->s_count++;
			spin_unlock(&sb_lock);

			down_read(&sb->s_umount);
			if (sb->s_root && sb->s_dirt)
				sb->s_op->write_super(sb);
			up_read(&sb->s_umount);

			spin_lock(&sb_lock);
			if (p)
				__put_super(p);
			p = sb;
		}
	}
	if (p)
		__put_super(p);
	spin_unlock(&sb_lock);
}

sync_supers函数逻辑非常简单,遍历所有超级块(通过内核提供的全局链表super_blocks,这个全局链表保存了操作系统当前所有挂载文件系统的super_block实例),如果实例不存在则continue下一个,如果实例存在则接着判断同步回写函数write_super是否存在(有些文件系统,例如虚拟的文件系统或基于物理内存的文件系统并不需要进行同步操作,所以可以不提供回写函数write_super,典型示例就是/proc文件系统)以及超级块是否脏而需要进行同步。
各个需要进行超级块数据同步的文件系统都会提供适当的回写函数,比如ext4:

static void ext4_write_super(struct super_block *sb)
{
	lock_super(sb);
	ext4_commit_super(sb, 1);
	unlock_super(sb);
}

static int ext4_commit_super(struct super_block *sb, int sync)
{
	struct ext4_super_block *es = EXT4_SB(sb)->s_es;
	struct buffer_head *sbh = EXT4_SB(sb)->s_sbh;
	int error = 0;

	if (!sbh)
		return error;
	if (buffer_write_io_error(sbh)) {
		/*
		 * Oh, dear.  A previous attempt to write the
		 * superblock failed.  This could happen because the
		 * USB device was yanked out.  Or it could happen to
		 * be a transient write error and maybe the block will
		 * be remapped.  Nothing we can do but to retry the
		 * write and hope for the best.
		 */
		ext4_msg(sb, KERN_ERR, "previous I/O error to "
		       "superblock detected");
		clear_buffer_write_io_error(sbh);
		set_buffer_uptodate(sbh);
	}
	/*
	 * If the file system is mounted read-only, don't update the
	 * superblock write time.  This avoids updating the superblock
	 * write time when we are mounting the root file system
	 * read/only but we need to replay the journal; at that point,
	 * for people who are east of GMT and who make their clock
	 * tick in localtime for Windows bug-for-bug compatibility,
	 * the clock is set in the future, and this will cause e2fsck
	 * to complain and force a full file system check.
	 */
	if (!(sb->s_flags & MS_RDONLY))
		es->s_wtime = cpu_to_le32(get_seconds());
	if (sb->s_bdev->bd_part)
		es->s_kbytes_written =
			cpu_to_le64(EXT4_SB(sb)->s_kbytes_written +
			    ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
			      EXT4_SB(sb)->s_sectors_written_start) >> 1));
	else
		es->s_kbytes_written =
			cpu_to_le64(EXT4_SB(sb)->s_kbytes_written);
	ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
					   &EXT4_SB(sb)->s_freeblocks_counter));
	es->s_free_inodes_count =
		cpu_to_le32(percpu_counter_sum_positive(
				&EXT4_SB(sb)->s_freeinodes_counter));
	sb->s_dirt = 0;
	BUFFER_TRACE(sbh, "marking dirty");
	mark_buffer_dirty(sbh);
	if (sync) {
		error = sync_dirty_buffer(sbh);
		if (error)
			return error;

		error = buffer_write_io_error(sbh);
		if (error) {
			ext4_msg(sb, KERN_ERR, "I/O error while writing "
			       "superblock");
			clear_buffer_write_io_error(sbh);
			set_buffer_uptodate(sbh);
		}
	}
	return error;
}

int sync_dirty_buffer(struct buffer_head *bh)
{
	return __sync_dirty_buffer(bh, WRITE_SYNC);
}
EXPORT_SYMBOL(sync_dirty_buffer);

转载请保留地址:http://lenky.info/2012/02/15/linux%e5%86%85%e6%a0%b8%e8%bf%9b%e7%a8%8b%e8%af%a6%e8%a7%a3%e4%b9%8b%e4%b8%80%ef%bc%9async_supers/http://lenky.info/?p=1095


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值