CVS: is/fs25 .cvsignore,NONE,1.1 AUTHORS,NONE,1.1 COPYING,NONE,1.1 ChangeLog,NONE,1.1 INSTALL,NONE,1.1 MANIFEST,NONE,1.1 Makefile.am,NONE,1.1 NEWS,NONE,1.1 README,NONE,1.1 autogen.sh,NONE,1.1 cache.c,NONE,1.1 configure.in,NONE,1.1 dcache.c,NONE,1.1 dir.c,NONE,1.1 ext_attr.c,NONE,1.1 file.c,NONE,1.1 fileset.c,NONE,1.1 inode.c,NONE,1.1 io_daemon.c,NONE,1.1 journal.c,NONE,1.1 journal_ext2.c,NONE,1.1 journal_ext3.c,NONE,1.1 journal_obdfs.c,NONE,1.1 journal_reiserfs.c,NONE,1.1 journal_tmpfs.c,NONE,1.1 journal_xfs.c,NONE,1.1 kml_reint.c,NONE,1.1 kml_unpack.c,NONE,1.1 methods.c,NONE,1.1 presto.c,NONE,1.1 psdev.c,NONE,1.1 replicator.c,NONE,1.1 super.c,NONE,1.1 sysctl.c,NONE,1.1 upcall.c,NONE,1.1 vfs.c,NONE,1.1
"Peter J. Braam" <[email protected]> Fri, 11 Oct 2002 15:52:04 -0700
| Newsgroups | gmane.comp.file-systems.intermezzo.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/intermezzo/is/fs25
In directory usw-pr-cvs1:/tmp/cvs-serv17557/fs25
Added Files:
.cvsignore AUTHORS COPYING ChangeLog INSTALL MANIFEST
Makefile.am NEWS README autogen.sh cache.c configure.in
dcache.c dir.c ext_attr.c file.c fileset.c inode.c io_daemon.c
journal.c journal_ext2.c journal_ext3.c journal_obdfs.c
journal_reiserfs.c journal_tmpfs.c journal_xfs.c kml_reint.c
kml_unpack.c methods.c presto.c psdev.c replicator.c super.c
sysctl.c upcall.c vfs.c
Log Message:
beginnings of 2.5 support
--- NEW FILE ---
.h
.out
config.mk
config.out
config.*T
Makefile
Makefile.in
aclocal.m4
configure
config.cache
config.log
config.status
.depfiles
.prereq.ok
.ready
.deps
--- NEW FILE ---
--- NEW FILE ---
NOTE! This copyright does *not* cover user programs that use kernel
services by normal system calls - this is merely considered normal use
of the kernel, and does *not* fall under the heading of "derived work".
Also note that the GPL below is copyrighted by the Free Software
Foundation, but the instance of code that it refers to (The InterMezzo
Filesytem Code) is copyrighted by me and others who actually wrote it.
Peter J. Braam
----------------------------------------
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
--- NEW FILE ---
2002-05-03 robert read <[email protected]>
* presto.c (izo_revoke_permit): call upc_revoke_permit after
permit has been revoked in kernel. need to allow final KML to be
saved first.
2002-04-27 robert read <[email protected]>
* kml_reint.c (reint_create): directory mod time was set
incorrectly by CREATE. In fact, many dates were unset.
* vfs.c (presto_do_unlink): unlink decremented dd_count too
aggressively on tmpfs. presto_d_release does this for us most of
the time.
--- NEW FILE ---
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.
The file `configure.in' is used to create `configure' by a program
called `autoconf'. You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. You can give `configure'
initial values for variables by setting them in the environment. Using
a Bourne-compatible shell, you can do that on the command line like
this:
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not supports the `VPATH'
variable, you have to compile the package for one architecture at a time
in the source code directory. After you have installed the package for
one architecture, use `make distclean' before reconfiguring for another
architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' can not figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it can not guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.
If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
produce code for and the `--build=TYPE' option to select the type of
system on which you are compiling the package.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.
--- NEW FILE ---
cache.c
configure
COPYING
.cvsignore
dcache.c
dir.c
ext_attr.c
file.c
fileset.c
fs-support/reiserpatch
fs-support/xfs-patch
inode.c
presto.c
journal.c
journal_ext2.c
journal_ext3.c
journal_obdfs.c
journal_reiserfs.c
journal_xfs.c
kml_unpack.c
kml_reint.c
linux/.cvsignore
linux/fsfilter.h
linux/intermezzo_fs.h
linux/intermezzo_idl.h
linux/intermezzo_psdev.h
Makefile.in
MANIFEST
methods.c
psdev.c
README
replicator.c
super.c
sysctl.c
upcall.c
vfs.c
--- NEW FILE ---
# Copyright (C) 2001, 2002 Cluster File Systems, Inc.
#
# This code is issued under the GNU General Public License.
# See the file COPYING in this distribution
NORECURSE = t
export NORECURSE
SUBDIRS = linux
VERSION:=@IVERSION@
DEFS:=
CONFIG_STATUS_DEPENDENCIES = $(srcdir)/configure
$(MODULE).o: $($(MODULE)_OBJECTS)
$(LD) -m "`$(LD) --help | awk '/supported emulations/ {print $$4}'`" -r -o $(MODULE).o $($(MODULE)_OBJECTS)
MODULE = intermezzo
modulefs_DATA = intermezzo.o
EXTRA_PROGRAMS = intermezzo
intermezzo_SOURCES = fileset.c journal_tmpfs.c cache.c inode.c journal_reiserfs.c presto.c upcall.c \
dcache.c journal.c journal_xfs.c psdev.c vfs.c dir.c \
journal_ext2.c kml_reint.c replicator.c ext_attr.c \
journal_ext3.c kml_unpack.c super.c file.c journal_obdfs.c \
methods.c sysctl.c
--- NEW FILE ---
--- NEW FILE ---
***********************************************************************
InterMezzo High Availability File System
Presto: kernel code for the InterMezzo file system
Cluster File Systems Inc.
Tacit Networks, Inc.
Stelias Computing Inc.
Red Hat Software Inc.
contact: [email protected]
***********************************************************************
DISCLAIMER AND WARNING:
Please read the license in the file COPYING.
InterMezzo is a file system, involving kernel code and daemons running
with root permissions. Use this system entirely at your own risk.
YOU RISK LOSING DATA AND YOU MAY INTRODUCE SECURITY PROBLEMS ON YOUR
COMPUTER.
INSTALLATION AND OPERATION:
The installation process and operation of the system is now described
in the InterMezzo-HOWTO file that is in the docs directory. This file
is distributed in its source SGML form InterMezzo-HOWTO.sgml and in
ASCII form InterMezzo-HOWTO.txt. The file is also available on the
web at http://www.inter-mezzo.org/docs/InterMezzo-HOWTO.html .
***********************************************************************
Please subscribe to [email protected] to receive
further release announcements.
***********************************************************************
--- NEW FILE ---
#!/bin/sh
automake --add-missing &&
aclocal &&
autoconf
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2000 Stelias Computing, Inc.
* Copyright (C) 2000 Red Hat, Inc.
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <stdarg.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
/*
This file contains the routines associated with managing a
cache of files for InterMezzo. These caches have two reqs:
- need to be found fast so they are hashed by the device,
with an attempt to have collision chains of length 1.
The methods for the cache are set up in methods.
*/
extern kmem_cache_t * presto_dentry_slab;
/* the intent of this hash is to have collision chains of length 1 */
#define CACHES_BITS 8
#define CACHES_SIZE (1 << CACHES_BITS)
#define CACHES_MASK CACHES_SIZE - 1
static struct list_head presto_caches[CACHES_SIZE];
static inline int presto_cache_hash(kdev_t dev)
{
return (CACHES_MASK) & ((0x000F & (dev)) + ((0x0F00 & (dev)) >>8));
}
inline void presto_cache_add(struct presto_cache *cache, kdev_t dev)
{
list_add(&cache->cache_chain,
&presto_caches[presto_cache_hash(dev)]);
cache->cache_dev = dev;
}
inline void presto_cache_init_hash(void)
{
int i;
for ( i = 0; i < CACHES_SIZE; i++ ) {
INIT_LIST_HEAD(&presto_caches[i]);
}
}
/* map a device to a cache */
struct presto_cache *presto_cache_find(kdev_t dev)
{
struct presto_cache *cache;
struct list_head *lh, *tmp;
lh = tmp = &(presto_caches[presto_cache_hash(dev)]);
while ( (tmp = lh->next) != lh ) {
cache = list_entry(tmp, struct presto_cache, cache_chain);
if ( cache->cache_dev == dev ) {
return cache;
}
}
return NULL;
}
/* map an inode to a cache */
struct presto_cache *presto_get_cache(struct inode *inode)
{
struct presto_cache *cache;
ENTRY;
/* find the correct presto_cache here, based on the device */
cache = presto_cache_find(inode->i_dev);
if ( !cache ) {
CERROR("WARNING: no presto cache for dev %x, ino %ld\n",
inode->i_dev, inode->i_ino);
EXIT;
return NULL;
}
EXIT;
return cache;
}
/* another debugging routine: check fs is InterMezzo fs */
int presto_ispresto(struct inode *inode)
{
struct presto_cache *cache;
if ( !inode )
return 0;
cache = presto_get_cache(inode);
if ( !cache )
return 0;
return (inode->i_dev == cache->cache_dev);
}
/* setup a cache structure when we need one */
struct presto_cache *presto_cache_init(void)
{
struct presto_cache *cache;
PRESTO_ALLOC(cache, sizeof(struct presto_cache));
if ( cache ) {
memset(cache, 0, sizeof(struct presto_cache));
INIT_LIST_HEAD(&cache->cache_chain);
INIT_LIST_HEAD(&cache->cache_fset_list);
cache->cache_lock = SPIN_LOCK_UNLOCKED;
cache->cache_reserved = 0;
}
return cache;
}
/* free a cache structure and all of the memory it is pointing to */
inline void presto_free_cache(struct presto_cache *cache)
{
if (!cache)
return;
list_del(&cache->cache_chain);
if (cache->cache_sb && cache->cache_sb->s_root &&
presto_d2d(cache->cache_sb->s_root)) {
kmem_cache_free(presto_dentry_slab,
presto_d2d(cache->cache_sb->s_root));
cache->cache_sb->s_root->d_fsdata = NULL;
}
PRESTO_FREE(cache, sizeof(struct presto_cache));
}
int presto_reserve_space(struct presto_cache *cache, loff_t req)
{
struct filter_fs *filter;
loff_t avail;
struct super_block *sb = cache->cache_sb;
filter = cache->cache_filter;
if (!filter ) {
EXIT;
return 0;
}
if (!filter->o_trops ) {
EXIT;
return 0;
}
if (!filter->o_trops->tr_avail ) {
EXIT;
return 0;
}
spin_lock(&cache->cache_lock);
avail = filter->o_trops->tr_avail(cache, sb);
CDEBUG(D_SUPER, "ESC::%ld +++> %ld \n", (long) cache->cache_reserved,
(long) (cache->cache_reserved + req));
CDEBUG(D_SUPER, "ESC::Avail::%ld \n", (long) avail);
if (req + cache->cache_reserved > avail) {
spin_unlock(&cache->cache_lock);
EXIT;
return -ENOSPC;
}
cache->cache_reserved += req;
spin_unlock(&cache->cache_lock);
EXIT;
return 0;
}
void presto_release_space(struct presto_cache *cache, loff_t req)
{
CDEBUG(D_SUPER, "ESC::%ld ---> %ld \n", (long) cache->cache_reserved,
(long) (cache->cache_reserved - req));
spin_lock(&cache->cache_lock);
cache->cache_reserved -= req;
spin_unlock(&cache->cache_lock);
}
--- NEW FILE ---
AC_INIT
# Copyright (C) 2001, 2002 Cluster File Systems, Inc.
#
# This code is issued under the GNU General Public License.
# See the file COPYING in this distribution
# Automake variables. Steal the version number from packaging/intersync.spec
AM_INIT_AUTOMAKE(intersync, builtin([esyscmd], [sed -ne '/.*define IVERSION /{ s/.*IVERSION //; p; }' super.c]))
#AM_MAINTAINER_MODE
AC_SUBST(IVERSION)
AC_PROG_CC
AC_PROG_RANLIB
AC_PREFIX_DEFAULT([])
if test "x$prefix" = xNONE || test "x$prefix" = x; then
usrprefix=/usr
else
usrprefix='${prefix}'
fi
AC_SUBST(usrprefix)
oldincludedir='${usrprefix}/include'
linuxdir_def=/usr/src/linux
AC_ARG_WITH(linux, [ --with-linux=[path] set path to Linux source (default=/usr/src/linux)], enable_linuxdir=$withval)
AC_ARG_ENABLE(linuxdir, [ --enable-linuxdir=[path] (deprecated) set path to Linux source (default=/usr/src/linux)],, enable_linuxdir=$linuxdir_def)
LINUX=$enable_linuxdir
AC_SUBST(LINUX)
AC_MSG_CHECKING(if make dep has been run in kernel source)
if test -f $LINUX/include/linux/config.h ; then
AC_MSG_RESULT(yes)
else
AC_MSG_ERROR(** cannot find $LINUX/include/linux/config.h. Run make dep in $LINUX.)
fi
AC_MSG_CHECKING(if autoconf.h is in kernel source)
if test -f $LINUX/include/linux/autoconf.h ; then
AC_MSG_RESULT(yes)
else
AC_MSG_ERROR(** cannot find $LINUX/include/linux/autoconf.h. Run make config in $LINUX.)
fi
AC_MSG_CHECKING(if you are compiling for user mode linux)
um_asm_link=`ls -l "$LINUX/include/asm" | sed -e "s%.* $LINUX/include/asm -> %%"`
if test "X$um_asm_link" = Xasm-um; then
AC_MSG_RESULT(yes)
KCFLAGS='-Wall -pipe -Wno-trigraphs -Wstrict-prototypes -fno-strict-aliasing -fno-common -g '
KCPPFLAGS='-D__KERNEL__ -DMODULE -I$(srcdir) -I$(LINUX)/include -I$(top_srcdir)/include -U__i386__ -Ui386 -DUM_FASTCALL -D__arch_um__ -DSUBARCH="i386" -DNESTING=0 -D_LARGEFILE64_SOURCE -I$(LINUX)/arch/um/include -Derrno=kernel_errno'
else
AC_MSG_RESULT(no)
KCFLAGS='-g -O2 -Wall -Wstrict-prototypes -pipe'
KCPPFLAGS='-D__KERNEL__ -DMODULE -I$(srcdir) -I$(LINUX)/include -I$(top_srcdir)/include'
fi
AC_MSG_CHECKING(for MODVERSIONS)
if egrep -e 'MODVERSIONS.*1' $LINUX/include/linux/autoconf.h >/dev/null 2>&1;
then
MFLAGS="-DMODVERSIONS -include $LINUX/include/linux/modversions.h"
AC_MSG_RESULT(yes)
else
MFLAGS=
AC_MSG_RESULT(no)
fi
AC_MSG_CHECKING(for SMP)
if egrep -e SMP=y $LINUX/.config >/dev/null 2>&1; then
SMPFLAG=-D__SMP__
AC_MSG_RESULT(yes)
else
SMPFLAG=
AC_MSG_RESULT(no)
fi
CFLAGS="$KCFLAGS"
CPPFLAGS="$MFLAGS $SMPFLAG $KCPPFLAGS"
AC_MSG_CHECKING(for Linux release)
dnl We need to rid ourselves of the nasty [ ] quotes.
changequote(,)
RELEASE=`sed -ne '/^#define *UTS_RELEASE *"/{ s/.*"\([^"]*\)".*/\1/; p; q; }' $LINUX/include/linux/version.h`
changequote([,])
moduledir='${prefix}/lib/modules/'$RELEASE
AC_SUBST(moduledir)
modulefsdir='${moduledir}/kernel/fs/intermezzo'
AC_SUBST(modulefsdir)
AC_MSG_RESULT($RELEASE)
AC_SUBST(RELEASE)
# Directories for documentation and demos.
docdir='${datadir}/doc/$(PACKAGE)'
AC_SUBST(docdir)
demodir='$(docdir)/demo'
AC_SUBST(demodir)
AC_OUTPUT(Makefile linux/Makefile)
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Original version: Copyright (C) 1996 P. Braam and M. Callahan
* Rewritten for Linux 2.1. Copyright (C) 1997 Carnegie Mellon University
* d_fsdata and NFS compatiblity fixes Copyright (C) 2001 Tacit Networks, Inc.
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Directory operations for InterMezzo filesystem
*/
/* inode dentry alias list walking code adapted from linux/fs/dcache.c
*
* fs/dcache.c
*
* (C) 1997 Thomas Schoebel-Theuer,
* with heavy changes by Linus Torvalds
*/
#define __NO_VERSION__
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/intermezzo_fs.h>
static kmem_cache_t * presto_dentry_slab;
/* called when a cache lookup succeeds */
static int presto_d_revalidate(struct dentry *de, int flag)
{
struct inode *inode = de->d_inode;
struct presto_file_set * root_fset;
ENTRY;
if (!inode) {
EXIT;
return 0;
}
if (is_bad_inode(inode)) {
EXIT;
return 0;
}
if (!presto_d2d(de)) {
presto_set_dd(de);
}
if (!presto_d2d(de)) {
EXIT;
return 0;
}
root_fset = presto_d2d(de->d_inode->i_sb->s_root)->dd_fset;
if (root_fset->fset_flags & FSET_FLAT_BRANCH &&
(presto_d2d(de)->dd_fset != root_fset )) {
presto_d2d(de)->dd_fset = root_fset;
}
EXIT;
return 1;
#if 0
/* The following is needed for metadata on demand. */
if ( S_ISDIR(inode->i_mode) ) {
EXIT;
return (presto_chk(de, PRESTO_DATA) &&
(presto_chk(de, PRESTO_ATTR)));
} else {
EXIT;
return presto_chk(de, PRESTO_ATTR);
}
#endif
}
static void presto_d_release(struct dentry *dentry)
{
if (!presto_d2d(dentry)) {
/* This can happen for dentries from NFSd */
return;
}
presto_d2d(dentry)->dd_count--;
if (!presto_d2d(dentry)->dd_count) {
kmem_cache_free(presto_dentry_slab, presto_d2d(dentry));
dentry->d_fsdata = NULL;
}
}
struct dentry_operations presto_dentry_ops =
{
.d_revalidate = presto_d_revalidate,
.d_release = presto_d_release
};
static inline int presto_is_dentry_ROOT (struct dentry *dentry)
{
return(dentry_name_cmp(dentry,"ROOT") &&
!dentry_name_cmp(dentry->d_parent,".intermezzo"));
}
static struct presto_file_set* presto_try_find_fset(struct dentry* dentry,
int *is_under_d_intermezzo)
{
struct dentry* temp_dentry;
struct presto_dentry_data *d_data;
int found_root=0;
ENTRY;
CDEBUG(D_FSDATA, "finding fileset for %p:%s\n", dentry,
dentry->d_name.name);
*is_under_d_intermezzo = 0;
/* walk up through the branch to get the fileset */
/* The dentry we are passed presumably does not have the correct
* fset information. However, we still want to start walking up
* the branch from this dentry to get our found_root and
* is_under_d_intermezzo decisions correct
*/
for (temp_dentry = dentry ; ; temp_dentry = temp_dentry->d_parent) {
CDEBUG(D_FSDATA, "--->dentry %p:%*s\n", temp_dentry,
temp_dentry->d_name.len,temp_dentry->d_name.name);
if (presto_is_dentry_ROOT(temp_dentry))
found_root = 1;
if (!found_root &&
dentry_name_cmp(temp_dentry, ".intermezzo")) {
*is_under_d_intermezzo = 1;
}
d_data = presto_d2d(temp_dentry);
if (d_data) {
/* If we found a "ROOT" dentry while walking up the
* branch, we will journal regardless of whether
* we are under .intermezzo or not.
* If we are already under d_intermezzo don't reverse
* the decision here...even if we found a "ROOT"
* dentry above .intermezzo (if we were ever to
* modify the directory structure).
*/
if (!*is_under_d_intermezzo)
*is_under_d_intermezzo = !found_root &&
(d_data->dd_flags & PRESTO_DONT_JOURNAL);
EXIT;
return d_data->dd_fset;
}
if (temp_dentry->d_parent == temp_dentry) {
break;
}
}
EXIT;
return NULL;
}
/* Only call this function on positive dentries */
static struct presto_dentry_data* presto_try_find_alias_with_dd (
struct dentry* dentry)
{
struct inode *inode=dentry->d_inode;
struct list_head *head, *next, *tmp;
struct dentry *tmp_dentry;
/* Search through the alias list for dentries with d_fsdata */
spin_lock(&dcache_lock);
head = &inode->i_dentry;
next = inode->i_dentry.next;
while (next != head) {
tmp = next;
next = tmp->next;
tmp_dentry = list_entry(tmp, struct dentry, d_alias);
if (!presto_d2d(tmp_dentry)) {
spin_unlock(&dcache_lock);
return presto_d2d(tmp_dentry);
}
}
spin_unlock(&dcache_lock);
return NULL;
}
/* Only call this function on positive dentries */
static void presto_set_alias_dd (struct dentry *dentry,
struct presto_dentry_data* dd)
{
struct inode *inode=dentry->d_inode;
struct list_head *head, *next, *tmp;
struct dentry *tmp_dentry;
/* Set d_fsdata for this dentry */
dd->dd_count++;
dentry->d_fsdata = dd;
/* Now set d_fsdata for all dentries in the alias list. */
spin_lock(&dcache_lock);
head = &inode->i_dentry;
next = inode->i_dentry.next;
while (next != head) {
tmp = next;
next = tmp->next;
tmp_dentry = list_entry(tmp, struct dentry, d_alias);
if (!presto_d2d(tmp_dentry)) {
dd->dd_count++;
tmp_dentry->d_fsdata = dd;
}
}
spin_unlock(&dcache_lock);
return;
}
inline struct presto_dentry_data *izo_alloc_ddata(void)
{
struct presto_dentry_data *dd;
dd = kmem_cache_alloc(presto_dentry_slab, SLAB_KERNEL);
if (dd == NULL) {
CERROR("IZO: out of memory trying to allocate presto_dentry_data\n");
return NULL;
}
memset(dd, 0, sizeof(*dd));
dd->dd_count = 1;
return dd;
}
/* This uses the BKL! */
int presto_set_dd(struct dentry * dentry)
{
struct presto_file_set *fset;
struct presto_dentry_data *dd;
int is_under_d_izo;
int error=0;
ENTRY;
if (!dentry)
BUG();
lock_kernel();
/* Did we lose a race? */
if (dentry->d_fsdata) {
CERROR("dentry %p already has d_fsdata set\n", dentry);
if (dentry->d_inode)
CERROR(" inode: %ld\n", dentry->d_inode->i_ino);
EXIT;
goto out_unlock;
}
if (dentry->d_inode != NULL) {
/* NFSd runs find_fh_dentry which instantiates disconnected
* dentries which are then connected without a lookup().
* So it is possible to have connected dentries that do not
* have d_fsdata set. So we walk the list trying to find
* an alias which has its d_fsdata set and then use that
* for all the other dentries as well.
* - SHP,Vinny.
*/
/* If there is an alias with d_fsdata use it. */
if ((dd = presto_try_find_alias_with_dd (dentry))) {
presto_set_alias_dd (dentry, dd);
EXIT;
goto out_unlock;
}
} else {
/* Negative dentry */
CDEBUG(D_FSDATA,"negative dentry %p: %*s\n", dentry,
dentry->d_name.len, dentry->d_name.name);
}
/* No pre-existing d_fsdata, we need to construct one.
* First, we must walk up the tree to find the fileset
* If a fileset can't be found, we leave a null fsdata
* and return EROFS to indicate that we can't journal
* updates.
*/
fset = presto_try_find_fset (dentry, &is_under_d_izo);
if (!fset) {
#ifdef PRESTO_NO_NFS
CERROR("No fileset for dentry %p: %*s\n", dentry,
dentry->d_name.len, dentry->d_name.name);
#endif
error = -EROFS;
EXIT;
goto out_unlock;
}
dentry->d_fsdata = izo_alloc_ddata();
if (!presto_d2d(dentry)) {
CERROR ("InterMezzo: out of memory allocating d_fsdata\n");
error = -ENOMEM;
goto out_unlock;
}
presto_d2d(dentry)->dd_fset = fset;
if (is_under_d_izo)
presto_d2d(dentry)->dd_flags |= PRESTO_DONT_JOURNAL;
EXIT;
out_unlock:
CDEBUG(D_FSDATA,"presto_set_dd dentry %p: %*s, d_fsdata %p\n",
dentry, dentry->d_name.len, dentry->d_name.name,
dentry->d_fsdata);
unlock_kernel();
return error;
}
int presto_init_ddata_cache(void)
{
ENTRY;
presto_dentry_slab =
kmem_cache_create("presto_cache",
sizeof(struct presto_dentry_data), 0,
SLAB_HWCACHE_ALIGN, NULL,
NULL);
EXIT;
return (presto_dentry_slab != NULL);
}
void presto_cleanup_ddata_cache(void)
{
kmem_cache_destroy(presto_dentry_slab);
}
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2000 Stelias Computing, Inc.
* Copyright (C) 2000 Red Hat, Inc.
* Copyright (C) 2000 Tacitus Systems
* Copyright (C) 2000 Peter J. Braam
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
[...1376 lines suppressed...]
};
struct inode_operations presto_dir_iops = {
.create = presto_create,
.lookup = presto_lookup,
.link = presto_link,
.unlink = presto_unlink,
.symlink = presto_symlink,
.mkdir = presto_mkdir,
.rmdir = presto_rmdir,
.mknod = presto_mknod,
.rename = presto_rename,
.permission = presto_permission,
.setattr = presto_setattr,
#ifdef CONFIG_FS_EXT_ATTR
.set_ext_attr = presto_set_ext_attr,
#endif
};
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2001 Tacit Networks, Inc.
* Author: Shirish H. Phatak <[email protected]>
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Extended attribute handling for presto.
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/unistd.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <asm/segment.h>
#include <linux/smp_lock.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
#ifdef CONFIG_FS_EXT_ATTR
#include <linux/ext_attr.h>
extern inline void presto_debug_fail_blkdev(struct presto_file_set *fset,
unsigned long value);
/* VFS interface */
/* XXX! Fixme test for user defined attributes */
int presto_set_ext_attr(struct inode *inode,
const char *name, void *buffer,
size_t buffer_len, int flags)
{
int error;
struct presto_cache *cache;
struct presto_file_set *fset;
struct lento_vfs_context info;
struct dentry *dentry;
int minor = presto_i2m(inode);
char *buf = NULL;
ENTRY;
if (minor < 0) {
EXIT;
return -1;
}
if ( ISLENTO(minor) ) {
EXIT;
return -EINVAL;
}
/* BAD...vfs should really pass down the dentry to use, especially
* since every other operation in iops does. But for now
* we do a reverse mapping from inode to the first dentry
*/
if (list_empty(&inode->i_dentry)) {
CERROR("No alias for inode %d\n", (int) inode->i_ino);
EXIT;
return -EINVAL;
}
dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias);
error = presto_prep(dentry, &cache, &fset);
if ( error ) {
EXIT;
return error;
}
if ((buffer != NULL) && (buffer_len != 0)) {
/* If buffer is a user space pointer copy it to kernel space
* and reset the flag. We do this since the journal functions need
* access to the contents of the buffer, and the file system
* does not care. When we actually invoke the function, we remove
* the EXT_ATTR_FLAG_USER flag.
*
* XXX:Check if the "fs does not care" assertion is always true -SHP
* (works for ext3)
*/
if (flags & EXT_ATTR_FLAG_USER) {
PRESTO_ALLOC(buf, buffer_len);
if (!buf) {
CERROR("InterMezzo: out of memory!!!\n");
return -ENOMEM;
}
error = copy_from_user(buf, buffer, buffer_len);
if (error)
return -EFAULT;
} else
buf = buffer;
} else
buf = buffer;
if ( presto_get_permit(inode) < 0 ) {
EXIT;
if (buffer_len && (flags & EXT_ATTR_FLAG_USER))
PRESTO_FREE(buf, buffer_len);
return -EROFS;
}
/* Simulate presto_setup_info */
memset(&info, 0, sizeof(info));
/* For now redundant..but we keep it around just in case */
info.flags = LENTO_FL_IGNORE_TIME;
if (!ISLENTO(cache->cache_psdev->uc_minor))
info.flags |= LENTO_FL_KML;
/* We pass in the kernel space pointer and reset the
* EXT_ATTR_FLAG_USER flag.
* See comments above.
*/
/* Note that mode is already set by VFS so we send in a NULL */
error = presto_do_set_ext_attr(fset, dentry, name, buf,
buffer_len, flags & ~EXT_ATTR_FLAG_USER,
NULL, &info);
presto_put_permit(inode);
if (buffer_len && (flags & EXT_ATTR_FLAG_USER))
PRESTO_FREE(buf, buffer_len);
EXIT;
return error;
}
/* Lento Interface */
/* XXX: ignore flags? We should be forcing these operations through? -SHP*/
int lento_set_ext_attr(const char *path, const char *name,
void *buffer, size_t buffer_len, int flags, mode_t mode,
struct lento_vfs_context *info)
{
int error;
char * pathname;
struct nameidata nd;
struct dentry *dentry;
struct presto_file_set *fset;
ENTRY;
lock_kernel();
pathname=getname(path);
error = PTR_ERR(pathname);
if (IS_ERR(pathname)) {
EXIT;
goto exit;
}
/* Note that ext_attrs apply to both files and directories..*/
error=presto_walk(pathname,&nd);
if (error)
goto exit;
dentry = nd.dentry;
fset = presto_fset(dentry);
error = -EINVAL;
if ( !fset ) {
CERROR("No fileset!\n");
EXIT;
goto exit_dentry;
}
if (buffer==NULL) buffer_len=0;
error = presto_do_set_ext_attr(fset, dentry, name, buffer,
buffer_len, flags, &mode, info);
exit_dentry:
path_release(&nd);
exit_path:
putname(pathname);
exit:
unlock_kernel();
return error;
}
#endif /*CONFIG_FS_EXT_ATTR*/
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2000 Stelias Computing, Inc.
* Copyright (C) 2000 Red Hat, Inc.
* Copyright (C) 2000 TurboLinux, Inc.
* Copyright (C) 2000 Los Alamos National Laboratory.
* Copyright (C) 2000, 2001 Tacit Networks, Inc.
* Copyright (C) 2000 Peter J. Braam
* Copyright (C) 2001 Mountain View Data, Inc.
* Copyright (C) 2001 Cluster File Systems, Inc.
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* This file manages file I/O
*
*/
#include <stdarg.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
#include <linux/fsfilter.h>
/*
* these are initialized in super.c
*/
extern int presto_permission(struct inode *inode, int mask);
static int presto_open_upcall(int minor, struct dentry *de)
{
int rc;
char *path, *buffer;
struct presto_file_set *fset;
int pathlen;
struct lento_vfs_context info;
struct presto_dentry_data *dd = presto_d2d(de);
PRESTO_ALLOC(buffer, PAGE_SIZE);
if ( !buffer ) {
CERROR("PRESTO: out of memory!\n");
return -ENOMEM;
}
fset = presto_fset(de);
path = presto_path(de, fset->fset_dentry, buffer, PAGE_SIZE);
pathlen = MYPATHLEN(buffer, path);
CDEBUG(D_FILE, "de %p, dd %p\n", de, dd);
if (dd->remote_ino == 0) {
rc = presto_get_fileid(minor, fset, de);
}
memset (&info, 0, sizeof(info));
if (dd->remote_ino > 0) {
info.remote_ino = dd->remote_ino;
info.remote_generation = dd->remote_generation;
} else
CERROR("get_fileid failed %d, ino: %Lx, fetching by name\n", rc,
dd->remote_ino);
rc = izo_upc_open(minor, pathlen, path, fset->fset_name, &info);
PRESTO_FREE(buffer, PAGE_SIZE);
return rc;
}
static inline int open_check_dod(struct file *file,
struct presto_file_set *fset)
{
int gen, is_iopen = 0, minor;
struct presto_cache *cache = fset->fset_cache;
ino_t inum;
minor = presto_c2m(cache);
if ( ISLENTO(minor) ) {
CDEBUG(D_CACHE, "is lento, not doing DOD.\n");
return 0;
}
/* Files are only ever opened by inode during backfetches, when by
* definition we have the authoritative copy of the data. No DOD. */
is_iopen = izo_dentry_is_ilookup(file->f_dentry, &inum, &gen);
if (is_iopen) {
CDEBUG(D_CACHE, "doing iopen, not doing DOD.\n");
return 0;
}
if (!(fset->fset_flags & FSET_DATA_ON_DEMAND)) {
CDEBUG(D_CACHE, "fileset not on demand.\n");
return 0;
}
if (file->f_flags & O_TRUNC) {
CDEBUG(D_CACHE, "fileset dod: O_TRUNC.\n");
return 0;
}
if (presto_chk(file->f_dentry, PRESTO_DONT_JOURNAL)) {
CDEBUG(D_CACHE, "file under .intermezzo, not doing DOD\n");
return 0;
}
if (presto_chk(file->f_dentry, PRESTO_DATA)) {
CDEBUG(D_CACHE, "PRESTO_DATA is set, not doing DOD.\n");
return 0;
}
if (cache->cache_filter->o_trops->tr_all_data(file->f_dentry->d_inode)) {
CDEBUG(D_CACHE, "file not sparse, not doing DOD.\n");
return 0;
}
return 1;
}
static int presto_file_open(struct inode *inode, struct file *file)
{
int rc = 0;
struct file_operations *fops;
struct presto_cache *cache;
struct presto_file_set *fset;
struct presto_file_data *fdata;
int writable = (file->f_flags & (O_RDWR | O_WRONLY));
int minor, i;
ENTRY;
if (presto_prep(file->f_dentry, &cache, &fset) < 0) {
EXIT;
return -EBADF;
}
minor = presto_c2m(cache);
CDEBUG(D_CACHE, "DATA_OK: %d, ino: %ld, islento: %d\n",
presto_chk(file->f_dentry, PRESTO_DATA), inode->i_ino,
ISLENTO(minor));
if ( !ISLENTO(minor) && (file->f_flags & O_RDWR ||
file->f_flags & O_WRONLY)) {
CDEBUG(D_CACHE, "calling presto_get_permit\n");
if ( presto_get_permit(inode) < 0 ) {
EXIT;
return -EROFS;
}
presto_put_permit(inode);
}
if (open_check_dod(file, fset)) {
CDEBUG(D_CACHE, "presto_open_upcall\n");
CDEBUG(D_CACHE, "dentry: %p setting DATA, ATTR\n", file->f_dentry);
presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA);
rc = presto_open_upcall(minor, file->f_dentry);
if (rc) {
EXIT;
CERROR("%s: returning error %d\n", __FUNCTION__, rc);
return rc;
}
}
/* file was truncated upon open: do not refetch */
if (file->f_flags & O_TRUNC) {
CDEBUG(D_CACHE, "setting DATA, ATTR\n");
presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA);
}
fops = filter_c2cffops(cache->cache_filter);
if ( fops->open ) {
CDEBUG(D_CACHE, "calling fs open\n");
rc = fops->open(inode, file);
if (rc) {
EXIT;
return rc;
}
}
if (writable) {
PRESTO_ALLOC(fdata, sizeof(*fdata));
if (!fdata) {
EXIT;
return -ENOMEM;
}
/* LOCK: XXX check that the kernel lock protects this alloc */
fdata->fd_do_lml = 0;
fdata->fd_bytes_written = 0;
fdata->fd_fsuid = current->fsuid;
fdata->fd_fsgid = current->fsgid;
fdata->fd_mode = file->f_dentry->d_inode->i_mode;
fdata->fd_uid = file->f_dentry->d_inode->i_uid;
fdata->fd_gid = file->f_dentry->d_inode->i_gid;
fdata->fd_ngroups = current->ngroups;
for (i=0 ; i < current->ngroups ; i++)
fdata->fd_groups[i] = current->groups[i];
if (!ISLENTO(minor))
fdata->fd_info.flags = LENTO_FL_KML;
else {
/* this is for the case of DOD,
reint_close will adjust flags if needed */
fdata->fd_info.flags = 0;
}
presto_getversion(&fdata->fd_version, inode);
file->private_data = fdata;
} else {
file->private_data = NULL;
}
EXIT;
return 0;
}
int presto_adjust_lml(struct file *file, struct lento_vfs_context *info)
{
struct presto_file_data *fdata =
(struct presto_file_data *) file->private_data;
if (!fdata) {
EXIT;
return -EINVAL;
}
memcpy(&fdata->fd_info, info, sizeof(*info));
EXIT;
return 0;
}
static int presto_file_release(struct inode *inode, struct file *file)
{
int rc;
struct file_operations *fops;
struct presto_cache *cache;
struct presto_file_set *fset;
struct presto_file_data *fdata =
(struct presto_file_data *)file->private_data;
ENTRY;
rc = presto_prep(file->f_dentry, &cache, &fset);
if ( rc ) {
EXIT;
return rc;
}
fops = filter_c2cffops(cache->cache_filter);
if (fops && fops->release)
rc = fops->release(inode, file);
CDEBUG(D_CACHE, "islento = %d (minor %d), rc %d, data %p\n",
ISLENTO(cache->cache_psdev->uc_minor),
cache->cache_psdev->uc_minor, rc, fdata);
/* this file was modified: ignore close errors, write KML */
if (fdata && fdata->fd_do_lml) {
/* XXX: remove when lento gets file granularity cd */
if ( presto_get_permit(inode) < 0 ) {
EXIT;
return -EROFS;
}
fdata->fd_info.updated_time = file->f_dentry->d_inode->i_mtime;
rc = presto_do_close(fset, file);
presto_put_permit(inode);
}
if (!rc && fdata) {
PRESTO_FREE(fdata, sizeof(*fdata));
file->private_data = NULL;
}
EXIT;
return rc;
}
static void presto_apply_write_policy(struct file *file,
struct presto_file_set *fset, loff_t res)
{
struct presto_file_data *fdata =
(struct presto_file_data *)file->private_data;
struct presto_cache *cache = fset->fset_cache;
struct presto_version new_file_ver;
int error;
struct rec_info rec;
/* Here we do a journal close after a fixed or a specified
amount of KBytes, currently a global parameter set with
sysctl. If files are open for a long time, this gives added
protection. (XXX todo: per cache, add ioctl, handle
journaling in a thread, add more options etc.)
*/
if ((fset->fset_flags & FSET_JCLOSE_ON_WRITE) &&
(!ISLENTO(cache->cache_psdev->uc_minor))) {
fdata->fd_bytes_written += res;
if (fdata->fd_bytes_written >= fset->fset_file_maxio) {
presto_getversion(&new_file_ver,
file->f_dentry->d_inode);
/* This is really heavy weight and should be fixed
ASAP. At most we should be recording the number
of bytes written and not locking the kernel,
wait for permits, etc, on the write path. SHP
*/
lock_kernel();
if ( presto_get_permit(file->f_dentry->d_inode) < 0 ) {
EXIT;
/* we must be disconnected, not to worry */
unlock_kernel();
return;
}
error = presto_journal_close(&rec, fset, file,
file->f_dentry,
&fdata->fd_version,
&new_file_ver);
presto_put_permit(file->f_dentry->d_inode);
unlock_kernel();
if ( error ) {
CERROR("presto_close: cannot journal close\n");
/* XXX these errors are really bad */
/* panic(); */
return;
}
fdata->fd_bytes_written = 0;
}
}
}
static ssize_t presto_file_write(struct file *file, const char *buf,
size_t size, loff_t *off)
{
struct rec_info rec;
int error;
struct presto_cache *cache;
struct presto_file_set *fset;
struct file_operations *fops;
ssize_t res;
int do_lml_here;
void *handle = NULL;
unsigned long blocks;
struct presto_file_data *fdata;
loff_t res_size;
error = presto_prep(file->f_dentry, &cache, &fset);
if ( error ) {
EXIT;
return error;
}
blocks = (size >> file->f_dentry->d_inode->i_sb->s_blocksize_bits) + 1;
/* XXX 3 is for ext2 indirect blocks ... */
res_size = 2 * PRESTO_REQHIGH + ((blocks+3)
<< file->f_dentry->d_inode->i_sb->s_blocksize_bits);
error = presto_reserve_space(fset->fset_cache, res_size);
CDEBUG(D_INODE, "Reserved %Ld for %d\n", res_size, size);
if ( error ) {
EXIT;
return -ENOSPC;
}
CDEBUG(D_INODE, "islento %d, minor: %d\n",
ISLENTO(cache->cache_psdev->uc_minor),
cache->cache_psdev->uc_minor);
/*
* XXX this lock should become a per inode lock when
* Vinny's changes are in; we could just use i_sem.
*/
read_lock(&fset->fset_lml.fd_lock);
fdata = (struct presto_file_data *)file->private_data;
do_lml_here = size && (fdata->fd_do_lml == 0) &&
!presto_chk(file->f_dentry, PRESTO_DONT_JOURNAL);
if (do_lml_here)
fdata->fd_do_lml = 1;
read_unlock(&fset->fset_lml.fd_lock);
/* XXX
There might be a bug here. We need to make
absolutely sure that the ext3_file_write commits
after our transaction that writes the LML record.
Nesting the file write helps if new blocks are allocated.
*/
res = 0;
if (do_lml_here) {
struct presto_version file_version;
/* handle different space reqs from file system below! */
handle = presto_trans_start(fset, file->f_dentry->d_inode,
KML_OPCODE_WRITE);
if ( IS_ERR(handle) ) {
presto_release_space(fset->fset_cache, res_size);
CERROR("presto_write: no space for transaction\n");
return -ENOSPC;
}
presto_getversion(&file_version, file->f_dentry->d_inode);
res = presto_write_lml_close(&rec, fset, file,
fdata->fd_info.remote_ino,
fdata->fd_info.remote_generation,
&fdata->fd_info.remote_version,
&file_version);
fdata->fd_lml_offset = rec.offset;
if ( res ) {
CERROR("intermezzo: PANIC failed to write LML\n");
*(int *)0 = 1;
EXIT;
goto exit_write;
}
presto_trans_commit(fset, handle);
}
fops = filter_c2cffops(cache->cache_filter);
res = fops->write(file, buf, size, off);
if ( res != size ) {
CDEBUG(D_FILE, "file write returns short write: size %d, res %d\n", size, res);
}
if ( (res > 0) && fdata )
presto_apply_write_policy(file, fset, res);
exit_write:
presto_release_space(fset->fset_cache, res_size);
return res;
}
struct file_operations presto_file_fops = {
.write = presto_file_write,
.open = presto_file_open,
.release = presto_file_release,
.ioctl = presto_ioctl
};
struct inode_operations presto_file_iops = {
.permission = presto_permission,
.setattr = presto_setattr,
#ifdef CONFIG_FS_EXT_ATTR
.set_ext_attr = presto_set_ext_attr,
#endif
};
/* FIXME: I bet we want to add a lock here and in presto_file_open. */
int izo_purge_file(struct presto_file_set *fset, char *file)
{
#if 0
void *handle = NULL;
char *path = NULL;
struct nameidata nd;
struct dentry *dentry;
int rc = 0, len;
loff_t oldsize;
/* FIXME: not mtpt it's gone */
len = strlen(fset->fset_cache->cache_mtpt) + strlen(file) + 1;
PRESTO_ALLOC(path, len + 1);
if (path == NULL)
return -1;
sprintf(path, "%s/%s", fset->fset_cache->cache_mtpt, file);
rc = izo_lookup_file(fset, path, &nd);
if (rc)
goto error;
dentry = nd.dentry;
/* FIXME: take a lock here */
if (dentry->d_inode->i_atime > CURRENT_TIME - 5) {
/* We lost the race; this file was accessed while we were doing
* ioctls and lookups and whatnot. */
rc = -EBUSY;
goto error_unlock;
}
/* FIXME: Check if this file is open. */
handle = presto_trans_start(fset, dentry->d_inode, KML_OPCODE_TRUNC);
if (IS_ERR(handle)) {
rc = -ENOMEM;
goto error_unlock;
}
/* FIXME: Write LML record */
oldsize = dentry->d_inode->i_size;
rc = izo_do_truncate(fset, dentry, 0, oldsize);
if (rc != 0)
goto error_clear;
rc = izo_do_truncate(fset, dentry, oldsize, 0);
if (rc != 0)
goto error_clear;
error_clear:
/* FIXME: clear LML record */
error_unlock:
/* FIXME: release the lock here */
error:
if (handle != NULL && !IS_ERR(handle))
presto_trans_commit(fset, handle);
if (path != NULL)
PRESTO_FREE(path, len + 1);
return rc;
#else
return 0;
#endif
}
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2001 Cluster File Systems, Inc. <[email protected]>
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Managing filesets
*
*/
#define __NO_VERSION__
#include <stdarg.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
static inline struct presto_file_set *presto_dentry2fset(struct dentry *dentry)
{
if (presto_d2d(dentry) == NULL) {
EXIT;
return NULL;
}
return presto_d2d(dentry)->dd_fset;
}
/* find the fileset dentry for this dentry */
struct presto_file_set *presto_fset(struct dentry *de)
{
struct dentry *fsde;
ENTRY;
if ( !de->d_inode ) {
/* FIXME: is this ok to be NULL? */
CDEBUG(D_INODE,"presto_fset: warning %*s has NULL inode.\n",
de->d_name.len, de->d_name.name);
}
for (fsde = de;; fsde = fsde->d_parent) {
if ( presto_dentry2fset(fsde) ) {
EXIT;
return presto_dentry2fset(fsde);
}
if (fsde->d_parent == fsde)
break;
}
EXIT;
return NULL;
}
int presto_get_lastrecno(char *path, off_t *recno)
{
struct nameidata nd;
struct presto_file_set *fset;
struct dentry *dentry;
int error;
ENTRY;
error = presto_walk(path, &nd);
if (error) {
EXIT;
return error;
}
dentry = nd.dentry;
error = -ENXIO;
if ( !presto_ispresto(dentry->d_inode) ) {
EXIT;
goto kml_out;
}
error = -EINVAL;
if ( ! presto_dentry2fset(dentry)) {
EXIT;
goto kml_out;
}
fset = presto_dentry2fset(dentry);
if (!fset) {
EXIT;
goto kml_out;
}
error = 0;
*recno = fset->fset_kml.fd_recno;
kml_out:
path_release(&nd);
return error;
}
static char * _izo_make_path(char *fsetname, char *name)
{
char *path = NULL;
int len;
len = strlen("/.intermezzo/") + strlen(fsetname)
+ 1 + strlen(name) + 1;
PRESTO_ALLOC(path, len);
if (path == NULL)
return NULL;
sprintf(path, "/.intermezzo/%s/%s", fsetname, name);
return path;
}
char * izo_make_path(struct presto_file_set *fset, char *name)
{
return _izo_make_path(fset->fset_name, name);
}
static struct file *_izo_fset_open(char *fsetname, char *name, int flags, int mode)
{
char *path;
struct file *f;
int error;
ENTRY;
path = _izo_make_path(fsetname, name);
if (path == NULL) {
EXIT;
return ERR_PTR(-ENOMEM);
}
CDEBUG(D_INODE, "opening file %s\n", path);
f = filp_open(path, flags, mode);
error = PTR_ERR(f);
if (IS_ERR(f)) {
CDEBUG(D_INODE, "Error %d\n", error);
}
PRESTO_FREE(path, strlen(path));
EXIT;
return f;
}
struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode)
{
return _izo_fset_open(fset->fset_name, name, flags, mode);
}
/*
* note: this routine "pins" a dentry for a fileset root
*/
int presto_set_fsetroot(struct dentry *ioctl_dentry, char *fsetname,
unsigned int flags)
{
struct presto_file_set *fset = NULL;
struct presto_cache *cache;
int error;
struct file *fset_root;
struct dentry *dentry;
ENTRY;
fset_root = _izo_fset_open(fsetname, "ROOT", O_RDONLY, 000);
if (IS_ERR(fset_root)) {
CERROR("Can't open %s/ROOT\n", fsetname);
EXIT;
error = PTR_ERR(fset_root);
goto out;
}
dentry = dget(fset_root->f_dentry);
filp_close(fset_root, NULL);
dentry->d_inode->i_op = ioctl_dentry->d_inode->i_op;
dentry->d_inode->i_fop = ioctl_dentry->d_inode->i_fop;
dentry->d_op = ioctl_dentry->d_op;
fset = presto_dentry2fset(dentry);
if (fset && (fset->fset_dentry == dentry) ) {
CERROR("Fsetroot already set (inode %ld)\n",
dentry->d_inode->i_ino);
/* XXX: ignore because clear_fsetroot is broken */
#if 0
dput(dentry);
EXIT;
error = -EEXIST;
goto out;
#endif
}
cache = presto_get_cache(dentry->d_inode);
if (!cache) {
CERROR("No cache found for inode %ld\n",
dentry->d_inode->i_ino);
EXIT;
error = -ENODEV;
goto out_free;
}
PRESTO_ALLOC(fset, sizeof(*fset));
if ( !fset ) {
CERROR("No memory allocating fset for %s\n", fsetname);
EXIT;
error = -ENOMEM;
goto out_free;
}
CDEBUG(D_INODE, "fset at %p\n", fset);
CDEBUG(D_INODE, "InterMezzo: fsetroot: inode %ld, fileset name %s\n",
dentry->d_inode->i_ino, fsetname);
fset->fset_mnt = mntget(current->fs->pwdmnt);
fset->fset_cache = cache;
fset->fset_dentry = dentry;
fset->fset_name = strdup(fsetname);
fset->fset_chunkbits = CHUNK_BITS;
fset->fset_flags = flags;
fset->fset_file_maxio = FSET_DEFAULT_MAX_FILEIO;
fset->fset_permit_lock = SPIN_LOCK_UNLOCKED;
PRESTO_ALLOC(fset->fset_reint_buf, 64 * 1024);
if (fset->fset_reint_buf == NULL) {
EXIT;
error = -ENOMEM;
goto out_free;
}
init_waitqueue_head(&fset->fset_permit_queue);
if (presto_d2d(dentry) == NULL) {
dentry->d_fsdata = izo_alloc_ddata();
}
if (presto_d2d(dentry) == NULL) {
CERROR("InterMezzo: %s: no memory\n", __FUNCTION__);
EXIT;
error = -ENOMEM;
goto out_free;
}
presto_d2d(dentry)->dd_fset = fset;
list_add(&fset->fset_list, &cache->cache_fset_list);
error = izo_init_kml_file(fset, &fset->fset_kml);
if ( error ) {
EXIT;
CDEBUG(D_JOURNAL, "Error init_kml %d\n", error);
goto out_list_del;
}
error = izo_init_lml_file(fset, &fset->fset_lml);
if ( error ) {
int rc;
EXIT;
rc = izo_log_close(&fset->fset_kml);
CDEBUG(D_JOURNAL, "Error init_lml %d, cleanup %d\n", error, rc);
goto out_list_del;
}
/* init_last_rcvd_file could trigger a presto_file_write(), which
* requires that the lml structure be initialized. -phil */
error = izo_init_last_rcvd_file(fset, &fset->fset_rcvd);
if ( error ) {
int rc;
EXIT;
rc = izo_log_close(&fset->fset_kml);
rc = izo_log_close(&fset->fset_lml);
CDEBUG(D_JOURNAL, "Error init_lastrcvd %d, cleanup %d\n", error, rc);
goto out_list_del;
}
CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p,"
"fset %s, cache %p, presto_d2d(dentry)->dd_fset %p\n",
fset, dentry, fset->fset_dentry, fset->fset_name, cache,
presto_d2d(dentry)->dd_fset);
EXIT;
return 0;
out_list_del:
list_del(&fset->fset_list);
presto_d2d(dentry)->dd_fset = NULL;
out_free:
if (fset) {
mntput(fset->fset_mnt);
if (fset->fset_reint_buf != NULL)
PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
PRESTO_FREE(fset, sizeof(*fset));
}
dput(dentry);
out:
return error;
}
static int izo_cleanup_fset(struct presto_file_set *fset)
{
int error;
struct presto_cache *cache;
ENTRY;
CERROR("Cleaning up fset %s\n", fset->fset_name);
error = izo_log_close(&fset->fset_kml);
if (error)
CERROR("InterMezzo: Closing kml for fset %s: %d\n",
fset->fset_name, error);
error = izo_log_close(&fset->fset_lml);
if (error)
CERROR("InterMezzo: Closing lml for fset %s: %d\n",
fset->fset_name, error);
error = izo_log_close(&fset->fset_rcvd);
if (error)
CERROR("InterMezzo: Closing last_rcvd for fset %s: %d\n",
fset->fset_name, error);
cache = fset->fset_cache;
list_del(&fset->fset_list);
presto_d2d(fset->fset_dentry)->dd_fset = NULL;
dput(fset->fset_dentry);
mntput(fset->fset_mnt);
PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1);
PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
PRESTO_FREE(fset, sizeof(*fset));
EXIT;
return error;
}
int izo_clear_fsetroot(struct dentry *dentry)
{
struct presto_file_set *fset;
ENTRY;
fset = presto_dentry2fset(dentry);
if (!fset) {
EXIT;
return -EINVAL;
}
izo_cleanup_fset(fset);
EXIT;
return 0;
}
int izo_clear_all_fsetroots(struct presto_cache *cache)
{
struct presto_file_set *fset;
struct list_head *tmp,*tmpnext;
int error;
error = 0;
tmp = &cache->cache_fset_list;
tmpnext = tmp->next;
while ( tmpnext != &cache->cache_fset_list) {
tmp = tmpnext;
tmpnext = tmp->next;
fset = list_entry(tmp, struct presto_file_set, fset_list);
error = izo_cleanup_fset(fset);
if (error)
break;
}
return error;
}
static struct vfsmount *izo_alloc_vfsmnt(void)
{
struct vfsmount *mnt;
PRESTO_ALLOC(mnt, sizeof(*mnt));
if (mnt) {
memset(mnt, 0, sizeof(struct vfsmount));
atomic_set(&mnt->mnt_count,1);
INIT_LIST_HEAD(&mnt->mnt_hash);
INIT_LIST_HEAD(&mnt->mnt_child);
INIT_LIST_HEAD(&mnt->mnt_mounts);
INIT_LIST_HEAD(&mnt->mnt_list);
}
return mnt;
}
static void izo_setup_ctxt(struct dentry *root, struct vfsmount *mnt,
struct run_ctxt *save)
{
struct run_ctxt new;
mnt->mnt_root = root;
mnt->mnt_sb = root->d_inode->i_sb;
unlock_super(mnt->mnt_sb);
new.rootmnt = mnt;
new.root = root;
new.pwdmnt = mnt;
new.pwd = root;
new.fsuid = 0;
new.fsgid = 0;
new.fs = get_fs();
/* XXX where can we get the groups from? */
new.ngroups = 0;
push_ctxt(save, &new);
}
static void izo_cleanup_ctxt(struct vfsmount *mnt, struct run_ctxt *save)
{
lock_super(mnt->mnt_sb);
pop_ctxt(save);
}
static int izo_simple_mkdir(struct dentry *dir, char *name, int mode)
{
struct dentry *dchild;
int err;
ENTRY;
dchild = lookup_one_len(name, dir, strlen(name));
if (IS_ERR(dchild)) {
EXIT;
return PTR_ERR(dchild);
}
if (dchild->d_inode) {
dput(dchild);
EXIT;
return -EEXIST;
}
err = vfs_mkdir(dir->d_inode, dchild, mode);
dput(dchild);
EXIT;
return err;
}
static int izo_simple_symlink(struct dentry *dir, char *name, char *tgt)
{
struct dentry *dchild;
int err;
ENTRY;
dchild = lookup_one_len(name, dir, strlen(name));
if (IS_ERR(dchild)) {
EXIT;
return PTR_ERR(dchild);
}
if (dchild->d_inode) {
dput(dchild);
EXIT;
return -EEXIST;
}
err = vfs_symlink(dir->d_inode, dchild, tgt);
dput(dchild);
EXIT;
return err;
}
/*
* run set_fsetroot in chroot environment
*/
int presto_set_fsetroot_from_ioc(struct dentry *root, char *fsetname,
unsigned int flags)
{
int rc;
struct presto_cache *cache;
struct vfsmount *mnt;
struct run_ctxt save;
if (root != root->d_inode->i_sb->s_root) {
CERROR ("IOC_SET_FSET must be called on mount point\n");
return -ENODEV;
}
cache = presto_get_cache(root->d_inode);
mnt = cache->cache_vfsmount;
if (!mnt) {
EXIT;
return -ENOMEM;
}
izo_setup_ctxt(root, mnt, &save);
rc = presto_set_fsetroot(root, fsetname, flags);
izo_cleanup_ctxt(mnt, &save);
return rc;
}
/* XXX: this function should detect if fsetname is already in use for
the cache under root
*/
int izo_prepare_fileset(struct dentry *root, char *fsetname)
{
int err;
struct dentry *dotizo = NULL, *fsetdir = NULL, *dotiopen = NULL;
struct presto_cache *cache;
struct vfsmount *mnt;
struct run_ctxt save;
cache = presto_get_cache(root->d_inode);
mnt = cache->cache_vfsmount = izo_alloc_vfsmnt();
if (!mnt) {
EXIT;
return -ENOMEM;
}
if (!fsetname)
fsetname = "rootfset";
izo_setup_ctxt(root, mnt, &save);
err = izo_simple_mkdir(root, ".intermezzo", 0755);
CDEBUG(D_CACHE, "mkdir on .intermezzo err %d\n", err);
err = izo_simple_mkdir(root, "..iopen..", 0755);
CDEBUG(D_CACHE, "mkdir on ..iopen.. err %d\n", err);
dotiopen = lookup_one_len("..iopen..", root, strlen("..iopen.."));
if (IS_ERR(dotiopen)) {
EXIT;
goto out;
}
dotiopen->d_inode->i_op = &presto_dir_iops;
dput(dotiopen);
dotizo = lookup_one_len(".intermezzo", root, strlen(".intermezzo"));
if (IS_ERR(dotizo)) {
EXIT;
goto out;
}
err = izo_simple_mkdir(dotizo, fsetname, 0755);
CDEBUG(D_CACHE, "mkdir err %d\n", err);
/* XXX find the dentry of the root of the fileset (root for now) */
fsetdir = lookup_one_len(fsetname, dotizo, strlen(fsetname));
if (IS_ERR(fsetdir)) {
EXIT;
goto out;
}
err = izo_simple_symlink(fsetdir, "ROOT", "../..");
/* XXX read flags from flags file */
err = presto_set_fsetroot(root, fsetname, 0);
CDEBUG(D_CACHE, "set_fsetroot err %d\n", err);
out:
if (dotizo && !IS_ERR(dotizo))
dput(dotizo);
if (fsetdir && !IS_ERR(fsetdir))
dput(fsetdir);
izo_cleanup_ctxt(mnt, &save);
return err;
}
int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data)
{
int rc = 0;
struct presto_cache *cache;
struct vfsmount *mnt;
struct run_ctxt save;
struct nameidata nd;
struct dentry *dentry;
struct presto_dentry_data *dd;
struct dentry *root;
char *buf = NULL;
ENTRY;
root = dir->f_dentry;
/* actually, needs to be called on ROOT of fset, not mount point
if (root != root->d_inode->i_sb->s_root) {
CERROR ("IOC_SET_FSET must be called on mount point\n");
return -ENODEV;
}
*/
cache = presto_get_cache(root->d_inode);
mnt = cache->cache_vfsmount;
if (!mnt) {
EXIT;
return -ENOMEM;
}
izo_setup_ctxt(root, mnt, &save);
PRESTO_ALLOC(buf, data->ioc_plen1);
if (!buf) {
rc = -ENOMEM;
EXIT;
goto out;
}
if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) {
rc = -EFAULT;
EXIT;
goto out;
}
rc = presto_walk(buf, &nd);
if (rc) {
CERROR("Unable to open: %s\n", buf);
EXIT;
goto out;
}
dentry = nd.dentry;
if (!dentry) {
CERROR("no dentry!\n");
rc = -EINVAL;
EXIT;
goto out_close;
}
dd = presto_d2d(dentry);
if (!dd) {
CERROR("no dentry_data!\n");
rc = -EINVAL;
EXIT;
goto out_close;
}
CDEBUG(D_FILE,"de:%p dd:%p\n", dentry, dd);
if (dd->remote_ino != 0) {
CERROR("remote_ino already set? %Lx:%Lx\n", dd->remote_ino,
dd->remote_generation);
rc = 0;
EXIT;
goto out_close;
}
CDEBUG(D_FILE,"setting %p %p, %s to %Lx:%Lx\n", dentry, dd,
buf, data->ioc_ino,
data->ioc_generation);
dd->remote_ino = data->ioc_ino;
dd->remote_generation = data->ioc_generation;
EXIT;
out_close:
path_release(&nd);
out:
if (buf)
PRESTO_FREE(buf, data->ioc_plen1);
izo_cleanup_ctxt(mnt, &save);
return rc;
}
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 1996 Peter J. Braam <[email protected]> and
* Michael Callahan <[email protected]>
* Copyright (C) 1999 Carnegie Mellon University
* Rewritten for Linux 2.1. Peter Braam <[email protected]>
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Super block/filesystem wide operations
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/unistd.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <asm/segment.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
extern void presto_free_cache(struct presto_cache *);
void presto_set_ops(struct inode *inode, struct filter_fs *filter)
{
ENTRY;
if (!inode || is_bad_inode(inode))
return;
if (S_ISREG(inode->i_mode)) {
if ( !filter_c2cfiops(filter) ) {
filter_setup_file_ops(filter,
inode, &presto_file_iops,
&presto_file_fops);
}
inode->i_op = filter_c2ufiops(filter);
inode->i_fop = filter_c2uffops(filter);
CDEBUG(D_INODE, "set file methods for %ld to %p\n",
inode->i_ino, inode->i_op);
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = filter_c2udiops(filter);
inode->i_fop = filter_c2udfops(filter);
CDEBUG(D_INODE, "set dir methods for %ld to %p ioctl %p\n",
inode->i_ino, inode->i_op, inode->i_fop->ioctl);
} else if (S_ISLNK(inode->i_mode)) {
if ( !filter_c2csiops(filter)) {
filter_setup_symlink_ops(filter,
inode,
&presto_sym_iops,
&presto_sym_fops);
}
inode->i_op = filter_c2usiops(filter);
inode->i_fop = filter_c2usfops(filter);
CDEBUG(D_INODE, "set link methods for %ld to %p\n",
inode->i_ino, inode->i_op);
}
EXIT;
}
void presto_read_inode(struct inode *inode)
{
struct presto_cache *cache;
cache = presto_get_cache(inode);
if ( !cache ) {
CERROR("PRESTO: BAD, BAD: cannot find cache\n");
make_bad_inode(inode);
return ;
}
filter_c2csops(cache->cache_filter)->read_inode(inode);
CDEBUG(D_INODE, "presto_read_inode: ino %ld, gid %d\n",
inode->i_ino, inode->i_gid);
presto_set_ops(inode, cache->cache_filter);
/* XXX handle special inodes here or not - probably not? */
}
static void presto_put_super(struct super_block *sb)
{
struct presto_cache *cache;
struct upc_channel *channel;
struct super_operations *sops;
struct list_head *lh;
int err;
ENTRY;
cache = presto_cache_find(sb->s_dev);
if (!cache) {
EXIT;
goto exit;
}
channel = &izo_channels[presto_c2m(cache)];
sops = filter_c2csops(cache->cache_filter);
err = izo_clear_all_fsetroots(cache);
if (err) {
CERROR("%s: err %d\n", __FUNCTION__, err);
}
PRESTO_FREE(cache->cache_vfsmount, sizeof(struct vfsmount));
/* look at kill_super - fsync_super is not exported GRRR but
probably not needed */
unlock_super(sb);
shrink_dcache_parent(cache->cache_root);
dput(cache->cache_root);
//fsync_super(sb);
lock_super(sb);
if (sops->write_super)
sops->write_super(sb);
if (sops->put_super)
sops->put_super(sb);
/* free any remaining async upcalls when the filesystem is unmounted */
spin_lock(&channel->uc_lock);
lh = channel->uc_pending.next;
while ( lh != &channel->uc_pending) {
struct upc_req *req;
req = list_entry(lh, struct upc_req, rq_chain);
/* assignment must be here: we are about to free &lh */
lh = lh->next;
if ( ! (req->rq_flags & REQ_ASYNC) )
continue;
list_del(&(req->rq_chain));
PRESTO_FREE(req->rq_data, req->rq_bufsize);
PRESTO_FREE(req, sizeof(struct upc_req));
}
list_del(&cache->cache_channel_list);
spin_unlock(&channel->uc_lock);
presto_free_cache(cache);
exit:
CDEBUG(D_MALLOC, "after umount: kmem %ld, vmem %ld\n",
presto_kmemory, presto_vmemory);
MOD_DEC_USE_COUNT;
return ;
}
struct super_operations presto_super_ops = {
.read_inode = presto_read_inode,
.put_super = presto_put_super,
};
/* symlinks can be chowned */
struct inode_operations presto_sym_iops = {
.setattr = presto_setattr
};
/* NULL for now */
struct file_operations presto_sym_fops;
--- NEW FILE ---
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 1998 Peter J. Braam
* Copyright (C) 2001 Cluster File Systems, Inc.
* Copyright (C) 2001 Tacit Networks, Inc. <[email protected]>
*
* Support for journalling extended attributes
* Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc.
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
[...2414 lines suppressed...]
logrecord = journal_log_prefix(record, opcode, rec);
logrecord = log_version(logrecord, ver);
logrecord = log_dentry_version(logrecord, dentry);
logrecord = logit(logrecord, &flags, sizeof(flags));
logrecord = logit(logrecord, &mode, sizeof(flags));
logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
logrecord = logit(logrecord, &namelen, sizeof(namelen));
logrecord = logit(logrecord, &buflen, sizeof(buflen));
logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
error = presto_log(fset, rec, record, size,
path, size_round(le32_to_cpu(pathlen)),
name, size_round(le32_to_cpu(namelen)),
buffer, size_round(le32_to_cpu(buflen)));
BUFF_FREE(temp);
EXIT;
return error;
}
#endif
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 1998 Peter J. Braam <[email protected]>
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/string.h>
#include <linux/ext2_fs.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
#if defined(CONFIG_EXT2_FS)
/* EXT2 has no journalling, so these functions do nothing */
static loff_t presto_e2_freespace(struct presto_cache *cache,
struct super_block *sb)
{
unsigned long freebl = le32_to_cpu(sb->u.ext2_sb.s_es->s_free_blocks_count);
unsigned long avail = freebl - le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count);
return (avail << EXT2_BLOCK_SIZE_BITS(sb));
}
/* start the filesystem journal operations */
static void *presto_e2_trans_start(struct presto_file_set *fset, struct inode *inode, int op)
{
__u32 avail_kmlblocks;
if ( presto_no_journal(fset) ||
strcmp(fset->fset_cache->cache_type, "ext2"))
return NULL;
avail_kmlblocks = inode->i_sb->u.ext2_sb.s_es->s_free_blocks_count;
if ( avail_kmlblocks < 3 ) {
return ERR_PTR(-ENOSPC);
}
if ( (op != KML_OPCODE_UNLINK && op != KML_OPCODE_RMDIR)
&& avail_kmlblocks < 6 ) {
return ERR_PTR(-ENOSPC);
}
return (void *) 1;
}
static void presto_e2_trans_commit(struct presto_file_set *fset, void *handle)
{
do {} while (0);
}
static int presto_e2_has_all_data(struct inode *inode)
{
BUG();
return 0;
}
struct journal_ops presto_ext2_journal_ops = {
tr_all_data: presto_e2_has_all_data,
tr_avail: presto_e2_freespace,
tr_start: presto_e2_trans_start,
tr_commit: presto_e2_trans_commit,
tr_journal_data: NULL
};
#endif /* CONFIG_EXT2_FS */
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 1998 Peter J. Braam <[email protected]>
* Copyright (C) 2000 Red Hat, Inc.
* Copyright (C) 2000 Los Alamos National Laboratory
* Copyright (C) 2000 TurboLinux, Inc.
* Copyright (C) 2001 Mountain View Data, Inc.
* Copyright (C) 2001 Tacit Networks, Inc. <[email protected]>
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/types.h>
#include <linux/param.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
#if defined(CONFIG_EXT3_FS) || defined (CONFIG_EXT3_FS_MODULE)
#include <linux/jbd.h>
#include <linux/ext3_fs.h>
#include <linux/ext3_jbd.h>
#endif
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
#if defined(CONFIG_EXT3_FS) || defined (CONFIG_EXT3_FS_MODULE)
#define MAX_PATH_BLOCKS(inode) (PATH_MAX >> EXT3_BLOCK_SIZE_BITS((inode)->i_sb))
#define MAX_NAME_BLOCKS(inode) (NAME_MAX >> EXT3_BLOCK_SIZE_BITS((inode)->i_sb))
/* space requirements:
presto_do_truncate:
used to truncate the KML forward to next fset->chunksize boundary
- zero partial block
- update inode
presto_write_record:
write header (< one block)
write one path (< MAX_PATHLEN)
possibly write another path (< MAX_PATHLEN)
write suffix (< one block)
presto_update_last_rcvd
write one block
*/
static loff_t presto_e3_freespace(struct presto_cache *cache,
struct super_block *sb)
{
loff_t freebl = le32_to_cpu(sb->u.ext3_sb.s_es->s_free_blocks_count);
loff_t avail = freebl -
le32_to_cpu(sb->u.ext3_sb.s_es->s_r_blocks_count);
return (avail << EXT3_BLOCK_SIZE_BITS(sb));
}
/* start the filesystem journal operations */
static void *presto_e3_trans_start(struct presto_file_set *fset,
struct inode *inode,
int op)
{
int jblocks;
int trunc_blks, one_path_blks, extra_path_blks,
extra_name_blks, lml_blks;
__u32 avail_kmlblocks;
handle_t *handle;
if ( presto_no_journal(fset) ||
strcmp(fset->fset_cache->cache_type, "ext3"))
{
CDEBUG(D_JOURNAL, "got cache_type \"%s\"\n",
fset->fset_cache->cache_type);
return NULL;
}
avail_kmlblocks = inode->i_sb->u.ext3_sb.s_es->s_free_blocks_count;
if ( avail_kmlblocks < 3 ) {
return ERR_PTR(-ENOSPC);
}
if ( (op != KML_OPCODE_UNLINK && op != KML_OPCODE_RMDIR)
&& avail_kmlblocks < 6 ) {
return ERR_PTR(-ENOSPC);
}
/* Need journal space for:
at least three writes to KML (two one block writes, one a path)
possibly a second name (unlink, rmdir)
possibly a second path (symlink, rename)
a one block write to the last rcvd file
*/
trunc_blks = EXT3_DATA_TRANS_BLOCKS + 1;
one_path_blks = 4*EXT3_DATA_TRANS_BLOCKS + MAX_PATH_BLOCKS(inode) + 3;
lml_blks = 4*EXT3_DATA_TRANS_BLOCKS + MAX_PATH_BLOCKS(inode) + 2;
extra_path_blks = EXT3_DATA_TRANS_BLOCKS + MAX_PATH_BLOCKS(inode);
extra_name_blks = EXT3_DATA_TRANS_BLOCKS + MAX_NAME_BLOCKS(inode);
/* additional blocks appear for "two pathname" operations
and operations involving the LML records
*/
switch (op) {
case KML_OPCODE_TRUNC:
jblocks = one_path_blks + extra_name_blks + trunc_blks
+ EXT3_DELETE_TRANS_BLOCKS;
break;
case KML_OPCODE_KML_TRUNC:
/* Hopefully this is a little better, but I'm still mostly
* guessing here. */
/* unlink 1 */
jblocks = extra_name_blks + trunc_blks +
EXT3_DELETE_TRANS_BLOCKS + 2;
/* unlink 2 */
jblocks += extra_name_blks + trunc_blks +
EXT3_DELETE_TRANS_BLOCKS + 2;
/* rename 1 */
jblocks += 2 * extra_path_blks + trunc_blks +
2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3;
/* rename 2 */
jblocks += 2 * extra_path_blks + trunc_blks +
2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3;
break;
case KML_OPCODE_RELEASE:
/*
jblocks = one_path_blks + lml_blks + 2*trunc_blks;
*/
jblocks = one_path_blks;
break;
case KML_OPCODE_SETATTR:
jblocks = one_path_blks + trunc_blks + 1 ;
break;
case KML_OPCODE_CREATE:
jblocks = one_path_blks + trunc_blks
+ EXT3_DATA_TRANS_BLOCKS + 3 + 2;
break;
case KML_OPCODE_LINK:
jblocks = one_path_blks + trunc_blks
+ EXT3_DATA_TRANS_BLOCKS + 2;
break;
case KML_OPCODE_UNLINK:
jblocks = one_path_blks + extra_name_blks + trunc_blks
+ EXT3_DELETE_TRANS_BLOCKS + 2;
break;
case KML_OPCODE_SYMLINK:
jblocks = one_path_blks + extra_path_blks + trunc_blks
+ EXT3_DATA_TRANS_BLOCKS + 5;
break;
case KML_OPCODE_MKDIR:
jblocks = one_path_blks + trunc_blks
+ EXT3_DATA_TRANS_BLOCKS + 4 + 2;
break;
case KML_OPCODE_RMDIR:
jblocks = one_path_blks + extra_name_blks + trunc_blks
+ EXT3_DELETE_TRANS_BLOCKS + 1;
break;
case KML_OPCODE_MKNOD:
jblocks = one_path_blks + trunc_blks +
EXT3_DATA_TRANS_BLOCKS + 3 + 2;
break;
case KML_OPCODE_RENAME:
jblocks = one_path_blks + extra_path_blks + trunc_blks +
2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3;
break;
case KML_OPCODE_WRITE:
jblocks = one_path_blks;
/* add this when we can wrap our transaction with
that of ext3_file_write (ordered writes)
+ EXT3_DATA_TRANS_BLOCKS;
*/
break;
default:
CDEBUG(D_JOURNAL, "invalid operation %d for journal\n", op);
return NULL;
}
CDEBUG(D_JOURNAL, "creating journal handle (%d blocks) for op %d\n",
jblocks, op);
/* journal_start/stop does not do its own locking while updating
* the handle/transaction information. Hence we create our own
* critical section to protect these calls. -SHP
*/
lock_kernel();
handle = journal_start(EXT3_JOURNAL(inode), jblocks);
unlock_kernel();
return handle;
}
static void presto_e3_trans_commit(struct presto_file_set *fset, void *handle)
{
if ( presto_no_journal(fset) || !handle)
return;
/* See comments before journal_start above. -SHP */
lock_kernel();
journal_stop(handle);
unlock_kernel();
}
static void presto_e3_journal_file_data(struct inode *inode)
{
#ifdef EXT3_JOURNAL_DATA_FL
inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
#else
#warning You must have a facility to enable journaled writes for recovery!
#endif
}
/* The logic here is a slightly modified version of ext3/inode.c:block_to_path
*/
static int presto_e3_has_all_data(struct inode *inode)
{
int ptrs = EXT3_ADDR_PER_BLOCK(inode->i_sb);
int ptrs_bits = EXT3_ADDR_PER_BLOCK_BITS(inode->i_sb);
const long direct_blocks = EXT3_NDIR_BLOCKS,
indirect_blocks = ptrs,
double_blocks = (1 << (ptrs_bits * 2));
long block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
inode->i_sb->s_blocksize_bits;
ENTRY;
if (inode->i_size == 0) {
EXIT;
return 1;
}
if (block < direct_blocks) {
/* No indirect blocks, no problem. */
} else if (block < indirect_blocks + direct_blocks) {
block++;
} else if (block < double_blocks + indirect_blocks + direct_blocks) {
block += 2;
} else if (((block - double_blocks - indirect_blocks - direct_blocks)
>> (ptrs_bits * 2)) < ptrs) {
block += 3;
}
block *= (inode->i_sb->s_blocksize / 512);
CDEBUG(D_CACHE, "Need %ld blocks, have %ld.\n", block, inode->i_blocks);
if (block > inode->i_blocks) {
EXIT;
return 0;
}
EXIT;
return 1;
}
struct journal_ops presto_ext3_journal_ops = {
.tr_all_data = presto_e3_has_all_data,
.tr_avail = presto_e3_freespace,
.tr_start = presto_e3_trans_start,
.tr_commit = presto_e3_trans_commit,
.tr_journal_data = presto_e3_journal_file_data,
.tr_ilookup = presto_iget_ilookup
};
#endif /* CONFIG_EXT3_FS */
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 1998 Peter J. Braam <[email protected]>
* Copyright (C) 2000 Red Hat, Inc.
* Copyright (C) 2000 Los Alamos National Laboratory
* Copyright (C) 2000 TurboLinux, Inc.
* Copyright (C) 2001 Mountain View Data, Inc.
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/types.h>
#include <linux/param.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/string.h>
#ifdef CONFIG_OBDFS_FS
#include /usr/src/obd/include/linux/obdfs.h
#endif
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
#ifdef CONFIG_OBDFS_FS
static unsigned long presto_obdfs_freespace(struct presto_file_set *fset,
struct super_block *sb)
{
return 0x0fffff;
}
/* start the filesystem journal operations */
static void *presto_obdfs_trans_start(struct presto_file_set *fset,
struct inode *inode,
int op)
{
return (void *) 1;
}
#if 0
int jblocks;
int trunc_blks, one_path_blks, extra_path_blks,
extra_name_blks, lml_blks;
__u32 avail_kmlblocks;
if ( presto_no_journal(fset) ||
strcmp(fset->fset_cache->cache_type, "ext3"))
{
CDEBUG(D_JOURNAL, "got cache_type \"%s\"\n",
fset->fset_cache->cache_type);
return NULL;
}
avail_kmlblocks = inode->i_sb->u.ext3_sb.s_es->s_free_blocks_count;
if ( avail_kmlblocks < 3 ) {
return ERR_PTR(-ENOSPC);
}
if ( (op != PRESTO_OP_UNLINK && op != PRESTO_OP_RMDIR)
&& avail_kmlblocks < 6 ) {
return ERR_PTR(-ENOSPC);
}
/* Need journal space for:
at least three writes to KML (two one block writes, one a path)
possibly a second name (unlink, rmdir)
possibly a second path (symlink, rename)
a one block write to the last rcvd file
*/
trunc_blks = EXT3_DATA_TRANS_BLOCKS + 1;
one_path_blks = 4*EXT3_DATA_TRANS_BLOCKS + MAX_PATH_BLOCKS(inode) + 3;
lml_blks = 4*EXT3_DATA_TRANS_BLOCKS + MAX_PATH_BLOCKS(inode) + 2;
extra_path_blks = EXT3_DATA_TRANS_BLOCKS + MAX_PATH_BLOCKS(inode);
extra_name_blks = EXT3_DATA_TRANS_BLOCKS + MAX_NAME_BLOCKS(inode);
/* additional blocks appear for "two pathname" operations
and operations involving the LML records
*/
switch (op) {
case PRESTO_OP_TRUNC:
jblocks = one_path_blks + extra_name_blks + trunc_blks
+ EXT3_DELETE_TRANS_BLOCKS;
break;
case PRESTO_OP_RELEASE:
/*
jblocks = one_path_blks + lml_blks + 2*trunc_blks;
*/
jblocks = one_path_blks;
break;
case PRESTO_OP_SETATTR:
jblocks = one_path_blks + trunc_blks + 1 ;
break;
case PRESTO_OP_CREATE:
jblocks = one_path_blks + trunc_blks
+ EXT3_DATA_TRANS_BLOCKS + 3;
break;
case PRESTO_OP_LINK:
jblocks = one_path_blks + trunc_blks
+ EXT3_DATA_TRANS_BLOCKS;
break;
case PRESTO_OP_UNLINK:
jblocks = one_path_blks + extra_name_blks + trunc_blks
+ EXT3_DELETE_TRANS_BLOCKS;
break;
case PRESTO_OP_SYMLINK:
jblocks = one_path_blks + extra_path_blks + trunc_blks
+ EXT3_DATA_TRANS_BLOCKS + 5;
break;
case PRESTO_OP_MKDIR:
jblocks = one_path_blks + trunc_blks
+ EXT3_DATA_TRANS_BLOCKS + 4;
break;
case PRESTO_OP_RMDIR:
jblocks = one_path_blks + extra_name_blks + trunc_blks
+ EXT3_DELETE_TRANS_BLOCKS;
break;
case PRESTO_OP_MKNOD:
jblocks = one_path_blks + trunc_blks +
EXT3_DATA_TRANS_BLOCKS + 3;
break;
case PRESTO_OP_RENAME:
jblocks = one_path_blks + extra_path_blks + trunc_blks +
2 * EXT3_DATA_TRANS_BLOCKS + 2;
break;
case PRESTO_OP_WRITE:
jblocks = one_path_blks;
/* add this when we can wrap our transaction with
that of ext3_file_write (ordered writes)
+ EXT3_DATA_TRANS_BLOCKS;
*/
break;
default:
CDEBUG(D_JOURNAL, "invalid operation %d for journal\n", op);
return NULL;
}
CDEBUG(D_JOURNAL, "creating journal handle (%d blocks)\n", jblocks);
return journal_start(EXT3_JOURNAL(inode), jblocks);
}
#endif
void presto_obdfs_trans_commit(struct presto_file_set *fset, void *handle)
{
#if 0
if ( presto_no_journal(fset) || !handle)
return;
journal_stop(handle);
#endif
}
void presto_obdfs_journal_file_data(struct inode *inode)
{
#ifdef EXT3_JOURNAL_DATA_FL
inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
#else
#warning You must have a facility to enable journaled writes for recovery!
#endif
}
struct journal_ops presto_obdfs_journal_ops = {
.tr_avail = presto_obdfs_freespace,
.tr_start = presto_obdfs_trans_start,
.tr_commit = presto_obdfs_trans_commit,
.tr_journal_data = presto_obdfs_journal_file_data
};
#endif
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 1998 Peter J. Braam <[email protected]>
* Copyright (C) 2000 Red Hat, Inc.
* Copyright (C) 2000 Los Alamos National Laboratory
* Copyright (C) 2000 TurboLinux, Inc.
* Copyright (C) 2001 Mountain View Data, Inc.
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/types.h>
#include <linux/param.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/smp_lock.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/string.h>
#if 0
#if defined(CONFIG_REISERFS_FS) || defined(CONFIG_REISERFS_FS_MODULE)
#include <linux/reiserfs_fs.h>
#include <linux/reiserfs_fs_sb.h>
#include <linux/reiserfs_fs_i.h>
#endif
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
#if defined(CONFIG_REISERFS_FS) || defined(CONFIG_REISERFS_FS_MODULE)
static loff_t presto_reiserfs_freespace(struct presto_cache *cache,
struct super_block *sb)
{
struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (sb);
loff_t avail;
avail = le32_to_cpu(rs->s_free_blocks) *
le16_to_cpu(rs->s_blocksize);
return avail;
}
/* start the filesystem journal operations */
static void *presto_reiserfs_trans_start(struct presto_file_set *fset,
struct inode *inode,
int op)
{
int jblocks;
__u32 avail_kmlblocks;
struct reiserfs_transaction_handle *th ;
PRESTO_ALLOC(th, sizeof(*th));
if (!th) {
CERROR("presto: No memory for trans handle\n");
return NULL;
}
avail_kmlblocks = presto_reiserfs_freespace(fset->fset_cache,
inode->i_sb);
if ( presto_no_journal(fset) ||
strcmp(fset->fset_cache->cache_type, "reiserfs"))
{
CDEBUG(D_JOURNAL, "got cache_type \"%s\"\n",
fset->fset_cache->cache_type);
return NULL;
}
if ( avail_kmlblocks < 3 ) {
return ERR_PTR(-ENOSPC);
}
if ( (op != PRESTO_OP_UNLINK && op != PRESTO_OP_RMDIR)
&& avail_kmlblocks < 6 ) {
return ERR_PTR(-ENOSPC);
}
jblocks = 3 + JOURNAL_PER_BALANCE_CNT * 4;
CDEBUG(D_JOURNAL, "creating journal handle (%d blocks)\n", jblocks);
lock_kernel();
journal_begin(th, inode->i_sb, jblocks);
unlock_kernel();
return th;
}
static void presto_reiserfs_trans_commit(struct presto_file_set *fset,
void *handle)
{
int jblocks;
jblocks = 3 + JOURNAL_PER_BALANCE_CNT * 4;
lock_kernel();
journal_end(handle, fset->fset_cache->cache_sb, jblocks);
unlock_kernel();
PRESTO_FREE(handle, sizeof(struct reiserfs_transaction_handle));
}
static void presto_reiserfs_journal_file_data(struct inode *inode)
{
#ifdef EXT3_JOURNAL_DATA_FL
inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
#else
#warning You must have a facility to enable journaled writes for recovery!
#endif
}
static int presto_reiserfs_has_all_data(struct inode *inode)
{
BUG();
return 0;
}
struct journal_ops presto_reiserfs_journal_ops = {
.tr_all_data = presto_reiserfs_has_all_data,
.tr_avail = presto_reiserfs_freespace,
.tr_start = presto_reiserfs_trans_start,
.tr_commit = presto_reiserfs_trans_commit,
.tr_journal_data = presto_reiserfs_journal_file_data
};
#endif
#endif
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 1998 Peter J. Braam <[email protected]>
* Copyright (C) 2000 Red Hat, Inc.
* Copyright (C) 2000 Los Alamos National Laboratory
* Copyright (C) 2000 TurboLinux, Inc.
* Copyright (C) 2001 Mountain View Data, Inc.
* Copyright (C) 2001 Tacit Networks, Inc. <[email protected]>
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/types.h>
#include <linux/param.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
#if defined(CONFIG_TMPFS)
#include <linux/jbd.h>
#if defined(CONFIG_EXT3)
#include <linux/ext3_fs.h>
#include <linux/ext3_jbd.h>
#endif
#endif
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
#if defined(CONFIG_TMPFS)
/* space requirements:
presto_do_truncate:
used to truncate the KML forward to next fset->chunksize boundary
- zero partial block
- update inode
presto_write_record:
write header (< one block)
write one path (< MAX_PATHLEN)
possibly write another path (< MAX_PATHLEN)
write suffix (< one block)
presto_update_last_rcvd
write one block
*/
static loff_t presto_tmpfs_freespace(struct presto_cache *cache,
struct super_block *sb)
{
return (1<<30);
}
/* start the filesystem journal operations */
static void *presto_tmpfs_trans_start(struct presto_file_set *fset,
struct inode *inode,
int op)
{
return (void *)1;
}
static void presto_tmpfs_trans_commit(struct presto_file_set *fset, void *handle)
{
return;
}
static void presto_tmpfs_journal_file_data(struct inode *inode)
{
return;
}
/* The logic here is a slightly modified version of ext3/inode.c:block_to_path
*/
static int presto_tmpfs_has_all_data(struct inode *inode)
{
return 0;
}
struct journal_ops presto_tmpfs_journal_ops = {
tr_all_data: presto_tmpfs_has_all_data,
tr_avail: presto_tmpfs_freespace,
tr_start: presto_tmpfs_trans_start,
tr_commit: presto_tmpfs_trans_commit,
tr_journal_data: presto_tmpfs_journal_file_data,
tr_ilookup: presto_tmpfs_ilookup,
tr_add_ilookup: presto_add_ilookup_dentry
};
#endif /* CONFIG_EXT3_FS */
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 1998 Peter J. Braam <[email protected]>
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/string.h>
#if 0
/* XFS Support not there yet */
#ifdef CONFIG_FS_XFS
#include <linux/xfs_fs.h>
#endif
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
#include <linux/intermezzo_journal.h>
#if 0
/* XFS has journalling, but these functions do nothing yet... */
static unsigned long presto_xfs_freespace(struct presto_file_set *fset,
struct super_block *sb)
{
#if 0
vfs_t *vfsp = LINVFS_GET_VFS(sb);
struct statvfs_t stat;
bhv_desc_t *bdp;
unsigned long avail;
int rc;
VFS_STATVFS(vfsp, &stat, NULL, rc);
avail = statp.f_bfree;
return sbp->sb_fdblocks;;
#endif
return 0x0fffffff;
}
/* start the filesystem journal operations */
static void *
presto_xfs_trans_start(struct presto_file_set *fset,
struct inode *inode, int op)
{
int xfs_op;
/* do a free blocks check as in journal_ext3? does anything protect
* the space in that case or can it disappear out from under us
* anyway? */
/* copied from xfs_trans.h, skipping header maze for now */
#define XFS_TRANS_SETATTR_NOT_SIZE 1
#define XFS_TRANS_SETATTR_SIZE 2
#define XFS_TRANS_INACTIVE 3
#define XFS_TRANS_CREATE 4
#define XFS_TRANS_CREATE_TRUNC 5
#define XFS_TRANS_TRUNCATE_FILE 6
#define XFS_TRANS_REMOVE 7
#define XFS_TRANS_LINK 8
#define XFS_TRANS_RENAME 9
#define XFS_TRANS_MKDIR 10
#define XFS_TRANS_RMDIR 11
#define XFS_TRANS_SYMLINK 12
/* map the op onto the values for XFS so it can do reservation. if
* we don't have enough info to differentiate between e.g. setattr
* with or without size, what do we do? will it adjust? */
switch (op) {
case PRESTO_OP_SETATTR:
/* or XFS_TRANS_SETATTR_NOT_SIZE? */
xfs_op = XFS_TRANS_SETATTR_SIZE;
break;
case PRESTO_OP_CREATE:
/* or CREATE_TRUNC? */
xfs_op = XFS_TRANS_CREATE;
break;
case PRESTO_OP_LINK:
xfs_op = XFS_TRANS_LINK;
break;
case PRESTO_OP_UNLINK:
xfs_op = XFS_TRANS_REMOVE;
break;
case PRESTO_OP_SYMLINK:
xfs_op = XFS_TRANS_SYMLINK;
break;
case PRESTO_OP_MKDIR:
xfs_op = XFS_TRANS_MKDIR;
break;
case PRESTO_OP_RMDIR:
xfs_op = XFS_TRANS_RMDIR;
break;
case PRESTO_OP_MKNOD:
/* XXX can't find an analog for mknod? */
xfs_op = XFS_TRANS_CREATE;
break;
case PRESTO_OP_RENAME:
xfs_op = XFS_TRANS_RENAME;
break;
default:
CDEBUG(D_JOURNAL, "invalid operation %d for journal\n", op);
return NULL;
}
return xfs_trans_start(inode, xfs_op);
}
static void presto_xfs_trans_commit(struct presto_file_set *fset, void *handle)
{
/* assert (handle == current->j_handle) */
xfs_trans_stop(handle);
}
static void presto_xfs_journal_file_data(struct inode *inode)
{
return;
}
static int presto_xfs_has_all_data(struct inode *inode)
{
BUG();
return 0;
}
struct journal_ops presto_xfs_journal_ops = {
.tr_all_data = presto_xfs_has_all_data,
.tr_avail = presto_xfs_freespace,
.tr_start = presto_xfs_trans_start,
.tr_commit = presto_xfs_trans_commit,
.tr_journal_data = presto_xfs_journal_file_data
};
#endif
#endif /* CONFIG_XFS_FS */
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2001 Cluster File Systems, Inc. <[email protected]>
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Reintegration of KML records
*
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/mmu_context.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
static void kmlreint_pre_secure(struct kml_rec *rec, struct file *dir,
struct run_ctxt *saved)
{
struct run_ctxt ctxt;
struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
int i;
ctxt.fsuid = rec->prefix.hdr->fsuid;
ctxt.fsgid = rec->prefix.hdr->fsgid;
ctxt.fs = KERNEL_DS;
ctxt.pwd = dd->dd_fset->fset_dentry;
ctxt.pwdmnt = dd->dd_fset->fset_mnt;
ctxt.root = ctxt.pwd;
ctxt.rootmnt = ctxt.pwdmnt;
if (rec->prefix.hdr->ngroups > 0) {
ctxt.ngroups = rec->prefix.hdr->ngroups;
for (i = 0; i< ctxt.ngroups; i++)
ctxt.groups[i] = rec->prefix.groups[i];
} else
ctxt.ngroups = 0;
push_ctxt(saved, &ctxt);
}
/* Append two strings in a less-retarded fashion. */
static char * path_join(char *p1, int p1len, char *p2, int p2len)
{
int size = p1len + p2len + 2; /* possibly one extra /, one NULL */
char *path;
path = kmalloc(size, GFP_KERNEL);
if (path == NULL)
return NULL;
memcpy(path, p1, p1len);
if (path[p1len - 1] != '/') {
path[p1len] = '/';
p1len++;
}
memcpy(path + p1len, p2, p2len);
path[p1len + p2len] = '\0';
return path;
}
static inline int kml_recno_equal(struct kml_rec *rec,
struct presto_file_set *fset)
{
return (rec->suffix->recno == fset->fset_lento_recno + 1);
}
static inline int version_equal(struct presto_version *a, struct inode *inode)
{
if (a == NULL)
return 1;
if (inode == NULL) {
CERROR("InterMezzo: NULL inode in version_equal()\n");
return 0;
}
if (inode->i_mtime == a->pv_mtime &&
(S_ISDIR(inode->i_mode) || inode->i_size == a->pv_size))
return 1;
return 0;
}
static int reint_close(struct kml_rec *rec, struct file *file,
struct lento_vfs_context *given_info)
{
struct run_ctxt saved_ctxt;
int error;
struct presto_file_set *fset;
struct lento_vfs_context info;
ENTRY;
memcpy(&info, given_info, sizeof(*given_info));
CDEBUG (D_KML, "=====REINT_CLOSE::%s\n", rec->path);
fset = presto_fset(file->f_dentry);
if (fset->fset_flags & FSET_DATA_ON_DEMAND) {
struct iattr iattr;
iattr.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_SIZE;
iattr.ia_mtime = (time_t)rec->new_objectv->pv_mtime;
iattr.ia_ctime = (time_t)rec->new_objectv->pv_ctime;
iattr.ia_size = (time_t)rec->new_objectv->pv_size;
/* no kml record, but update last rcvd */
/* save fileid in dentry for later backfetch */
info.flags |= LENTO_FL_EXPECT | LENTO_FL_SET_DDFILEID;
info.remote_ino = rec->ino;
info.remote_generation = rec->generation;
info.flags &= ~LENTO_FL_KML;
kmlreint_pre_secure(rec, file, &saved_ctxt);
error = lento_setattr(rec->path, &iattr, &info);
pop_ctxt(&saved_ctxt);
presto_d2d(file->f_dentry)->dd_flags &= ~PRESTO_DATA;
} else {
int minor = presto_f2m(fset);
info.updated_time = rec->new_objectv->pv_mtime;
memcpy(&info.remote_version, rec->old_objectv,
sizeof(*rec->old_objectv));
info.remote_ino = rec->ino;
info.remote_generation = rec->generation;
error = izo_upc_backfetch(minor, rec->path, fset->fset_name,
&info);
if (error) {
CERROR("backfetch error %d\n", error);
/* if file doesn't exist anymore, then ignore the CLOSE
* and just update the last_rcvd.
*/
if (error == ENOENT) {
CDEBUG(D_KML, "manually updating remote offset uuid %s"
"recno %d offset %Lu\n", info.uuid, info.recno, info.kml_offset);
error = izo_rcvd_upd_remote(fset, info.uuid, info.recno, info.kml_offset);
if(error)
CERROR("izo_rcvd_upd_remote error %d\n", error);
}
}
/* propagate error to avoid further reint */
}
EXIT;
return error;
}
static int reint_create(struct kml_rec *rec, struct file *dir,
struct lento_vfs_context *info)
{
struct run_ctxt saved_ctxt;
int error; ENTRY;
CDEBUG (D_KML, "=====REINT_CREATE::%s\n", rec->path);
info->updated_time = rec->new_objectv->pv_ctime;
kmlreint_pre_secure(rec, dir, &saved_ctxt);
error = lento_create(rec->path, rec->mode, info);
pop_ctxt(&saved_ctxt);
EXIT;
return error;
}
static int reint_link(struct kml_rec *rec, struct file *dir,
struct lento_vfs_context *info)
{
struct run_ctxt saved_ctxt;
int error;
ENTRY;
CDEBUG (D_KML, "=====REINT_LINK::%s -> %s\n", rec->path, rec->target);
info->updated_time = rec->new_objectv->pv_mtime;
kmlreint_pre_secure(rec, dir, &saved_ctxt);
error = lento_link(rec->path, rec->target, info);
pop_ctxt(&saved_ctxt);
EXIT;
return error;
}
static int reint_mkdir(struct kml_rec *rec, struct file *dir,
struct lento_vfs_context *info)
{
struct run_ctxt saved_ctxt;
int error;
ENTRY;
CDEBUG (D_KML, "=====REINT_MKDIR::%s\n", rec->path);
info->updated_time = rec->new_objectv->pv_ctime;
kmlreint_pre_secure(rec, dir, &saved_ctxt);
error = lento_mkdir(rec->path, rec->mode, info);
pop_ctxt(&saved_ctxt);
EXIT;
return error;
}
static int reint_mknod(struct kml_rec *rec, struct file *dir,
struct lento_vfs_context *info)
{
struct run_ctxt saved_ctxt;
int error, dev;
ENTRY;
CDEBUG (D_KML, "=====REINT_MKNOD::%s\n", rec->path);
info->updated_time = rec->new_objectv->pv_ctime;
kmlreint_pre_secure(rec, dir, &saved_ctxt);
dev = rec->rdev ?: MKDEV(rec->major, rec->minor);
error = lento_mknod(rec->path, rec->mode, dev, info);
pop_ctxt(&saved_ctxt);
EXIT;
return error;
}
static int reint_noop(struct kml_rec *rec, struct file *dir,
struct lento_vfs_context *info)
{
return 0;
}
static int reint_rename(struct kml_rec *rec, struct file *dir,
struct lento_vfs_context *info)
{
struct run_ctxt saved_ctxt;
int error;
ENTRY;
CDEBUG (D_KML, "=====REINT_RENAME::%s -> %s\n", rec->path, rec->target);
info->updated_time = rec->new_objectv->pv_mtime;
kmlreint_pre_secure(rec, dir, &saved_ctxt);
error = lento_rename(rec->path, rec->target, info);
pop_ctxt(&saved_ctxt);
EXIT;
return error;
}
static int reint_rmdir(struct kml_rec *rec, struct file *dir,
struct lento_vfs_context *info)
{
struct run_ctxt saved_ctxt;
int error;
char *path;
ENTRY;
path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen);
if (path == NULL) {
EXIT;
return -ENOMEM;
}
CDEBUG (D_KML, "=====REINT_RMDIR::%s\n", path);
info->updated_time = rec->new_parentv->pv_mtime;
kmlreint_pre_secure(rec, dir, &saved_ctxt);
error = lento_rmdir(path, info);
pop_ctxt(&saved_ctxt);
kfree(path);
EXIT;
return error;
}
static int reint_setattr(struct kml_rec *rec, struct file *dir,
struct lento_vfs_context *info)
{
struct run_ctxt saved_ctxt;
struct iattr iattr;
int error;
ENTRY;
iattr.ia_valid = rec->valid;
iattr.ia_mode = (umode_t)rec->mode;
iattr.ia_uid = (uid_t)rec->uid;
iattr.ia_gid = (gid_t)rec->gid;
iattr.ia_size = (off_t)rec->size;
iattr.ia_ctime = (time_t)rec->ctime;
iattr.ia_mtime = (time_t)rec->mtime;
iattr.ia_atime = iattr.ia_mtime; /* We don't track atimes. */
iattr.ia_attr_flags = rec->flags;
CDEBUG (D_KML, "=====REINT_SETATTR::%s (%d)\n", rec->path, rec->valid);
kmlreint_pre_secure(rec, dir, &saved_ctxt);
error = lento_setattr(rec->path, &iattr, info);
pop_ctxt(&saved_ctxt);
EXIT;
return error;
}
static int reint_symlink(struct kml_rec *rec, struct file *dir,
struct lento_vfs_context *info)
{
struct run_ctxt saved_ctxt;
int error;
ENTRY;
CDEBUG (D_KML, "=====REINT_SYMLINK::%s -> %s\n", rec->path, rec->target);
info->updated_time = rec->new_objectv->pv_ctime;
kmlreint_pre_secure(rec, dir, &saved_ctxt);
error = lento_symlink(rec->target, rec->path, info);
pop_ctxt(&saved_ctxt);
EXIT;
return error;
}
static int reint_unlink(struct kml_rec *rec, struct file *dir,
struct lento_vfs_context *info)
{
struct run_ctxt saved_ctxt;
int error;
char *path;
ENTRY;
path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen);
if (path == NULL) {
EXIT;
return -ENOMEM;
}
CDEBUG (D_KML, "=====REINT_UNLINK::%s\n", path);
info->updated_time = rec->new_parentv->pv_mtime;
kmlreint_pre_secure(rec, dir, &saved_ctxt);
error = lento_unlink(path, info);
pop_ctxt(&saved_ctxt);
kfree(path);
EXIT;
return error;
}
static int branch_reint_rename(struct presto_file_set *fset, struct kml_rec *rec,
struct file *dir, struct lento_vfs_context *info,
char * kml_data, __u64 kml_size)
{
int error;
ENTRY;
error = reint_rename(rec, dir, info);
if (error == -ENOENT) {
/* normal reint failed because path was not found */
struct rec_info rec;
CDEBUG(D_KML, "saving branch rename kml\n");
rec.is_kml = 1;
rec.size = kml_size;
error = presto_log(fset, &rec, kml_data, kml_size,
NULL, 0, NULL, 0, NULL, 0);
if (error == 0)
error = presto_write_last_rcvd(&rec, fset, info);
}
EXIT;
return error;
}
int branch_reinter(struct presto_file_set *fset, struct kml_rec *rec,
struct file *dir, struct lento_vfs_context *info,
char * kml_data, __u64 kml_size)
{
int error = 0;
int op = rec->prefix.hdr->opcode;
if (op == KML_OPCODE_CLOSE) {
/* regular close and backfetch */
error = reint_close(rec, dir, info);
} else if (op == KML_OPCODE_RENAME) {
/* rename only if name already exists */
error = branch_reint_rename(fset, rec, dir, info,
kml_data, kml_size);
} else {
/* just rewrite kml into branch/kml and update last_rcvd */
struct rec_info rec;
CDEBUG(D_KML, "Saving branch kml\n");
rec.is_kml = 1;
rec.size = kml_size;
error = presto_log(fset, &rec, kml_data, kml_size,
NULL, 0, NULL, 0, NULL, 0);
if (error == 0)
error = presto_write_last_rcvd(&rec, fset, info);
}
return error;
}
typedef int (*reinter_t)(struct kml_rec *rec, struct file *basedir,
struct lento_vfs_context *info);
static reinter_t presto_reinters[KML_OPCODE_NUM] =
{
[KML_OPCODE_CLOSE] = reint_close,
[KML_OPCODE_CREATE] = reint_create,
[KML_OPCODE_LINK] = reint_link,
[KML_OPCODE_MKDIR] = reint_mkdir,
[KML_OPCODE_MKNOD] = reint_mknod,
[KML_OPCODE_NOOP] = reint_noop,
[KML_OPCODE_RENAME] = reint_rename,
[KML_OPCODE_RMDIR] = reint_rmdir,
[KML_OPCODE_SETATTR] = reint_setattr,
[KML_OPCODE_SYMLINK] = reint_symlink,
[KML_OPCODE_UNLINK] = reint_unlink,
};
static inline reinter_t get_reinter(int op)
{
if (op < 0 || op >= sizeof(presto_reinters) / sizeof(reinter_t))
return NULL;
else
return presto_reinters[op];
}
int kml_reint_rec(struct file *dir, struct izo_ioctl_data *data)
{
char *ptr;
char *end;
struct kml_rec rec;
int error = 0;
struct lento_vfs_context info;
struct presto_cache *cache;
struct presto_file_set *fset;
struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
int op;
reinter_t reinter;
struct izo_rcvd_rec lr_rec;
int off;
ENTRY;
error = presto_prep(dir->f_dentry, &cache, &fset);
if ( error ) {
CERROR("intermezzo: Reintegration on invalid file\n");
return error;
}
if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) {
CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n",
dir->f_dentry->d_inode->i_ino);
return -EINVAL;
}
if (data->ioc_plen1 > 64 * 1024) {
EXIT;
return -ENOSPC;
}
ptr = fset->fset_reint_buf;
end = ptr + data->ioc_plen1;
if (copy_from_user(ptr, data->ioc_pbuf1, data->ioc_plen1)) {
EXIT;
error = -EFAULT;
goto out;
}
error = kml_unpack(&rec, &ptr, end);
if (error) {
EXIT;
error = -EFAULT;
goto out;
}
off = izo_rcvd_get(&lr_rec, fset, data->ioc_uuid);
if (off < 0) {
CERROR("No last_rcvd record, setting to 0\n");
memset(&lr_rec, 0, sizeof(lr_rec));
}
data->ioc_kmlsize = ptr - fset->fset_reint_buf;
if (rec.suffix->recno != lr_rec.lr_remote_recno + 1) {
CERROR("KML record number %Lu expected, not %d\n",
lr_rec.lr_remote_recno + 1,
rec.suffix->recno);
#if 0
if (!version_check(&rec, dd->dd_fset, &info)) {
/* FIXME: do an upcall to resolve conflicts */
CERROR("intermezzo: would be a conflict!\n");
error = -EINVAL;
EXIT;
goto out;
}
#endif
}
op = rec.prefix.hdr->opcode;
reinter = get_reinter(op);
if (!reinter) {
CERROR("%s: Unrecognized KML opcode %d\n", __FUNCTION__, op);
error = -EINVAL;
EXIT;
goto out;
}
info.kml_offset = data->ioc_offset + data->ioc_kmlsize;
info.recno = rec.suffix->recno;
info.flags = LENTO_FL_EXPECT;
if (data->ioc_flags)
info.flags |= LENTO_FL_KML;
memcpy(info.uuid, data->ioc_uuid, sizeof(info.uuid));
if (fset->fset_flags & FSET_IS_BRANCH && data->ioc_flags)
error = branch_reinter(fset, &rec, dir, &info, fset->fset_reint_buf,
data->ioc_kmlsize);
else
error = reinter(&rec, dir, &info);
out:
EXIT;
return error;
}
int izo_get_fileid(struct file *dir, struct izo_ioctl_data *data)
{
char *buf = NULL;
char *ptr;
char *end;
struct kml_rec rec;
struct file *file;
struct presto_cache *cache;
struct presto_file_set *fset;
struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
struct run_ctxt saved_ctxt;
int error;
ENTRY;
error = presto_prep(dir->f_dentry, &cache, &fset);
if ( error ) {
CERROR("intermezzo: Reintegration on invalid file\n");
return error;
}
if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) {
CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n",
dir->f_dentry->d_inode->i_ino);
return -EINVAL;
}
PRESTO_ALLOC(buf, data->ioc_plen1);
if (!buf) {
EXIT;
return -ENOMEM;
}
ptr = buf;
end = buf + data->ioc_plen1;
if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) {
EXIT;
PRESTO_FREE(buf, data->ioc_plen1);
return -EFAULT;
}
error = kml_unpack(&rec, &ptr, end);
if (error) {
EXIT;
PRESTO_FREE(buf, data->ioc_plen1);
return -EFAULT;
}
kmlreint_pre_secure(&rec, dir, &saved_ctxt);
file = filp_open(rec.path, O_RDONLY, 0);
if (!file || IS_ERR(file)) {
error = PTR_ERR(file);
goto out;
}
data->ioc_ino = file->f_dentry->d_inode->i_ino;
data->ioc_generation = file->f_dentry->d_inode->i_generation;
filp_close(file, 0);
CDEBUG(D_FILE, "%s ino %Lx, gen %Lx\n", rec.path,
data->ioc_ino, data->ioc_generation);
out:
if (buf)
PRESTO_FREE(buf, data->ioc_plen1);
pop_ctxt(&saved_ctxt);
EXIT;
return error;
}
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2001 Cluster File Systems, Inc. <[email protected]>
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Unpacking of KML records
*
*/
#ifdef __KERNEL__
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/major.h>
# include <linux/sched.h>
# include <linux/lp.h>
# include <linux/slab.h>
# include <linux/ioport.h>
# include <linux/fcntl.h>
# include <linux/delay.h>
# include <linux/skbuff.h>
# include <linux/proc_fs.h>
# include <linux/vmalloc.h>
# include <linux/fs.h>
# include <linux/poll.h>
# include <linux/init.h>
# include <linux/list.h>
# include <linux/stat.h>
# include <asm/io.h>
# include <asm/segment.h>
# include <asm/system.h>
# include <asm/poll.h>
# include <asm/uaccess.h>
#else
# include <time.h>
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <errno.h>
# include <sys/stat.h>
# include <glib.h>
#endif
#include <linux/intermezzo_lib.h>
#include <linux/intermezzo_idl.h>
#include <linux/intermezzo_fs.h>
int kml_unpack_version(struct presto_version **ver, char **buf, char *end)
{
char *ptr = *buf;
struct presto_version *pv;
UNLOGP(*ver, struct presto_version, ptr, end);
pv = *ver;
pv->pv_mtime = NTOH__u64(pv->pv_mtime);
pv->pv_ctime = NTOH__u64(pv->pv_ctime);
pv->pv_size = NTOH__u64(pv->pv_size);
*buf = ptr;
return 0;
}
static int kml_unpack_noop(struct kml_rec *rec, char **buf, char *end)
{
return 0;
}
static int kml_unpack_get_fileid(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
LUNLOGV(rec->pathlen, __u32, ptr, end);
UNLOGL(rec->path, char, rec->pathlen, ptr, end);
*buf = ptr;
return 0;
}
static int kml_unpack_create(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
kml_unpack_version(&rec->old_parentv, &ptr, end);
kml_unpack_version(&rec->new_parentv, &ptr, end);
kml_unpack_version(&rec->new_objectv, &ptr, end);
LUNLOGV(rec->mode, __u32, ptr, end);
LUNLOGV(rec->uid, __u32, ptr, end);
LUNLOGV(rec->gid, __u32, ptr, end);
LUNLOGV(rec->pathlen, __u32, ptr, end);
UNLOGL(rec->path, char, rec->pathlen, ptr, end);
*buf = ptr;
return 0;
}
static int kml_unpack_mkdir(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
kml_unpack_version(&rec->old_parentv, &ptr, end);
kml_unpack_version(&rec->new_parentv, &ptr, end);
kml_unpack_version(&rec->new_objectv, &ptr, end);
LUNLOGV(rec->mode, __u32, ptr, end);
LUNLOGV(rec->uid, __u32, ptr, end);
LUNLOGV(rec->gid, __u32, ptr, end);
LUNLOGV(rec->pathlen, __u32, ptr, end);
UNLOGL(rec->path, char, rec->pathlen, ptr, end);
*buf = ptr;
return 0;
}
static int kml_unpack_unlink(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
kml_unpack_version(&rec->old_parentv, &ptr, end);
kml_unpack_version(&rec->new_parentv, &ptr, end);
kml_unpack_version(&rec->old_objectv, &ptr, end);
LUNLOGV(rec->old_mode, __u32, ptr, end);
LUNLOGV(rec->old_rdev, __u32, ptr, end);
LUNLOGV(rec->old_uid, __u64, ptr, end);
LUNLOGV(rec->old_gid, __u64, ptr, end);
LUNLOGV(rec->pathlen, __u32, ptr, end);
LUNLOGV(rec->targetlen, __u32, ptr, end);
LUNLOGV(rec->old_targetlen, __u32, ptr, end);
UNLOGL(rec->path, char, rec->pathlen, ptr, end);
UNLOGL(rec->target, char, rec->targetlen, ptr, end);
UNLOGL(rec->old_target, char, rec->old_targetlen, ptr, end);
*buf = ptr;
return 0;
}
static int kml_unpack_rmdir(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
kml_unpack_version(&rec->old_parentv, &ptr, end);
kml_unpack_version(&rec->new_parentv, &ptr, end);
kml_unpack_version(&rec->old_objectv, &ptr, end);
LUNLOGV(rec->old_mode, __u32, ptr, end);
LUNLOGV(rec->old_rdev, __u32, ptr, end);
LUNLOGV(rec->old_uid, __u64, ptr, end);
LUNLOGV(rec->old_gid, __u64, ptr, end);
LUNLOGV(rec->pathlen, __u32, ptr, end);
LUNLOGV(rec->targetlen, __u32, ptr, end);
UNLOGL(rec->path, char, rec->pathlen, ptr, end);
UNLOGL(rec->target, char, rec->targetlen, ptr, end);
*buf = ptr;
return 0;
}
static int kml_unpack_close(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
LUNLOGV(rec->mode, __u32, ptr, end); // used for open_mode
LUNLOGV(rec->uid, __u32, ptr, end); // used for open_uid
LUNLOGV(rec->gid, __u32, ptr, end); // used for open_gid
kml_unpack_version(&rec->old_objectv, &ptr, end);
kml_unpack_version(&rec->new_objectv, &ptr, end);
LUNLOGV(rec->ino, __u64, ptr, end);
LUNLOGV(rec->generation, __u32, ptr, end);
LUNLOGV(rec->pathlen, __u32, ptr, end);
UNLOGL(rec->path, char, rec->pathlen, ptr, end);
*buf = ptr;
return 0;
}
static int kml_unpack_symlink(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
kml_unpack_version(&rec->old_parentv, &ptr, end);
kml_unpack_version(&rec->new_parentv, &ptr, end);
kml_unpack_version(&rec->new_objectv, &ptr, end);
LUNLOGV(rec->uid, __u32, ptr, end);
LUNLOGV(rec->gid, __u32, ptr, end);
LUNLOGV(rec->pathlen, __u32, ptr, end);
LUNLOGV(rec->targetlen, __u32, ptr, end);
UNLOGL(rec->path, char, rec->pathlen, ptr, end);
UNLOGL(rec->target, char, rec->targetlen, ptr, end);
*buf = ptr;
return 0;
}
static int kml_unpack_rename(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
kml_unpack_version(&rec->old_objectv, &ptr, end);
kml_unpack_version(&rec->new_objectv, &ptr, end);
kml_unpack_version(&rec->old_parentv, &ptr, end);
kml_unpack_version(&rec->new_parentv, &ptr, end);
LUNLOGV(rec->pathlen, __u32, ptr, end);
LUNLOGV(rec->targetlen, __u32, ptr, end);
UNLOGL(rec->path, char, rec->pathlen, ptr, end);
UNLOGL(rec->target, char, rec->targetlen, ptr, end);
*buf = ptr;
return 0;
}
static int kml_unpack_setattr(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
kml_unpack_version(&rec->old_objectv, &ptr, end);
LUNLOGV(rec->valid, __u32, ptr, end);
LUNLOGV(rec->mode, __u32, ptr, end);
LUNLOGV(rec->uid, __u32, ptr, end);
LUNLOGV(rec->gid, __u32, ptr, end);
LUNLOGV(rec->size, __u64, ptr, end);
LUNLOGV(rec->mtime, __u64, ptr, end);
LUNLOGV(rec->ctime, __u64, ptr, end);
LUNLOGV(rec->flags, __u32, ptr, end);
LUNLOGV(rec->old_mode, __u32, ptr, end);
LUNLOGV(rec->old_rdev, __u32, ptr, end);
LUNLOGV(rec->old_uid, __u64, ptr, end);
LUNLOGV(rec->old_gid, __u64, ptr, end);
LUNLOGV(rec->pathlen, __u32, ptr, end);
UNLOGL(rec->path, char, rec->pathlen, ptr, end);
*buf = ptr;
return 0;
}
static int kml_unpack_link(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
kml_unpack_version(&rec->old_parentv, &ptr, end);
kml_unpack_version(&rec->new_parentv, &ptr, end);
kml_unpack_version(&rec->new_objectv, &ptr, end);
LUNLOGV(rec->pathlen, __u32, ptr, end);
LUNLOGV(rec->targetlen, __u32, ptr, end);
UNLOGL(rec->path, char, rec->pathlen, ptr, end);
UNLOGL(rec->target, char, rec->targetlen, ptr, end);
*buf = ptr;
return 0;
}
static int kml_unpack_mknod(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
kml_unpack_version(&rec->old_parentv, &ptr, end);
kml_unpack_version(&rec->new_parentv, &ptr, end);
kml_unpack_version(&rec->new_objectv, &ptr, end);
LUNLOGV(rec->mode, __u32, ptr, end);
LUNLOGV(rec->uid, __u32, ptr, end);
LUNLOGV(rec->gid, __u32, ptr, end);
LUNLOGV(rec->major, __u32, ptr, end);
LUNLOGV(rec->minor, __u32, ptr, end);
LUNLOGV(rec->pathlen, __u32, ptr, end);
UNLOGL(rec->path, char, rec->pathlen, ptr, end);
*buf = ptr;
return 0;
}
static int kml_unpack_write(struct kml_rec *rec, char **buf, char *end)
{
printf("NOT IMPLEMENTED");
return 0;
}
static int kml_unpack_release(struct kml_rec *rec, char **buf, char *end)
{
printf("NOT IMPLEMENTED");
return 0;
}
static int kml_unpack_trunc(struct kml_rec *rec, char **buf, char *end)
{
printf("NOT IMPLEMENTED");
return 0;
}
static int kml_unpack_setextattr(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
kml_unpack_version(&rec->old_objectv, &ptr, end);
kml_unpack_version(&rec->new_objectv, &ptr, end);
LUNLOGV(rec->flags, __u32, ptr, end);
LUNLOGV(rec->mode, __u32, ptr, end);
LUNLOGV(rec->pathlen, __u32, ptr, end);
LUNLOGV(rec->namelen, __u32, ptr, end);
LUNLOGV(rec->targetlen, __u32, ptr, end);
UNLOGL(rec->path, char, rec->pathlen, ptr, end);
UNLOGL(rec->name, char, rec->namelen, ptr, end);
UNLOGL(rec->target, char, rec->targetlen, ptr, end);
*buf = ptr;
return 0;
}
static int kml_unpack_delextattr(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
kml_unpack_version(&rec->old_objectv, &ptr, end);
kml_unpack_version(&rec->new_objectv, &ptr, end);
LUNLOGV(rec->flags, __u32, ptr, end);
LUNLOGV(rec->mode, __u32, ptr, end);
LUNLOGV(rec->pathlen, __u32, ptr, end);
LUNLOGV(rec->namelen, __u32, ptr, end);
LUNLOGV(rec->targetlen, __u32, ptr, end);
UNLOGL(rec->path, char, rec->pathlen, ptr, end);
UNLOGL(rec->name, char, rec->namelen, ptr, end);
*buf = ptr;
return 0;
}
static int kml_unpack_open(struct kml_rec *rec, char **buf, char *end)
{
printf("NOT IMPLEMENTED");
return 0;
}
static int kml_unpack_kml_trunc(struct kml_rec *rec, char **buf, char *end)
{
printf("NOT IMPLEMENTED");
return 0;
}
typedef int (*unpacker)(struct kml_rec *rec, char **buf, char *end);
static unpacker unpackers[KML_OPCODE_NUM] =
{
[KML_OPCODE_NOOP] = kml_unpack_noop,
[KML_OPCODE_CREATE] = kml_unpack_create,
[KML_OPCODE_MKDIR] = kml_unpack_mkdir,
[KML_OPCODE_UNLINK] = kml_unpack_unlink,
[KML_OPCODE_RMDIR] = kml_unpack_rmdir,
[KML_OPCODE_CLOSE] = kml_unpack_close,
[KML_OPCODE_SYMLINK] = kml_unpack_symlink,
[KML_OPCODE_RENAME] = kml_unpack_rename,
[KML_OPCODE_SETATTR] = kml_unpack_setattr,
[KML_OPCODE_LINK] = kml_unpack_link,
[KML_OPCODE_OPEN] = kml_unpack_open,
[KML_OPCODE_MKNOD] = kml_unpack_mknod,
[KML_OPCODE_WRITE] = kml_unpack_write,
[KML_OPCODE_RELEASE] = kml_unpack_release,
[KML_OPCODE_TRUNC] = kml_unpack_trunc,
[KML_OPCODE_SETEXTATTR] = kml_unpack_setextattr,
[KML_OPCODE_DELEXTATTR] = kml_unpack_delextattr,
[KML_OPCODE_KML_TRUNC] = kml_unpack_kml_trunc,
[KML_OPCODE_GET_FILEID] = kml_unpack_get_fileid
};
int kml_unpack_prefix(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
int n;
UNLOGP(rec->prefix.hdr, struct kml_prefix_hdr, ptr, end);
rec->prefix.hdr->len = NTOH__u32(rec->prefix.hdr->len);
rec->prefix.hdr->version = NTOH__u32(rec->prefix.hdr->version);
rec->prefix.hdr->pid = NTOH__u32(rec->prefix.hdr->pid);
rec->prefix.hdr->auid = NTOH__u32(rec->prefix.hdr->auid);
rec->prefix.hdr->fsuid = NTOH__u32(rec->prefix.hdr->fsuid);
rec->prefix.hdr->fsgid = NTOH__u32(rec->prefix.hdr->fsgid);
rec->prefix.hdr->opcode = NTOH__u32(rec->prefix.hdr->opcode);
rec->prefix.hdr->ngroups = NTOH__u32(rec->prefix.hdr->ngroups);
UNLOGL(rec->prefix.groups, __u32, rec->prefix.hdr->ngroups, ptr, end);
for (n = 0; n < rec->prefix.hdr->ngroups; n++) {
rec->prefix.groups[n] = NTOH__u32(rec->prefix.groups[n]);
}
*buf = ptr;
return 0;
}
int kml_unpack_suffix(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
UNLOGP(rec->suffix, struct kml_suffix, ptr, end);
rec->suffix->prevrec = NTOH__u32(rec->suffix->prevrec);
rec->suffix->recno = NTOH__u32(rec->suffix->recno);
rec->suffix->time = NTOH__u32(rec->suffix->time);
rec->suffix->len = NTOH__u32(rec->suffix->len);
*buf = ptr;
return 0;
}
int kml_unpack(struct kml_rec *rec, char **buf, char *end)
{
char *ptr = *buf;
int err;
if (((unsigned long)ptr % 4) != 0) {
printf("InterMezzo: %s: record misaligned.\n", __FUNCTION__);
return -EINVAL;
}
while (ptr < end) {
__u32 *i = (__u32 *)ptr;
if (*i)
break;
ptr += sizeof(*i);
}
*buf = ptr;
memset(rec, 0, sizeof(*rec));
err = kml_unpack_prefix(rec, &ptr, end);
if (err) {
printf("InterMezzo: %s: unpack_prefix failed: %d\n",
__FUNCTION__, err);
return err;
}
if (rec->prefix.hdr->opcode < 0 ||
rec->prefix.hdr->opcode >= KML_OPCODE_NUM) {
printf("InterMezzo: %s: invalid opcode (%d)\n",
__FUNCTION__, rec->prefix.hdr->opcode);
return -EINVAL;
}
err = unpackers[rec->prefix.hdr->opcode](rec, &ptr, end);
if (err) {
printf("InterMezzo: %s: unpacker failed: %d\n",
__FUNCTION__, err);
return err;
}
err = kml_unpack_suffix(rec, &ptr, end);
if (err) {
printf("InterMezzo: %s: unpack_suffix failed: %d\n",
__FUNCTION__, err);
return err;
}
if (rec->prefix.hdr->len != rec->suffix->len) {
printf("InterMezzo: %s: lengths don't match\n",
__FUNCTION__);
return -EINVAL;
}
if ((rec->prefix.hdr->len % 4) != 0) {
printf("InterMezzo: %s: record length not a "
"multiple of 4.\n", __FUNCTION__);
return -EINVAL;
}
if (ptr - *buf != rec->prefix.hdr->len) {
printf("InterMezzo: %s: unpacking error\n",
__FUNCTION__);
return -EINVAL;
}
while (ptr < end) {
__u32 *i = (__u32 *)ptr;
if (*i)
break;
ptr += sizeof(*i);
}
*buf = ptr;
return 0;
}
#ifndef __KERNEL__
#define STR(ptr) ((ptr))? (ptr) : ""
#define OPNAME(n) [KML_OPCODE_##n] = #n
static char *opnames[KML_OPCODE_NUM] = {
OPNAME(NOOP),
OPNAME(CREATE),
OPNAME(MKDIR),
OPNAME(UNLINK),
OPNAME(RMDIR),
OPNAME(CLOSE),
OPNAME(SYMLINK),
OPNAME(RENAME),
OPNAME(SETATTR),
OPNAME(LINK),
OPNAME(OPEN),
OPNAME(MKNOD),
OPNAME(WRITE),
OPNAME(RELEASE),
OPNAME(TRUNC),
OPNAME(SETEXTATTR),
OPNAME(DELEXTATTR),
OPNAME(KML_TRUNC),
OPNAME(GET_FILEID)
};
#undef OPNAME
static char *print_opname(int op)
{
if (op < 0 || op >= sizeof (opnames) / sizeof (*opnames))
return NULL;
return opnames[op];
}
static char *print_time(__u64 i)
{
char buf[128];
memset(buf, 0, 128);
#ifndef __KERNEL__
strftime(buf, 128, "%Y/%m/%d %H:%M:%S", gmtime((time_t *)&i));
#else
sprintf(buf, "%Ld\n", i);
#endif
return strdup(buf);
}
static char *print_version(struct presto_version *ver)
{
char ver_buf[128];
char *mtime;
char *ctime;
if (!ver || ver->pv_ctime == 0) {
return strdup("");
}
mtime = print_time(ver->pv_mtime);
ctime = print_time(ver->pv_ctime);
sprintf(ver_buf, "mtime %s, ctime %s, len %lld",
mtime, ctime, ver->pv_size);
free(mtime);
free(ctime);
return strdup(ver_buf);
}
char *kml_print_rec(struct kml_rec *rec, int brief)
{
char *str;
char *nov, *oov, *ntv, *otv, *npv, *opv;
char *rectime, *mtime, *ctime;
if (brief) {
str = g_strdup_printf(" %08d %7s %*s %*s",
rec->suffix->recno,
print_opname (rec->prefix.hdr->opcode),
rec->pathlen, STR(rec->path),
rec->targetlen, STR(rec->target));
return str;
}
rectime = print_time(rec->suffix->time);
mtime = print_time(rec->mtime);
ctime = print_time(rec->ctime);
nov = print_version(rec->new_objectv);
oov = print_version(rec->old_objectv);
ntv = print_version(rec->new_targetv);
otv = print_version(rec->old_targetv);
npv = print_version(rec->new_parentv);
opv = print_version(rec->old_parentv);
str = g_strdup_printf("\n -- Record:\n"
" Recno %d\n"
" KML off %lld\n"
" Version %d\n"
" Len %d\n"
" Suf len %d\n"
" Time %s\n"
" Opcode %d\n"
" Op %s\n"
" Pid %d\n"
" AUid %d\n"
" Fsuid %d\n"
" Fsgid %d\n"
" Prevrec %d\n"
" Ngroups %d\n"
//" Groups @{$self->{groups}}\n"
" -- Path:\n"
" Inode %d\n"
" Gen num %u\n"
" Old mode %o\n"
" Old rdev %x\n"
" Old uid %llu\n"
" Old gid %llu\n"
" Path %*s\n"
//" Open_mode %o\n",
" Pathlen %d\n"
" Tgt %*s\n"
" Tgtlen %d\n"
" Old Tgt %*s\n"
" Old Tgtln %d\n"
" -- Attr:\n"
" Valid %x\n"
" mode %o, uid %d, gid %d, size %lld, mtime %s, ctime %s rdev %x (%d:%d)\n"
" -- Versions:\n"
" New object %s\n"
" Old object %s\n"
" New target %s\n"
" Old target %s\n"
" New parent %s\n"
" Old parent %s\n",
rec->suffix->recno,
rec->offset,
rec->prefix.hdr->version,
rec->prefix.hdr->len,
rec->suffix->len,
rectime,
rec->prefix.hdr->opcode,
print_opname (rec->prefix.hdr->opcode),
rec->prefix.hdr->pid,
rec->prefix.hdr->auid,
rec->prefix.hdr->fsuid,
rec->prefix.hdr->fsgid,
rec->suffix->prevrec,
rec->prefix.hdr->ngroups,
rec->ino,
rec->generation,
rec->old_mode,
rec->old_rdev,
rec->old_uid,
rec->old_gid,
rec->pathlen,
STR(rec->path),
rec->pathlen,
rec->targetlen,
STR(rec->target),
rec->targetlen,
rec->old_targetlen,
STR(rec->old_target),
rec->old_targetlen,
rec->valid,
rec->mode,
rec->uid,
rec->gid,
rec->size,
mtime,
ctime,
rec->rdev, rec->major, rec->minor,
nov, oov, ntv, otv, npv, opv);
free(nov);
free(oov);
free(ntv);
free(otv);
free(npv);
free(opv);
free(rectime);
free(ctime);
free(mtime);
return str;
}
#endif
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2000 Stelias Computing, Inc.
* Copyright (C) 2000 Red Hat, Inc.
* Copyright (C) 2000 Mountain View Data, Inc.
*
* Extended Attribute Support
* Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc.
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <stdarg.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
#include <linux/blkdev.h>
#include <linux/init.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/fsfilter.h>
#include <linux/intermezzo_fs.h>
int filter_print_entry = 0;
int filter_debug = 0xfffffff;
/*
* The function in this file are responsible for setting up the
* correct methods layered file systems like InterMezzo and snapfs
*/
static struct filter_fs filter_oppar[FILTER_FS_TYPES];
/* get to the upper methods (intermezzo, snapfs) */
inline struct super_operations *filter_c2usops(struct filter_fs *cache)
{
return &cache->o_fops.filter_sops;
}
inline struct inode_operations *filter_c2udiops(struct filter_fs *cache)
{
return &cache->o_fops.filter_dir_iops;
}
inline struct inode_operations *filter_c2ufiops(struct filter_fs *cache)
{
return &cache->o_fops.filter_file_iops;
}
inline struct inode_operations *filter_c2usiops(struct filter_fs *cache)
{
return &cache->o_fops.filter_sym_iops;
}
inline struct file_operations *filter_c2udfops(struct filter_fs *cache)
{
return &cache->o_fops.filter_dir_fops;
}
inline struct file_operations *filter_c2uffops(struct filter_fs *cache)
{
return &cache->o_fops.filter_file_fops;
}
inline struct file_operations *filter_c2usfops(struct filter_fs *cache)
{
return &cache->o_fops.filter_sym_fops;
}
inline struct dentry_operations *filter_c2udops(struct filter_fs *cache)
{
return &cache->o_fops.filter_dentry_ops;
}
/* get to the cache (lower) methods */
inline struct super_operations *filter_c2csops(struct filter_fs *cache)
{
return cache->o_caops.cache_sops;
}
inline struct inode_operations *filter_c2cdiops(struct filter_fs *cache)
{
return cache->o_caops.cache_dir_iops;
}
inline struct inode_operations *filter_c2cfiops(struct filter_fs *cache)
{
return cache->o_caops.cache_file_iops;
}
inline struct inode_operations *filter_c2csiops(struct filter_fs *cache)
{
return cache->o_caops.cache_sym_iops;
}
inline struct file_operations *filter_c2cdfops(struct filter_fs *cache)
{
return cache->o_caops.cache_dir_fops;
}
inline struct file_operations *filter_c2cffops(struct filter_fs *cache)
{
return cache->o_caops.cache_file_fops;
}
inline struct file_operations *filter_c2csfops(struct filter_fs *cache)
{
return cache->o_caops.cache_sym_fops;
}
inline struct dentry_operations *filter_c2cdops(struct filter_fs *cache)
{
return cache->o_caops.cache_dentry_ops;
}
void filter_setup_journal_ops(struct filter_fs *ops, char *cache_type)
{
if ( strlen(cache_type) == strlen("ext2") &&
memcmp(cache_type, "ext2", strlen("ext2")) == 0 ) {
#if CONFIG_EXT2_FS
ops->o_trops = &presto_ext2_journal_ops;
#else
ops->o_trops = NULL;
#endif
FDEBUG(D_SUPER, "ops at %p\n", ops);
}
if ( strlen(cache_type) == strlen("ext3") &&
memcmp(cache_type, "ext3", strlen("ext3")) == 0 ) {
#if defined(CONFIG_EXT3_FS) || defined (CONFIG_EXT3_FS_MODULE)
ops->o_trops = &presto_ext3_journal_ops;
#else
ops->o_trops = NULL;
#endif
FDEBUG(D_SUPER, "ops at %p\n", ops);
}
if ( strlen(cache_type) == strlen("tmpfs") &&
memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) {
#if defined(CONFIG_TMPFS)
ops->o_trops = &presto_tmpfs_journal_ops;
#else
ops->o_trops = NULL;
#endif
FDEBUG(D_SUPER, "ops at %p\n", ops);
}
if ( strlen(cache_type) == strlen("reiserfs") &&
memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) {
#if 0
/* #if defined(CONFIG_REISERFS_FS) || defined(CONFIG_REISERFS_FS_MODULE) */
ops->o_trops = &presto_reiserfs_journal_ops;
#else
ops->o_trops = NULL;
#endif
FDEBUG(D_SUPER, "ops at %p\n", ops);
}
if ( strlen(cache_type) == strlen("xfs") &&
memcmp(cache_type, "xfs", strlen("xfs")) == 0 ) {
#if 0
/*#if defined(CONFIG_XFS_FS) || defined (CONFIG_XFS_FS_MODULE) */
ops->o_trops = &presto_xfs_journal_ops;
#else
ops->o_trops = NULL;
#endif
FDEBUG(D_SUPER, "ops at %p\n", ops);
}
if ( strlen(cache_type) == strlen("obdfs") &&
memcmp(cache_type, "obdfs", strlen("obdfs")) == 0 ) {
#if defined(CONFIG_OBDFS_FS) || defined (CONFIG_OBDFS_FS_MODULE)
ops->o_trops = presto_obdfs_journal_ops;
#else
ops->o_trops = NULL;
#endif
FDEBUG(D_SUPER, "ops at %p\n", ops);
}
}
/* find the cache for this FS */
struct filter_fs *filter_get_filter_fs(const char *cache_type)
{
struct filter_fs *ops = NULL;
FENTRY;
if ( strlen(cache_type) == strlen("ext2") &&
memcmp(cache_type, "ext2", strlen("ext2")) == 0 ) {
ops = &filter_oppar[FILTER_FS_EXT2];
FDEBUG(D_SUPER, "ops at %p\n", ops);
}
if ( strlen(cache_type) == strlen("xfs") &&
memcmp(cache_type, "xfs", strlen("xfs")) == 0 ) {
ops = &filter_oppar[FILTER_FS_XFS];
FDEBUG(D_SUPER, "ops at %p\n", ops);
}
if ( strlen(cache_type) == strlen("ext3") &&
memcmp(cache_type, "ext3", strlen("ext3")) == 0 ) {
ops = &filter_oppar[FILTER_FS_EXT3];
FDEBUG(D_SUPER, "ops at %p\n", ops);
}
if ( strlen(cache_type) == strlen("tmpfs") &&
memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) {
ops = &filter_oppar[FILTER_FS_TMPFS];
FDEBUG(D_SUPER, "ops at %p\n", ops);
}
if ( strlen(cache_type) == strlen("reiserfs") &&
memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) {
ops = &filter_oppar[FILTER_FS_REISERFS];
FDEBUG(D_SUPER, "ops at %p\n", ops);
}
if ( strlen(cache_type) == strlen("obdfs") &&
memcmp(cache_type, "obdfs", strlen("obdfs")) == 0 ) {
ops = &filter_oppar[FILTER_FS_OBDFS];
FDEBUG(D_SUPER, "ops at %p\n", ops);
}
if (ops == NULL) {
CERROR("prepare to die: unrecognized cache type for Filter\n");
}
return ops;
FEXIT;
}
/*
* Frobnicate the InterMezzo operations
* this establishes the link between the InterMezzo file system
* and the underlying file system used for the cache.
*/
void filter_setup_super_ops(struct filter_fs *cache, struct super_operations *cache_sops, struct super_operations *filter_sops)
{
/* Get ptr to the shared struct snapfs_ops structure. */
struct filter_ops *props = &cache->o_fops;
/* Get ptr to the shared struct cache_ops structure. */
struct cache_ops *caops = &cache->o_caops;
FENTRY;
if ( cache->o_flags & FILTER_DID_SUPER_OPS ) {
FEXIT;
return;
}
cache->o_flags |= FILTER_DID_SUPER_OPS;
/* Set the cache superblock operations to point to the
superblock operations of the underlying file system. */
caops->cache_sops = cache_sops;
/*
* Copy the cache (real fs) superblock ops to the "filter"
* superblock ops as defaults. Some will be changed below
*/
memcpy(&props->filter_sops, cache_sops, sizeof(*cache_sops));
/* 'put_super' unconditionally is that of filter */
if (filter_sops->put_super) {
props->filter_sops.put_super = filter_sops->put_super;
}
if (cache_sops->read_inode) {
props->filter_sops.read_inode = filter_sops->read_inode;
FDEBUG(D_INODE, "setting filter_read_inode, cache_ops %p, cache %p, ri at %p\n",
cache, cache, props->filter_sops.read_inode);
}
if (cache_sops->remount_fs)
props->filter_sops.remount_fs = filter_sops->remount_fs;
FEXIT;
}
void filter_setup_dir_ops(struct filter_fs *cache, struct inode *inode, struct inode_operations *filter_iops, struct file_operations *filter_fops)
{
struct inode_operations *cache_filter_iops;
struct inode_operations *cache_iops = inode->i_op;
struct file_operations *cache_fops = inode->i_fop;
FENTRY;
if ( cache->o_flags & FILTER_DID_DIR_OPS ) {
FEXIT;
return;
}
cache->o_flags |= FILTER_DID_DIR_OPS;
/* former ops become cache_ops */
cache->o_caops.cache_dir_iops = cache_iops;
cache->o_caops.cache_dir_fops = cache_fops;
FDEBUG(D_SUPER, "filter at %p, cache iops %p, iops %p\n",
cache, cache_iops, filter_c2udiops(cache));
/* setup our dir iops: copy and modify */
memcpy(filter_c2udiops(cache), cache_iops, sizeof(*cache_iops));
/* abbreviate */
cache_filter_iops = filter_c2udiops(cache);
/* methods that filter if cache filesystem has these ops */
if (cache_iops->lookup && filter_iops->lookup)
cache_filter_iops->lookup = filter_iops->lookup;
if (cache_iops->create && filter_iops->create)
cache_filter_iops->create = filter_iops->create;
if (cache_iops->link && filter_iops->link)
cache_filter_iops->link = filter_iops->link;
if (cache_iops->unlink && filter_iops->unlink)
cache_filter_iops->unlink = filter_iops->unlink;
if (cache_iops->mkdir && filter_iops->mkdir)
cache_filter_iops->mkdir = filter_iops->mkdir;
if (cache_iops->rmdir && filter_iops->rmdir)
cache_filter_iops->rmdir = filter_iops->rmdir;
if (cache_iops->symlink && filter_iops->symlink)
cache_filter_iops->symlink = filter_iops->symlink;
if (cache_iops->rename && filter_iops->rename)
cache_filter_iops->rename = filter_iops->rename;
if (cache_iops->mknod && filter_iops->mknod)
cache_filter_iops->mknod = filter_iops->mknod;
if (cache_iops->permission && filter_iops->permission)
cache_filter_iops->permission = filter_iops->permission;
if (cache_iops->getattr)
cache_filter_iops->getattr = filter_iops->getattr;
/* Some filesystems do not use a setattr method of their own
instead relying on inode_setattr/write_inode. We still need to
journal these so we make setattr an unconditional operation.
XXX: we should probably check for write_inode. SHP
*/
/*if (cache_iops->setattr)*/
cache_filter_iops->setattr = filter_iops->setattr;
#ifdef CONFIG_FS_EXT_ATTR
/* For now we assume that posix acls are handled through extended
* attributes. If this is not the case, we must explicitly trap
* posix_set_acl. SHP
*/
if (cache_iops->set_ext_attr && filter_iops->set_ext_attr)
cache_filter_iops->set_ext_attr = filter_iops->set_ext_attr;
#endif
/* copy dir fops */
memcpy(filter_c2udfops(cache), cache_fops, sizeof(*cache_fops));
/* unconditional filtering operations */
filter_c2udfops(cache)->ioctl = filter_fops->ioctl;
FEXIT;
}
void filter_setup_file_ops(struct filter_fs *cache, struct inode *inode, struct inode_operations *filter_iops, struct file_operations *filter_fops)
{
struct inode_operations *pr_iops;
struct inode_operations *cache_iops = inode->i_op;
struct file_operations *cache_fops = inode->i_fop;
FENTRY;
if ( cache->o_flags & FILTER_DID_FILE_OPS ) {
FEXIT;
return;
}
cache->o_flags |= FILTER_DID_FILE_OPS;
/* steal the old ops */
/* former ops become cache_ops */
cache->o_caops.cache_file_iops = cache_iops;
cache->o_caops.cache_file_fops = cache_fops;
/* abbreviate */
pr_iops = filter_c2ufiops(cache);
/* setup our dir iops: copy and modify */
memcpy(pr_iops, cache_iops, sizeof(*cache_iops));
/* copy dir fops */
CERROR("*** cache file ops at %p\n", cache_fops);
memcpy(filter_c2uffops(cache), cache_fops, sizeof(*cache_fops));
/* assign */
/* See comments above in filter_setup_dir_ops. SHP */
/*if (cache_iops->setattr)*/
pr_iops->setattr = filter_iops->setattr;
if (cache_iops->getattr)
pr_iops->getattr = filter_iops->getattr;
/* XXX Should this be conditional rmr ? */
pr_iops->permission = filter_iops->permission;
#ifdef CONFIG_FS_EXT_ATTR
/* For now we assume that posix acls are handled through extended
* attributes. If this is not the case, we must explicitly trap and
* posix_set_acl
*/
if (cache_iops->set_ext_attr && filter_iops->set_ext_attr)
pr_iops->set_ext_attr = filter_iops->set_ext_attr;
#endif
/* unconditional filtering operations */
filter_c2uffops(cache)->open = filter_fops->open;
filter_c2uffops(cache)->release = filter_fops->release;
filter_c2uffops(cache)->write = filter_fops->write;
filter_c2uffops(cache)->ioctl = filter_fops->ioctl;
FEXIT;
}
/* XXX in 2.3 there are "fast" and "slow" symlink ops for ext2 XXX */
void filter_setup_symlink_ops(struct filter_fs *cache, struct inode *inode, struct inode_operations *filter_iops, struct file_operations *filter_fops)
{
struct inode_operations *pr_iops;
struct inode_operations *cache_iops = inode->i_op;
struct file_operations *cache_fops = inode->i_fop;
FENTRY;
if ( cache->o_flags & FILTER_DID_SYMLINK_OPS ) {
FEXIT;
return;
}
cache->o_flags |= FILTER_DID_SYMLINK_OPS;
/* steal the old ops */
cache->o_caops.cache_sym_iops = cache_iops;
cache->o_caops.cache_sym_fops = cache_fops;
/* abbreviate */
pr_iops = filter_c2usiops(cache);
/* setup our dir iops: copy and modify */
memcpy(pr_iops, cache_iops, sizeof(*cache_iops));
/* See comments above in filter_setup_dir_ops. SHP */
/* if (cache_iops->setattr) */
pr_iops->setattr = filter_iops->setattr;
if (cache_iops->getattr)
pr_iops->getattr = filter_iops->getattr;
/* assign */
/* copy fops - careful for symlinks they might be NULL */
if ( cache_fops ) {
memcpy(filter_c2usfops(cache), cache_fops, sizeof(*cache_fops));
}
FEXIT;
}
void filter_setup_dentry_ops(struct filter_fs *cache,
struct dentry_operations *cache_dop,
struct dentry_operations *filter_dop)
{
if ( cache->o_flags & FILTER_DID_DENTRY_OPS ) {
FEXIT;
return;
}
cache->o_flags |= FILTER_DID_DENTRY_OPS;
cache->o_caops.cache_dentry_ops = cache_dop;
memcpy(&cache->o_fops.filter_dentry_ops,
filter_dop, sizeof(*filter_dop));
if (cache_dop && cache_dop != filter_dop && cache_dop->d_revalidate){
CERROR("WARNING: filter overriding revalidation!\n");
}
return;
}
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Author: Peter J. Braam <[email protected]>
* Copyright (C) 1998 Stelias Computing Inc
* Copyright (C) 1999 Red Hat Inc.
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* This file implements basic routines supporting the semantics
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
int presto_walk(const char *name, struct nameidata *nd)
{
int err;
/* we do not follow symlinks to support symlink operations
correctly. The vfs should always hand us resolved dentries
so we should not be required to use LOOKUP_FOLLOW. At the
reintegrating end, lento again should be working with the
resolved pathname and not the symlink. SHP
XXX: This code implies that direct symlinks do not work. SHP
*/
unsigned int flags = LOOKUP_POSITIVE;
ENTRY;
err = 0;
if (path_init(name, flags, nd))
err = path_walk(name, nd);
return err;
}
/* find the presto minor device for this inode */
int presto_i2m(struct inode *inode)
{
struct presto_cache *cache;
ENTRY;
cache = presto_get_cache(inode);
CDEBUG(D_PSDEV, "\n");
if ( !cache ) {
CERROR("PRESTO: BAD: cannot find cache for dev %d, ino %ld\n",
inode->i_dev, inode->i_ino);
EXIT;
return -1;
}
EXIT;
return cache->cache_psdev->uc_minor;
}
inline int presto_f2m(struct presto_file_set *fset)
{
return fset->fset_cache->cache_psdev->uc_minor;
}
inline int presto_c2m(struct presto_cache *cache)
{
return cache->cache_psdev->uc_minor;
}
/* XXX check this out */
struct presto_file_set *presto_path2fileset(const char *name)
{
struct nameidata nd;
struct presto_file_set *fileset;
int error;
ENTRY;
error = presto_walk(name, &nd);
if (!error) {
#if 0
error = do_revalidate(nd.dentry);
#endif
if (!error)
fileset = presto_fset(nd.dentry);
path_release(&nd);
EXIT;
} else
fileset = ERR_PTR(error);
EXIT;
return fileset;
}
/* check a flag on this dentry or fset root. Semantics:
- most flags: test if it is set
- PRESTO_ATTR, PRESTO_DATA return 1 if PRESTO_FSETINSYNC is set
*/
int presto_chk(struct dentry *dentry, int flag)
{
int minor;
struct presto_file_set *fset = presto_fset(dentry);
ENTRY;
minor = presto_i2m(dentry->d_inode);
if ( izo_channels[minor].uc_no_filter ) {
EXIT;
return ~0;
}
/* if the fileset is in sync DATA and ATTR are OK */
if ( fset &&
(flag == PRESTO_ATTR || flag == PRESTO_DATA) &&
(fset->fset_flags & FSET_INSYNC) ) {
CDEBUG(D_INODE, "fset in sync (ino %ld)!\n",
fset->fset_dentry->d_inode->i_ino);
EXIT;
return 1;
}
EXIT;
return (presto_d2d(dentry)->dd_flags & flag);
}
/* set a bit in the dentry flags */
void presto_set(struct dentry *dentry, int flag)
{
ENTRY;
if ( dentry->d_inode ) {
CDEBUG(D_INODE, "SET ino %ld, flag %x\n",
dentry->d_inode->i_ino, flag);
}
if ( presto_d2d(dentry) == NULL) {
CERROR("dentry without d_fsdata in presto_set: %p: %*s", dentry,
dentry->d_name.len, dentry->d_name.name);
BUG();
}
presto_d2d(dentry)->dd_flags |= flag;
EXIT;
}
/* given a path: complete the closes on the fset */
int lento_complete_closes(char *path)
{
struct nameidata nd;
struct dentry *dentry;
int error;
struct presto_file_set *fset;
ENTRY;
error = presto_walk(path, &nd);
if (error) {
EXIT;
return error;
}
dentry = nd.dentry;
error = -ENXIO;
if ( !presto_ispresto(dentry->d_inode) ) {
EXIT;
goto out_complete;
}
fset = presto_fset(dentry);
error = -EINVAL;
if ( !fset ) {
CERROR("No fileset!\n");
EXIT;
goto out_complete;
}
/* transactions and locking are internal to this function */
error = presto_complete_lml(fset);
EXIT;
out_complete:
path_release(&nd);
return error;
}
#if 0
/* given a path: write a close record and cancel an LML record, finally
call truncate LML. Lento is doing this so it goes in with uid/gid's
root.
*/
int lento_cancel_lml(char *path,
__u64 lml_offset,
__u64 remote_ino,
__u32 remote_generation,
__u32 remote_version,
struct lento_vfs_context *info)
{
struct nameidata nd;
struct rec_info rec;
struct dentry *dentry;
int error;
struct presto_file_set *fset;
void *handle;
struct presto_version new_ver;
ENTRY;
error = presto_walk(path, &nd);
if (error) {
EXIT;
return error;
}
dentry = nd.dentry;
error = -ENXIO;
if ( !presto_ispresto(dentry->d_inode) ) {
EXIT;
goto out_cancel_lml;
}
fset = presto_fset(dentry);
error=-EINVAL;
if (fset==NULL) {
CERROR("No fileset!\n");
EXIT;
goto out_cancel_lml;
}
/* this only requires a transaction below which is automatic */
handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_RELEASE);
if ( IS_ERR(handle) ) {
error = -ENOMEM;
EXIT;
goto out_cancel_lml;
}
if (info->flags & LENTO_FL_CANCEL_LML) {
error = presto_clear_lml_close(fset, lml_offset);
if ( error ) {
presto_trans_commit(fset, handle);
EXIT;
goto out_cancel_lml;
}
}
if (info->flags & LENTO_FL_WRITE_KML) {
struct file file;
file.private_data = NULL;
file.f_dentry = dentry;
presto_getversion(&new_ver, dentry->d_inode);
error = presto_journal_close(&rec, fset, &file, dentry,
&new_ver);
if ( error ) {
EXIT;
presto_trans_commit(fset, handle);
goto out_cancel_lml;
}
}
if (info->flags & LENTO_FL_WRITE_EXPECT) {
error = presto_write_last_rcvd(&rec, fset, info);
if ( error < 0 ) {
EXIT;
presto_trans_commit(fset, handle);
goto out_cancel_lml;
}
}
presto_trans_commit(fset, handle);
if (info->flags & LENTO_FL_CANCEL_LML) {
presto_truncate_lml(fset);
}
out_cancel_lml:
EXIT;
path_release(&nd);
return error;
}
#endif
/* given a dentry, operate on the flags in its dentry. Used by downcalls */
int izo_mark_dentry(struct dentry *dentry, int and_flag, int or_flag,
int *res)
{
int error = 0;
if (presto_d2d(dentry) == NULL) {
CERROR("InterMezzo: no ddata for inode %ld in %s\n",
dentry->d_inode->i_ino, __FUNCTION__);
return -EINVAL;
}
CDEBUG(D_INODE, "inode: %ld, and flag %x, or flag %x, dd_flags %x\n",
dentry->d_inode->i_ino, and_flag, or_flag,
presto_d2d(dentry)->dd_flags);
presto_d2d(dentry)->dd_flags &= and_flag;
presto_d2d(dentry)->dd_flags |= or_flag;
if (res)
*res = presto_d2d(dentry)->dd_flags;
return error;
}
/* given a path, operate on the flags in its cache. Used by mark_ioctl */
int izo_mark_cache(struct dentry *dentry, int and_flag, int or_flag,
int *res)
{
struct presto_cache *cache;
if (presto_d2d(dentry) == NULL) {
CERROR("InterMezzo: no ddata for inode %ld in %s\n",
dentry->d_inode->i_ino, __FUNCTION__);
return -EINVAL;
}
CDEBUG(D_INODE, "inode: %ld, and flag %x, or flag %x, dd_flags %x\n",
dentry->d_inode->i_ino, and_flag, or_flag,
presto_d2d(dentry)->dd_flags);
cache = presto_get_cache(dentry->d_inode);
if ( !cache ) {
CERROR("PRESTO: BAD: cannot find cache in izo_mark_cache\n");
return -EBADF;
}
((int)cache->cache_flags) &= and_flag;
((int)cache->cache_flags) |= or_flag;
if (res)
*res = (int)cache->cache_flags;
return 0;
}
int presto_set_max_kml_size(const char *path, unsigned long max_size)
{
struct presto_file_set *fset;
ENTRY;
fset = presto_path2fileset(path);
if (IS_ERR(fset)) {
EXIT;
return PTR_ERR(fset);
}
fset->kml_truncate_size = max_size;
CDEBUG(D_CACHE, "KML truncate size set to %lu bytes for fset %s.\n",
max_size, path);
EXIT;
return 0;
}
int izo_mark_fset(struct dentry *dentry, int and_flag, int or_flag,
int * res)
{
struct presto_file_set *fset;
fset = presto_fset(dentry);
if ( !fset ) {
CERROR("PRESTO: BAD: cannot find cache in izo_mark_cache\n");
make_bad_inode(dentry->d_inode);
return -EBADF;
}
((int)fset->fset_flags) &= and_flag;
((int)fset->fset_flags) |= or_flag;
if (res)
*res = (int)fset->fset_flags;
return 0;
}
/* talk to Lento about the permit */
static int presto_permit_upcall(struct dentry *dentry)
{
int rc;
char *path, *buffer;
int pathlen;
int minor;
int fsetnamelen;
struct presto_file_set *fset = NULL;
ENTRY;
if ( (minor = presto_i2m(dentry->d_inode)) < 0) {
EXIT;
return -EINVAL;
}
fset = presto_fset(dentry);
if (!fset) {
EXIT;
return -ENOTCONN;
}
if ( !presto_lento_up(minor) ) {
if ( fset->fset_flags & FSET_STEAL_PERMIT ) {
EXIT;
return 0;
} else {
EXIT;
return -ENOTCONN;
}
}
PRESTO_ALLOC(buffer, PAGE_SIZE);
if ( !buffer ) {
CERROR("PRESTO: out of memory!\n");
EXIT;
return -ENOMEM;
}
path = presto_path(dentry, fset->fset_dentry, buffer, PAGE_SIZE);
pathlen = MYPATHLEN(buffer, path);
fsetnamelen = strlen(fset->fset_name);
rc = izo_upc_permit(minor, dentry, pathlen, path, fset->fset_name);
PRESTO_FREE(buffer, PAGE_SIZE);
EXIT;
return rc;
}
/* get a write permit for the fileset of this inode
* - if this returns a negative value there was an error
* - if 0 is returned the permit was already in the kernel -- or --
* Lento gave us the permit without reintegration
* - lento returns the number of records it reintegrated
*
* Note that if this fileset has branches, a permit will -never- to a normal
* process for writing in the data area (ie, outside of .intermezzo)
*/
int presto_get_permit(struct inode * inode)
{
struct dentry *de;
struct presto_file_set *fset;
int minor = presto_i2m(inode);
int rc = 0;
ENTRY;
if (minor < 0) {
EXIT;
return -1;
}
if ( ISLENTO(minor) ) {
EXIT;
return 0;
}
if (list_empty(&inode->i_dentry)) {
CERROR("No alias for inode %d\n", (int) inode->i_ino);
EXIT;
return -EINVAL;
}
de = list_entry(inode->i_dentry.next, struct dentry, d_alias);
if (presto_chk(de, PRESTO_DONT_JOURNAL)) {
EXIT;
return 0;
}
fset = presto_fset(de);
if ( !fset ) {
CERROR("Presto: no fileset in presto_get_permit!\n");
EXIT;
return -EINVAL;
}
if (fset->fset_flags & FSET_HAS_BRANCHES) {
EXIT;
return -EROFS;
}
spin_lock(&fset->fset_permit_lock);
if (fset->fset_flags & FSET_HASPERMIT) {
fset->fset_permit_count++;
CDEBUG(D_INODE, "permit count now %d, inode %lx\n",
fset->fset_permit_count, inode->i_ino);
spin_unlock(&fset->fset_permit_lock);
EXIT;
return 0;
}
/* Allow reintegration to proceed without locks -SHP */
fset->fset_permit_upcall_count++;
if (fset->fset_permit_upcall_count == 1) {
spin_unlock(&fset->fset_permit_lock);
rc = presto_permit_upcall(fset->fset_dentry);
spin_lock(&fset->fset_permit_lock);
fset->fset_permit_upcall_count--;
if (rc == 0) {
izo_mark_fset(fset->fset_dentry, ~0, FSET_HASPERMIT,
NULL);
fset->fset_permit_count++;
} else if (rc == ENOTCONN) {
CERROR("InterMezzo: disconnected operation. stealing permit.\n");
izo_mark_fset(fset->fset_dentry, ~0, FSET_HASPERMIT,
NULL);
fset->fset_permit_count++;
/* set a disconnected flag here to stop upcalls */
rc = 0;
} else {
CERROR("InterMezzo: presto_permit_upcall failed: %d\n", rc);
rc = -EROFS;
/* go to sleep here and try again? */
}
wake_up_interruptible(&fset->fset_permit_queue);
} else {
/* Someone is already doing an upcall; go to sleep. */
DECLARE_WAITQUEUE(wait, current);
spin_unlock(&fset->fset_permit_lock);
add_wait_queue(&fset->fset_permit_queue, &wait);
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
spin_lock(&fset->fset_permit_lock);
if (fset->fset_permit_upcall_count == 0)
break;
spin_unlock(&fset->fset_permit_lock);
if (signal_pending(current)) {
remove_wait_queue(&fset->fset_permit_queue,
&wait);
return -ERESTARTSYS;
}
schedule();
}
remove_wait_queue(&fset->fset_permit_queue, &wait);
/* We've been woken up: do we have the permit? */
if (fset->fset_flags & FSET_HASPERMIT)
/* FIXME: Is this the right thing? */
rc = -EAGAIN;
}
CDEBUG(D_INODE, "permit count now %d, ino %ld (likely 1), "
"rc %d\n", fset->fset_permit_count, inode->i_ino, rc);
spin_unlock(&fset->fset_permit_lock);
EXIT;
return rc;
}
int presto_put_permit(struct inode * inode)
{
struct dentry *de;
struct presto_file_set *fset;
int minor = presto_i2m(inode);
ENTRY;
if (minor < 0) {
EXIT;
return -1;
}
if ( ISLENTO(minor) ) {
EXIT;
return 0;
}
if (list_empty(&inode->i_dentry)) {
CERROR("No alias for inode %d\n", (int) inode->i_ino);
EXIT;
return -1;
}
de = list_entry(inode->i_dentry.next, struct dentry, d_alias);
fset = presto_fset(de);
if ( !fset ) {
CERROR("InterMezzo: no fileset in %s!\n", __FUNCTION__);
EXIT;
return -1;
}
if (presto_chk(de, PRESTO_DONT_JOURNAL)) {
EXIT;
return 0;
}
spin_lock(&fset->fset_permit_lock);
if (fset->fset_flags & FSET_HASPERMIT) {
if (fset->fset_permit_count > 0)
fset->fset_permit_count--;
else
CERROR("Put permit while permit count is 0, "
"inode %ld!\n", inode->i_ino);
} else {
fset->fset_permit_count = 0;
CERROR("InterMezzo: put permit while no permit, inode %ld, "
"flags %x!\n", inode->i_ino, fset->fset_flags);
}
CDEBUG(D_INODE, "permit count now %d, inode %ld\n",
fset->fset_permit_count, inode->i_ino);
if (fset->fset_flags & FSET_PERMIT_WAITING &&
fset->fset_permit_count == 0) {
CDEBUG(D_INODE, "permit count now 0, ino %ld, wake sleepers\n",
inode->i_ino);
wake_up_interruptible(&fset->fset_permit_queue);
}
spin_unlock(&fset->fset_permit_lock);
EXIT;
return 0;
}
void presto_getversion(struct presto_version * presto_version,
struct inode * inode)
{
presto_version->pv_mtime = (__u64)inode->i_mtime;
presto_version->pv_ctime = (__u64)inode->i_ctime;
presto_version->pv_size = (__u64)inode->i_size;
}
/* If uuid is non-null, it is the uuid of the peer that's making the revocation
* request. If it is null, this request was made locally, without external
* pressure to give up the permit. This most often occurs when a client
* starts up.
*
* FIXME: this function needs to be refactored slightly once we start handling
* multiple clients.
*/
int izo_revoke_permit(struct dentry *dentry, __u8 uuid[16])
{
struct presto_file_set *fset;
DECLARE_WAITQUEUE(wait, current);
int minor, rc;
ENTRY;
minor = presto_i2m(dentry->d_inode);
if (minor < 0) {
EXIT;
return -ENODEV;
}
fset = presto_fset(dentry);
if (fset == NULL) {
EXIT;
return -ENODEV;
}
spin_lock(&fset->fset_permit_lock);
if (fset->fset_flags & FSET_PERMIT_WAITING) {
CERROR("InterMezzo: Two processes are waiting on the same permit--this not yet supported! Aborting this particular permit request...\n");
EXIT;
spin_unlock(&fset->fset_permit_lock);
return -EINVAL;
}
if (fset->fset_permit_count == 0)
goto got_permit;
/* Something is still using this permit. Mark that we're waiting for it
* and go to sleep. */
rc = izo_mark_fset(dentry, ~0, FSET_PERMIT_WAITING, NULL);
spin_unlock(&fset->fset_permit_lock);
if (rc < 0) {
EXIT;
return rc;
}
add_wait_queue(&fset->fset_permit_queue, &wait);
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
spin_lock(&fset->fset_permit_lock);
if (fset->fset_permit_count == 0)
break;
spin_unlock(&fset->fset_permit_lock);
if (signal_pending(current)) {
/* FIXME: there must be a better thing to return... */
remove_wait_queue(&fset->fset_permit_queue, &wait);
EXIT;
return -ERESTARTSYS;
}
/* FIXME: maybe there should be a timeout here. */
schedule();
}
remove_wait_queue(&fset->fset_permit_queue, &wait);
got_permit:
/* By this point fset->fset_permit_count is zero and we're holding the
* lock. */
CDEBUG(D_CACHE, "InterMezzo: releasing permit inode %ld\n",
dentry->d_inode->i_ino);
if (uuid != NULL) {
rc = izo_upc_revoke_permit(minor, fset->fset_name, uuid);
if (rc < 0) {
spin_unlock(&fset->fset_permit_lock);
EXIT;
return rc;
}
}
izo_mark_fset(fset->fset_dentry, ~FSET_PERMIT_WAITING, 0, NULL);
izo_mark_fset(fset->fset_dentry, ~FSET_HASPERMIT, 0, NULL);
spin_unlock(&fset->fset_permit_lock);
EXIT;
return 0;
}
inline int presto_is_read_only(struct presto_file_set * fset)
{
int minor, mask;
struct presto_cache *cache = fset->fset_cache;
minor= cache->cache_psdev->uc_minor;
mask= (ISLENTO(minor)? FSET_LENTO_RO : FSET_CLIENT_RO);
if ( fset->fset_flags & mask )
return 1;
mask= (ISLENTO(minor)? CACHE_LENTO_RO : CACHE_CLIENT_RO);
return ((cache->cache_flags & mask)? 1 : 0);
}
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* An implementation of a loadable kernel mode driver providing
* multiple kernel/user space bidirectional communications links.
*
* Author: Alan Cox <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* Adapted to become the Linux 2.0 Coda pseudo device
* Peter Braam <[email protected]>
* Michael Callahan <[email protected]>
*
* Changes for Linux 2.1
* Copyright (c) 1997 Carnegie-Mellon University
*
* Redone again for InterMezzo
* Copyright (c) 1998 Peter J. Braam
* Copyright (c) 2000 Mountain View Data, Inc.
* Copyright (c) 2000 Tacitus Systems, Inc.
* Copyright (c) 2001 Cluster File Systems, Inc.
*
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/lp.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/poll.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
#ifdef PRESTO_DEVEL
int presto_print_entry = 1;
int presto_debug = 4095;
#else
int presto_print_entry = 0;
int presto_debug = 0;
#endif
/* Like inode.c (presto_sym_iops), the initializer is just to prevent
izo_channels from appearing as a COMMON symbol (and therefore
interfering with other modules that use the same variable name). */
struct upc_channel izo_channels[MAX_CHANNEL] = {{0}};
int izo_psdev_get_free_channel(void)
{
int i, result = -1;
for (i = 0 ; i < MAX_CHANNEL ; i++ ) {
if (list_empty(&(izo_channels[i].uc_cache_list))) {
result = i;
break;
}
}
return result;
}
int izo_psdev_setpid(int minor)
{
struct upc_channel *channel;
if (minor < 0 || minor >= MAX_CHANNEL) {
return -EINVAL;
}
channel = &(izo_channels[minor]);
/*
* This ioctl is performed by each Lento that starts up
* and wants to do further communication with presto.
*/
CDEBUG(D_PSDEV, "Setting current pid to %d channel %d\n",
current->pid, minor);
channel->uc_pid = current->pid;
spin_lock(&channel->uc_lock);
if ( !list_empty(&channel->uc_processing) ) {
struct list_head *lh;
struct upc_req *req;
CERROR("WARNING: setpid & processing not empty!\n");
lh = &channel->uc_processing;
while ( (lh = lh->next) != &channel->uc_processing) {
req = list_entry(lh, struct upc_req, rq_chain);
/* freeing of req and data is done by the sleeper */
wake_up(&req->rq_sleep);
}
}
if ( !list_empty(&channel->uc_processing) ) {
CERROR("BAD: FAILDED TO CLEAN PROCESSING LIST!\n");
}
spin_unlock(&channel->uc_lock);
EXIT;
return 0;
}
int izo_psdev_setchannel(struct file *file, int fd)
{
struct file *psdev_file = fget(fd);
struct presto_cache *cache = presto_get_cache(file->f_dentry->d_inode);
if (!psdev_file) {
CERROR("%s: no psdev_file!\n", __FUNCTION__);
return -EINVAL;
}
if (!cache) {
CERROR("%s: no cache!\n", __FUNCTION__);
fput(psdev_file);
return -EINVAL;
}
if (psdev_file->private_data) {
CERROR("%s: channel already set!\n", __FUNCTION__);
fput(psdev_file);
return -EINVAL;
}
psdev_file->private_data = cache->cache_psdev;
fput(psdev_file);
EXIT;
return 0;
}
inline int presto_lento_up(int minor)
{
return izo_channels[minor].uc_pid;
}
static unsigned int presto_psdev_poll(struct file *file, poll_table * wait)
{
struct upc_channel *channel = (struct upc_channel *)file->private_data;
unsigned int mask = POLLOUT | POLLWRNORM;
/* ENTRY; this will flood you */
if ( ! channel ) {
CERROR("%s: bad psdev file\n", __FUNCTION__);
return -EBADF;
}
poll_wait(file, &(channel->uc_waitq), wait);
spin_lock(&channel->uc_lock);
if (!list_empty(&channel->uc_pending)) {
CDEBUG(D_PSDEV, "Non-empty pending list.\n");
mask |= POLLIN | POLLRDNORM;
}
spin_unlock(&channel->uc_lock);
/* EXIT; will flood you */
return mask;
}
/*
* Receive a message written by Lento to the psdev
*/
static ssize_t presto_psdev_write(struct file *file, const char *buf,
size_t count, loff_t *off)
{
struct upc_channel *channel = (struct upc_channel *)file->private_data;
struct upc_req *req = NULL;
struct upc_req *tmp;
struct list_head *lh;
struct izo_upcall_resp hdr;
int error;
if ( ! channel ) {
CERROR("%s: bad psdev file\n", __FUNCTION__);
return -EBADF;
}
/* Peek at the opcode, uniquefier */
if ( count < sizeof(hdr) ) {
CERROR("presto_psdev_write: Lento didn't write full hdr.\n");
return -EINVAL;
}
error = copy_from_user(&hdr, buf, sizeof(hdr));
if ( error )
return -EFAULT;
CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%d,%d)\n",
current->pid, hdr.opcode, hdr.unique);
spin_lock(&channel->uc_lock);
/* Look for the message on the processing queue. */
lh = &channel->uc_processing;
while ( (lh = lh->next) != &channel->uc_processing ) {
tmp = list_entry(lh, struct upc_req , rq_chain);
if (tmp->rq_unique == hdr.unique) {
req = tmp;
/* unlink here: keeps search length minimal */
list_del_init(&req->rq_chain);
CDEBUG(D_PSDEV,"Eureka opc %d uniq %d!\n",
hdr.opcode, hdr.unique);
break;
}
}
spin_unlock(&channel->uc_lock);
if (!req) {
CERROR("psdev_write: msg (%d, %d) not found\n",
hdr.opcode, hdr.unique);
return(-ESRCH);
}
/* move data into response buffer. */
if (req->rq_bufsize < count) {
CERROR("psdev_write: too much cnt: %d, cnt: %d, "
"opc: %d, uniq: %d.\n",
req->rq_bufsize, count, hdr.opcode, hdr.unique);
count = req->rq_bufsize; /* don't have more space! */
}
error = copy_from_user(req->rq_data, buf, count);
if ( error )
return -EFAULT;
/* adjust outsize: good upcalls can be aware of this */
req->rq_rep_size = count;
req->rq_flags |= REQ_WRITE;
wake_up(&req->rq_sleep);
return(count);
}
/*
* Read a message from the kernel to Lento
*/
static ssize_t presto_psdev_read(struct file * file, char * buf,
size_t count, loff_t *off)
{
struct upc_channel *channel = (struct upc_channel *)file->private_data;
struct upc_req *req;
int result = count;
if ( ! channel ) {
CERROR("%s: bad psdev file\n", __FUNCTION__);
return -EBADF;
}
spin_lock(&channel->uc_lock);
if (list_empty(&(channel->uc_pending))) {
CDEBUG(D_UPCALL, "Empty pending list in read, not good\n");
spin_unlock(&channel->uc_lock);
return -EINVAL;
}
req = list_entry((channel->uc_pending.next), struct upc_req, rq_chain);
list_del(&(req->rq_chain));
if (! (req->rq_flags & REQ_ASYNC) ) {
list_add(&(req->rq_chain), channel->uc_processing.prev);
}
spin_unlock(&channel->uc_lock);
req->rq_flags |= REQ_READ;
/* Move the input args into userspace */
CDEBUG(D_PSDEV, "\n");
if (req->rq_bufsize <= count) {
result = req->rq_bufsize;
}
if (count < req->rq_bufsize) {
CERROR ("psdev_read: buffer too small, read %d of %d bytes\n",
count, req->rq_bufsize);
}
if ( copy_to_user(buf, req->rq_data, result) ) {
BUG();
return -EFAULT;
}
/* If request was asynchronous don't enqueue, but free */
if (req->rq_flags & REQ_ASYNC) {
CDEBUG(D_PSDEV, "psdev_read: async msg (%d, %d), result %d\n",
req->rq_opcode, req->rq_unique, result);
PRESTO_FREE(req->rq_data, req->rq_bufsize);
PRESTO_FREE(req, sizeof(*req));
return result;
}
return result;
}
static int presto_psdev_open(struct inode * inode, struct file * file)
{
ENTRY;
file->private_data = NULL;
MOD_INC_USE_COUNT;
CDEBUG(D_PSDEV, "Psdev_open: caller: %d, flags: %d\n", current->pid, file->f_flags);
EXIT;
return 0;
}
static int presto_psdev_release(struct inode * inode, struct file * file)
{
struct upc_channel *channel = (struct upc_channel *)file->private_data;
struct upc_req *req;
struct list_head *lh;
ENTRY;
if ( ! channel ) {
CERROR("%s: bad psdev file\n", __FUNCTION__);
return -EBADF;
}
MOD_DEC_USE_COUNT;
CDEBUG(D_PSDEV, "Lento: pid %d\n", current->pid);
channel->uc_pid = 0;
/* Wake up clients so they can return. */
CDEBUG(D_PSDEV, "Wake up clients sleeping for pending.\n");
spin_lock(&channel->uc_lock);
lh = &channel->uc_pending;
while ( (lh = lh->next) != &channel->uc_pending) {
req = list_entry(lh, struct upc_req, rq_chain);
/* Async requests stay around for a new lento */
if (req->rq_flags & REQ_ASYNC) {
continue;
}
/* the sleeper will free the req and data */
req->rq_flags |= REQ_DEAD;
wake_up(&req->rq_sleep);
}
CDEBUG(D_PSDEV, "Wake up clients sleeping for processing\n");
lh = &channel->uc_processing;
while ( (lh = lh->next) != &channel->uc_processing) {
req = list_entry(lh, struct upc_req, rq_chain);
/* freeing of req and data is done by the sleeper */
req->rq_flags |= REQ_DEAD;
wake_up(&req->rq_sleep);
}
spin_unlock(&channel->uc_lock);
CDEBUG(D_PSDEV, "Done.\n");
EXIT;
return 0;
}
static struct file_operations presto_psdev_fops = {
.read = presto_psdev_read,
.write = presto_psdev_write,
.poll = presto_psdev_poll,
.open = presto_psdev_open,
.release = presto_psdev_release
};
/* modules setup */
static struct miscdevice intermezzo_psdev = {
INTERMEZZO_MINOR,
"intermezzo",
&presto_psdev_fops
};
int presto_psdev_init(void)
{
int i;
int err;
if ( (err = misc_register(&intermezzo_psdev)) ) {
CERROR("%s: cannot register %d err %d\n",
__FUNCTION__, INTERMEZZO_MINOR, err);
return -EIO;
}
memset(&izo_channels, 0, sizeof(izo_channels));
for ( i = 0 ; i < MAX_CHANNEL ; i++ ) {
struct upc_channel *channel = &(izo_channels[i]);
INIT_LIST_HEAD(&channel->uc_pending);
INIT_LIST_HEAD(&channel->uc_processing);
INIT_LIST_HEAD(&channel->uc_cache_list);
init_waitqueue_head(&channel->uc_waitq);
channel->uc_lock = SPIN_LOCK_UNLOCKED;
channel->uc_hard = 0;
channel->uc_no_filter = 0;
channel->uc_no_journal = 0;
channel->uc_no_upcall = 0;
channel->uc_timeout = 30;
channel->uc_errorval = 0;
channel->uc_minor = i;
}
return 0;
}
void presto_psdev_cleanup(void)
{
int i;
misc_deregister(&intermezzo_psdev);
for ( i = 0 ; i < MAX_CHANNEL ; i++ ) {
struct upc_channel *channel = &(izo_channels[i]);
struct list_head *lh;
spin_lock(&channel->uc_lock);
if ( ! list_empty(&channel->uc_pending)) {
CERROR("Weird, tell Peter: module cleanup and pending list not empty dev %d\n", i);
}
if ( ! list_empty(&channel->uc_processing)) {
CERROR("Weird, tell Peter: module cleanup and processing list not empty dev %d\n", i);
}
if ( ! list_empty(&channel->uc_cache_list)) {
CERROR("Weird, tell Peter: module cleanup and cache listnot empty dev %d\n", i);
}
lh = channel->uc_pending.next;
while ( lh != &channel->uc_pending) {
struct upc_req *req;
req = list_entry(lh, struct upc_req, rq_chain);
lh = lh->next;
if ( req->rq_flags & REQ_ASYNC ) {
list_del(&(req->rq_chain));
CDEBUG(D_UPCALL, "free pending upcall type %d\n",
req->rq_opcode);
PRESTO_FREE(req->rq_data, req->rq_bufsize);
PRESTO_FREE(req, sizeof(struct upc_req));
} else {
req->rq_flags |= REQ_DEAD;
wake_up(&req->rq_sleep);
}
}
lh = &channel->uc_processing;
while ( (lh = lh->next) != &channel->uc_processing ) {
struct upc_req *req;
req = list_entry(lh, struct upc_req, rq_chain);
list_del(&(req->rq_chain));
req->rq_flags |= REQ_DEAD;
wake_up(&req->rq_sleep);
}
spin_unlock(&channel->uc_lock);
}
}
/*
* lento_upcall and lento_downcall routines
*/
static inline unsigned long lento_waitfor_upcall
(struct upc_channel *channel, struct upc_req *req, int minor)
{
DECLARE_WAITQUEUE(wait, current);
unsigned long posttime;
req->rq_posttime = posttime = jiffies;
add_wait_queue(&req->rq_sleep, &wait);
for (;;) {
if ( izo_channels[minor].uc_hard == 0 )
set_current_state(TASK_INTERRUPTIBLE);
else
set_current_state(TASK_UNINTERRUPTIBLE);
/* got a reply */
if ( req->rq_flags & (REQ_WRITE | REQ_DEAD) )
break;
/* these cases only apply when TASK_INTERRUPTIBLE */
if ( !izo_channels[minor].uc_hard && signal_pending(current) ) {
/* if this process really wants to die, let it go */
if (sigismember(&(current->pending.signal), SIGKILL)||
sigismember(&(current->pending.signal), SIGINT) )
break;
/* signal is present: after timeout always return
really smart idea, probably useless ... */
if ( time_after(jiffies, req->rq_posttime +
izo_channels[minor].uc_timeout * HZ) )
break;
}
schedule();
}
spin_lock(&channel->uc_lock);
list_del_init(&req->rq_chain);
spin_unlock(&channel->uc_lock);
remove_wait_queue(&req->rq_sleep, &wait);
set_current_state(TASK_RUNNING);
CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ld\n",
posttime, jiffies-posttime);
return (jiffies - posttime);
}
/*
* lento_upcall will return an error in the case of
* failed communication with Lento _or_ will peek at Lento
* reply and return Lento's error.
*
* As lento has 2 types of errors, normal errors (positive) and internal
* errors (negative), normal errors are negated, while internal errors
* are all mapped to -EINTR, while showing a nice warning message. (jh)
*
* lento_upcall will always free buffer, either directly, when an upcall
* is read (in presto_psdev_read), when the filesystem is unmounted, or
* when the module is unloaded.
*/
int izo_upc_upcall(int minor, int *size, struct izo_upcall_hdr *buffer,
int async)
{
unsigned long runtime;
struct upc_channel *channel;
struct izo_upcall_resp *out;
struct upc_req *req;
int error = 0;
ENTRY;
channel = &(izo_channels[minor]);
if (channel->uc_no_upcall) {
EXIT;
goto exit_buf;
}
if (!channel->uc_pid && !async) {
EXIT;
error = -ENXIO;
goto exit_buf;
}
/* Format the request message. */
PRESTO_ALLOC(req, sizeof(struct upc_req));
if ( !req ) {
EXIT;
error = -ENOMEM;
goto exit_buf;
}
req->rq_data = (void *)buffer;
req->rq_flags = 0;
req->rq_bufsize = *size;
req->rq_rep_size = 0;
req->rq_opcode = buffer->u_opc;
req->rq_unique = ++channel->uc_seq;
init_waitqueue_head(&req->rq_sleep);
/* Fill in the common input args. */
buffer->u_uniq = req->rq_unique;
buffer->u_async = async;
spin_lock(&channel->uc_lock);
/* Append msg to pending queue and poke Lento. */
list_add(&req->rq_chain, channel->uc_pending.prev);
spin_unlock(&channel->uc_lock);
CDEBUG(D_UPCALL,
"Proc %d waking Lento %d for(opc,uniq) =(%d,%d) msg at %p.\n",
current->pid, channel->uc_pid, req->rq_opcode,
req->rq_unique, req);
wake_up_interruptible(&channel->uc_waitq);
if ( async ) {
/* req, rq_data are freed in presto_psdev_read for async */
req->rq_flags = REQ_ASYNC;
EXIT;
return 0;
}
/* We can be interrupted while we wait for Lento to process
* our request. If the interrupt occurs before Lento has read
* the request, we dequeue and return. If it occurs after the
* read but before the reply, we dequeue, send a signal
* message, and return. If it occurs after the reply we ignore
* it. In no case do we want to restart the syscall. If it
* was interrupted by a lento shutdown (psdev_close), return
* ENODEV. */
/* Go to sleep. Wake up on signals only after the timeout. */
runtime = lento_waitfor_upcall(channel, req, minor);
CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
req->rq_opcode, jiffies - req->rq_posttime,
req->rq_unique, req->rq_rep_size);
CDEBUG(D_UPCALL,
"..process %d woken up by Lento for req at 0x%x, data at %x\n",
current->pid, (int)req, (int)req->rq_data);
if (channel->uc_pid) { /* i.e. Lento is still alive */
/* Op went through, interrupt or not we go on */
if (req->rq_flags & REQ_WRITE) {
out = (struct izo_upcall_resp *)req->rq_data;
/* here we map positive Lento errors to kernel errors */
if ( out->result < 0 ) {
CERROR("Tell Peter: Lento returns negative error %d, for oc %d!\n",
out->result, out->opcode);
out->result = EINVAL;
}
error = -out->result;
CDEBUG(D_UPCALL, "upcall: (u,o,r) (%d, %d, %d) out at %p\n",
out->unique, out->opcode, out->result, out);
*size = req->rq_rep_size;
EXIT;
goto exit_req;
}
/* Interrupted before lento read it. */
if ( !(req->rq_flags & REQ_READ) && signal_pending(current)) {
CDEBUG(D_UPCALL,
"Interrupt before read: (op,un)=(%d,%d), flags %x\n",
req->rq_opcode, req->rq_unique, req->rq_flags);
/* perhaps the best way to convince the app to give up? */
error = -EINTR;
EXIT;
goto exit_req;
}
/* interrupted after Lento did its read, send signal */
if ( (req->rq_flags & REQ_READ) && signal_pending(current) ) {
CDEBUG(D_UPCALL,"Interrupt after read: op = %d.%d, flags = %x\n",
req->rq_opcode, req->rq_unique, req->rq_flags);
error = -EINTR;
} else {
CERROR("Lento: Strange interruption - tell Peter.\n");
error = -EINTR;
}
} else { /* If lento died i.e. !UC_OPEN(channel) */
CERROR("lento_upcall: Lento dead on (op,un) (%d.%d) flags %d\n",
req->rq_opcode, req->rq_unique, req->rq_flags);
error = -ENODEV;
}
exit_req:
PRESTO_FREE(req, sizeof(struct upc_req));
exit_buf:
return error;
}
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2001 Cluster File Systems, Inc. <[email protected]>
* Copyright (C) 2001 Tacit Networks, Inc. <[email protected]>
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Manage RCVD records for clients in the kernel
*
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <stdarg.h>
#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/intermezzo_fs.h>
/*
* this file contains a hash table of replicators/clients for a
* fileset. It allows fast lookup and update of reintegration status
*/
struct izo_offset_rec {
struct list_head or_list;
char or_uuid[16];
loff_t or_offset;
};
#define RCACHE_BITS 8
#define RCACHE_SIZE (1 << RCACHE_BITS)
#define RCACHE_MASK (RCACHE_SIZE - 1)
static struct list_head *
izo_rep_cache(void)
{
int i;
struct list_head *cache;
PRESTO_ALLOC(cache, sizeof(struct list_head) * RCACHE_SIZE);
if (cache == NULL) {
CERROR("intermezzo-fatal: no memory for replicator cache\n");
return NULL;
}
memset(cache, 0, sizeof(struct list_head) * RCACHE_SIZE);
for (i = 0; i < RCACHE_SIZE; i++)
INIT_LIST_HEAD(&cache[i]);
return cache;
}
static struct list_head *
izo_rep_hash(struct list_head *cache, char *uuid)
{
return &cache[(RCACHE_MASK & uuid[1])];
}
static void
izo_rep_cache_clean(struct presto_file_set *fset)
{
int i;
struct list_head *bucket;
struct list_head *tmp;
if (fset->fset_clients == NULL)
return;
for (i = 0; i < RCACHE_SIZE; i++) {
tmp = bucket = &fset->fset_clients[i];
tmp = tmp->next;
while (tmp != bucket) {
struct izo_offset_rec *offrec;
tmp = tmp->next;
list_del(tmp);
offrec = list_entry(tmp, struct izo_offset_rec,
or_list);
PRESTO_FREE(offrec, sizeof(struct izo_offset_rec));
}
}
}
struct izo_offset_rec *
izo_rep_cache_find(struct presto_file_set *fset, char *uuid)
{
struct list_head *buck = izo_rep_hash(fset->fset_clients, uuid);
struct list_head *tmp = buck;
struct izo_offset_rec *rec = NULL;
while ( (tmp = tmp->next) != buck ) {
rec = list_entry(tmp, struct izo_offset_rec, or_list);
if ( memcmp(rec->or_uuid, uuid, sizeof(rec->or_uuid)) == 0 )
return rec;
}
return NULL;
}
static int
izo_rep_cache_add(struct presto_file_set *fset, struct izo_rcvd_rec *rec,
loff_t offset)
{
struct izo_offset_rec *offrec;
if (izo_rep_cache_find(fset, rec->lr_uuid)) {
CERROR("izo: duplicate client entry %s off %Ld\n",
fset->fset_name, offset);
return -EINVAL;
}
PRESTO_ALLOC(offrec, sizeof(*offrec));
if (offrec == NULL) {
CERROR("izo: cannot allocate offrec\n");
return -ENOMEM;
}
memcpy(offrec->or_uuid, rec->lr_uuid, sizeof(rec->lr_uuid));
offrec->or_offset = offset;
list_add(&offrec->or_list,
izo_rep_hash(fset->fset_clients, rec->lr_uuid));
return 0;
}
int
izo_rep_cache_init(struct presto_file_set *fset)
{
struct izo_rcvd_rec rec;
loff_t offset = 0, last_offset = 0;
fset->fset_clients = izo_rep_cache();
if (fset->fset_clients == NULL) {
CERROR("Error initializing client cache\n");
return -ENOMEM;
}
while ( presto_fread(fset->fset_rcvd.fd_file, (char *)&rec,
sizeof(rec), &offset) == sizeof(rec) ) {
int rc;
if ((rc = izo_rep_cache_add(fset, &rec, last_offset)) < 0) {
izo_rep_cache_clean(fset);
return rc;
}
last_offset = offset;
}
return 0;
}
/*
* Return local last_rcvd record for the client. Update or create
* if necessary.
*
* XXX: After this call, any -EINVAL from izo_rcvd_get is a real error.
*/
int
izo_repstatus(struct presto_file_set *fset, __u64 client_kmlsize,
struct izo_rcvd_rec *lr_client, struct izo_rcvd_rec *lr_server)
{
int rc;
rc = izo_rcvd_get(lr_server, fset, lr_client->lr_uuid);
if (rc < 0 && rc != -EINVAL) {
return rc;
}
/* client is new or has been reset. */
if (rc < 0 || (client_kmlsize == 0 && lr_client->lr_remote_offset == 0)) {
memset(lr_server, 0, sizeof(*lr_server));
memcpy(lr_server->lr_uuid, lr_client->lr_uuid, sizeof(lr_server->lr_uuid));
rc = izo_rcvd_write(fset, lr_server);
if (rc < 0)
return rc;
}
/* update intersync */
rc = izo_upc_repstatus(presto_f2m(fset), fset->fset_name, lr_server);
return rc;
}
loff_t
izo_rcvd_get(struct izo_rcvd_rec *rec, struct presto_file_set *fset, char *uuid)
{
struct izo_offset_rec *offrec;
struct izo_rcvd_rec tmprec;
loff_t offset;
offrec = izo_rep_cache_find(fset, uuid);
if (offrec == NULL) {
CDEBUG(D_SPECIAL, "izo_get_rcvd: uuid not in hash.\n");
return -EINVAL;
}
offset = offrec->or_offset;
if (rec == NULL)
return offset;
if (presto_fread(fset->fset_rcvd.fd_file, (char *)&tmprec,
sizeof(tmprec), &offset) != sizeof(tmprec)) {
CERROR("izo_get_rcvd: Unable to read from last_rcvd file offset "
"%Lu\n", offset);
return -EIO;
}
memcpy(rec->lr_uuid, tmprec.lr_uuid, sizeof(tmprec.lr_uuid));
rec->lr_remote_recno = le64_to_cpu(tmprec.lr_remote_recno);
rec->lr_remote_offset = le64_to_cpu(tmprec.lr_remote_offset);
rec->lr_local_recno = le64_to_cpu(tmprec.lr_local_recno);
rec->lr_local_offset = le64_to_cpu(tmprec.lr_local_offset);
rec->lr_last_ctime = le64_to_cpu(tmprec.lr_last_ctime);
return offrec->or_offset;
}
/* Try to lookup the UUID in the hash. Insert it if it isn't found. Write the
* data to the file.
*
* Returns the offset of the beginning of the record in the last_rcvd file. */
loff_t
izo_rcvd_write(struct presto_file_set *fset, struct izo_rcvd_rec *rec)
{
struct izo_offset_rec *offrec;
loff_t offset, rc;
ENTRY;
offrec = izo_rep_cache_find(fset, rec->lr_uuid);
if (offrec == NULL) {
/* I don't think it should be possible for an entry to be not in
* the hash table without also having an invalid offset, but we
* handle it gracefully regardless. */
write_lock(&fset->fset_rcvd.fd_lock);
offset = fset->fset_rcvd.fd_offset;
fset->fset_rcvd.fd_offset += sizeof(*rec);
write_unlock(&fset->fset_rcvd.fd_lock);
rc = izo_rep_cache_add(fset, rec, offset);
if (rc < 0) {
EXIT;
return rc;
}
} else
offset = offrec->or_offset;
rc = presto_fwrite(fset->fset_rcvd.fd_file, (char *)rec, sizeof(*rec),
&offset);
if (rc == sizeof(*rec))
/* presto_fwrite() advances 'offset' */
rc = offset - sizeof(*rec);
EXIT;
return rc;
}
loff_t
izo_rcvd_upd_remote(struct presto_file_set *fset, char * uuid, __u64 remote_recno,
__u64 remote_offset)
{
struct izo_rcvd_rec rec;
loff_t rc;
ENTRY;
rc = izo_rcvd_get(&rec, fset, uuid);
if (rc < 0)
return rc;
rec.lr_remote_recno = remote_recno;
rec.lr_remote_offset = remote_offset;
rc = izo_rcvd_write(fset, &rec);
EXIT;
if (rc < 0)
return rc;
return 0;
}
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 1998 Peter J. Braam <[email protected]>
* Copyright (C) 2000 Stelias Computing, Inc.
* Copyright (C) 2000 Red Hat, Inc.
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* presto's super.c
*/
static char rcsid[] __attribute ((unused)) = "$Id: super.c,v 1.1 2002/10/11 22:52:01 braam Exp $";
#define INTERMEZZO_VERSION "$Revision: 1.1 $"
#include <stdarg.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/devfs_fs_kernel.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
#ifdef PRESTO_DEBUG
long presto_vmemory = 0;
long presto_kmemory = 0;
#endif
/* returns an allocated string, copied out from data if opt is found */
static char *opt_read(const char *opt, char *data)
{
char *value;
char *retval;
CDEBUG(D_SUPER, "option: %s, data %s\n", opt, data);
if ( strncmp(opt, data, strlen(opt)) )
return NULL;
if ( (value = strchr(data, '=')) == NULL )
return NULL;
value++;
PRESTO_ALLOC(retval, strlen(value) + 1);
if ( !retval ) {
CERROR("InterMezzo: Out of memory!\n");
return NULL;
}
strcpy(retval, value);
CDEBUG(D_SUPER, "Assigned option: %s, value %s\n", opt, retval);
return retval;
}
static void opt_store(char **dst, char *opt)
{
if (!dst)
CERROR("intermezzo: store_opt, error dst == NULL\n");
if (*dst)
PRESTO_FREE(*dst, strlen(*dst) + 1);
*dst = opt;
}
static void opt_set_default(char **dst, char *defval)
{
if (!dst)
CERROR("intermezzo: store_opt, error dst == NULL\n");
if (*dst)
PRESTO_FREE(*dst, strlen(*dst) + 1);
if (defval) {
char *def_alloced;
PRESTO_ALLOC(def_alloced, strlen(defval)+1);
if (!def_alloced) {
CERROR("InterMezzo: Out of memory!\n");
return ;
}
strcpy(def_alloced, defval);
*dst = def_alloced;
}
}
/* Find the options for InterMezzo in "options", saving them into the
* passed pointers. If the pointer is null, the option is discarded.
* Copy out all non-InterMezzo options into cache_data (to be passed
* to the read_super operation of the cache). The return value will
* be a pointer to the end of the cache_data.
*/
static char *presto_options(struct super_block *sb,
char *options, char *cache_data,
char **cache_type, char **fileset,
char **channel)
{
char *this_char;
char *cache_data_end = cache_data;
/* set the defaults */
if (strcmp(sb->s_type->name, "intermezzo") == 0)
opt_set_default(cache_type, "ext3");
else
opt_set_default(cache_type, "tmpfs");
if (!options || !cache_data)
return cache_data_end;
CDEBUG(D_SUPER, "parsing options\n");
for (this_char = strtok (options, ",");
this_char != NULL;
this_char = strtok (NULL, ",")) {
char *opt;
CDEBUG(D_SUPER, "this_char %s\n", this_char);
if ( (opt = opt_read("fileset", this_char)) ) {
opt_store(fileset, opt);
continue;
}
if ( (opt = opt_read("cache_type", this_char)) ) {
opt_store(cache_type, opt);
continue;
}
if ( (opt = opt_read("channel", this_char)) ) {
opt_store(channel, opt);
continue;
}
cache_data_end +=
sprintf(cache_data_end, "%s%s",
cache_data_end != cache_data ? ",":"",
this_char);
}
return cache_data_end;
}
static int presto_set_channel(struct presto_cache *cache, char *channel)
{
int minor;
ENTRY;
if (!channel) {
minor = izo_psdev_get_free_channel();
} else {
minor = simple_strtoul(channel, NULL, 0);
}
if (minor < 0 || minor >= MAX_CHANNEL) {
CERROR("all channels in use or channel too large %d\n",
minor);
return -EINVAL;
}
cache->cache_psdev = &(izo_channels[minor]);
list_add(&cache->cache_channel_list,
&cache->cache_psdev->uc_cache_list);
EXIT;
return minor;
}
/* We always need to remove the presto options before passing
mount options to cache FS */
struct super_block * presto_read_super(struct super_block * sb,
void * data, int silent)
{
struct file_system_type *fstype;
struct presto_cache *cache = NULL;
char *cache_data = NULL;
char *cache_data_end;
char *cache_type = NULL;
char *fileset = NULL;
char *channel = NULL;
int err;
unsigned int minor;
ENTRY;
/* reserve space for the cache's data */
PRESTO_ALLOC(cache_data, PAGE_SIZE);
if ( !cache_data ) {
CERROR("presto_read_super: Cannot allocate data page.\n");
EXIT;
goto out_err;
}
/* read and validate options */
cache_data_end = presto_options(sb, data, cache_data, &cache_type,
&fileset, &channel);
/* was there anything for the cache filesystem in the data? */
if (cache_data_end == cache_data) {
PRESTO_FREE(cache_data, PAGE_SIZE);
cache_data = NULL;
} else {
CDEBUG(D_SUPER, "cache_data at %p is: %s\n", cache_data,
cache_data);
}
/* set up the cache */
cache = presto_cache_init();
if ( !cache ) {
CERROR("presto_read_super: failure allocating cache.\n");
EXIT;
goto out_err;
}
cache->cache_type = cache_type;
/* link cache to channel */
minor = presto_set_channel(cache, channel);
if (minor < 0) {
EXIT;
goto out_err;
}
CDEBUG(D_SUPER, "Presto: type=%s, fset=%s, dev= %d, flags %x\n",
cache_type, fileset?fileset:"NULL", minor, cache->cache_flags);
MOD_INC_USE_COUNT;
/* get the filter for the cache */
fstype = get_fs_type(cache_type);
cache->cache_filter = filter_get_filter_fs((const char *)cache_type);
if ( !fstype || !cache->cache_filter) {
CERROR("Presto: unrecognized fs type or cache type\n");
MOD_DEC_USE_COUNT;
EXIT;
goto out_err;
}
/* can we in fact mount the cache */
if ((fstype->fs_flags & FS_REQUIRES_DEV) && !sb->s_bdev) {
CERROR("filesystem \"%s\" requires a valid block device\n",
cache_type);
MOD_DEC_USE_COUNT;
EXIT;
goto out_err;
}
sb = fstype->read_super(sb, cache_data, silent);
/* this might have been freed above */
if (cache_data) {
PRESTO_FREE(cache_data, PAGE_SIZE);
cache_data = NULL;
}
if ( !sb ) {
CERROR("InterMezzo: cache mount failure.\n");
MOD_DEC_USE_COUNT;
EXIT;
goto out_err;
}
cache->cache_sb = sb;
cache->cache_root = dget(sb->s_root);
/* we now know the dev of the cache: hash the cache */
presto_cache_add(cache, sb->s_dev);
err = izo_prepare_fileset(sb->s_root, fileset);
filter_setup_journal_ops(cache->cache_filter, cache->cache_type);
/* make sure we have our own super operations: sb
still contains the cache operations */
filter_setup_super_ops(cache->cache_filter, sb->s_op,
&presto_super_ops);
sb->s_op = filter_c2usops(cache->cache_filter);
/* get izo directory operations: sb->s_root->d_inode exists now */
filter_setup_dir_ops(cache->cache_filter, sb->s_root->d_inode,
&presto_dir_iops, &presto_dir_fops);
filter_setup_dentry_ops(cache->cache_filter, sb->s_root->d_op,
&presto_dentry_ops);
sb->s_root->d_inode->i_op = filter_c2udiops(cache->cache_filter);
sb->s_root->d_inode->i_fop = filter_c2udfops(cache->cache_filter);
sb->s_root->d_op = filter_c2udops(cache->cache_filter);
EXIT;
return sb;
out_err:
CDEBUG(D_SUPER, "out_err called\n");
if (cache)
PRESTO_FREE(cache, sizeof(struct presto_cache));
if (cache_data)
PRESTO_FREE(cache_data, PAGE_SIZE);
if (fileset)
PRESTO_FREE(fileset, strlen(fileset) + 1);
if (channel)
PRESTO_FREE(channel, strlen(channel) + 1);
if (cache_type)
PRESTO_FREE(cache_type, strlen(cache_type) + 1);
CDEBUG(D_MALLOC, "mount error exit: kmem %ld, vmem %ld\n",
presto_kmemory, presto_vmemory);
return NULL;
}
#ifdef PRESTO_DEVEL
static DECLARE_FSTYPE(presto_fs_type, "izo", presto_read_super, FS_REQUIRES_DEV);
static DECLARE_FSTYPE(vpresto_fs_type, "vintermezzo", presto_read_super, FS_LITTER);
#else
static DECLARE_FSTYPE(vpresto_fs_type, "vintermezzo", presto_read_super, FS_LITTER);
static DECLARE_FSTYPE(presto_fs_type, "intermezzo", presto_read_super, FS_REQUIRES_DEV);
#endif
int __init init_intermezzo_fs(void)
{
int status;
printk(KERN_INFO "InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION
" [email protected]\n");
status = presto_psdev_init();
if ( status ) {
CERROR("Problem (%d) in init_intermezzo_psdev\n", status);
return status;
}
status = init_intermezzo_sysctl();
if (status) {
CERROR("presto: failed in init_intermezzo_sysctl!\n");
}
presto_cache_init_hash();
if (!presto_init_ddata_cache()) {
CERROR("presto out of memory!\n");
return -ENOMEM;
}
status = register_filesystem(&presto_fs_type);
if (status) {
CERROR("presto: failed in register_filesystem!\n");
}
status = register_filesystem(&vpresto_fs_type);
if (status) {
CERROR("vpresto: failed in register_filesystem!\n");
}
return status;
}
void __exit exit_intermezzo_fs(void)
{
int err;
ENTRY;
if ( (err = unregister_filesystem(&presto_fs_type)) != 0 ) {
CERROR("presto: failed to unregister filesystem\n");
}
if ( (err = unregister_filesystem(&vpresto_fs_type)) != 0 ) {
CERROR("vpresto: failed to unregister filesystem\n");
}
presto_psdev_cleanup();
cleanup_intermezzo_sysctl();
presto_cleanup_ddata_cache();
CERROR("after cleanup: kmem %ld, vmem %ld\n",
presto_kmemory, presto_vmemory);
}
MODULE_AUTHOR("Cluster Filesystems Inc. <[email protected]>");
MODULE_DESCRIPTION("InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION);
MODULE_LICENSE("GPL");
module_init(init_intermezzo_fs)
module_exit(exit_intermezzo_fs)
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 1999 Peter J. Braam <[email protected]>
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Sysctrl entries for Intermezzo!
*/
#define __NO_VERSION__
#include <linux/config.h> /* for CONFIG_PROC_FS */
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/swapctl.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/stat.h>
#include <linux/ctype.h>
#include <linux/init.h>
#include <asm/bitops.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/utsname.h>
#include <linux/blk.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
/* /proc entries */
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_fs_intermezzo;
int intermezzo_mount_get_info( char * buffer, char ** start, off_t offset,
int length)
{
int len=0;
/* this works as long as we are below 1024 characters! */
*start = buffer + offset;
len -= offset;
if ( len < 0 )
return -EINVAL;
return len;
}
#endif
/* SYSCTL below */
static struct ctl_table_header *intermezzo_table_header = NULL;
/* 0x100 to avoid any chance of collisions at any point in the tree with
* non-directories
*/
#define PSDEV_INTERMEZZO (0x100)
#define PSDEV_DEBUG 1 /* control debugging */
#define PSDEV_TRACE 2 /* control enter/leave pattern */
#define PSDEV_TIMEOUT 3 /* timeout on upcalls to become intrble */
#define PSDEV_HARD 4 /* mount type "hard" or "soft" */
#define PSDEV_NO_FILTER 5 /* controls presto_chk */
#define PSDEV_NO_JOURNAL 6 /* controls presto_chk */
#define PSDEV_NO_UPCALL 7 /* controls lento_upcall */
#define PSDEV_ERRORVAL 8 /* controls presto_debug_fail_blkdev */
#define PSDEV_EXCL_GID 9 /* which GID is ignored by presto */
#define PSDEV_BYTES_TO_CLOSE 11 /* bytes to write before close */
/* These are global presto control options */
#define PRESTO_PRIMARY_CTLCNT 2
static struct ctl_table presto_table[ PRESTO_PRIMARY_CTLCNT + MAX_CHANNEL + 1] =
{
{PSDEV_DEBUG, "debug", &presto_debug, sizeof(int), 0644, NULL, &proc_dointvec},
{PSDEV_TRACE, "trace", &presto_print_entry, sizeof(int), 0644, NULL, &proc_dointvec},
};
/*
* Intalling the sysctl entries: strategy
* - have templates for each /proc/sys/intermezzo/ entry
* such an entry exists for each /dev/presto
* (proto_channel_entry)
* - have a template for the contents of such directories
* (proto_psdev_table)
* - have the master table (presto_table)
*
* When installing, malloc, memcpy and fix up the pointers to point to
* the appropriate constants in izo_channels[your_minor]
*/
static ctl_table proto_psdev_table[] = {
{PSDEV_HARD, "hard", 0, sizeof(int), 0644, NULL, &proc_dointvec},
{PSDEV_NO_FILTER, "no_filter", 0, sizeof(int), 0644, NULL, &proc_dointvec},
{PSDEV_NO_JOURNAL, "no_journal", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
{PSDEV_NO_UPCALL, "no_upcall", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
{PSDEV_TIMEOUT, "timeout", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
#ifdef PRESTO_DEBUG
{PSDEV_ERRORVAL, "errorval", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
#endif
{ 0 }
};
static ctl_table proto_channel_entry = {
PSDEV_INTERMEZZO, 0, NULL, 0, 0555, 0,
};
static ctl_table intermezzo_table[2] = {
{PSDEV_INTERMEZZO, "intermezzo", NULL, 0, 0555, presto_table},
{0}
};
/* support for external setting and getting of opts. */
/* particularly via ioctl. The Right way to do this is via sysctl,
* but that will have to wait until intermezzo gets its own nice set of
* sysctl IDs
*/
/* we made these separate as setting may in future be more restricted
* than getting
*/
#ifdef RON_MINNICH
int dosetopt(int minor, struct psdev_opt *opt)
{
int retval = 0;
int newval = opt->optval;
ENTRY;
switch(opt->optname) {
case PSDEV_TIMEOUT:
izo_channels[minor].uc_timeout = newval;
break;
case PSDEV_HARD:
izo_channels[minor].uc_hard = newval;
break;
case PSDEV_NO_FILTER:
izo_channels[minor].uc_no_filter = newval;
break;
case PSDEV_NO_JOURNAL:
izo_channels[minor].uc_no_journal = newval;
break;
case PSDEV_NO_UPCALL:
izo_channels[minor].uc_no_upcall = newval;
break;
#ifdef PRESTO_DEBUG
case PSDEV_ERRORVAL: {
/* If we have a positive arg, set a breakpoint for that
* value. If we have a negative arg, make that device
* read-only. FIXME It would be much better to only
* allow setting the underlying device read-only for the
* current presto cache.
*/
int errorval = izo_channels[minor].uc_errorval;
if (errorval < 0) {
if (newval == 0)
set_device_ro(-errorval, 0);
else
CERROR("device %s already read only\n",
kdevname(-errorval));
} else {
if (newval < 0)
set_device_ro(-newval, 1);
izo_channels[minor].uc_errorval = newval;
CDEBUG(D_PSDEV, "setting errorval to %d\n", newval);
}
break;
}
#endif
case PSDEV_TRACE:
case PSDEV_DEBUG:
case PSDEV_BYTES_TO_CLOSE:
default:
CDEBUG(D_PSDEV,
"ioctl: dosetopt: minor %d, bad optname 0x%x, \n",
minor, opt->optname);
retval = -EINVAL;
}
EXIT;
return retval;
}
int dogetopt(int minor, struct psdev_opt *opt)
{
int retval = 0;
ENTRY;
switch(opt->optname) {
case PSDEV_TIMEOUT:
opt->optval = izo_channels[minor].uc_timeout;
break;
case PSDEV_HARD:
opt->optval = izo_channels[minor].uc_hard;
break;
case PSDEV_NO_FILTER:
opt->optval = izo_channels[minor].uc_no_filter;
break;
case PSDEV_NO_JOURNAL:
opt->optval = izo_channels[minor].uc_no_journal;
break;
case PSDEV_NO_UPCALL:
opt->optval = izo_channels[minor].uc_no_upcall;
break;
#ifdef PSDEV_DEBUG
case PSDEV_ERRORVAL: {
int errorval = izo_channels[minor].uc_errorval;
if (errorval < 0 && is_read_only(-errorval))
CERROR("device %s has been set read-only\n",
kdevname(-errorval));
opt->optval = izo_channels[minor].uc_errorval;
break;
}
#endif
case PSDEV_TRACE:
case PSDEV_DEBUG:
case PSDEV_BYTES_TO_CLOSE:
default:
CDEBUG(D_PSDEV,
"ioctl: dogetopt: minor %d, bad optval 0x%x, \n",
minor, opt->optname);
retval = -EINVAL;
}
EXIT;
return retval;
}
#endif
/* allocate the tables for the presto devices. We need
* sizeof(proto_channel_table)/sizeof(proto_channel_table[0])
* entries for each dev
*/
int /* __init */ init_intermezzo_sysctl(void)
{
int i;
int total_dev = MAX_CHANNEL;
int entries_per_dev = sizeof(proto_psdev_table) /
sizeof(proto_psdev_table[0]);
int total_entries = entries_per_dev * total_dev;
ctl_table *dev_ctl_table;
PRESTO_ALLOC(dev_ctl_table, sizeof(ctl_table) * total_entries);
if (! dev_ctl_table) {
CERROR("WARNING: presto couldn't allocate dev_ctl_table\n");
EXIT;
return -ENOMEM;
}
/* now fill in the entries ... we put the individual presto<x>
* entries at the end of the table, and the per-presto stuff
* starting at the front. We assume that the compiler makes
* this code more efficient, but really, who cares ... it
* happens once per reboot.
*/
for(i = 0; i < total_dev; i++) {
/* entry for this /proc/sys/intermezzo/intermezzo"i" */
ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT];
/* entries for the individual "files" in this "directory" */
ctl_table *psdev_entries = &dev_ctl_table[i * entries_per_dev];
/* init the psdev and psdev_entries with the prototypes */
*psdev = proto_channel_entry;
memcpy(psdev_entries, proto_psdev_table,
sizeof(proto_psdev_table));
/* now specialize them ... */
/* the psdev has to point to psdev_entries, and fix the number */
psdev->ctl_name = psdev->ctl_name + i + 1; /* sorry */
PRESTO_ALLOC((void*)psdev->procname, PROCNAME_SIZE);
if (!psdev->procname) {
PRESTO_FREE(dev_ctl_table,
sizeof(ctl_table) * total_entries);
return -ENOMEM;
}
sprintf((char *) psdev->procname, "intermezzo%d", i);
/* hook presto into */
psdev->child = psdev_entries;
/* now for each psdev entry ... */
psdev_entries[0].data = &(izo_channels[i].uc_hard);
psdev_entries[1].data = &(izo_channels[i].uc_no_filter);
psdev_entries[2].data = &(izo_channels[i].uc_no_journal);
psdev_entries[3].data = &(izo_channels[i].uc_no_upcall);
psdev_entries[4].data = &(izo_channels[i].uc_timeout);
#ifdef PRESTO_DEBUG
psdev_entries[5].data = &(izo_channels[i].uc_errorval);
#endif
}
#ifdef CONFIG_SYSCTL
if ( !intermezzo_table_header )
intermezzo_table_header =
register_sysctl_table(intermezzo_table, 0);
#endif
#ifdef CONFIG_PROC_FS
proc_fs_intermezzo = proc_mkdir("intermezzo", proc_root_fs);
proc_fs_intermezzo->owner = THIS_MODULE;
create_proc_info_entry("mounts", 0, proc_fs_intermezzo,
intermezzo_mount_get_info);
#endif
return 0;
}
void cleanup_intermezzo_sysctl(void)
{
int total_dev = MAX_CHANNEL;
int entries_per_dev = sizeof(proto_psdev_table) /
sizeof(proto_psdev_table[0]);
int total_entries = entries_per_dev * total_dev;
int i;
#ifdef CONFIG_SYSCTL
if ( intermezzo_table_header )
unregister_sysctl_table(intermezzo_table_header);
intermezzo_table_header = NULL;
#endif
for(i = 0; i < total_dev; i++) {
/* entry for this /proc/sys/intermezzo/intermezzo"i" */
ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT];
PRESTO_FREE(psdev->procname, PROCNAME_SIZE);
}
/* presto_table[PRESTO_PRIMARY_CTLCNT].child points to the
* dev_ctl_table previously allocated in init_intermezzo_psdev()
*/
PRESTO_FREE(presto_table[PRESTO_PRIMARY_CTLCNT].child, sizeof(ctl_table) * total_entries);
#if CONFIG_PROC_FS
remove_proc_entry("mounts", proc_fs_intermezzo);
remove_proc_entry("intermezzo", proc_root_fs);
#endif
}
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2001, 2002 Cluster File Systems, Inc. <[email protected]>
* Copyright (C) 2001 Tacit Networks, Inc. <[email protected]>
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with InterMezzo; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Mostly platform independent upcall operations to a cache manager:
* -- upcalls
* -- upcall routines
*
*/
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/signal.h>
#include <linux/signal.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/locks.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <asm/segment.h>
#include <linux/intermezzo_lib.h>
#include <linux/intermezzo_fs.h>
#include <linux/intermezzo_psdev.h>
#include <linux/intermezzo_idl.h>
/*
At present:
-- Asynchronous calls:
- kml: give a "more" kml indication to userland
- kml_truncate: initiate KML truncation
- release_permit: kernel is done with permit
-- Synchronous
- open: fetch file
- permit: get a permit
Errors returned by user level code are positive
*/
static struct izo_upcall_hdr *upc_pack(__u32 opcode, int pathlen, char *path,
char *fsetname, int reclen, char *rec,
int *size)
{
struct izo_upcall_hdr *hdr;
char *ptr;
ENTRY;
*size = sizeof(struct izo_upcall_hdr);
if ( fsetname ) {
*size += round_strlen(fsetname);
}
if ( path ) {
*size += round_strlen(path);
}
if ( rec ) {
*size += size_round(reclen);
}
PRESTO_ALLOC(hdr, *size);
if (!hdr) {
CERROR("intermezzo upcall: out of memory (opc %d)\n", opcode);
EXIT;
return NULL;
}
memset(hdr, 0, *size);
ptr = (char *)hdr + sizeof(*hdr);
/* XXX do we need fsuid ? */
hdr->u_len = *size;
hdr->u_version = IZO_UPC_VERSION;
hdr->u_opc = opcode;
hdr->u_pid = current->pid;
hdr->u_uid = current->fsuid;
if (path) {
/*XXX Robert: please review what len to pass in for
NUL terminated strings */
hdr->u_pathlen = strlen(path);
LOGL0(path, hdr->u_pathlen, ptr);
}
if (fsetname) {
hdr->u_fsetlen = strlen(fsetname);
LOGL0(fsetname, strlen(fsetname), ptr);
}
if (rec) {
hdr->u_reclen = reclen;
LOGL(rec, reclen, ptr);
}
EXIT;
return hdr;
}
/* the upcalls */
int izo_upc_kml(int minor, __u64 offset, __u32 first_recno, __u64 length, __u32 last_recno, char *fsetname)
{
int size;
int error;
struct izo_upcall_hdr *hdr;
ENTRY;
if (!presto_lento_up(minor)) {
EXIT;
return 0;
}
hdr = upc_pack(IZO_UPC_KML, 0, NULL, fsetname, 0, NULL, &size);
if (!hdr || IS_ERR(hdr)) {
EXIT;
return -PTR_ERR(hdr);
}
hdr->u_offset = offset;
hdr->u_first_recno = first_recno;
hdr->u_length = length;
hdr->u_last_recno = last_recno;
CDEBUG(D_UPCALL, "KML: fileset %s, offset %Lu, length %Lu, "
"first %u, last %d; minor %d\n",
fsetname, hdr->u_offset, hdr->u_length, hdr->u_first_recno,
hdr->u_last_recno, minor);
error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
EXIT;
return -error;
}
int izo_upc_kml_truncate(int minor, __u64 length, __u32 last_recno, char *fsetname)
{
int size;
int error;
struct izo_upcall_hdr *hdr;
ENTRY;
if (!presto_lento_up(minor)) {
EXIT;
return 0;
}
hdr = upc_pack(IZO_UPC_KML_TRUNC, 0, NULL, fsetname, 0, NULL, &size);
if (!hdr || IS_ERR(hdr)) {
EXIT;
return -PTR_ERR(hdr);
}
hdr->u_length = length;
hdr->u_last_recno = last_recno;
CDEBUG(D_UPCALL, "KML TRUNCATE: fileset %s, length %Lu, "
"last recno %d, minor %d\n",
fsetname, hdr->u_length, hdr->u_last_recno, minor);
error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
EXIT;
return error;
}
int izo_upc_open(int minor, __u32 pathlen, char *path, char *fsetname, struct lento_vfs_context *info)
{
int size;
int error;
struct izo_upcall_hdr *hdr;
ENTRY;
if (!presto_lento_up(minor)) {
EXIT;
return -EIO;
}
hdr = upc_pack(IZO_UPC_OPEN, pathlen, path, fsetname,
sizeof(*info), (char*)info, &size);
if (!hdr || IS_ERR(hdr)) {
EXIT;
return -PTR_ERR(hdr);
}
CDEBUG(D_UPCALL, "path %s\n", path);
error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
if (error)
CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
EXIT;
return -error;
}
int izo_upc_get_fileid(int minor, __u32 reclen, char *rec,
__u32 pathlen, char *path, char *fsetname)
{
int size;
int error;
struct izo_upcall_hdr *hdr;
ENTRY;
if (!presto_lento_up(minor)) {
EXIT;
return -EIO;
}
hdr = upc_pack(IZO_UPC_GET_FILEID, pathlen, path, fsetname, reclen, rec, &size);
if (!hdr || IS_ERR(hdr)) {
EXIT;
return -PTR_ERR(hdr);
}
CDEBUG(D_UPCALL, "path %s\n", path);
error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
if (error)
CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
EXIT;
return -error;
}
int izo_upc_backfetch(int minor, char *path, char *fsetname, struct lento_vfs_context *info)
{
int size;
int error;
struct izo_upcall_hdr *hdr;
ENTRY;
if (!presto_lento_up(minor)) {
EXIT;
return -EIO;
}
hdr = upc_pack(IZO_UPC_BACKFETCH, strlen(path), path, fsetname,
sizeof(*info), (char *)info, &size);
if (!hdr || IS_ERR(hdr)) {
EXIT;
return -PTR_ERR(hdr);
}
/* This is currently synchronous, kml_reint_record blocks */
error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
if (error)
CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
EXIT;
return -error;
}
int izo_upc_permit(int minor, struct dentry *dentry, __u32 pathlen, char *path,
char *fsetname)
{
int size;
int error;
struct izo_upcall_hdr *hdr;
ENTRY;
hdr = upc_pack(IZO_UPC_PERMIT, pathlen, path, fsetname, 0, NULL, &size);
if (!hdr || IS_ERR(hdr)) {
EXIT;
return -PTR_ERR(hdr);
}
CDEBUG(D_UPCALL, "Permit minor %d path %s\n", minor, path);
error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
if (error == -EROFS) {
int err;
CERROR("InterMezzo: ERROR - requested permit for read-only "
"fileset.\n Setting \"%s\" read-only!\n", path);
err = izo_mark_cache(dentry, 0xFFFFFFFF, CACHE_CLIENT_RO, NULL);
if (err)
CERROR("InterMezzo ERROR: mark_cache %d\n", err);
} else if (error) {
CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
}
EXIT;
return error;
}
/* This is a ping-pong upcall handled on the server when a client (uuid)
* requests the permit for itself. */
int izo_upc_revoke_permit(int minor, char *fsetname, __u8 uuid[16])
{
int size;
int error;
struct izo_upcall_hdr *hdr;
ENTRY;
hdr = upc_pack(IZO_UPC_REVOKE_PERMIT, 0, NULL, fsetname, 0, NULL, &size);
if (!hdr || IS_ERR(hdr)) {
EXIT;
return -PTR_ERR(hdr);
}
memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
if (error)
CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
EXIT;
return -error;
}
int izo_upc_go_fetch_kml(int minor, char *fsetname, __u8 uuid[16],
__u64 kmlsize)
{
int size;
int error;
struct izo_upcall_hdr *hdr;
ENTRY;
if (!presto_lento_up(minor)) {
EXIT;
return -EIO;
}
hdr = upc_pack(IZO_UPC_GO_FETCH_KML, 0, NULL, fsetname, 0, NULL, &size);
if (!hdr || IS_ERR(hdr)) {
EXIT;
return -PTR_ERR(hdr);
}
hdr->u_offset = kmlsize;
memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
if (error)
CERROR("%s: error %d\n", __FUNCTION__, error);
EXIT;
return -error;
}
int izo_upc_connect(int minor, __u64 ip_address, __u64 port, __u8 uuid[16],
int client_flag)
{
int size;
int error;
struct izo_upcall_hdr *hdr;
ENTRY;
if (!presto_lento_up(minor)) {
EXIT;
return -EIO;
}
hdr = upc_pack(IZO_UPC_CONNECT, 0, NULL, NULL, 0, NULL, &size);
if (!hdr || IS_ERR(hdr)) {
EXIT;
return -PTR_ERR(hdr);
}
hdr->u_offset = ip_address;
hdr->u_length = port;
memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
hdr->u_first_recno = client_flag;
error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
if (error) {
CERROR("%s: error %d\n", __FUNCTION__, error);
}
EXIT;
return -error;
}
int izo_upc_set_kmlsize(int minor, char *fsetname, __u8 uuid[16], __u64 kmlsize)
{
int size;
int error;
struct izo_upcall_hdr *hdr;
ENTRY;
if (!presto_lento_up(minor)) {
EXIT;
return -EIO;
}
hdr = upc_pack(IZO_UPC_SET_KMLSIZE, 0, NULL, fsetname, 0, NULL, &size);
if (!hdr || IS_ERR(hdr)) {
EXIT;
return -PTR_ERR(hdr);
}
memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
hdr->u_length = kmlsize;
error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
if (error)
CERROR("%s: error %d\n", __FUNCTION__, error);
EXIT;
return -error;
}
int izo_upc_repstatus(int minor, char * fsetname, struct izo_rcvd_rec *lr_server)
{
int size;
int error;
struct izo_upcall_hdr *hdr;
ENTRY;
if (!presto_lento_up(minor)) {
EXIT;
return -EIO;
}
hdr = upc_pack(IZO_UPC_REPSTATUS, 0, NULL, fsetname,
sizeof(*lr_server), (char*)lr_server,
&size);
if (!hdr || IS_ERR(hdr)) {
EXIT;
return -PTR_ERR(hdr);
}
error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
if (error)
CERROR("%s: error %d\n", __FUNCTION__, error);
EXIT;
return -error;
}
#if 0
int izo_upc_client_make_branch(int minor, char *fsetname, char *tagname,
char *branchname)
{
int size, error;
struct izo_upcall_hdr *hdr;
int pathlen;
char *path;
ENTRY;
hdr = upc_pack(IZO_UPC_CLIENT_MAKE_BRANCH, strlen(tagname), tagname,
fsetname, strlen(branchname) + 1, branchname, &size);
if (!hdr || IS_ERR(hdr)) {
error = -PTR_ERR(hdr);
goto error;
}
error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
if (error)
CERROR("InterMezzo: error %d\n", error);
error:
PRESTO_FREE(path, pathlen);
EXIT;
return error;
}
#endif
int izo_upc_server_make_branch(int minor, char *fsetname)
{
int size, error;
struct izo_upcall_hdr *hdr;
ENTRY;
hdr = upc_pack(IZO_UPC_SERVER_MAKE_BRANCH, 0, NULL, fsetname, 0, NULL, &size);
if (!hdr || IS_ERR(hdr)) {
error = -PTR_ERR(hdr);
goto error;
}
error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
if (error)
CERROR("InterMezzo: error %d\n", error);
error:
EXIT;
return -error;
}
int izo_upc_branch_undo(int minor, char *fsetname, char *branchname)
{
int size;
int error;
struct izo_upcall_hdr *hdr;
ENTRY;
if (!presto_lento_up(minor)) {
EXIT;
return -EIO;
}
hdr = upc_pack(IZO_UPC_BRANCH_UNDO, strlen(branchname), branchname,
fsetname, 0, NULL, &size);
if (!hdr || IS_ERR(hdr)) {
EXIT;
return -PTR_ERR(hdr);
}
error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
if (error)
CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
EXIT;
return -error;
}
int izo_upc_branch_redo(int minor, char *fsetname, char *branchname)
{
int size;
int error;
struct izo_upcall_hdr *hdr;
ENTRY;
if (!presto_lento_up(minor)) {
EXIT;
return -EIO;
}
hdr = upc_pack(IZO_UPC_BRANCH_REDO, strlen(branchname) + 1, branchname,
fsetname, 0, NULL, &size);
if (!hdr || IS_ERR(hdr)) {
EXIT;
return -PTR_ERR(hdr);
}
error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
if (error)
CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
EXIT;
return -error;
}
--- NEW FILE ---
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2001, 2002 Cluster File Systems, Inc.
* Copyright (C) 2000 Stelias Computing, Inc.
* Copyright (C) 2000 Red Hat, Inc.
*
* This file is part of InterMezzo, http://www.inter-mezzo.org.
*
* InterMezzo is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* InterMezzo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
[...2426 lines suppressed...]
presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x10);
if ( presto_do_kml(info, dentry) )
error = presto_journal_set_ext_attr
(&rec, fset, dentry, &ver, name, buffer,
buffer_len, flags);
presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x20);
if ( presto_do_rcvd(info, dentry) )
error = presto_write_last_rcvd(&rec, fset, info);
presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x30);
EXIT;
exit:
presto_release_space(fset->fset_cache, PRESTO_REQHIGH);
presto_trans_commit(fset, handle);
return error;
}
#endif
-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf