Changeset View
Changeset View
Standalone View
Standalone View
stand/libsa/open.c
Show First 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "stand.h" | #include "stand.h" | ||||
struct fs_ops *exclusive_file_system; | struct fs_ops *exclusive_file_system; | ||||
struct open_file files[SOPEN_MAX]; | /* | ||||
* Open file list. The current implementation and assumption is, | |||||
* we only remove entries from tail and we only add new entries to tail. | |||||
* This decision is to keep file id management simple - we get list | |||||
* entries ordered by continiously growing f_id field. | |||||
* If we do have multiple files open and we do close file not from tail, | |||||
* this entry will be marked unused. open() will reuse unused entry, or | |||||
* close will free all unused tail entries. | |||||
* | |||||
* Only case we expect open file list to grow long, is with zfs pools with | |||||
* many disks. | |||||
*/ | |||||
file_list_t files = TAILQ_HEAD_INITIALIZER(files); | |||||
/* | |||||
* Walk file list and return pointer to open_file structure. | |||||
* if fd is < 0, return first unused open_file. | |||||
*/ | |||||
struct open_file * | |||||
fd2open_file(int fd) | |||||
{ | |||||
struct open_file *f; | |||||
TAILQ_FOREACH(f, &files, f_link) { | |||||
if (fd >= 0) { | |||||
if (f->f_id == fd) | |||||
break; | |||||
continue; | |||||
} | |||||
if (f->f_flags == 0) | |||||
break; | |||||
} | |||||
return (f); | |||||
} | |||||
static int | static int | ||||
o_gethandle(void) | o_gethandle(struct open_file **ptr) | ||||
{ | { | ||||
int fd; | struct open_file *f, *last; | ||||
for (fd = 0; fd < SOPEN_MAX; fd++) | /* Pick up unused entry */ | ||||
if (files[fd].f_flags == 0) | f = fd2open_file(-1); | ||||
return (fd); | if (f != NULL) { | ||||
*ptr = f; | |||||
return (f->f_id); | |||||
} | |||||
/* Add new entry */ | |||||
f = calloc(1, sizeof (*f)); | |||||
if (f == NULL) | |||||
return (-1); | return (-1); | ||||
last = TAILQ_LAST(&files, file_list); | |||||
if (last != NULL) | |||||
f->f_id = last->f_id + 1; | |||||
imp: I think this is my answer to the questions. But you should document the requirement that the… | |||||
Done Inline ActionsYea, we can use different strategies to handle ID. But it is not just about how we manage ID, but also combination with entry search for lookup/remove/add... anyhow, since both open file and sockets lists do have special properties there, I think this approach is reasonably good... :) tsoome: Yea, we can use different strategies to handle ID. But it is not just about how we manage ID… | |||||
TAILQ_INSERT_TAIL(&files, f, f_link); | |||||
*ptr = f; | |||||
return (f->f_id); | |||||
} | } | ||||
static void | static void | ||||
o_rainit(struct open_file *f) | o_rainit(struct open_file *f) | ||||
{ | { | ||||
f->f_rabuf = malloc(SOPEN_RASIZE); | f->f_rabuf = malloc(SOPEN_RASIZE); | ||||
f->f_ralen = 0; | f->f_ralen = 0; | ||||
f->f_raoffset = 0; | f->f_raoffset = 0; | ||||
} | } | ||||
int | int | ||||
open(const char *fname, int mode) | open(const char *fname, int mode) | ||||
{ | { | ||||
struct fs_ops *fs; | struct fs_ops *fs; | ||||
struct open_file *f; | struct open_file *f; | ||||
int fd, i, error, besterror; | int fd, i, error, besterror; | ||||
const char *file; | const char *file; | ||||
TSENTER(); | TSENTER(); | ||||
if ((fd = o_gethandle()) == -1) { | if ((fd = o_gethandle(&f)) == -1) { | ||||
errno = EMFILE; | errno = EMFILE; | ||||
return (-1); | return (-1); | ||||
} | } | ||||
f = &files[fd]; | |||||
f->f_flags = mode + 1; | f->f_flags = mode + 1; | ||||
f->f_dev = NULL; | f->f_dev = NULL; | ||||
f->f_ops = NULL; | f->f_ops = NULL; | ||||
f->f_offset = 0; | f->f_offset = 0; | ||||
f->f_devdata = NULL; | f->f_devdata = NULL; | ||||
file = NULL; | file = NULL; | ||||
if (exclusive_file_system != NULL) { | if (exclusive_file_system != NULL) { | ||||
▲ Show 20 Lines • Show All 49 Lines • Show Last 20 Lines |
I think this is my answer to the questions. But you should document the requirement that the list be ordered by fd,.
The reason I say "I think" is because I don't think we need to keep the freed internal entries if we want to preserve the behavior that the last open_file* on the list has the highest f_id