📄 019_using_uml.html
字号:
} /* used to insert page numbers */ div.google_header::before, div.google_footer::before { position: absolute; top: 0; } div.google_footer { flow: static(footer); } /* always consider this element at the start of the doc */ div#google_footer { flow: static(footer, start); } span.google_pagenumber { content: counter(page); } span.google_pagecount { content: counter(pages); } } @page { @top { content: flow(header); } @bottom { content: flow(footer); } } /* end default print css */ /* custom css *//* end custom css */ /* ui edited css */ body { font-family: Verdana; font-size: 10.0pt; line-height: normal; background-color: #ffffff; } .documentBG { background-color: #ffffff; } /* end ui edited css */</style> </head> <body revision="dcbsxfpf_60cr7cm55r:8"> <div id=zf3z>
<table align=center border=0 cellpadding=0 cellspacing=0 height=5716 id=t2aa width=800>
<tbody id=jj_y>
<tr id=v4g1>
<td height=5716 id=g16n valign=top width=100%>
<pre id=tlt6>2006-8-2<br id=mjmu><br id=k7yq> 真是没有用过linux,很多事情搞不清楚呢还。读mm/shmem.c 的时候看到mmap<br id=zsau>的私有共享影射使用了tmpfs的文件,但是ls /dev/shm并没有看到那个dev/zero名<br id=ws82>字的文件。于是想搞清楚。(mm/shmem.c shmem_zero_setup)<br id=f7c-> <br id=xoav> 先是考虑ls使用什么系统调用读取文件夹内的文件名列表,开始没有经验,就是搜索<br id=jx8r>到了sysv_readdir这个系统调用.顺着看下去,觉得vfs_readdir是个关键的函数。并<br id=wsz_>通过查看tmpfs的相关代码确认了这一点。sys_open->dentry_open-><br id=rkxj>fops_get(inode->i_fop)然后看tmpfs的inode,shmem_get_inode 使用的是<br id=d0ut>simple_dir_operations。<br id=rb2c> <br id=n_vn> 然后看dcache_readdir,开始没有仔细看,只是注意到有如下的一句:<br id=ip4.> (本文实际上都是采用kernel2.6.14)<br id=ihvq> if (d_unhashed(next) || !next->d_inode)<br id=a3a_> continue;<br id=x4bg> 直接注释掉,编译内核,测试。不幸,什么都没有。<br id=r1ve> <br id=u1mj> 如此反复了好几次,后来又改shemem_setup_zero,初看觉得inode->i_link被置位0了,<br id=q1qk>去掉(注意,这里已经走入歧途了),还是没有结果。这样改来改去没有任何结果编译<br id=xcm0>了多次内核。倒是体会到,这样的小改动只需要<br id=djzb> make<br id=n-cu> 即可,无须make clean等操作。<br id=nc1u> <br id=v9.f> 过了几天,感觉需要先找个什么方法看看是不是这样行的通。于是直接将shmem_<br id=o:2b>zero_setup的shmem_file_setup换成相应的filp_open(注意需要创建,并且名字不<br id=n.mp>能相同)。居然可以了。(后来意识到这样不过是饮鸩止渴)<br id=b253> 于是认定只要走一个完整的filp_open就可以将问题找出来(没想到这样是在错误<br id=rkjh>的方向上越走越远)。于是将filp_open拆分,改动到shmem.c.经历了‘成功’后,这<br id=ff4a>次痛苦的时间更长了。下面是相关的改动(注意这不能工作,老是死机):<br id=cizf>int shmem_do_open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)<br id=yf5z>{<br id=u0la><br id=w-_9> struct dentry *dentry;<br id=v0gm> struct dentry *dir;<br id=xh83> struct qstr *this;<br id=wttn><br id=uhvo>/*prepare ND */<br id=fpr8> /* Fill in the open() intent data */<br id=drn0> nd->intent.open.flags = flag;<br id=adkr> nd->intent.open.create_mode = mode;<br id=pbzb><br id=qg.u> /*<br id=ryh9> * Create - we need to know the parent. <br id=l-qz> */<br id=ju97> /*Get parent nd*/<br id=nuc0>#if 0<br id=ffm:> error = path_lookup(pathname, LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, nd);<br id=r-t1> if (error)<br id=bj68> return error;<br id=ow_o>#endif <br id=xr38> nd->dentry = shm_mnt->mnt_root;<br id=f7t6> nd->mnt = mntget(shm_mnt);<br id=l.20> nd->last_type= LAST_NORM;<br id=m-7x>{ /*prepare last compnet hash*/<br id=b9_c> this= &nd->last;<br id=cwoh> unsigned long hash;<br id=aurj> unsigned char c;<br id=dp73> <br id=i6nm> this->name = pathname;<br id=df.s> c = *(const unsigned char *)pathname;<br id=vcic><br id=gxwe> hash = init_name_hash();<br id=w5.9> do {<br id=huis> pathname++;<br id=ttdj> hash = partial_name_hash(c, hash);<br id=u16a> c = *(const unsigned char *)pathname;<br id=aj4v> } while (c && (c != '/'));<br id=ujsh> this->len = pathname - (const char *) this->name;<br id=ui3y> this->hash = end_name_hash(hash);<br id=bgn6>}<br id=lii2> <br id=x7qm> dir = shm_mnt->mnt_root;<br id=xd:d> nd->flags &= ~LOOKUP_PARENT;<br id=qrqe> <br id=zmpq>{ <br id=v8j5> /*dentry = shmem__lookup_hash(&nd->last, nd->dentry, nd);*/<br id=j9x9> dentry = d_alloc(dir, &nd->last);<br id=ea7v><br id=d-ln> if (!dentry)<br id=koxi> return 0;<br id=anp->}<br id=mrjh> /* dentry = inode->i_op->lookup(inode, new, nd); */<br id=lbzh> d_add(dentry, NULL);<br id=lr93><br id=z258> <br id=pxhh> /* Negative dentry, just create the file */<br id=ihfq> /*error = shmem_create(dir->d_inode, dentry, mode, nd);*/<br id=x10z> struct inode *inode = shmem_get_inode(dir->d_sb, S_IFREG | S_IRWXUGO, 0);;<br id=uu8d><br id=l06:> if (inode) {<br id=juwe> dir->d_inode->i_size += BOGO_DIRENT_SIZE;<br id=jqzo> dir->d_inode->i_ctime = dir->d_inode->i_mtime = CURRENT_TIME;<br id=cvkf> d_instantiate(dentry, inode);<br id=j55b><br id=nw-y> <br id=ef-2> }else <br id=m6b3> return -ENOSPC;<br id=jdpb> <br id=e22c> nd->dentry = dentry;<br id=r3ci> <br id=pvvg><br id=pf:1> return 0;<br id=nqyw>}<br id=cbeq><br id=ypi->struct file *shmem_filp_open(const char * filename, int flags, int mode)<br id=z7ra>{<br id=u4:g> int error;<br id=l:k7> struct nameidata nd;<br id=rlxf><br id=ji4y> error = shmem_do_open_namei(filename, flags, mode, &nd);<br id=lw__><br id=igw2><br id=pq_k> {<br id=wq5k> /*<br id=z9:y> if (!error)<br id=l..y> return dentry_open(nd.dentry, nd.mnt, flags);*/<br id=s6zy> struct file * f;<br id=gtf4> struct inode *inode;<br id=uwv1> int error;<br id=gt9w> <br id=dxee> error = -ENFILE;<br id=y06f> f = get_empty_filp();<br id=oibz> if (!f)<br id=r3wu> goto cleanup_dentry;<br id=gyp:> f->f_flags = flags;<br id=ve5:> f->f_mode = FMODE_WRITE | FMODE_READ;;<br id=uw85> inode = nd.dentry->d_inode;<br id=yb2t> <br id=yg2w> <br id=psx6> file_ra_state_init(&f->f_ra, inode->i_mapping);<br id=hz57> f->f_dentry = nd.dentry;<br id=yuwm> f->f_vfsmnt =nd.mnt;<br id=o36s> f->f_pos = 0;<br id=gevp> f->f_op = &shmem_file_operations;<br id=dtpm> file_move(f, &inode->i_sb->s_files);<br id=y0wu> <br id=vmuj> <br id=x85r> return f;<br id=t1.d> <br id=wi6k> cleanup_dentry:<br id=k_5l> dput(nd.dentry);<br id=prk6> mntput(nd.mnt);<br id=nj2l> return ERR_PTR(error);<br id=tpf1> }<br id=kv4:>}<br id=shof>/*<br id=loca> * shmem_zero_setup - setup a shared anonymous mapping<br id=vc7f> *<br id=cre1> * @vma: the vma to be mmapped is prepared by do_mmap_pgoff<br id=u8la> */<br id=tp_v>void itoax(char *str, int num)<br id=tf3i>{<br id=k14z> int i=32;<br id=lt-n> while(i)<br id=s5wf> {<br id=l8.n> if(num&0x1) *str++ = '1';<br id=hr.:> else *str++='0';<br id=qfrl> num>>=1;<br id=f70.> i--;<br id=irq6> if(num==0) break;<br id=sho3> }<br id=ykpu> <br id=muo:> *str=0;<br id=ygsf>}<br id=e3vd>int shmem_zero_setup(struct vm_area_struct *vma)<br id=wglh>{<br id=sbuy> struct file *file;<br id=ebwf> loff_t size = vma->vm_end - vma->vm_start;<br id=wa-1><br id=ur_j> /*file = shmem_file_setup("zero", size, vma->vm_flags);*/<br id=mbie>{ static int i=0;<br id=la7f> char name[128], num[33];<br id=un:_> strcpy(name,"zerov");<br id=i25b> itoax(num,i);<br id=t68t> strcat(name,num);<br id=czbb> /*file = shmem_filp_open(name,FMODE_READ|FMODE_WRITE,0700);*/<br id=mufi> filp_open(name,O_WRONLY|O_CREAT,0700);<br id=i1ch> file = shmem_file_setup(name, size, vma->vm_flags);<br id=tlyc> file->f_dentry->d_inode->i_size=size;<br id=rewd> i++;<br id=qag8><br id=n7y3>}<br id=xetm> if (IS_ERR(file))<br id=ftmr> return PTR_ERR(file);<br id=t0d6><br id=qeo_> if (vma->vm_file)<br id=puu.> fput(vma->vm_file);<br id=dnu8><br id=bezt> vma->vm_file = file;<br id=b2xw> vma->vm_ops = &shmem_vm_ops;<br id=xg:l> return 0;<br id=fduh>}<br id=hdxq> <br id=gvp7> 痛苦的久了就想到了‘万能’的调试,实在是增很printk(何况还不知道如何查<br id=na57>看输出信息,ft)。只是知道printk,kgdb,qmenu(?)可以工作,但是我感觉<br id=plcs>User mode linux对付这个问题才是王道。<br id=uc08> 于是查找uml的使用指南,并逐步实施。<br id=b2t9> <br id=qm1j> <br id=sv6v> I) 首先是找一个合适的内核版本来编译ARCH=um的内核。我选择了2.6.14,后<br id=al87>来证明这个内核比较稳定,编译没有问题。<br id=k10u> 解压缩到/usr/src/linux2.6.14-uml。<br id=tf0n> <br id=hdv4> II)到上述目录<br id=yl6_> make clean<br id=beav> make mrproper (这两个操作对于以前编译过其他arch的情况比较重要)<br id=yyo_> make xconfig ARCH=um<br id=xb8d> make all ARCH=um<br id=ubvu> <br id=i2.s> 现在目录下有个linux的可执行文件。<br id=l6il> <br id=htuj> III)不幸,运行uml还需要一个rootfs,就是uml的‘硬盘’啦。当然下载一个<br id=y2lp> 比较快,http://user-mode-linux.sourceforge.net/dl-sf.html<br id=pyzb> 选择了Debian-3.0r0.ext2.bz2,解压缩后改名为root_fs<br id=e-oj> <br id=r.o0> IV)./linux ubd0=root_fs 这样就搞定了。<br id=efna> <br id=egu.> <br id=uygk> V)其实还有要注意的事情:make xconfig ARCH=um的时候注意<br id=msjp> <br id=p_d3> 1.如果有如下提示:<br id=btrr> VFS: Cannot open root device "ubd0" or unknown-block(0,0) <br id=jn05> 则大概问题如下<br id=xkm6> 1)需要支持rootfs的文件类型,选上ext2,ext3支持<br id=cb2_> 2)选上Block devices/Virtual block device[*](ubd支持)<br id=s0ym> <br id=z6b0> 2.如果提示: Cannot open init console <br id=ln-s> 则你的rootfs 的/dev/console文件不存在,需要<br id=a1oa> mount -o loop root_fs /mnt <br id=xern> #cp -dpR /dev/tty[0-9] /mnt/dev<br id=t-ni> #cp -dpR /dev/ram* /mnt/dev<br id=n3c9> #cp -dpR /dev/console /mnt/dev<br id=bqf0> 3.如果提示:cannot setup thead-local storage: cannot setup LDT for <br id=vaf1> thread-local storage, 那么证明你的rootfs使用了NPTL,不幸现在uml<br id=wh9z> 还不能很好支持这个特性。换个简单点的rootfs吧。<br id=wq6b> <br id=me:l> VI)具体到我推荐的这个rootfs,还是有些问题的:<br id=fitw> 1。竟然没有启动bash, 在相应的runlevel中加上启动bash的命令即可<br id=i-g5> 2。没有安装shm,编辑fstab加上相应条目即可<br id=rnlc> 3。fstab文件中 / 安装在 /dev/ubd/0,改为/dev/ubd0<br id=kpvi> 4。编译uml的时候当然要选上proc支持<br id=wcrd> <br id=yuu9> VII)我使用的host linux也是linux2.6.14,挺好用,如果你么有发现更好的<br id=fzta> 用这个就可以了。并且我使用的是FC4,不推荐FC5。<br id=qk2g> <br id=ebwt> <br id=cv1.> 这样,搞定了uml,可以测试了。我写了一个小程序,只有一行:<br id=h-lh>#include <sys/mman.h><br id=x0a0>#include <sys/types.h><br id=t:yj>#include <fcntl.h><br id=q5do>#include <unistd.h><br id=xxr9>main(int argc, char** argv)<br id=w2w:>{<br id=aqau> int i;<br id=jt4_> char *p_map;<br id=s.:s> char temp;<br id=j6bk> p_map=(char*)mmap(NULL,10*10,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);<br id=by9:> if(p_map==NULL)<br id=p9vc> printf("mmap error!\n");<br id=bb6k>}<br id=a_7l> 在host linux下编译,拷贝到uml rootfs即可。测试的时候执行 shm&,让他后<br id=ojpz>台运行。<br id=x13v> <br id=h2-r> <br id=rtpv> 至于调试,就是:(直接在/usr/src/linux2.6.14-uml下执行)<br id=ce75> <br id=ye8s> #gdb<br id=f4mm> # (gdb) set args ubd0=root_fs<br id=ej0.> # (gdb) file linux<br id=n6qf> # (gdb) run<br id=up4y> # (gdb) c (不断回车直到uml启动完成)<br id=ki9h> # (gdb) break dcache_readdir<br id=af91> # (gdb) c<br id=c3_-> 进入到uml<br id=xy56> #(none):shm&<br id=ar2v> #(none):ls /dev/shm<br id=zeap> <br id=trto> 好,会在一个奇怪的地方断住, c,然后就到了dcache_readdir.<br id=oo:c> 不断的用n,s,finish等命令调试你的uml内核即可. 可以用p命令打印相应变量.<br id=b62->info break 可以看断点,clear 可以清楚断点.好像我就用了这几个命令.bt都没有<br id=ja::>用过.<br id=naw6><br id=me7y> 调试的结果很令人不快.问题依然.要注意的是内核编译有-O2优化,代码执行起<br id=fu80>来怪怪的,如果你想加一段程序,gcc看起来没有用就会不执行到(甚至都没有,优化掉<br id=koxo>了),解决的方法是:<br id=fz1o><br id=n5c0> var=....;<br id=rww-> pirntk("",var);<br id=x78a> <br id=cnp:> 这样可以骗过gcc,保留你的代码.<br id=e_7v> 如果你改动了几个文件,只需要<br id=m7p_> <br id=f1-5> make ARCH=um即可,编译很快的.<br id=no40> <br id=kebs> <br id=yyh8> 不再详述调试过程了,最后的转机是在2006.8.1号,昨天,突然注意到,dcache_read<br id=o8fv>dir中filp->f_dentry(/dev/shm->root of tmpfs)的地址并不是shm_mnt->root的地址,<br id=evpu>终于明白了,原来不是一棵树,赫赫.剩下的就简单了,只要修改dcache_readdir将<br id=lrtj> struct dentry *dentry = filp->f_dentry;<br id=qip3> 换成<br id=j_65> struct dentry *dentry = shm_mnt->root;/*注意,需要将shm_mnt声明为非static*/<br id=caqh> 然后删除:<br id=rb5m> if (d_unhashed(next) || !next->d_inode)<br id=llkr> continue;<br id=utt6> 就可以在ls /dev/shm的时候看到一堆 dev/zero文件了.<br id=v04_>int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)<br id=q-v.>{<br id=g19z> struct dentry *dentry = filp->f_dentry;<br id=a2z1> struct dentry *cursor = filp->private_data; /*dcache_dir_open 将cursor 设置为dentry ''.''*/<br id=p3b7> /* cursor d_child 挂入了filp->f_dentry->d_subdirs */<br id=dfnp> struct list_head *p, *q = &cursor->d_child; <br id=o7ia> ino_t ino;<br id=cq5i> int i = filp->f_pos;<br id=bggp><br id=zlu1> switch (i) {<br id=q:dz> case 0:<br id=l1vj> ino = dentry->d_inode->i_ino;<br id=gm::> if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)<br id=do:o> break;<br id=jh91> filp->f_pos++;<br id=wnoc> i++;<br id=o:70> /* fallthrough */<br id=y648> case 1:<br id=h61o> ino = parent_ino(dentry);<br id=ouk7> if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)<br id=wy-x> break;<br id=pu3g> filp->f_pos++;<br id=a_sk> i++;<br id=frxz> /* fallthrough */<br id=tz.y> default:<br id=p.rz> spin_lock(&dcache_lock);<br id=tk2:> if (filp->f_pos == 2) { /* pos=2 意味从头开始 */<br id=alp1> list_del(q);/*将cursor从f_dentry->d_subdirs 删除*/<br id=ewme> list_add(q, &dentry->d_subdirs);/*又加回来,从而位于subdir之首*/<br id=v11m> }<br id=lr0z><br id=rzmy> /*从cursor 的下一个subdir 开始*/<br id=fh8l> for (p=q->next; p != &dentry->d_subdirs; p=p->next) {<br id=kd-a> struct dentry *next;<br id=la:0> next = list_entry(p, struct dentry, d_child);<br id=xt4e> if (d_unhashed(next) || !next->d_inode)<br id=lxrj> continue;<br id=jl4_><br id=rrvg> spin_unlock(&dcache_lock);<br id=f5_9> if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, <br id=nqmm> next->d_inode->i_ino, dt_type(next->d_inode)) < 0)<br id=pesu> return 0;<br id=x3vz> spin_lock(&dcache_lock);<br id=q3xv> /* next is still alive */<br id=uj6g> list_del(q); /*q 是cursor, 后移一个位置 */<br id=i5t_> list_add(q, p);<br id=bhbn> p = q; /*从cursor 取下一个subdir*/<br id=v2ti> filp->f_pos++;<br id=podh> }<br id=txii> spin_unlock(&dcache_lock);<br id=w_w2> }<br id=c1a-> return 0;<br id=lo3e>}<br id=qo_7> <br id=wb2r> <br id=nuh7> 最后, ls 使用的函数是:sys_getdents64.<br id=pw39> <br id=awaq> 2006.8.2 by hyl.<br id=hsjd> <br id=hhb:> <br id=u:qy> <br id=q0m4> <br id=brma> <br id=jbds> <br id=t_sa> <br id=jlq5> <br id=nu:a><br id=b-3a></pre>
</td>
</tr>
</tbody>
</table>
</div></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -