📄 040_fs_fcntl_c.html
字号:
} } @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_28j5n5phdd:135"> <table align=center cellpadding=0 cellspacing=0 height=5716 width=802>
<tbody>
<tr>
<td height=5716 valign=top width=802>
<pre>2007-12-25 <br><br> 这个文件实现了几个系统调用接口.sys_dup sys_dup2 sys_fcntl 和fasync(异步).<br><br><font size=5><b>1.sys_dup sys_dup2</b></font><br><br> 就是clone一个fd到另一个fd,实现本身平淡无奇就是操作 task_struct:struct files_struct *files;数组,其索引就是<br>大名顶顶的fd了. 下面是man dup的简单介绍. <br> dup() and dup2() create a copy of the file descriptor oldfd.<br><br> After a successful return from dup() or dup2(), the old and new file descriptors may be<br> used interchangeably. They refer to the same open file description (see open(2)) and<br> thus share file offset and file status flags; for example, if the file offset is modi-<br> fied by using lseek(2) on one of the descriptors, the offset is also changed for the<br> other.<br><br> <b>The two descriptors do not share file descriptor flags (the close-on-exec flag)</b>.<br> The close-on-exec flag (FD_CLOEXEC; see fcntl(2)) for the duplicate descriptor is off.<br><br> dup() uses the lowest-numbered unused descriptor for the new descriptor.<br><br> dup2() makes newfd be the copy of oldfd, closing newfd first if necessary.<br>dup后clos_on_exec将被清除.<br>值得一提的就是task_struct->files,就是fd的动态增长增加了些复杂度.<br>struct <font color=#000099><b>files_struct</b></font> {<br> atomic_t count;<br> rwlock_t file_lock;<br> int max_fds;<br> int max_fdset;<br> int next_fd;<br> struct file ** <font color=#009900>fd</font>; /* current fd array,init is fd_arrary */<br> fd_set *<font color=#009900>close_on_exec</font>;<br> fd_set *<font color=#009900>open_fds</font>; /*bitmap for open fd_array*/<br> fd_set close_on_exec_init;<br> fd_set open_fds_init;<br> struct file * fd_array[NR_OPEN_DEFAULT]; /*inline fd array*/<br>};<br>sys_dup寻找一个空闲的fd,而sys_dup2则使用指定的fd(老的fd其文件将被释放).<br>动态增长fd的代码就不看了.其实其中的竞争关系,files_struct的各个域的精确涵义值得去体会的...(应该不是个遗憾事...)<br><br><br><font size=5><b>2. fcntl <font size=4>ioctl sysctl</font></b></font><br> 这里是只有fcntl的. 至于sysctl是对系统本身参数的控制. ioctl大部分都是控制驱动程序的. 这些ctl函数提供给user以便于<br>user对内核各个部分做出相应的调整. 其实现本身就是<span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">dispatch的过程.<br> 最直接的办法是man,然后看看源代码,知道这个流程即可,具体到特性,那是纷繁复杂,每一个特性都属于不同的领域/特性.<br><font color=#000099><br><b>fcntl overview:</b></font><br></span></pre>
<ul>
<li>
<span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">
Duplicating a file descriptor</span>
</li>
</ul>
<ul>
<li>
<span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">
File descriptor flags (close on exec)<br>
</span>
</li>
</ul>
<pre><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal"> F_GETFD<br> Read the file descriptor flags.<br> F_SETFD<br> Set the file descriptor flags to the value specified by arg.<br></span></pre>
<ul>
<li>
<span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">
File status flags</span>
</li>
</ul>
<pre><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal"> F_GETFL<br> Read the file status flags.<br> F_SETFL<br> Set the file status flags to the value specified by arg. File access mode<br> (O_RDONLY, O_WRONLY, O_RDWR) and file creation flags (i.e., O_CREAT, O_EXCL,<br> O_NOCTTY, O_TRUNC) in arg are ignored. On Linux this command can only change<br> the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags.<br></span></pre>
<ul>
<li>
<font color=#006600><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">Advisory
locking</span></font>
</li>
</ul>
<pre><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal"> F_GETLK, F_SETLK and F_SETLKW are used to acquire, release, and test for the existence<br> of record locks (also known as file-segment or file-region locks). The third argument<br> lock is a pointer to a structure that has at least the following fields (in unspecified<br> order).<br><br> struct <font color=#3333ff><b>flock </b></font>{<br> ...<br> short l_type; /* Type of lock: F_RDLCK,<br> F_WRLCK, F_UNLCK */<br> short l_whence; /* How to interpret l_start:<br> SEEK_SET, SEEK_CUR, SEEK_END */<br> off_t l_start; /* Starting offset for lock */<br> off_t l_len; /* Number of bytes to lock */<br> pid_t l_pid; /* PID of process blocking our lock<br> (F_GETLK only) */<br> ...<br> };<br></span></pre>
<ul>
<li>
<span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">
Mandatory locking</span>
</li>
</ul>
<pre><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal"> (Non-POSIX.) The above record locks may be either advisory or mandatory, and are advi-<br> sory by default.<br><br> Advisory locks are not enforced and are useful only between cooperating processes.<br><br> Mandatory locks are enforced for all processes. If a process tries to perform an<br> incompatible access (e.g., read(2) or write(2)) on a file region that has an incompati-<br> ble mandatory lock, then the result depends upon whether the O_NONBLOCK flag is enabled<br> for its open file description. If the O_NONBLOCK flag is not enabled, then system call<br> is blocked until the lock is removed or converted to a mode that is compatible with the<br> access. If the O_NONBLOCK flag is enabled, then the system call fails with the error<br> EAGAIN or EWOULDBLOCK.<br><br> To make use of mandatory locks, mandatory locking must be enabled both on the file sys-<br> tem that contains the file to be locked, and on the file itself. Mandatory locking is<br> enabled on a file system using the "-o mand" option to mount(8), or the MS_MANDLOCK<br> flag for mount(2). Mandatory locking is enabled on a file by disabling group execute<br> permission on the file and enabling the set-group-ID permission bit (see chmod(1) and<br> chmod(2)).<br><br></span><font color=#3333ff>说到文件加锁,linux有两种文件加锁的系统调用:<br>flock, fcntl(lockf就是fcntl). fcntl默认是</font><font color=#3333ff><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">Advisory lock需要</span><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">Mandatory lock是需要以特殊的方式安装文<br>件系统然后再把文件的属性改为:</span></font><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal"><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal"><font color=#3333ff>disabling group execute + enabling the set-group-ID. 然后用fcntl<br>加锁后就是Mandatory lock了.<br>flock只容许对整个文件进行加锁,是BSD风格的. fntl是posix的锁.在linux内部是都是使用 flle_lock来实现<br>的.</font><br>struct <font color=#000099><b>file_lock</b></font> {<br> struct file_lock *fl_next; /* singly linked list for this inode */<br> struct list_head fl_link; /* doubly linked list of all locks */<br> struct list_head fl_block; /* circular list of blocked processes */<br> fl_owner_t fl_owner;<br> unsigned int fl_pid;<br> wait_queue_head_t fl_wait;<br> struct file *fl_file;<br> unsigned char fl_flags;<br> unsigned char fl_type;<br> loff_t fl_start;<br> loff_t fl_end;<br><br> void (*fl_notify)(struct file_lock *); /* unblock callback */<br> void (*fl_insert)(struct file_lock *); /* lock insertion callback */<br> void (*fl_remove)(struct file_lock *); /* lock removal callback */<br><br> struct fasync_struct * fl_fasync; /* for lease break notifications */<br><br> union {<br> struct nfs_lock_info nfs_fl;<br> } fl_u;<br>};<br><br></span></span></pre>
<ul>
<li>
<span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal"><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">
Managing signals</span></span>
</li>
</ul>
<pre><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal"><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal"> F_GETOWN, F_SETOWN, F_GETSIG and F_SETSIG are used to manage I/O availability signals:</span></span></pre>
<ul>
<li>
Leases
</li>
</ul>
<pre> F_SETLEASE and F_GETLEASE (Linux 2.4 onwards) are used (respectively) to establish and<br> retrieve the current setting of the calling process’s lease on the file referred to by<br> fd. A file lease provides a mechanism whereby the process holding the lease (the<br> "lease holder") is notified (via delivery of a signal) when a process (the "lease<br> breaker") tries to open(2) or truncate(2) that file.<br>关于Leases,man里介绍的很清楚了.<br><br><font color=#3333ff><br>我们来具体看看fcntl的功能,这里仅仅给出一个简单的注释,</font><br>static long <font color=#000099><b>do_fcntl</b></font>(unsigned int fd, unsigned int cmd,<br> unsigned long arg, struct file * filp)<br>{<br> long err = -EINVAL;<br><br> switch (cmd) {<br> case F_DUPFD: <font color=#3333ff>/* 类似dup2,但是不是强制以arg为fd,而是dup到arg开始的第一个空闲fd */</font><br> if (arg < NR_OPEN) {<br> get_file(filp);<br> err = dupfd(filp, arg);<br> }<br> break;<br> case F_GETFD: <font color=#000099>/* get set close on exec*/</font><br> .....<br> case F_SETFD:<br> .....<br> case F_GETFL: <font color=#3333ff>/*get set filp->f_flags*/</font><br> ......<br> case F_SETFL:<br> .....<br> <b>case F_GETLK</b>: <font color=#3333ff><b>/*Posix Lock 操作*/</b></font><br> err = fcntl_getlk(fd, (struct flock *) arg);<br> break;<br> <b>case F_SETLK</b>:<br> <b>case F_SETLKW</b>:<br> err = fcntl_setlk(fd, cmd, (struct flock *) arg);<br> break;<br> case<font color=#3333ff> F_GETOWN</font>: <font color=#3333ff>/*分析dnotify.c的时候说过,owener用于记录当文件发生变化<br> 需要通知的进程, owener在不同的情景中有不同的用法:<br> <font color=#cc0000> 1. dir notify 2.lease(via fl->fl_fasync) <br> 3. fasync (via specific fasync queue)</font><br> */</font><br> /*<br> * XXX If f_owner is a process group, the<br> * negative return value will get converted<br> * into an error. Oops. If we keep the<br> * current syscall conventions, the only way<br> * to fix this will be in libc.<br> */<br> err = filp->f_owner.pid;<br> break;<br> case<font color=#3333ff> F_SETOWN:</font><br> lock_kernel();<br> filp->f_owner.pid = arg;<br> filp->f_owner.uid = current->uid;<br> filp->f_owner.euid = current->euid;<br> err = 0;<br> if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))<br> err = sock_fcntl (filp, F_SETOWN, arg);<br> unlock_kernel();<br> break;<br> case <font color=#3333ff>F_GETSIG:</font><br> err = filp->f_owner.signum;<br> break;<br> case <font color=#3333ff>F_SETSIG</font>:<br> /* arg == 0 restores default behaviour. */<br> if (arg < 0 || arg > _NSIG) {<br> break;<br> }<br> err = 0;<br> filp->f_owner.signum = arg;<br> break;<br> <font color=#cc33cc>case F_GETLEASE:</font><br> err = fcntl_getlease(filp);<br> break;<br> <font color=#cc33cc>case F_SETLEASE:</font><br> err = fcntl_setlease(fd, filp, arg);<br> break;<br> <font color=#336666>case F_NOTIFY: /*dir notify 通知*/</font><br> err = fcntl_dirnotify(fd, filp, arg);<br> break;<br> default:<br> /* sockets need a few special fcntls. */<br> err = -EINVAL;<br> if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))<br> err = sock_fcntl (filp, cmd, arg);<br> break;<br> }<br><br> return err;<br>}<br><br><font size=5><b>3. fasync</b></font><br><br>这里着重解释下 filp->f_owner, dnotify, lease,和 fasync直接的关系: 文件异步通知的使用.<br>思路蛮简单的:<br> 一个file结构是一次open特定的(多个file可以使用同一个dentry),也就是说file是一个进程特定的结构,其中的<br>f_owner,用于记录需要获取异步通知的进程之uid/gid/signum等信息, <b>f_owner是需要通知的进程</b>.<br> 然后,有两中方式使用f_owner: <br>1) dnotify_struct -> filep->f_owner <br> dnotify 使用了异步通知机制, dnotify_struct挂接到inode下,需要的时候从inode找到owner,发送一个信号给指定进程.<br>dnotify 创建时直接初始化了owner,设置好了各个参数.<br><br>2) fasync 文件异步通知<br>struct <font color=#000099><b>fasync_struct</b></font> {<br> int magic;<br> int fa_fd;<br> struct fasync_struct *fa_next; /* singly linked list */<br> struct file *fa_file;<br>};<br> 其实dir notify也可以用这个东西的,这是一个通用的结构.和dnotify_struct 其实没有什么不同.<br>有两个函数提供fasync: <br><br> a)生成一个fasync结构,挂接到指定队列.<br>extern int <font color=#3333ff><b>fasync_helper</b></font>(int, struct file *, int, struct fasync_struct **);<br><br> b)通知指定的owner<br>extern void <font color=#3333ff><b>kill_fasync</b></font>(struct fasync_struct **, int, int);<br><br><br>3)file lease <br> 这是建立在fasync机制上的一个应用. 特殊的地方是挂接到file_lock->fl_fasync.... (这也能叫特殊啊)<br><br>4)fasync调用<br>file_operations{ fasync }<br>就是调用<font color=#3333ff><b>fasync_helper, </b><font color=#000000>就是队列不同而已. 合适的时候会有sig发送到指定进程....<br>(这个和fsync可不是一对啊)<br><br><br></font></font></pre>
</td>
</tr>
</tbody>
</table></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -