📄 049_fs_namei_c.html
字号:
<html lang="zh-CN" xmlns:gdoc=""> <head> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <style type="text/css">/* default css */table { font-size: 1em; line-height: inherit;}div, address, ol, ul, li, option, select { margin-top: 0px; margin-bottom: 0px;}p { margin: 0px;}body { margin: 0px; padding: 0px; font-family: Verdana, sans-serif; font-size: 10pt; background-color: #ffffff;}h6 { font-size: 10pt }h5 { font-size: 11pt }h4 { font-size: 12pt }h3 { font-size: 13pt }h2 { font-size: 14pt }h1 { font-size: 16pt }blockquote {padding: 10px; border: 1px #DDD dashed }a img {border: 0}div.google_header, div.google_footer { position: relative; margin-top: 1em; margin-bottom: 1em;}/* end default css */ /* default print css */ @media print { body { padding: 0; margin: 0; } div.google_header, div.google_footer { display: block; min-height: 0; border: none; } div.google_header { flow: static(header); } /* 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: Arial; font-size: 10.0pt; line-height: normal; background-color: #ffffff; } .documentBG { background-color: #ffffff; } /* end ui edited css */</style> </head> <body revision="dcbsxfpf_72kqwmrhj:358"> <div align=center id=vwb2>
<table align=center border=0 cellpadding=0 cellspacing=0 height=5716 id=rdfz width=800>
<tbody id=qc9l>
<tr id=gb0d>
<td height=5716 id=xuow valign=top width=100%>
<pre id=sl2q>2008-1-30</pre>
<pre id=nr:i><br id=q.qt> <br id=cm_y> 此文件是个巨无霸,对外接口已经很清晰的列了出来.我们标注了三个极为核心的函数.集中精力分析下. <<情景分析>>也是大力解析这几个<br id=d0dr>函数.其余函数随着分析之深入,逐步介绍,如果发现疑问,再就地解决.<br id=b:ex><span id=kz1r style="FONT-FAMILY:Courier New">/*</span><br id=gruw style="FONT-FAMILY:Courier New"><span id=wif0 style="FONT-FAMILY:Courier New"> *Interface:</span><br id=yj6g style="FONT-FAMILY:Courier New"><span id=zuem style="FONT-FAMILY:Courier New"> * int __user_walk(const char *name, unsigned flags, struct nameidata *nd)</span><br id=tx2_ style="FONT-FAMILY:Courier New"><span id=rhik style="FONT-FAMILY:Courier New"> * int </span><font color=#3333ff id=k0k4 style="FONT-FAMILY:Courier New"><b id=cmm1>open_namei</b></font><span id=szm9 style="FONT-FAMILY:Courier New">(const char * pathname, int flag, int mode, struct nameidata *nd)</span><br id=eon1 style="FONT-FAMILY:Courier New"><span id=ufnv style="FONT-FAMILY:Courier New"> * int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)</span><br id=wlt5 style="FONT-FAMILY:Courier New"><span id=rfc3 style="FONT-FAMILY:Courier New"> * int vfs_readlink(struct dentry *dentry, char *buffer, int buflen, const char *link)</span><br id=dn08 style="FONT-FAMILY:Courier New"><span id=lbkg style="FONT-FAMILY:Courier New"> * int </span><font color=#3333ff id=v3h1 style="FONT-FAMILY:Courier New"><b id=xuox>path_walk</b></font><span id=yppf style="FONT-FAMILY:Courier New">(const char * name, struct nameidata *nd);</span><br id=r36s style="FONT-FAMILY:Courier New"><span id=d.yj style="FONT-FAMILY:Courier New"> * char * getname(const char * filename);</span><br id=fupu style="FONT-FAMILY:Courier New"><span id=ffud style="FONT-FAMILY:Courier New"> * int permission(struct inode * inode,int mask)</span><br id=si:p style="FONT-FAMILY:Courier New"><span id=r:je style="FONT-FAMILY:Courier New"> * int get_write_access(struct inode * inode);</span><br id=c-:o style="FONT-FAMILY:Courier New"><span id=f_ze style="FONT-FAMILY:Courier New"> * int deny_write_access(struct file * file)</span><br id=tpzr style="FONT-FAMILY:Courier New"><span id=r03o style="FONT-FAMILY:Courier New"> * void path_release(struct nameidata *nd)</span><br id=iqbr style="FONT-FAMILY:Courier New"><span id=xoo6 style="FONT-FAMILY:Courier New"> * int follow_down(struct vfsmount **mnt, struct dentry **dentry)</span><br id=feq. style="FONT-FAMILY:Courier New"><span id=b5ef style="FONT-FAMILY:Courier New"> * void set_fs_altroot(void)</span><br id=kxxz style="FONT-FAMILY:Courier New"><span id=zlmx style="FONT-FAMILY:Courier New"> * int </span><font color=#3333ff id=y_:8 style="FONT-FAMILY:Courier New"><b id=ab-:>path_init</b></font><span id=vpm9 style="FONT-FAMILY:Courier New">(const char *name, unsigned int flags, struct nameidata *nd)</span><br id=ohxf style="FONT-FAMILY:Courier New"><span id=lwkx style="FONT-FAMILY:Courier New"> * int vfs_follow_link(struct nameidata *nd, const char *link)</span><br id=dq0z style="FONT-FAMILY:Courier New"><span id=h08g style="FONT-FAMILY:Courier New"> *Sub Interface:</span><br id=m5g5 style="FONT-FAMILY:Courier New"><span id=d_q1 style="FONT-FAMILY:Courier New"> * struct dentry * lookup_hash(struct qstr *name, struct dentry * base)</span><br id=fv1c style="FONT-FAMILY:Courier New"><span id=b0hf style="FONT-FAMILY:Courier New"> *</span><br id=pfdd style="FONT-FAMILY:Courier New"><span id=k0_x style="FONT-FAMILY:Courier New"> *</span><br id=flrw style="FONT-FAMILY:Courier New"><span id=cl1m style="FONT-FAMILY:Courier New"> */</span><br id=e2.t>进行之前,先旁路些mini的函数,以免干扰主要思路:<br id=z1gx> <br id=qxwp>char * <font color=#38761d id=u.1j><b id=by:s>getname</b></font>(const char * filename) /*分配一个页面,将用户传递的参数复制到分配的页面中,并返回此页面指针*/<br id=c3qj> <font color=#38761d id=mvng><b id=iakh>putname</b></font>(name); /* 和上面函数配对,释放此页面*/<br id=ddt2>这对函数涉及到一个普遍常见的操作<br id=q_sz><font color=#38761d id=if4r><b id=cy..>set_fs</b></font>(get_ds());<br id=gbq1><font color=#38761d id=l-_w><b id=dfsy>set_fs</b></font>(old_ds) <br id=sj4e>常见于内核中操作文件的操作,这对操作的含义在下面这个函数中:<br id=y37m>static inline int<b id=x.4-> do_getname</b>(const char *filename, char *page)<br id=xjd4>{<br id=ocme> int retval;<br id=lwem> unsigned long len = PATH_MAX + 1;<br id=tav-><br id=z2rf> if ((unsigned long) <b id=xbg0>filename </b>>= <font color=#cc0000 id=ryp4>TASK_SIZE</font>) { <font color=#3d85c6 id=ylcx>/*如果是内核传递的参数*/</font><br id=ymuj> if (!segment_eq(<font color=#cc0000 id=fr_0><font color=#0b5394 id=rflh><b id=nt_w>get_fs</b></font>()</font>, <font color=#cc0000 id=f7st>KERNEL_DS</font>)) <font color=#0b5394 id=rslx>/*则必须addr limit 等于KERNEL_DS: 不是cpu的寄存器...*/</font><br id=z_-d> return -EFAULT;<br id=mo6m> } else if (TASK_SIZE - (unsigned long) filename < PAGE_SIZE) <font color=#0000ff id=mlvr>/*内核传递的参数跳过这个检查*/</font><br id=ab-o> len = TASK_SIZE - (unsigned long) filename;<br id=k57q> .........<br id=dlgu>}<br id=vcch><br id=tndk><br id=qb7q>分析permission之前看看inode的几个相关变量:<br id=ybyb>struct inode {<br id=b9uu> struct list_head i_hash;<br id=ou7r> struct list_head i_list;<br id=xccb> struct list_head i_dentry;<br id=dnl1> <br id=gf.a> struct list_head i_dirty_buffers;<br id=u8-u><br id=b45h> unsigned long i_ino;<br id=ew4g> atomic_t i_count;<br id=lxls> kdev_t i_dev;<br id=rslm> umode_t <font color=#38761d id=ky00><b id=p02m>i_mode</b></font>; /*LNK,REG,DIR,CHR,BLK,FIFO,SOCK |permition user|limit group|limit other*/<br id=i_n1> nlink_t i_nlink;<br id=a47b> uid_t <font color=#38761d id=i0b2><b id=xq8t>i_uid</b></font>; /*owner*/<br id=bdub> gid_t <font color=#38761d id=ius1><b id=woi9>i_gid</b></font>; /*owner's group?*/<br id=kob0> kdev_t i_rdev;<br id=mjm4> loff_t i_size;<br id=kyy2> time_t i_atime;<br id=t32t> time_t i_mtime;<br id=iej1> time_t i_ctime;<br id=hv5g> unsigned long i_blksize;<br id=pnvk> unsigned long i_blocks;<br id=n:vf> unsigned long i_version;<br id=jjks> struct semaphore i_sem;<br id=lvbm> struct semaphore i_zombie;<br id=dv4i> struct inode_operations *i_op;<br id=qc56> struct file_operations *i_fop; /* former ->i_op->default_file_ops */<br id=pdiw> struct super_block *i_sb;<br id=vovc> wait_queue_head_t i_wait;<br id=l9rx> struct file_lock *i_flock;<br id=qfur> struct address_space *i_mapping;<br id=npq2> struct address_space i_data; <br id=uhpl> struct dquot *i_dquot[MAXQUOTAS];<br id=i7n_> struct pipe_inode_info *i_pipe;<br id=s50o> struct block_device *i_bdev;<br id=uh7e><br id=k::0> unsigned long i_dnotify_mask; /* Directory notify events */<br id=u4kp> struct dnotify_struct *i_dnotify; /* for directory notifications */<br id=nu6d><br id=upzh> unsigned long i_state;<br id=n0r6><br id=y13i> unsigned int i_flags;<br id=tlxs> unsigned char i_sock;<br id=f:_i><br id=zo__> atomic_t i_writecount;<br id=vfr-> unsigned int i_attr_flags;<br id=a-y.> __u32 i_generation;<br id=w5qa> union {} u;<br id=z8dn>};</pre>
<pre id=xj2y>注意i_mode被分成几个部分使用:文件模式/权限(U,G,O)对应于owener权限,本group权限,other权限<br id=nn_e>int <font color=#38761d id=xtwp><b id=ho.y>permission</b></font>(struct inode * inode,int mask) <font color=#0000ff id=v2hc>/*要不使用文件系统自定义的权限检查,要不使用默认的权限检查*/</font><br id=f89:><font color=#0000ff id=j_f3><font color=#cc6600 id=t01y><b id=t5b1>DAC: 自主访问控制</b></font></font><br id=t_dx>/*<br id=bais> * permission()<br id=kr-t> * 根据文件的<br id=qb_-> * is used to check for read/write/execute permissions on a file.<br id=fg28> * We use "fsuid" for this, letting us set arbitrary permissions<br id=csaz> * for filesystem access without changing the "normal" uids which<br id=nhdg> * are used for other things..<br id=v6uh> */<br id=w0yx>int <font color=#38761d id=erw0><b id=m3wc>vfs_permission</b></font>(struct inode * inode,int mask) <font color=#0000ff id=qbu4>/*文件系统默认的权限检查...*/</font><br id=c9bs>{<br id=c_ya> int mode = inode->i_mode;<br id=lq.l><br id=ya-:> if ((mask & S_IWOTH) && <font color=#cc0000 id=j_a.>IS_RDONLY</font>(inode) && /*<font color=#cc0000 id=waio>IS_RDONLY判断</font>文件系统的安装属性*/<br id=ehgx> (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))<br id=d0tt> return -EROFS; /* Nobody gets write access to a read-only fs */ <font color=#0000ff id=n67:>/*文件系统级别判断*/</font><br id=gtmc><br id=na2e> if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))<br id=xxc2> return -EACCES; /* Nobody gets write access to an immutable file */ <font color=#0000ff id=t7jt>/*不可变更属性检查*/</font><br id=kjag><br id=x8kg> <font color=#0000ff id=n0wp>/*根据当前进程是owner/group/other来解析出文件对应的limitation*/</font><br id=cg25> if (current->fsuid == inode->i_uid) /*owner*/<br id=sqca> mode >>= 6;<br id=g6yr> else if (in_group_p(inode->i_gid)) /*group*/<br id=pv9i> mode >>= 3;<br id=r-hd> /*other*/<br id=ae8j><br id=gt8n> /*权限容许,或者当前进程拥有DACOVERRIDE权限: DAC,<font id=f0cg size=2><a class=l href=http://uw713doc.sco.com/en/SEC_file/_Discretionary_Access_Control_DAC_ACLs.html id=kptg target=_blank>Discretionary <font color=#cc0033 id=ockv>access</font> control (<font color=#cc0033 id=pg0c>DAC</font>)</a></font>*/<br id=bx90> if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE)) /*CAP是posix的定义的一系列访问权限*/<br id=wfl4> return 0;<br id=tlur><br id=alxc> <font color=#0000ff id=r.ig>/* read and search access */</font><br id=osvz> if ((mask == S_IROTH) ||<br id=pww.> (S_ISDIR(inode->i_mode) && !(mask & ~(S_IROTH | S_IXOTH))))<br id=x9zw> if (capable(CAP_DAC_READ_SEARCH))<br id=hi3g> return 0;<br id=cq:h><br id=dmdb> return -EACCES;<br id=ctb6>}<br id=cgyo>上面的分析随不够极度细致,也足以作为入门了,所以就看这么多吧.<br id=epo0><br id=dgzy>下面是write acess的两个函数: 此权限用于互斥mmap的VM_DENYWRITE属性和write操作. 就是mmap时指定了denywrite则普通文件就不能<br id=r_va>容许写操作了:<br id=iw8_>int <font color=#38761d id=s8gw><b id=gy:t>get_write_access</b></font>(struct inode * inode) /*普通文件写操作时判断有没有VM_DENYWRITE属性的mmap*/<br id=k1of><br id=ds5b>int <font color=#38761d id=wp6.><b id=ed50>deny_write_access</b></font>(struct file * file) /*mmap一个VM_DENYWRITE属性的区域需要拒绝普通文件的写操作*/<br id=ly3d></pre>
<div align=center id=fu3o>
<pre id=u77r><br id=i3y.><font id=yril size=4><font color=#0000ff id=d6g-><b id=e99e>path walk </b></font><br id=qw.t></font></pre>
</div>
<p align=justify id=di6r>
<br id=wfvj>
下面看看比较关键的一个文件系统的函数,也是文件系统之所以这么power的一个接口:字符串,路径接口.
path_walk.先研究下路径查找过程的中间结果:<br id=gxpf>
<font face="Courier New" id=kthy>struct nameidata {<br id=d53m>
struct dentry *dentry;
/*当前的dentry,从此目录开始查找*/<br id=ijb4>
struct vfsmount *mnt; /*当前dentry
所属的mnt*/<br id=ve76>
struct qstr last;
/*<font color=#0000ff id=w_.x>只有指定</font><font color=#0000ff id=nrpz>lOOKUP_PARENT时才需要关心(</font>__vfs_follow_link,使得非parent查找也有值,非主流...)*/<br id=ubfg>
unsigned int flags; /*查找参数:no
alt/positive/parent/follow/directory/<font color=#ff0000 id=v:sz>continue</font>*/<br id=q7es>
int last_type; /*NORM, ROOT, DOT,DOTDOT,
<font color=#ff0000 id=of8g>BIND</font>:
<font color=#0000ff id=u1h:>只有指定lOOKUP_PARENT时才有效</font>*/<br id=a7lv>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -