xv6, line by line
kernel/file.c

kernel/file.c

C · 179 lines · annotated 100% · kernel · upstream

About this file

The layer between file descriptors and the things they refer to. A file descriptor is a small integer that indexes the process’s ofile array; each slot points to a struct file, an open file (struct file), kept in the system-wide table ftable defined here. A struct file records what is open (a pipe, an inode, or a device), whether it may be read or written, and the current offset.

This file allocates and frees those structures with a reference count, and routes read, write and fstat to the right implementation: kernel/pipe.c for pipes, readi/writei in kernel/fs.c for files and directories, and the devsw table for devices such as the console.

Its callers are the system calls in kernel/sysfile.c (which turn the descriptor number into a struct file *), kfork and kexit in kernel/proc.c, and pipealloc.

Read before: kernel/file.h, kernel/fs.c. Read next: kernel/sysfile.c, kernel/pipe.c.

1//
2// Support functions for system calls that involve file descriptors.
3//
5#include "types.h"
6#include "riscv.h"
7#include "defs.h"
8#include "param.h"
9#include "fs.h"
12#include "file.h"
13#include "stat.h"
14#include "proc.h"
16struct devsw devsw[NDEV];
17struct {
18 struct spinlock lock;
19 struct file file[NFILE];
22void
25 initlock(&ftable.lock, "ftable");
28// Allocate a file structure.
29struct file *
32 struct file *f;
35 for (f = ftable.file; f < ftable.file + NFILE; f++) {
36 if (f->ref == 0) {
37 f->ref = 1;
39 return f;
40 }
41 }
43 return 0;
46// Increment ref count for file f.
47struct file *
48filedup(struct file *f)
51 if (f->ref < 1)
52 panic("filedup");
53 f->ref++;
55 return f;
58// Close file f. (Decrement ref count, close when reaches 0.)
59void
60fileclose(struct file *f)
62 struct file ff;
65 if (f->ref < 1)
66 panic("fileclose");
67 if (--f->ref > 0) {
69 return;
70 }
71 ff = *f;
72 f->ref = 0;
76 if (ff.type == FD_PIPE) {
78 } else if (ff.type == FD_INODE || ff.type == FD_DEVICE) {
82 }
85// Get metadata about file f.
86// addr is a user virtual address, pointing to a struct stat.
87int
90 struct proc *p = myproc();
91 struct stat st;
93 if (f->type == FD_INODE || f->type == FD_DEVICE) {
95 stati(f->ip, &st);
97 if (copyout(p->pagetable, p->sz, addr, (char *)&st, sizeof(st)) < 0)
98 return -1;
99 return 0;
100 }
101 return -1;
104// Read from file f.
105// addr is a user virtual address.
106int
107fileread(struct file *f, uint64 addr, int n)
109 int r = 0;
111 if (f->readable == 0 || n < 0)
112 return -1;
114 if (f->type == FD_PIPE) {
116 } else if (f->type == FD_DEVICE) {
117 if (f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
118 return -1;
119 r = devsw[f->major].read(1, addr, n);
120 } else if (f->type == FD_INODE) {
122 if ((r = readi(f->ip, 1, addr, f->off, n)) > 0)
123 f->off += r;
125 } else {
126 panic("fileread");
127 }
129 return r;
132// Write to file f.
133// addr is a user virtual address.
134int
135filewrite(struct file *f, uint64 addr, int n)
137 int r, ret = 0;
139 if (f->writable == 0 || n < 0)
140 return -1;
142 if (f->type == FD_PIPE) {
144 } else if (f->type == FD_DEVICE) {
145 if (f->major < 0 || f->major >= NDEV || !devsw[f->major].write)
146 return -1;
148 } else if (f->type == FD_INODE) {
149 // write a few blocks at a time to avoid exceeding
150 // the maximum log transaction size, including
151 // i-node, indirect block, allocation blocks,
152 // and 2 blocks of slop for non-aligned writes.
153 int max = ((MAXOPBLOCKS - 1 - 1 - 2) / 2) * BSIZE;
154 int i = 0;
155 while (i < n) {
156 int n1 = n - i;
157 if (n1 > max)
162 if ((r = writei(f->ip, 1, addr + i, f->off, n1)) > 0)
163 f->off += r;
167 if (r != n1) {
168 // error from writei
169 break;
170 }
171 i += r;
172 }
173 ret = (i == n ? n : -1);
174 } else {
175 panic("filewrite");
176 }
178 return ret;