From: Mark Glines Date: Mon, 7 Jan 2002 16:32:02 +0000 (+0000) Subject: Added statfs support to kernel, lib, examples, and perl X-Git-Tag: fuse_0_95~3 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=d84b39ac42882a2cc2e7f85ed5f02ada03744d9e;p=qemu-gpiodev%2Flibfuse.git Added statfs support to kernel, lib, examples, and perl other minor perl fixes (still unstable) --- diff --git a/ChangeLog b/ChangeLog index cf7aaa8..d2a2c0b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2002-01-07 Mark Glines + + * Added statfs() support to kernel, lib, examples, and perl! + 2001-12-20 Miklos Szeredi * Added function fuse_get_context() to library API (inspired by diff --git a/TODO b/TODO index fbf6d70..971ea9e 100644 --- a/TODO +++ b/TODO @@ -2,6 +2,4 @@ - Integrate (parts of) fusermount into mount(8) - - Statfs operation - - Etc, etc... diff --git a/example/fusexmp.c b/example/fusexmp.c index b9df79c..b921d56 100644 --- a/example/fusexmp.c +++ b/example/fusexmp.c @@ -17,6 +17,7 @@ #include #include #include +#include static int xmp_getattr(const char *path, struct stat *stbuf) { @@ -231,6 +232,15 @@ static int xmp_write(const char *path, const char *buf, size_t size, return res; } +static int xmp_statfs(struct statfs *fst) +{ + struct statfs st; + int rv = statfs("/",&st); + if(!rv) + memcpy(fst,&st,sizeof(st)); + return rv; +} + static struct fuse_operations xmp_oper = { getattr: xmp_getattr, readlink: xmp_readlink, @@ -249,6 +259,7 @@ static struct fuse_operations xmp_oper = { open: xmp_open, read: xmp_read, write: xmp_write, + statfs: xmp_statfs, }; int main(int argc, char *argv[]) diff --git a/example/hello.c b/example/hello.c index e0010cd..ccd4b5f 100644 --- a/example/hello.c +++ b/example/hello.c @@ -84,6 +84,7 @@ static struct fuse_operations hello_oper = { open: hello_open, read: hello_read, write: NULL, + statfs: NULL, }; int main(int argc, char *argv[]) diff --git a/example/null.c b/example/null.c index 7be4ab4..71e9a19 100644 --- a/example/null.c +++ b/example/null.c @@ -64,6 +64,11 @@ static int null_write(const char *path, const char *UNUSED(buf), size_t size, return size; } +static int null_statfs(struct statfs *st) +{ + return st->f_blocks = st->f_bavail = st->f_bsize = st->f_files = + st->f_ffree = st->f_namelen = 0; +} static struct fuse_operations null_oper = { getattr: null_getattr, @@ -83,6 +88,7 @@ static struct fuse_operations null_oper = { open: null_open, read: null_read, write: null_write, + statfs: null_statfs, }; int main(int argc, char *argv[]) diff --git a/include/fuse.h b/include/fuse.h index bafa182..46fc87b 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -13,6 +13,7 @@ #include #include +#include #include /* ----------------------------------------------------------- * @@ -81,6 +82,7 @@ struct fuse_operations { int (*open) (const char *, int); int (*read) (const char *, char *, size_t, off_t); int (*write) (const char *, const char *, size_t, off_t); + int (*statfs) (struct statfs *); }; /** Extra context that may be needed by some filesystems */ diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 53cb3f0..40f3950 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -83,6 +83,7 @@ enum fuse_opcode { FUSE_OPEN = 14, FUSE_READ = 15, FUSE_WRITE = 16, + FUSE_STATFS = 17, }; /* Conservative buffer size for the client */ @@ -156,6 +157,19 @@ struct fuse_write_in { char buf[0]; }; +typedef struct fuse_statfs { + long block_size; + long blocks; + long blocks_free; + long files; + long files_free; + long namelen; +} fuse_statfs_t; + +struct fuse_statfs_out { + struct fuse_statfs st; +}; + struct fuse_in_header { int unique; enum fuse_opcode opcode; diff --git a/kernel/inode.c b/kernel/inode.c index 7fc5cfe..6c38708 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -70,10 +70,44 @@ static void fuse_put_super(struct super_block *sb) spin_unlock(&fuse_lock); } +static void convert_fuse_statfs(struct statfs *stbuf, struct fuse_statfs *attr) +{ + stbuf->f_type = FUSE_SUPER_MAGIC; + stbuf->f_bsize = attr->block_size; + stbuf->f_blocks = attr->blocks; + stbuf->f_bfree = stbuf->f_bavail = attr->blocks_free; + stbuf->f_files = attr->files; + stbuf->f_ffree = attr->files_free; + /* Is this field necessary? Most filesystems ignore it... + stbuf->f_fsid.val[0] = (FUSE_SUPER_MAGIC>>16)&0xffff; + stbuf->f_fsid.val[1] = FUSE_SUPER_MAGIC &0xffff; */ + stbuf->f_namelen = attr->namelen; +} + +static int fuse_statfs(struct super_block *sb, struct statfs *st) +{ + struct fuse_conn *fc = sb->u.generic_sbp; + struct fuse_in in = FUSE_IN_INIT; + struct fuse_out out = FUSE_OUT_INIT; + struct fuse_statfs_out outarg; + + in.numargs = 0; + in.h.opcode = FUSE_STATFS; + out.numargs = 1; + out.args[0].size = sizeof(outarg); + out.args[0].value = &outarg; + request_send(fc, &in, &out); + if(!out.h.error) + convert_fuse_statfs(st,&outarg.st); + + return out.h.error; +} + static struct super_operations fuse_super_operations = { read_inode: fuse_read_inode, clear_inode: fuse_clear_inode, put_super: fuse_put_super, + statfs: fuse_statfs, }; diff --git a/lib/fuse.c b/lib/fuse.c index 98bab3f..88f3eae 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -306,6 +306,16 @@ static void convert_stat(struct stat *stbuf, struct fuse_attr *attr) attr->_dummy = 4096; } +static void convert_statfs(struct statfs *st, struct fuse_statfs *fst) +{ + fst->block_size = st->f_bsize; + fst->blocks = st->f_blocks; + fst->blocks_free = st->f_bavail; + fst->files = st->f_files; + fst->files_free = st->f_ffree; + fst->namelen = st->f_namelen; +} + static int fill_dir(struct fuse_dirhandle *dh, char *name, int type) { struct fuse_dirent dirent; @@ -793,6 +803,20 @@ static void do_write(struct fuse *f, struct fuse_in_header *in, send_reply(f, in, res, NULL, 0); } +static void do_statfs(struct fuse *f, struct fuse_in_header *in) +{ + int res; + struct statfs sbuf; + struct fuse_statfs_out arg; + + res = -ENOSYS; + if(f->op.statfs) + res = f->op.statfs(&sbuf); + if(!res) + convert_statfs(&sbuf,&arg.st); + send_reply(f, in, res, &arg, sizeof(arg)); +} + static void free_cmd(struct fuse_cmd *cmd) { free(cmd->buf); @@ -878,6 +902,10 @@ void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd) do_write(f, in, (struct fuse_write_in *) inarg); break; + case FUSE_STATFS: + do_statfs(f, in); + break; + default: fprintf(stderr, "Operation %i not implemented\n", in->opcode); send_reply(f, in, -ENOSYS, NULL, 0); diff --git a/perl/.cvsignore b/perl/.cvsignore new file mode 100644 index 0000000..5d5c2dc --- /dev/null +++ b/perl/.cvsignore @@ -0,0 +1 @@ +Fuse.bs Fuse.c Makefile blib pm_to_blib diff --git a/perl/Fuse.pm b/perl/Fuse.pm index 93acfb6..3a20fd9 100644 --- a/perl/Fuse.pm +++ b/perl/Fuse.pm @@ -65,8 +65,8 @@ sub AUTOLOAD { bootstrap Fuse $VERSION; sub main { - my (@subs) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); - my (@names) = qw(getattr readlink getdir mknod mkdir unlink rmdir symlink rename link chmod chown truncate utime open read write); + my (@subs) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + my (@names) = qw(getattr readlink getdir mknod mkdir unlink rmdir symlink rename link chmod chown truncate utime open read write statfs); my ($tmp) = 0; my (%mapping) = map { $_ => $tmp++ } (@names); my (%otherargs) = (debug=>0, threaded=>1, mountpoint=>""); @@ -121,6 +121,14 @@ Every constant you need (file types, open() flags, error values, etc) can be imported either from POSIX or from Fcntl, often both. See their respective documentations, for more information. +=head2 EXPORT + +None by default. + +=head2 EXPORTABLE CONSTANTS + +None. + =head2 FUNCTIONS YOUR FILESYSTEM MAY IMPLEMENT =head3 getattr @@ -278,13 +286,20 @@ Returns an errno. Called in an attempt to write (or overwrite) a portion of the file. Be prepared because $buffer could contain random binary data with NULLs and all sorts of other wonderful stuff. -=head2 EXPORT +=head3 statfs -None by default. +Arguments: none +Returns any of the following: -=head2 Exportable constants +-ENOANO() -None. +or + +$namelen, $files, $files_free, $blocks, $blocks_avail, $blocksize + +or + +-ENOANO(), $namelen, $files, $files_free, $blocks, $blocks_avail, $blocksize =head1 AUTHOR diff --git a/perl/Fuse.xs b/perl/Fuse.xs index ca0459d..6061d9f 100644 --- a/perl/Fuse.xs +++ b/perl/Fuse.xs @@ -24,7 +24,7 @@ constant(char *name, int len, int arg) return 0; } -SV *_PLfuse_callbacks[17]; +SV *_PLfuse_callbacks[18]; int _PLfuse_getattr(const char *file, struct stat *result) { dSP; @@ -472,6 +472,42 @@ int _PLfuse_write (const char *file, const char *buf, size_t buflen, off_t off) return rv; } +int _PLfuse_statfs (struct statfs *st) { + int rv; + char *rvstr; + dSP; + DEBUGf("statfs begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + PUTBACK; + rv = call_sv(_PLfuse_callbacks[17],G_ARRAY); + SPAGAIN; + if(rv > 5) { + st->f_bsize = POPi; + st->f_bavail = st->f_bfree = POPi; + st->f_blocks = POPi; + st->f_ffree = POPi; + st->f_files = POPi; + st->f_namelen = POPi; + if(rv > 6) + rv = POPi; + else + rv = 0; + } else + if(rv > 1) + croak("inappropriate number of returned values from statfs"); + else + if(rv) + rv = POPi; + else + rv = -ENOSYS; + FREETMPS; + LEAVE; + DEBUGf("statfs end\n"); + return rv; +} + struct fuse_operations _available_ops = { getattr: _PLfuse_getattr, _PLfuse_readlink, @@ -489,7 +525,8 @@ getattr: _PLfuse_getattr, _PLfuse_utime, _PLfuse_open, _PLfuse_read, - _PLfuse_write + _PLfuse_write, + _PLfuse_statfs }; MODULE = Fuse PACKAGE = Fuse @@ -512,13 +549,13 @@ constant(sv,arg) void perl_fuse_main(...) PREINIT: - struct fuse_operations fops = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + struct fuse_operations fops = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; int i, varnum = 0, threads, debug, argc; char **argv; STRLEN n_a; STRLEN l; INIT: - if(items != 21) { + if(items != 22) { fprintf(stderr,"Perl<->C inconsistency or internal error\n"); XSRETURN_UNDEF; } @@ -544,7 +581,7 @@ perl_fuse_main(...) else argc--; - for(i=0;i<17;i++) { + for(i=0;i<18;i++) { SV *var = ST(i+4); if((var != &PL_sv_undef) && SvROK(var)) { if(SvTYPE(SvRV(var)) == SVt_PVCV) { diff --git a/perl/example.pl b/perl/example.pl index bc62cad..d01278c 100755 --- a/perl/example.pl +++ b/perl/example.pl @@ -70,6 +70,8 @@ sub e_read { return substr($files{$file}{cont},$off,$buf); } +sub e_statfs { return 255, 1, 1, 1, 1, 2 } + # If you run the script directly, it will run fusermount, which will in turn # re-run this script. Hence the funky semantics. my ($mountpoint) = ""; @@ -79,6 +81,7 @@ Fuse::main( getattr=>\&e_getattr, getdir=>\&e_getdir, open=>\&e_open, + statfs=>\&e_statfs, #read=>\&e_read, #debug=>1, threaded=>0 );