read和write系统调用

http://blog.chinaunix.net/space.php?uid=12567959&do=blog&id=161002

read()和write()系统调用

read()write()系统调用非常相似。它们都需要三个参数:一个文件描述符fd,一个内存区的地址buf(该缓冲区包含接受的数据或者要传送的数据的存放位置),以及一个数count(指定应该传送多少字节)。两个系统调用都返回所成功传送的字节数,或者发送一个错误条件的信号并返回-1

 

返回值小于count并不意味着发生了错误。即使请求的字节没有都被传送,也总是允许内核终止系统调用,因此用户应用程序必须检查返回值并重新发出系统调用(如果必要)。

 

一般会有这几种典型情况下返回小于count的值:当从管道或终端设备读取时,当读到文件的末尾时,或者当系统调用被信号中断时。文件结束条件(EOF)很容易从read()的空返回值中判断出来。这个条件不会与因信号引起的异常终止混淆在一起,因为如果读取数据之前read()被一个信号中断,则发生一个错误。

 

读或写操作总是发生在由当前文件指针所指定的文件偏移处(文件对象的f_pos字段)。两个系统调用都通过把所传送的字节数加到文件指针上而更新文件指针。

 

先来看read系统调用的实现,由sys_read()服务例程来实现,其定义为:

---------------------------------------------------------------------

fs/read_write.c

374SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)

375{

376        struct file *file;

377        ssize_t ret = -EBADF;

378        int fput_needed;

379

380        file = fget_light(fd,&fput_needed);

381        if (file) {

382                loff_t pos =file_pos_read(file);

383                ret = vfs_read(file, buf,count, &pos);

384                file_pos_write(file, pos);

385                fput_light(file, fput_needed);

386        }

387

388        return ret;

389}

---------------------------------------------------------------------

它执行的步骤如下:

1、调用fget_light()fd获取当前进程相应文件对象的地址file

---------------------------------------------------------------------

fs/file_table.c

292/*

293 * Lightweight file lookup - no refcntincrement if fd table isn't shared.

294 * You can use this only if it is guranteedthat the current task already

295 * holds a refcnt to that file. That check hasto be done at fget() only

296 * and a flag is returned to be passed to thecorresponding fput_light().

297 * There must not be a cloning between anfget_light/fput_light pair.

298 */

299struct file *fget_light(unsigned int fd, int *fput_needed)

300{

301        struct file *file;

302        struct files_struct *files =current->files;

303

304        *fput_needed = 0;

305        if (likely((atomic_read(&files->count)== 1))) {

306                file = fcheck_files(files,fd);

307        } else {

308                rcu_read_lock();

309                file = fcheck_files(files,fd);

310                if (file) {

311                        if (atomic_long_inc_not_zero(&file->f_count))

312                                *fput_needed =1;

313                        else

314                                /* Didn't getthe reference, someone's freed */

315                                file = NULL;

316                }

317                rcu_read_unlock();

318        }

319

320        return file;

321}

---------------------------------------------------------------------

 

---------------------------------------------------------------------

include/linux/fdtable.h

82static inline struct file * fcheck_files(struct files_struct *files, unsignedint fd)

83{

84        struct file * file = NULL;

85        struct fdtable *fdt =files_fdtable(files);

86

87        if (fd < fdt->max_fds)

88                file =rcu_dereference_check_fdtable(files, fdt->fd[fd]);

89        return file;

90}

---------------------------------------------------------------------

 

2、调用file_pos_read(file)获得当前的文件指针,并保存在局部变量pos中。

 

3、调用vfs_read(structfile *file, char __user *buf, size_t count, loff_t *pos)来完成读操作。

---------------------------------------------------------------------

fs/read_write.c

278ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t*pos)

279{

280        ssize_t ret;

281

282        if (!(file->f_mode & FMODE_READ))

283                return -EBADF;

284        if (!file->f_op ||(!file->f_op->read && !file->f_op->aio_read))

285                return -EINVAL;

286        if (unlikely(!access_ok(VERIFY_WRITE,buf, count)))

287                return -EFAULT;

288

289        ret = rw_verify_area(READ, file, pos,count);

290        if (ret >= 0) {

291                count = ret;

292                if (file->f_op->read)

293                        ret =file->f_op->read(file, buf, count, pos);

294                else

295                        ret =do_sync_read(file, buf, count, pos);

296                if (ret > 0) {

297                        fsnotify_access(file->f_path.dentry);

298                        add_rchar(current,ret);

299                }

300                inc_syscr(current);

301        }

302

303        return ret;

304}

---------------------------------------------------------------------

这个函数完成如下操作:

a.如果file->f_mode中的标志不允许所请求的读操作访问(file->f_mode没有设置FMODE_READ位),则返回一个错误码-EBADF

 

b.如果文件对象没有read()aio_read()文件操作,则返回一个错误码-EINVAL

 

c.调用access_ok()粗略地检查bufcount参数。

 

d.调用rw_verify_area()对要访问的文件部分检查是否有冲突的强制锁。如果有,则返回一个错误码,如果该锁已经被F_SETLKW命令请求,那么就挂起当前进程。

 

e.调用file->f_op->read(如果已定义)来传送数据;否则,调用 do_sync_read(file, buf, count, pos),这个函数本质上调用file->f_op->aio_read来完成读操作。所有这些方法都返回实际传送的字节数。另一方面的作用是,文件指针被适当地更新。

4.调用file_pos_write(file,pos)将保存在局部变量pos中的当前的文件指针写回。

 

5、调用fput_light()释放文件对象。

 

6、返回实际传送的字节数。

 

write 系统调用大致也是同样的流程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值