首页 > *nix技术, 内核技术, 系统管理 > Linux内核进程详解之一:sync_supers

Linux内核进程详解之一:sync_supers

2012年2月15日 发表评论 阅读评论 11,142 次浏览

先说下环境,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://www.lenky.info/archives/2012/02/1095http://lenky.info/?p=1095


备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以Email或书面等方式告知,本站将及时删除相关内容或链接。

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.