linux c 对磁盘指定块进行读写,Linux 0.11中write实现

看了一下Linux 0.11版本write的实现,首先它在标准头文件unistd.h中有定义

int write(int fildes, const char * buf, off_t count);

接下来看write.c

/*

* linux/lib/write.c

*

* (C) 1991 Linus Torvalds

*/

#define __LIBRARY__

#include

//定义write的实现

_syscall3(int,write,int,fd,const char *,buf,off_t,count)

这里说明一下为什么要有#define __LIBRARY__。因为在unistd.h有

#ifdef __LIBRARY__

/*中间省略*/

#define __NR_write4

/*中间省略*/

//有3个参数的系统调用宏函数

#define _syscall3(type,name,atype,a,btype,b,ctype,c) \

type name(atype a,btype b,ctype c) \

{ \

long __res; \

__asm__ volatile ("int $0x80" \

: "=a" (__res) \

: "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \

if (__res>=0) \

return (type) __res; \

errno=-__res; \

return -1; \

}

#endif /* __LIBRARY__ */

可以发现,若在#include 之前没有#define __LIBRARY__,则下面的_syscall3(int,write,int,fd,const char *,buf,off_t,count)是找不到的。

这种设计很优美,不需要系统调用的文件通过不包含#define __LIBRARY__,便能省去unistd.h中一些无用的定义。

这样write便拥有了实现,我们发现其中有__NR_##name,在write中它为__NR_##write。它在上面有定义#define __NR_write4。4代表什么,有下面的定义

fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,

sys_write, ... };

也就是所write会调用sys_write,sys_write在read_write.c文件中

int sys_write(unsigned int fd,char * buf,int count) //将用户进程要写的内容写入到内核的文件页面缓冲中

{

struct file * file;

struct m_inode * inode;

//异常错误处理

if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd]))

return -EINVAL;

if (!count)

return 0;

//取文件对应的i节点,若是管道文件,并且是写管道文件模式,则进行写管道操作

inode=file->f_inode;

if (inode->i_pipe)

return (file->f_mode&2)?write_pipe(inode,buf,count):-EIO;

//如果是字符型文件,则进行写字符设备

if (S_ISCHR(inode->i_mode))

return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos);

//如果是块设备文件,则进行块设备写操作

if (S_ISBLK(inode->i_mode))

return block_write(inode->i_zone[0],&file->f_pos,buf,count);

//如果是常规文件,则进行写文件

if (S_ISREG(inode->i_mode))

return file_write(inode,file,buf,count);

printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode);

return -EINVAL;

}

这里看一看常规文件写操作file_write,在file_dev.c中

//根据i节点和文件结构信息,将用户数据写入指定设备

int file_write(struct m_inode * inode, struct file * filp, char * buf, int count)

{

off_t pos;

int block,c;

struct buffer_head * bh;

char * p;

int i=0;

/*

* ok, append may not work when many processes are writing at the same time

* but so what. That way leads to madness anyway.

*/

//如果是要向文件后添加数据,则将文件读写指针移到文件尾部,否则就将在文件读写指针出写入

if (filp->f_flags & O_APPEND)

pos = inode->i_size;

else

pos = filp->f_pos;

//若已经写入字节数i小于需要写入的字节数count,则循环

while (i

//创建数据块号pos/BLOCK_SIZE在设备上对应的逻辑块

if (!(block = create_block(inode,pos/BLOCK_SIZE)))

break;

if (!(bh=bread(inode->i_dev,block)))

break;

//求出文件读写指针在数据块中的偏移值c,将p指向读出数据块缓冲区中开始读取的位置,置该缓冲区已修改标志

c = pos % BLOCK_SIZE;

p = c + bh->b_data;

bh->b_dirt = 1;

//从开始读写位置到块末共可写入c = BLOCK_SIZE-c个字节,若c大于剩余还需写入的字节数count-i,则

//此次只需再写入c = count-i

c = BLOCK_SIZE-c;

if (c > count-i) c = count-i;

//文件读写指针前移此次需写入的字节数,如果当前文件读写指针位置值超过了文件的大小,则修改i节点中文件

//大小字段,并置i节点已修改标志

pos += c;

if (pos > inode->i_size) {

inode->i_size = pos;

inode->i_dirt = 1;

}

//已写入字节计数累加此次写入的字节数c。从用户缓冲区buf中复制c个字节到高速缓冲区中p指向开始的位置处,

//然后释放该缓冲区

i += c;

while (c-->0)

*(p++) = get_fs_byte(buf++);

brelse(bh);

}

//更改文件修改时间为当前时间

inode->i_mtime = CURRENT_TIME;

//如果此次操作不是在文件尾部添加,则把文件读写指针调整到当前写位置。并更改i节点修改时间为当前时间

if (!(filp->f_flags & O_APPEND)) {

filp->f_pos = pos;

inode->i_ctime = CURRENT_TIME;

}

return (i?i:-1);

}

总结:

我们在用户层可以对磁盘、串口和文件通用wirte,但在系统调用层便进行了区分。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值