📄 _2_4_054_fs_super_c.html
字号:
font-size: 10.0pt; line-height: normal; background-color: #ffffff; } .documentBG { background-color: #ffffff; } /* end ui edited css */</style> </head> <body revision="dcbsxfpf_215fb9cjsgv:253"> <DIV ALIGN=center ID=qf-i>
<TABLE ALIGN=center BORDER=0 CELLPADDING=0 CELLSPACING=0 HEIGHT=5716 ID=u3_i WIDTH=801>
<TBODY ID=jsmi>
<TR ID=fyzl>
<TD HEIGHT=5716 ID=ci:d VALIGN=top WIDTH=100%>
<PRE ID=vvtc>2007-8-22<BR ID=ydur>fs/super.c<BR ID=sly1><BR ID=o:82> 重读2.4,这是最后一篇了, 之后该读2.6..<BR ID=b9n5><BR ID=cuzh>内存管理和vfs文件系统,是学习的基础(for me),process也非常重要融入其中把...<BR ID=x27p></PRE>
<HR ID=jrti STYLE="WIDTH:100%; HEIGHT:2px">
<PRE ID=vvtc><FONT COLOR=#0b5394 ID=xqu2 SIZE=4><B ID=gc43>filesystems</B></FONT><BR ID=wsk5><BR ID=w1t0>这个模块分成三个部分的内容:filesystem管理, super块管理, mount/umount管理. 先看简单的filesystem管理,此乃一链表,够简单.<BR ID=dod5>struct file_system_type {<BR ID=xb.5> const char *name;<BR ID=z2yv> int fs_flags;<BR ID=c.a4> struct super_block *(*read_super) (struct super_block *, void *, int);<BR ID=az8q> struct module *owner;<BR ID=hawc> struct vfsmount *kern_mnt; /* For kernel mount, if it's FS_SINGLE fs */<BR ID=g70l> struct file_system_type * next;<BR ID=ms.u>};<BR ID=zla1><BR ID=dy.k>注意下do_mount函数获取super block的方式: 想ext2是 required dev, 代表着只要是同一个dev,使用同一个superblock, 而像虚拟文<BR ID=g8gq>件系统devpts则指明了SINGLE属性,多次安装都是同一个super block. 同一个superblock的含义是:同一目录棵树. 到2.6, 这些属性消<BR ID=zce7>失不见,代替为各个文件系统自己的read_super自己处理安装方式.<BR ID=wg_a><BR ID=ywoe>具体细节不再罗列.<BR ID=zy.g><FONT COLOR=#0000ff ID=ro:e>/*<BR ID=mg4u> * Handling of filesystem drivers list.<BR ID=a9e-> * Rules:<BR ID=q0y:> * Inclusion to/removals from/scanning of list are protected by spinlock.<BR ID=n6g-> * During the unload module must call unregister_filesystem().<BR ID=fix8> * We can access the fields of list element if:<BR ID=i66e> * 1) spinlock is held or<BR ID=i0-q> * 2) we hold the reference to the module.<BR ID=ojqz> * The latter can be guaranteed by call of try_inc_mod_count(); if it<BR ID=iotr> * returned 0 we must skip the element, otherwise we got the reference.<BR ID=ff56> * Once the reference is obtained we can drop the spinlock.<BR ID=x1-s> */<BR ID=ax8_></FONT><BR ID=i3et>static struct file_system_type *file_systems;<BR ID=x0xj>static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED;<BR ID=jm:v><BR ID=huos>asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2) /*非常*/<BR ID=xoce><BR ID=tjxc></PRE>
<HR ID=xv8d STYLE="WIDTH:100%; HEIGHT:2px">
<PRE ID=vvtc><FONT COLOR=#0b5394 ID=cvt8 SIZE=4><SPAN ID=ytz8><B ID=kjrt>super block的简单管理</B></SPAN></FONT><BR ID=csay><BR ID=olnf>一个链表,然后,如果是SINGLE类型的文件系统,super block还挂接到file_system_type::kern_mnt->mnt_sb.<BR ID=pnp_>int nr_super_blocks;<BR ID=gjtn>int max_super_blocks = NR_SUPER;<BR ID=gzau>LIST_HEAD(super_blocks);<BR ID=mtwu><BR ID=pbln>struct super_block * <FONT COLOR=#38761d ID=u3xm><B ID=po6q>get_super</B></FONT>(kdev_t dev) <BR ID=ltla>/*<FONT ID=ctme><FONT COLOR=#38761d ID=u3xm>get_super </FONT></FONT>遍历上面的superblock链表,找到指定dev的sb,如果没有就返回NULL,代表需要创建. 给mount_root和required dev类型的<BR ID=maoq>文件系统使用 dev相同就. 或者用此函数超找已经安装文件的sb */ <BR ID=o-py><BR ID=qm93>struct super_block *get_empty_super(void) /*不用说了,分配新sb,挂入链表*/<BR ID=nkjz><BR ID=bf06>static struct super_block *<FONT COLOR=#0000ff ID=j1q5><SPAN ID=kbur><B ID=cyum>get_sb_nodev</B></SPAN></FONT>(struct file_system_type *fs_type,int flags, void * data)<BR ID=cbre>{ <FONT COLOR=#0000ff ID=ifwc>/*为不需要dev的文件系统:(非single并且不是requied dev类型, 如shm,nfs等)*/</FONT><BR ID=uwab> kdev_t dev;<BR ID=zy0_> int error = -EMFILE;<BR ID=db9i> down(&mount_sem);<BR ID=l-2e> dev = get_unnamed_dev(); /*Major:0 */<BR ID=v2_0> if (dev) {<BR ID=akzb> struct super_block * sb;<BR ID=otoc> error = -EINVAL;<BR ID=sfme> sb = read_super(dev, NULL, fs_type, flags, data, 0); /*直接分配新的sb,除非filesystem另有考虑(2.4没有)*/<BR ID=pp1h> ......<BR ID=or90>}<BR ID=afa4><BR ID=ytkr>static struct super_block *<FONT COLOR=#0b5394 ID=t1q.><SPAN ID=pa4n><B ID=efav>get_sb_single</B></SPAN></FONT>(struct file_system_type *fs_type,<BR ID=og_u> int flags, void *data)<BR ID=gkf4>{<FONT COLOR=#0b5394 ID=ynxl> /*上面说了比如devpts之类文件系统*/</FONT><BR ID=y16_> /*<BR ID=a0_i> * Get the superblock of kernel-wide instance, but<BR ID=ttp_> * keep the reference to fs_type.<BR ID=qjk_> */<BR ID=os5_> ...<BR ID=g9.5> sb = fs_type->kern_mnt->mnt_sb;<FONT COLOR=#0000ff ID=sgul> /*绝对共享superblock*/</FONT><BR ID=us33> ....<BR ID=vfvl> do_remount_sb(sb, flags, data); <FONT COLOR=#0000ff ID=gevv>/*sb->s_op->remount_fs, 给文件系统的重新安装准备的,不是专门给SINGLE类型使用的*/</FONT><BR ID=bzb.> return sb;<BR ID=kpcq>}<BR ID=fs6:>static struct super_block *<FONT COLOR=#0b5394 ID=bdql><SPAN ID=zg2h><B ID=w_5p>get_sb_bdev</B></SPAN></FONT>(struct file_system_type *fs_type,<BR ID=cvan> char *dev_name, int flags, void * data)<BR ID=uqsf>{ <FONT COLOR=#0000ff ID=kr8v>/*普通文件系统, 需要dev支持*/</FONT><BR ID=p2xf> ....<BR ID=sks3> if (path_init(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd)) <FONT COLOR=#0000ff ID=r5jy>/*打开设备文件*/</FONT><BR ID=svd7> error = path_walk(dev_name, &nd);<BR ID=hj_q> ...<BR ID=t1a4> bdev = inode->i_bdev; <FONT COLOR=#0000ff ID=o21s>/*获取bdev以及其ops*/</FONT><BR ID=l1.n> bdops = devfs_get_ops ( devfs_get_handle_from_inode (inode) );<FONT COLOR=#0000ff ID=kf9i>/*尝试从devpts文件系统获取...没有devpts就没有*/</FONT><BR ID=amxa> if (bdops) bdev->bd_op = bdops;<BR ID=hkx7> ...<BR ID=po95> sb = get_super(dev); <FONT COLOR=#0000ff ID=nm7j>/*看看是否已经安装*/</FONT><BR ID=icxy> if (sb) {<BR ID=e7az> if (fs_type == sb->s_type &&<BR ID=k7:s> ((flags ^ sb->s_flags) & MS_RDONLY) == 0) { <FONT COLOR=#0000ff ID=hsci>/*安装两次的dev设备不能改变其只读属性,否则出错*/</FONT><BR ID=wjm6> .... /*没有改变*/<BR ID=cvuy> return sb;<BR ID=o40y> }<BR ID=wtg3> } else {<BR ID=k4sa> .....<BR ID=oukz> error = blkdev_get(bdev, mode, 0, BDEV_FS); <FONT COLOR=#0000ff ID=j1uo>/*还会尝试获取bdev ops*/</FONT><BR ID=wshk> ... /*disk change ,略...*/<BR ID=tb6s> sb = read_super(dev, bdev, fs_type, flags, data, 0); <FONT COLOR=#0000ff ID=lu4c>/*通过filesystem注册的read_super读入超级块*/</FONT><BR ID=z5i2> ......<BR ID=rkht>}<BR ID=vcfm> <BR ID=a76v>void sync_supers(kdev_t dev) <FONT COLOR=#0000ff ID=zo3y>/*找到指定dev的super调用sb->s_op->write_super*/<BR ID=thed><BR ID=o:.c></FONT>static void <FONT COLOR=#0b5394 ID=zz9c><SPAN ID=hhbb><B ID=flwn>kill_super</B></SPAN></FONT>(struct super_block *sb, int umount_root) <FONT COLOR=#0000ff ID=u9u_>/*给mount/umount准备的函数*/</FONT><BR ID=slhx>{ <FONT COLOR=#0000ff ID=lv5w>/*kill super的时候已经做过fsyn_dev,shrink_dcache_sb了*/</FONT><BR ID=wekx> ........<BR ID=f:5q> sb->s_root = NULL; /**/<BR ID=obvz> /* Need to clean after the sucker */<BR ID=kcfm> if (fs->fs_flags & <FONT COLOR=#0000ff ID=n8td>FS_LITTER</FONT>)<BR ID=wdf3> d_genocide(root);<FONT COLOR=#0000ff ID=v2nm> /*把dentry的引用技术减1,种族灭绝....keep dentry in memory... tmpfs(shm),ramfs*/</FONT><BR ID=r:dw> if (fs->fs_flags & (FS_SINGLE|FS_LITTER))<BR ID=kxzl> shrink_dcache_parent(root); <FONT COLOR=#38761d ID=ipsj>/*引用计数为0的放入unused队然后最终释放掉.<FONT COLOR=#ff0000 ID=ukp5>2.6 umount的时候都要调用这个函数的</FONT>*/</FONT><BR ID=hsoz> dput(root); <FONT COLOR=#0000ff ID=kj0y>/*释放root dentry*/</FONT><BR ID=ovu3> lock_super(sb);<BR ID=vzep> if (sop) { <FONT COLOR=#0000ff ID=u6y5>/*回写super block*/</FONT><BR ID=q6od> if (sop->write_super && sb->s_dirt)<BR ID=mtml> sop->write_super(sb);<BR ID=w35o> if (sop->put_super)<BR ID=nohq> sop->put_super(sb);<BR ID=ec2f> }<BR ID=s8:b><BR ID=n1bw> /* Forget any remaining inodes */<BR ID=sk6g> if (invalidate_inodes(sb)) { <FONT COLOR=#ff0000 ID=zffb>/*强制释放所有还没有释放的inode,如果有,呵呵....*/</FONT><BR ID=ohb5> ...."Self-destruct in 5 seconds. Have a nice day...\n");<BR ID=ztxl> }<BR ID=uwpc><BR ID=pqhi> dev = sb->s_dev;<BR ID=z_:y> sb->s_dev = 0; <FONT COLOR=#0000ff ID=xk87>/* Free the superblock,<FONT COLOR=#ff00ff ID=xdka>见get_empty_super,只分配不会最终释放的...</FONT> */</FONT><BR ID=l.-c> .....<BR ID=c_-e> if (umount_root) {<BR ID=an7y> /* special: the old device driver is going to be<BR ID=i3g2> a ramdisk and the point of this call is to free its<BR ID=s7yu> protected memory (even if dirty). */<BR ID=cb:j> destroy_buffers(dev); <FONT COLOR=#0000ff ID=r.kc>/*chang root.....释放dev相关的buffer cache*/</FONT><BR ID=y2tj> }<BR ID=uvy6> ...<BR ID=hu.->}<BR ID=eepc><BR ID=iw8f><BR ID=a-y9>这里着重介绍一下这个flag,..在2.6中被<CODE ID=uwns>kill_super_litter所代替,先看网上关于这个的一点介绍:</CODE><BR ID=uch:><FONT COLOR=#ff0000 ID=ils-><SPAN ID=vupq><B ID=fhb5>FS_LITTER</B></SPAN></FONT> (gone) /*dentry创建的时候引用计数被加了1....*/</PRE>
<P ID=pu1t>
The <CODE ID=c.-m>FS_LITTER</CODE> flag (2.4.0test3-2.5.7) says that after umount a <CODE ID=yvhw>d_genocide()</CODE> is
needed. This will remove one reference<BR ID=df63>
</P>
<P ID=pu1t>
from all dentries in that tree, probably killing all of them, which is
necessary in case at creation time the dentries already
</P>
<P ID=pu1t>
got reference count 1. (This is typically done for an in-core
filesystem where dentries cannot be recreated when needed.)<BR ID=u.s_>
</P>
<P ID=pu1t>
This flag disappeared in Linux 2.5.7 when the explicit <CODE ID=uwns>kill_super</CODE> method
<CODE ID=t3.4>kill_litter_super</CODE> was introduced.
</P>
<PRE ID=vvtc>This flag for in-memory filesystems without backing store - they need an additional <CODE ID=fix:>dget()</CODE><BR ID=kxat>when a file is created (so that their dentries always have a nonzero reference count and are not garbage collected), <BR ID=c9gi>and the <CODE ID=g8v3>d_genocide() </CODE>that is the difference between <CODE ID=dwqh>kill_anon_super</CODE> and <CODE ID=ak_d>kill_litter_super</CODE> does the balancing <CODE ID=qm77>dput()</CODE>.<BR ID=z9pz><BR ID=urzg>大意是,纯粹呆在内存的文件系统, 为了达到denty不被flush出去的目的,在创建文件的时候对dentry的引用计数凭空增加了1,所以需要在<BR ID=rihf>kill_super中 d_genocide(root), 比如shmem的create函数:<BR ID=jlxo>static int <SPAN ID=xiwq><B ID=p83g>shmem_mknod</B></SPAN>(struct inode *dir, struct dentry *dentry, int mode, int dev)<BR ID=orty>{<BR ID=pqxw> struct inode * inode = shmem_get_inode(dir->i_sb, mode, dev);<BR ID=ofx5> int error = -ENOSPC;<BR ID=bhoz><BR ID=iupv> if (inode) {<BR ID=dhk4> d_instantiate(dentry, inode);<BR ID=hvkk> <FONT COLOR=#cc0000 ID=ein2>dget(dentry); /* Extra count - pin the dentry in core */</FONT><BR ID=ajc4> error = 0;<BR ID=h:5c> }<BR ID=t:je> return error;<BR ID=e6ia>}<BR ID=fwzd></PRE>
<HR ID=hs4g STYLE="WIDTH:100%; HEIGHT:2px">
<PRE ID=vvtc><FONT COLOR=#0b5394 ID=u:i: SIZE=4><SPAN ID=ieb2><B ID=cpm9>kernel mount 以及杂项</B></SPAN></FONT><BR ID=fdkh><BR ID=ihux>static LIST_HEAD(vfsmntlist); <BR ID=rwjf><BR ID=qdgk>static struct vfsmount *add_vfsmnt(struct nameidata *nd,struct dentry *root,const char *dev_name)<BR ID=k.8z><IMG ALT="" ID=nmw1><IMG ALT="" ID=q3tw>static void remove_vfsmnt(struct vfsmount *mnt) /*从链表删除,释放对其他节点引用,释放mnt占用内存*/<BR ID=pmdv>代码不说了,就是建立下面的指针关系: vfsmnt是联系mount point/mount root/super block的一个纽带<BR ID=lx3m><DIV ID=j1ag STYLE="PADDING:1em 0pt; TEXT-ALIGN:left"><DIV ID=jp_u STYLE="PADDING:1em 0pt; TEXT-ALIGN:left"><IMG ID=y5-e SRC=_2_4_054_fs_super_c_images/dcbsxfpf_217dmmkkvfg_b.jpg STYLE="WIDTH:608px; HEIGHT:726px"></DIV><BR ID=k:b0></DIV><BR ID=g5rv><FONT COLOR=#0000ff ID=homf>/*<BR ID=az76> * 安装到filesystem->kern_mnt<BR ID=rxjp> */<BR ID=i_4m>/* 使用kernel_mount安装的虚拟文件系统与do_mount安装的文件系统有可能<BR ID=ry:5> * 不使用同一个sb(以及root),除非文件系统的性质是FS_SINGLE.<BR ID=xwkk> */</FONT><BR ID=at.9>struct vfsmount *<FONT COLOR=#0b5394 ID=izbp><B ID=o515>kern_mount</B></FONT>(struct file_system_type *type)<BR ID=z_is>{<BR ID=z5c1> kdev_t dev = get_unnamed_dev();<FONT COLOR=#0000ff ID=ulcf>/*获得一个unnamed dev,专门为虚拟文件系统准备*/</FONT><BR ID=jc8g> struct super_block *sb;<BR ID=k8px> struct vfsmount *mnt;<BR ID=yjsg> if (!dev)<BR ID=neqo> return ERR_PTR(-EMFILE);<BR ID=qqly><BR ID=joo3> <FONT COLOR=#0000ff ID=w_s0>/*malloc sb, and type->read_super,like shmem_read_super*/</FONT><BR ID=f5xh> sb = read_super(dev, NULL, type, 0, NULL, 0);<BR ID=nxzl> if (!sb) {<BR ID=uobs> put_unnamed_dev(dev);<BR ID=go3-> return ERR_PTR(-EINVAL);<BR ID=c3e5> }<BR ID=u:7q><BR ID=mg9v> <FONT COLOR=#0000ff ID=a2_1>/*仅仅获得一个mnt 结构, 安装点是自己(自环), mnt_parent也是自己*/</FONT><BR ID=inaw> mnt = add_vfsmnt(NULL, sb->s_root, NULL);<BR ID=xl58> if (!mnt) {<BR ID=mxtq> kill_super(sb, 0);<BR ID=ismc> return ERR_PTR(-ENOMEM);<BR ID=hmch> }<BR ID=frm1> <BR ID=w-g2> type->kern_mnt = mnt; <FONT COLOR=#0000ff ID=cr9.>/*内核可以使用此文件系统,对kernel 的user不可见*/</FONT><BR ID=b3os> return mnt;<BR ID=dyow>}<BR ID=k16z><BR ID=udlw>/* Call only after unregister_filesystem() - it's a final cleanup */<BR ID=ez4t>void <SPAN ID=l:wa><FONT COLOR=#0b5394 ID=vted><B ID=wu4f>kern_umount</B></FONT></SPAN>(struct vfsmount *mnt)<BR ID=zyk7><BR ID=pcu:>int <SPAN ID=v2ge><B ID=lurs>get_filesystem_info</B></SPAN>( char *buf ) /*获取文件系统信息... 略*/<BR ID=al:y>asmlinkage long <SPAN ID=s6x1><B ID=f_x9>sys_ustat</B></SPAN>(dev_t dev, struct ustat * ubuf) /*获系统信息... 略*/<BR ID=monf><BR ID=sl:x></PRE>
<HR ID=cbih STYLE="WIDTH:100%; HEIGHT:2px">
<PRE ID=vvtc><FONT COLOR=#0b5394 ID=ozjx SIZE=4><SPAN ID=vr4-><B ID=r.2.>sys_mount</B></SPAN><BR ID=uhkv></FONT><BR ID=b1.t>asmlinkage long <FONT COLOR=#0b5394 ID=b:0w><SPAN ID=nid7><B ID=pnvp>sys_mount</B></SPAN></FONT>(char * dev_name, char * dir_name, char * type,<BR ID=yd5q> unsigned long flags, void * data)<BR ID=b.16>{<BR ID=t2l5> ... <FONT COLOR=#0000ff ID=tvbu>/*从用户空间copy安装参数*/</FONT><BR ID=twtn><BR ID=dy.x> lock_kernel();<BR ID=gt9i> retval = <FONT COLOR=#38761d ID=mp2c><SPAN ID=gb7r><B ID=dic4>do_mount</B></SPAN></FONT>((char*)dev_page, dir_page, (char*)type_page,<BR ID=o-jt> flags, (void*)data_page);<BR ID=f2m:> unlock_kernel();<BR ID=x_op> .......<BR ID=vr6d> return retval;<BR ID=u2g1>}<BR ID=kbnu><BR ID=rzw2>long do_mount(char * dev_name, char * dir_name, char *type_page,<BR ID=yuj6> unsigned long flags, void *data_page)<BR ID=dfq_>{<BR ID=lnzg> ..... <FONT COLOR=#0000ff ID=nm10>/*sanity check*/</FONT><BR ID=t0gj> <FONT COLOR=#0000ff ID=bo48>/* just change the flags? - capabilities are checked in do_remount() */</FONT><BR ID=f_bs> if (flags & MS_REMOUNT) <FONT COLOR=#0000ff ID=yoz3>/*remount处理*/</FONT><BR ID=ke1h> return <FONT COLOR=#38761d ID=ozn5><SPAN ID=eppk><B ID=my7_>do_remount</B></SPAN></FONT>(dir_name, flags & ~MS_REMOUNT,(char *) data_page);<BR ID=ej1-><BR ID=up.d> <FONT COLOR=#0000ff ID=dm17>/* "mount --bind"? Equivalent to older "mount -t bind" */<BR ID=bmz-> /* No capabilities? What if users do thousands of these? */</FONT><BR ID=i598> if (flags & MS_BIND) <FONT COLOR=#0000ff ID=x0:2>/*loopback mount处理*/</FONT><BR ID=h2vu> return <FONT COLOR=#38761d ID=jnp6><B ID=czt_>do_loopback</B></FONT>(dev_name, dir_name);<BR ID=a16y><BR ID=c3v7> /* For the rest we need the type */<BR ID=w:.j> ....<FONT COLOR=#0000ff ID=vln6> /*sanity check和权限检查*/</FONT><BR ID=l5kc><BR ID=rngv> /* ... filesystem driver... */<BR ID=ckid> fstype = <FONT COLOR=#38761d ID=x20a><SPAN ID=zlss><B ID=pdo0>get_fs_type</B></SPAN></FONT>(type_page); <FONT COLOR=#0000ff ID=t7f1>/*获取文件系统类型,前边分析了,这里清楚了...*/</FONT><BR ID=fivz> .....<BR ID=k-2j> /* ... and mountpoint. Do the lookup first to force automounting. */<BR ID=zjeb> if (path_init(dir_name,<BR ID=s-nm> LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd))<BR ID=l3ro> retval = <FONT COLOR=#38761d ID=bbvn><SPAN ID=rxi_><B ID=er_i>path_walk</B></SPAN></FONT>(dir_name, &nd); <FONT COLOR=#0000ff ID=hfu7>/*获取安装点*/</FONT><BR ID=eba0> if (retval)<BR ID=ox97> goto fs_out;<BR ID=uto6><BR ID=x5oc> <FONT COLOR=#ff0000 ID=d7te>/* get superblock, locks mount_sem on success */<BR ID=kh.8> /*前边已经分析过各种类型的文件系统在获取super block的异同了.*/<BR ID=eo28></FONT> if (fstype->fs_flags & FS_NOMOUNT)<BR ID=q29k> sb = ERR_PTR(-EINVAL);<BR ID=m:7n> else if (fstype->fs_flags & FS_REQUIRES_DEV)<BR ID=gdup> sb = <FONT COLOR=#38761d ID=e_.5><SPAN ID=ncqk><B ID=u.gn>get_sb_bdev</B></SPAN></FONT>(fstype, dev_name, flags, data_page); <FONT COLOR=#0000ff ID=r7zd>/*设备相关的文件系统*/</FONT><BR ID=any1> else if (fstype->fs_flags & FS_SINGLE)<BR ID=easu> sb = <FONT COLOR=#38761d ID=fam-><SPAN ID=d.hx><B ID=sr.q>get_sb_single</B></SPAN></FONT>(fstype, flags, data_page); <FONT COLOR=#0000ff ID=dgb2>/*SINGLE super block 的虚拟文件系统*/</FONT><BR ID=qbbv> else<BR ID=shdx> sb = <FONT COLOR=#38761d ID=taor><SPAN ID=o283><B ID=r69g>get_sb_nodev</B></SPAN></FONT>(fstype, flags, data_page); <FONT COLOR=#0000ff ID=q__d>/*比较纯粹的虚拟文件系统,每安装一次产生一个super block*/</FONT><BR ID=e:qm><BR ID=nwpx> ......<BR ID=wvkd><BR ID=o680> <FONT COLOR=#ff0000 ID=rcmh>/* Something was mounted here while we slept */</FONT><BR ID=r1py> while(d_mountpoint(nd.dentry) && follow_down(&nd.mnt, &nd.dentry))<BR ID=zku_> ;<BR ID=jh2v><BR ID=z_if> <FONT COLOR=#ff0000 ID=hi7i>/* Refuse the same filesystem on the same mount point */</FONT><BR ID=do5v> retval = -EBUSY;<BR ID=j7jq> if (nd.mnt && nd.mnt->mnt_sb == sb<BR ID=zr7c> && nd.mnt->mnt_root == nd.dentry)<BR ID=ll6x> goto fail;<BR ID=nq2w><BR ID=f5hn> retval = -ENOENT;<BR ID=dxnr> if (!nd.dentry->d_inode)<BR ID=l5b0> goto fail;<BR ID=h3y-> <FONT COLOR=#0000ff ID=iifc> /*真正的安装也比较简单的,就是上面所说的add_vfsmnt*/</FONT><BR ID=v6l7> down(&nd.dentry->d_inode->i_zombie);<BR ID=o_gx> if (!IS_DEADDIR(nd.dentry->d_inode)) {<BR ID=p.05> retval = -ENOMEM;<BR ID=lxxa> mnt = <FONT COLOR=#38761d ID=kdgj><SPAN ID=mx4i><B ID=qtxx>add_vfsmnt</B></SPAN></FONT>(&nd, sb->s_root, dev_name);<BR ID=gpnr> }<BR ID=hq8k> ......<BR ID=rmk0>}<BR ID=c13k><BR ID=th53>安装文件系统, 主要还是建立内存中mount point,mount root,mnt,super block之间的关系,设置好各个ops. 这里就是super block需要从<BR ID=cock>设备上读取,或者从内存中'凭空'产生.<BR ID=ziz->下面看第一分支, remount:<BR ID=c26b>static int <FONT COLOR=#0b5394 ID=ftr_><SPAN ID=la:h><B ID=pxi8>do_remount</B></SPAN></FONT>(const char *dir,int flags,char *data)<BR ID=if4g>{<BR ID=h2.x> <FONT COLOR=#0000ff ID=mx_5>.... /*sanity 和权限检查*/</FONT><BR ID=mc3p> if (path_init(dir, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))<BR ID=rit2> retval = path_walk(dir, &nd); <FONT COLOR=#0000ff ID=zl6e>/*找到要重新安装的文件系统root:path walk跳过安装点到达安装的文件系<BR ID=jdnm> 统的root dentry*/</FONT><BR ID=z:jr> if (!retval) {<BR ID=ddam> struct super_block * sb = nd.dentry->d_inode->i_sb;<FONT COLOR=#0000ff ID=qgbp> /*找到super block*/</FONT><BR ID=dzsu> retval = -ENODEV;<BR ID=pqzw> if (sb) {<BR ID=tvz6> retval = -EINVAL;<BR ID=byqm> if (nd.dentry == sb->s_root) { <FONT COLOR=#ff0000 ID=uzen>/*如果你安装到了 /mnt/hgfs/, 你不应用/mnt/hgfs/cross remount*/</FONT><BR ID=ubmz> /*<BR ID=kzks> * Shrink the dcache and sync the device.<BR ID=xl6h> */<BR ID=tfr.> shrink_dcache_sb(sb); <FONT COLOR=#0000ff ID=sx22>/*释放不用的dentry*/</FONT><BR ID=selx> fsync_dev(sb->s_dev); <FONT COLOR=#0000ff ID=ebdd>/*向磁盘写入所有数据*/</FONT><BR ID=a58v> if (flags & MS_RDONLY)<BR ID=cr6o> acct_auto_close(sb->s_dev);<BR ID=nja9> retval =<FONT COLOR=#0000ff ID=bgbg><SPAN ID=q4lq><B ID=mha-> do_remount_sb</B></SPAN></FONT>(sb, flags, data); <FONT COLOR=#0000ff ID=p44l>/*目的就是改变安装参数,要通知具体文件系统*/</FONT><BR ID=q6sh> }<BR ID=lj17> }<BR ID=y:d0> path_release(&nd);<BR ID=a48i> }<BR ID=ahsk> return retval;<BR ID=fuhd>}<FONT COLOR=#0000ff ID=o28-><BR ID=cc0-><BR ID=n:od>第二个安装分支是loopback安装: 不要误以为是mount -loop, 而是mount -bind.. 剩下的.. 就很简单了</FONT><BR ID=lpos>/*<BR ID=rbxk> * do loopback mount.<BR ID=u_ye> */<BR ID=zevc>static int do_loopback(char *old_name, char *new_name)<BR ID=x5wk>{<BR ID=c.ep> <FONT COLOR=#0000ff ID=rwrb> /* 找到oldname和newname的dentry, 用一个add_vfsmnt把他们连接起来就可以了 */</FONT><BR ID=b3tq> add_vfsmnt(&new_nd, old_nd.dentry, old_nd.mnt->mnt_devname));<BR ID=tvhn>}<BR ID=ehzq></PRE>
<HR ID=xum. STYLE="WIDTH:100%; HEIGHT:2px">
<PRE ID=vvtc><FONT COLOR=#0b5394 ID=ehum SIZE=4><b>sys_umount</b></FONT><BR ID=r7s4><BR ID=hk15>直接看do_umount吧:<BR ID=ij6e>umount主要考虑被多次安装的情况. 然后需要sync...<BR ID=zv9i>static int <FONT COLOR=#38761d ID=w_yr><SPAN ID=h6er><B ID=r-nj>do_umount</B></SPAN></FONT>(struct vfsmount *mnt, int umount_root, int flags)<BR ID=uzca>{<BR ID=j:8b> struct super_block * sb = mnt->mnt_sb;<BR ID=uzoc> if (mnt == current->fs->rootmnt && !umount_root) {<FONT COLOR=#0000ff ID=ooft> /*如果要umount 进程rootmnt又没有明确指定*/</FONT><BR ID=ocwm> int retval = 0;<BR ID=tk0z> mntput(mnt);<BR ID=mkyt> if (!(sb->s_flags & MS_RDONLY))<BR ID=a47q> retval = do_remount_sb(sb, MS_RDONLY, 0);<FONT COLOR=#0000ff ID=r9z4> /*就改变安装类型为readonly*/</FONT><BR ID=o75m> return retval;<BR ID=mjw8> }<BR ID=bp:y> spin_lock(&dcache_lock);<BR ID=f784> if (mnt-><FONT COLOR=#38761d ID=t51a>mnt_instances</FONT>.next != mnt->mnt_instances.prev) {<FONT COLOR=#0000ff ID=g6ht> /*文件系统被多次安装*/</FONT><BR ID=eohy> if (atomic_read(&mnt->mnt_count) > 2) { <FONT COLOR=#0000ff ID=msju>/*看看这个安装实例是否可以释放*/</FONT><BR ID=apz:> spin_unlock(&dcache_lock);<BR ID=vp85> mntput(mnt);<BR ID=o2-v> return -EBUSY;<BR ID=zstd> }<BR ID=tyx1> .... <FONT COLOR=#0000ff ID=azci>/*仅释放这个安装*/</FONT><BR ID=e2u6> return 0;<BR ID=jvph> }<BR ID=r_03> spin_unlock(&dcache_lock);<BR ID=ar8q><FONT COLOR=#0000ff ID=d56r> /*先关闭quta*/</FONT><BR ID=bcd2> DQUOT_OFF(sb);<BR ID=ufep> acct_auto_close(sb->s_dev);<BR ID=zoj2> if( (flags&MNT_FORCE) && sb->s_op->umount_begin)<FONT COLOR=#0000ff ID=wbji> /*这个考虑挺玄,没有理解,nfs的人得出来说说...*/</FONT><BR ID=pmuw> sb->s_op->umount_begin(sb);<BR ID=g_i6> shrink_dcache_sb(sb); <FONT COLOR=#0000ff ID=mivn>/*当文件系统被多次安装,不做这个动作*/</FONT><BR ID=uyor> fsync_dev(sb->s_dev); <FONT COLOR=#0000ff ID=l23n>/*这些保证只有root在使用中,并且是clean的*/<BR ID=pbqa></FONT> if (sb->s_root->d_inode->i_state) {<BR ID=kc03> mntput(mnt);<BR ID=h30l> return -EBUSY;<BR ID=m9qg> }<BR ID=qlp0> /* Something might grab it again - redo checks */<BR ID=xz73> spin_lock(&dcache_lock);<BR ID=ttem> if (atomic_read(&mnt->mnt_count) > 2) { <FONT COLOR=#0000ff ID=ylnx>/*看看是否被抢先了...(前边没有检查啊...?)*/</FONT><BR ID=d0d9> spin_unlock(&dcache_lock);<BR ID=f9je> mntput(mnt);<BR ID=imy_> return -EBUSY;<BR ID=hta3> }<BR ID=uc41> /* OK, that's the point of no return */<BR ID=p0bl> mntput(mnt);<BR ID=em:q> remove_vfsmnt(mnt); <FONT COLOR=#0000ff ID=oad:>/*最终撤销安装*/</FONT><BR ID=qygq> kill_super(sb, umount_root);<BR ID=xtuy> return 0;<BR ID=ma42>}<BR ID=sjo8><BR ID=udv.></PRE>
<HR ID=cca5 STYLE="WIDTH:100%; HEIGHT:2px">
<PRE ID=vvtc>mount root<BR ID=neb0><BR ID=nrkr>关于mount root,我们现在只关心下initrd吧.2.6的一篇分析文章请参考:<BR ID=btvf><A HREF=Doc?id=dcbsxfpf_210dcjjrbd2 ID=jsyj TITLE=http://docs.google.com/Doc?id=dcbsxfpf_210dcjjrbd2>http://docs.google.com/Doc?id=dcbsxfpf_210dcjjrbd2</A> <BR ID=h4op><BR ID=paur>void __init <FONT COLOR=#0c343d ID=o5hl><SPAN ID=itpl><b>mount_root</b></SPAN></FONT>(void)<BR ID=ezz:>{<BR ID=wtl2> .....<BR ID=agsz>#ifdef CONFIG_ROOT_NFS <FONT COLOR=#0000ff ID=ak1o>/*by pass*/</FONT><BR ID=w-0t> <BR ID=eet9>#endif<BR ID=j3.l>#ifdef CONFIG_BLK_DEV_FD<BR ID=o.yk> if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { <FONT COLOR=#0000ff ID=tk2w>/*需要floppy的,跳过...*/</FONT><BR ID=szha> }<BR ID=ioi1>#endif<BR ID=gxhh> ......... <FONT COLOR=#0000ff ID=q6ni>/*通过devfs查找root dev,不看...现在都sysfs+udev了..*/</FONT><BR ID=kzyx><BR ID=lx8m> /* <FONT COLOR=#0000ff ID=x:bx>那么谁能设置ROOT_DEV这个全局变量呢..</FONT>就是:<FONT COLOR=#38761d ID=b:53><SPAN ID=b70.><b>initrd_load</b></SPAN></FONT> */<BR ID=zah:> if (!ROOT_DEV)<BR ID=q6ed> panic("I have no root and I want to scream");<BR ID=d24y> <FONT COLOR=#0000ff ID=w9:f> <FONT COLOR=#ff0000 ID=yivr>/*2.4里处理initrd比较特殊:直接模拟open,mount来安装rootfs, 2.6可以直接使用open和mount*/<BR ID=ub:2> <FONT COLOR=#0000ff ID=r3l:> /*step1: 避开文件系统的open,打开dev设备*/</FONT><BR ID=simi></FONT></FONT> bdev = <FONT COLOR=#38761d ID=t2wg><SPAN ID=pywf><b>bdget</b></SPAN></FONT>(kdev_t_to_nr(ROOT_DEV)); <FONT COLOR=#0000ff ID=xkki>/*分配bdev结构*/</FONT><BR ID=ptb0> if (!bdev)<BR ID=qdvm> panic(__FUNCTION__ ": unable to allocate root device");<BR ID=i9gs> bdev->bd_op = <FONT COLOR=#38761d ID=v5rp><SPAN ID=js4v><b>devfs_get_ops</b></SPAN></FONT> (handle); <FONT COLOR=#0000ff ID=as1x>/*获取bd_ops, 这里是rd.c,ramdisk的blk dev*/</FONT><BR ID=n6vo> ... <FONT COLOR=#0000ff ID=hbbo>/*devpts*/</FONT><BR ID=lv0c> mode = FMODE_READ;<BR ID=f-3h> if (!(root_mountflags & MS_RDONLY))<BR ID=j87f> mode |= FMODE_WRITE;<BR ID=iaoi> retval = <FONT COLOR=#38761d ID=znj6><b>blkdev_get</b></FONT>(bdev, mode, 0, BDEV_FS); <FONT COLOR=#0000ff ID=szrf>/*be_ops->open*/<BR ID=q.5h> ....<BR ID=ox1r></FONT> if (retval) { <FONT COLOR=#0000ff ID=qlgv>/*error process*/</FONT><BR ID=b9a-> ....<BR ID=mj4v> }<BR ID=p9qh> check_disk_change(ROOT_DEV);<BR ID=sjc7> sb = get_super(ROOT_DEV);<FONT COLOR=#0000ff ID=yyss> /*看看是否已经安装, initrd不会的....*/</FONT><BR ID=z-gi> if (sb) {<BR ID=k:vk> fs_type = sb->s_type;<BR ID=o5jo> goto mount_it;<BR ID=gpf.> }<BR ID=s2w0> <FONT COLOR=#0000ff ID=ndzk> /*尝试所有文件系统,看看能否支持initrd*/</FONT><BR ID=bkw7> read_lock(&file_systems_lock);<BR ID=ifma> for (fs_type = <FONT COLOR=#990000 ID=fdpq><b>file_systems</b></FONT> ; fs_type ; fs_type = fs_type->next) {<BR ID=v_4k> .... /*sanity check*/<BR ID=jdn_> sb = <FONT COLOR=#38761d ID=d9uk><SPAN ID=u.mu><b>read_super</b></SPAN></FONT>(ROOT_DEV,bdev,fs_type,root_mountflags,NULL,1);<BR ID=kn11> if (sb) <FONT COLOR=#0000ff ID=gtmg>/*got ...*/</FONT><BR ID=pd:e> goto mount_it;<BR ID=vz3z> .....<BR ID=dd9x> }<BR ID=nsmc> .....<BR ID=zmak>mount_it:<BR ID=zp_u> ... <FONT COLOR=#0000ff ID=q3w1>/*devpts处理略...*/</FONT><BR ID=t24-><BR ID=rbix> vfsmnt = add_vfsmnt(NULL, sb->s_root, "/dev/root"); <FONT COLOR=#0000ff ID=uwv1>/*安装.... 注:/dev/root只是个名字,没有pathwalk*/</FONT><BR ID=stwt> /* FIXME: if something will try to umount us right now... */<BR ID=je:f> if (vfsmnt) { <FONT COLOR=#0000ff ID=urcs>/*更新init进程的root和pwd*/</FONT><BR ID=j_7l> set_fs_root(current->fs, vfsmnt, sb->s_root);<BR ID=hj6d> set_fs_pwd(current->fs, vfsmnt, sb->s_root);<BR ID=krfi> ....<BR ID=t9ep>}<BR ID=v.7t><BR ID=l850><FONT COLOR=#0000ff ID=h8oc>下面看看initrd的load: (就不详细看了,只看看ROOT_DEV的设置过程吧...)</FONT><BR ID=p2jn>/*<BR ID=ef22> * This routine loads in the RAM disk image.<BR ID=d0y4> */<BR ID=mutz>static void __init <FONT COLOR=#274e13 ID=fp48><SPAN ID=kxz4><b>rd_load_image</b></SPAN></FONT>(kdev_t device, int offset, int unit)<BR ID=cqrh>{<BR ID=vkxs> ram_device = MKDEV(MAJOR_NR, unit);<BR ID=nl_0> /<FONT COLOR=#0000ff ID=xc2l>*模拟文件创建过程:open infile(initrd),outfile*/</FONT><BR ID=c0es> if ((inode = get_empty_inode()) == NULL) <BR ID=dphl> return;<BR ID=faxo> memset(&infile, 0, sizeof(infile));<BR ID=a2kr> memset(&in_dentry, 0, sizeof(in_dentry));<BR ID=yctd> infile.f_mode = 1; /* read only */<BR ID=qk4z> infile.f_dentry = &in_dentry;<BR ID=c0ev> in_dentry.d_inode = inode;<BR ID=ow13> infile.f_op = &<FONT COLOR=#990000 ID=ye8c><SPAN ID=gfg_><b>def_blk_fops</b></SPAN></FONT>; <FONT COLOR=#cc0000 ID=hjd.>/*blkdev是ramdisk*/</FONT><BR ID=jk_i> <FONT COLOR=#274e13 ID=q17d><SPAN ID=t:k_><b>init_special_inode</b></SPAN></FONT>(inode, S_IFBLK | S_IRUSR, kdev_t_to_nr(device));<FONT COLOR=#ff0000 ID=fxmd> /*file: ramdisk dev [1,250]*/</FONT><BR ID=vmw_> .. <FONT COLOR=#ff0000 ID=rnz5>/*outfile: ramdiks dev [1,0],即/dev/ram*/<BR ID=ch-j></FONT><BR ID=qwym><FONT COLOR=#ff0000 ID=kbt-> /*打开设备*/</FONT><BR ID=hi_:> if (<FONT COLOR=#38761d ID=k-os><SPAN ID=af.1><b>blkdev_open</b></SPAN></FONT>(inode, &infile) != 0) <FONT COLOR=#990000 ID=fnxp><SPAN ID=fpl4><b>/*rd_open :filp->f_op = &initrd_fops :</b></SPAN></FONT><FONT COLOR=#274e13 ID=up_w><b>initrd_read</b></FONT>*/<BR ID=n0ow> goto free_inode;<BR ID=uikb> if (blkdev_open(out_inode, &outfile) != 0) <FONT COLOR=#38761d ID=o8no><b>/*这个就是是def_blk_fops了*/</b></FONT><BR ID=p-yv> goto free_inodes;<BR ID=owod> ...<BR ID=z-3m> nblocks = <FONT COLOR=#38761d ID=tfw_><SPAN ID=wy7x><b>identify_ramdisk_image</b></SPAN></FONT>(device, &infile, offset); <FONT COLOR=#0000ff ID=mhg4>/*看看initrd有多少block*/</FONT><BR ID=ol1c> if (nblocks < 0)<BR ID=kr_x> goto done;<BR ID=h.tw> .....<FONT COLOR=#0000ff ID=ycn2> /*sanity check*/</FONT><BR ID=q9rr> <BR ID=slho> for (i=0; i < nblocks; i++) {<BR ID=pfx3> if (i && (i % devblocks == 0)) {<BR ID=j.5d> printk("done disk #%d.\n", i/devblocks);<BR ID=a7gd> ......<BR ID=k31.> printk("Loading disk #%d... ", i/devblocks+1);<BR ID=ed-v> }<BR ID=a9hb> infile.f_op-><FONT COLOR=#38761d ID=inrm><SPAN ID=v0u-><b>read</b></SPAN></FONT>(&infile, buf, BLOCK_SIZE, &infile.f_pos); /*从[1,250]copy到[1,0]*/<BR ID=k95r> outfile.f_op-><FONT COLOR=#38761d ID=mj:q><SPAN ID=y-l6><b>write</b></SPAN></FONT>(&outfile, buf, BLOCK_SIZE, &outfile.f_pos);<BR ID=um2r> ...... <BR ID=vu5y> }<BR ID=sfax> ....<BR ID=xmuz>}<BR ID=nlc2>这里明了了initrd如何进入一个ramdisk...<BR ID=b2oa></PRE>
<HR ID=a3j. STYLE="WIDTH:100%; HEIGHT:4px; FONT-WEIGHT:bold">
<PRE ID=vvtc><FONT COLOR=#0b5394 ID=su_o SIZE=4><b>change root</b></FONT><BR ID=c6qj><BR ID=eond>int __init <FONT COLOR=#0b5394 ID=zzz-><SPAN ID=uq.2><b>change_root</b></SPAN></FONT>(kdev_t new_root_dev,const char *put_old)<BR ID=lli9>{<BR ID=g45f><FONT COLOR=#0000ff ID=k:g7>/*将root 安装到new_root_dev,然后将现有的root 放到新安装的root文件系统的 put_old*/<BR ID=mtpd> ...<BR ID=fe9u></FONT> read_lock(&current->fs->lock);<BR ID=dbew> old_rootmnt = <FONT COLOR=#38761d ID=lstu><SPAN ID=g:8d><b>mntget</b></SPAN></FONT>(current->fs->rootmnt); <FONT COLOR=#0000ff ID=gjim>/*保存老的root mnt*/</FONT><BR ID=yvwa> read_unlock(&current->fs->lock);<BR ID=ewgo> <FONT COLOR=#0000ff ID=jt4v>/* devfs 处理略.*/</FONT><BR ID=nc2k> <FONT COLOR=#990000 ID=dkh9><SPAN ID=ccvj><b>ROOT_DEV</b></SPAN></FONT> = new_root_dev; <FONT COLOR=#0000ff ID=z5b8>/*安装新的root*/</FONT><BR ID=qhic> mount_root(); <BR ID=maue>#if 1<BR ID=xhs_> shrink_dcache();<FONT COLOR=#0000ff ID=lad_> /*将老的decahe 清除...*/</FONT><BR ID=iy83>#endif<BR ID=ccjr> <FONT COLOR=#0000ff ID=tpfn>/*devfs略*/</FONT><BR ID=vjw1> <FONT COLOR=#0000ff ID=ho3w>/*找找新文件系统的put_old目录*/</FONT><BR ID=o4-l> if (path_init(put_old, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd))<BR ID=c-5t> error = path_walk(put_old, &nd);<BR ID=a4mj> if (error) {.....<BR ID=fl0c> }<BR ID=fz_3> /* FIXME: we should hold i_zombie on nd.dentry */<BR ID=knnw> move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old"); /*"/dev/root.ol"只是名字...*/<BR ID=w66q> .....<BR ID=wcvh>}<BR ID=pthl><BR ID=t99g><BR ID=l5sw>static void <FONT COLOR=#38761d ID=f_ir><SPAN ID=c:ia><b>move_vfsmnt</b></SPAN></FONT>(struct vfsmount *mnt,<BR ID=u85c> struct dentry *mountpoint,<BR ID=jl.r> struct vfsmount *parent,<BR ID=u8i9> const char *dev_name)<BR ID=ib:a>{ /*把mnt从老的的安装点摘除,放到新的mount point*/<BR ID=h456> .....<BR ID=r2nt> spin_lock(&dcache_lock);<BR ID=fq55> old_mountpoint = mnt->mnt_mountpoint;<BR ID=dq4j> old_parent = mnt->mnt_parent;<BR ID=uckj> ...<FONT COLOR=#0000ff ID=quae>//copy name</FONT><BR ID=sa:g> /* flip the linkage */<BR ID=zv0y> mnt->mnt_mountpoint = dget(mountpoint);<BR ID=pcfw> mnt->mnt_parent = parent ? mntget(parent) : mnt;<BR ID=pv.d> list_del(&mnt->mnt_clash); <FONT COLOR=#38761d ID=s65f>/*把oldmnt从老安装点dentry的(链表)摘除*/</FONT><BR ID=vzz0> list_del(&mnt->mnt_child); <FONT COLOR=#38761d ID=ht0b>/*从mnt tree摘除*/</FONT><BR ID=i9jl> if (parent) { <FONT COLOR=#ff0000 ID=t51c>/*设置新的链表*/</FONT><BR ID=mpjt> list_add(&mnt->mnt_child, &parent->mnt_mounts);<BR ID=pm59> list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt);<BR ID=bfqf> } else {<BR ID=lp19> INIT_LIST_HEAD(&mnt->mnt_child);<BR ID=ubx_> INIT_LIST_HEAD(&mnt->mnt_clash);<BR ID=t3cg> }<BR ID=fy3a> spin_unlock(&dcache_lock);<BR ID=klan> <FONT COLOR=#0000ff ID=zy11>/* put the old stuff */<BR ID=gq.j> ... /*减引用计数*/</FONT><BR ID=s3km>}<BR ID=wzp7></PRE>
<HR ID=v07b STYLE="WIDTH:100%; HEIGHT:2px">
<PRE ID=vvtc><FONT COLOR=#0b5394 ID=uz6- SIZE=4><SPAN ID=e.j8><b>给用户使用的change root: pivot root </b></SPAN></FONT>(翻译成旋转?)<BR ID=gmln><FONT COLOR=#0000ff ID=lzrm><BR ID=kvff>/*<BR ID=qnz4> * 比如吧现在的/mnt/hda1这个安装点设置成新的根目录, 吧现在的'/'放到/mnt/hda1/mnt/old.</FONT><BR ID=w4yt> * <FONT COLOR=#990000 ID=t:2h>注意了:这两个目录都要求不能在老的根文件系统内...</FONT><BR ID=oui2> */<BR ID=naz0>为了好理解,奉图一张...<BR ID=xt9s><DIV ID=lflz STYLE="PADDING:1em 0pt; TEXT-ALIGN:left"><IMG ID=fzwq SRC=_2_4_054_fs_super_c_images/dcbsxfpf_218g6q2qfcj_b.jpg STYLE="WIDTH:530px; HEIGHT:484px"></DIV><BR ID=ajn3>asmlinkage long <FONT COLOR=#0b5394 ID=ar1f><SPAN ID=w-iw><b>sys_pivot_root</b></SPAN></FONT>(const char *new_root, const char *put_old)<BR ID=hglv>{<BR ID=jv0y> .... <FONT COLOR=#0000ff ID=m900>/*权限检查, sanity check, old name,new_root的path walk*/</FONT><BR ID=m-sd><BR ID=u6tg> read_lock(&current->fs->lock);<BR ID=z-xa> <SPAN ID=uwcr><b>root_mnt</b></SPAN> = mntget(current->fs->rootmnt);<BR ID=lrzd> <SPAN ID=tf1e><b>root </b></SPAN>= dget(current->fs->root);<BR ID=hw6l> read_unlock(&current->fs->lock);<BR ID=kf8:> ..... <FONT COLOR=#3d85c6 ID=r8mw>/*sanity check*/</FONT><BR ID=yn_6> if (new_nd.mnt == root_mnt || old_nd.mnt == root_mnt) <FONT COLOR=#0000ff ID=i5y6><SPAN ID=b4hs><b>/*new_root 和old_nd 等于rootmnd? 看上图即可明了*/</b></SPAN></FONT><BR ID=gs_6> goto out2; /* loop */<BR ID=sd2x> error = -EINVAL;<BR ID=fatz> tmp = old_nd.mnt;<FONT COLOR=#0000ff ID=hset> /* 检查从new root 是否能找的到put old */</FONT><BR ID=lk8q> spin_lock(&dcache_lock);<BR ID=jmor> if (tmp != new_nd.mnt) {<BR ID=v4e4> for (;;) {<BR ID=gi4j> if (tmp->mnt_parent == tmp)<BR ID=jyrw> goto out3;<BR ID=pg6s> if (tmp->mnt_parent == new_nd.mnt) <FONT COLOR=#0000ff ID=mh0o>/*从put old的nnt parent可以到达new root即可*/</FONT><BR ID=z8oa> break;<BR ID=k_bj> tmp = tmp->mnt_parent;<BR ID=mt.b> }<BR ID=z9:7> if (!is_subdir(tmp->mnt_mountpoint, new_nd.dentry))<BR ID=fxw-> goto out3;<BR ID=oh.0> } else if (!is_subdir(old_nd.dentry, new_nd.dentry))<BR ID=kxcl> goto out3;<BR ID=izcu> spin_unlock(&dcache_lock);<BR ID=wjn2><BR ID=ayhd> <FONT COLOR=#38761d ID=j8it><SPAN ID=h0q3><b>move_vfsmnt</b></SPAN></FONT>(new_nd.mnt, new_nd.dentry, NULL, NULL); /<FONT COLOR=#ff0000 ID=sttc>*升级new root, parent为0*/</FONT><BR ID=tdt1> <FONT COLOR=#38761d ID=cz9d><SPAN ID=l7yw><b>move_vfsmnt</b></SPAN></FONT>(root_mnt, old_nd.dentry, old_nd.mnt, NULL); <FONT COLOR=#990000 ID=oszi>/*把当前root安装到put_old*/</FONT><BR ID=nhv0> chroot_fs_refs(root,root_mnt,new_nd.dentry,new_nd.mnt); <FONT COLOR=#0000ff ID=jjc->/*更改所有进程的fs/pwd等*/</FONT><BR ID=jixq> error = 0;<BR ID=n3m3> ..... <FONT COLOR=#0000ff ID=wue3>/*出错处理*/</FONT><BR ID=ak7.> <BR ID=okjd>}<BR ID=wq1q><BR ID=i.ox><BR ID=l316><BR ID=y35r></PRE>
</TD>
</TR>
</TBODY>
</TABLE>
</DIV></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -