Commit 9b59f031 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.open-osd.org/linux-open-osd

* 'for-linus' of git://git.open-osd.org/linux-open-osd:
  fs: Add exofs to Kernel build
  exofs: Documentation
  exofs: export_operations
  exofs: super_operations and file_system_type
  exofs: dir_inode and directory operations
  exofs: address_space_operations
  exofs: symlink_inode and fast_symlink_inode operations
  exofs: file and file_inode operations
  exofs: Kbuild, Headers and osd utils
parents ac7c1a77 0d8fe329
===============================================================================
WHAT IS EXOFS?
===============================================================================
exofs is a file system that uses an OSD and exports the API of a normal Linux
file system. Users access exofs like any other local file system, and exofs
will in turn issue commands to the local OSD initiator.
OSD is a new T10 command set that views storage devices not as a large/flat
array of sectors but as a container of objects, each having a length, quota,
time attributes and more. Each object is addressed by a 64bit ID, and is
contained in a 64bit ID partition. Each object has associated attributes
attached to it, which are integral part of the object and provide metadata about
the object. The standard defines some common obligatory attributes, but user
attributes can be added as needed.
===============================================================================
ENVIRONMENT
===============================================================================
To use this file system, you need to have an object store to run it on. You
may download a target from:
http://open-osd.org
See Documentation/scsi/osd.txt for how to setup a working osd environment.
===============================================================================
USAGE
===============================================================================
1. Download and compile exofs and open-osd initiator:
You need an external Kernel source tree or kernel headers from your
distribution. (anything based on 2.6.26 or later).
a. download open-osd including exofs source using:
[parent-directory]$ git clone git://git.open-osd.org/open-osd.git
b. Build the library module like this:
[parent-directory]$ make -C KSRC=$(KER_DIR) open-osd
This will build both the open-osd initiator as well as the exofs kernel
module. Use whatever parameters you compiled your Kernel with and
$(KER_DIR) above pointing to the Kernel you compile against. See the file
open-osd/top-level-Makefile for an example.
2. Get the OSD initiator and target set up properly, and login to the target.
See Documentation/scsi/osd.txt for farther instructions. Also see ./do-osd
for example script that does all these steps.
3. Insmod the exofs.ko module:
[exofs]$ insmod exofs.ko
4. Make sure the directory where you want to mount exists. If not, create it.
(For example, mkdir /mnt/exofs)
5. At first run you will need to invoke the mkfs.exofs application
As an example, this will create the file system on:
/dev/osd0 partition ID 65536
mkfs.exofs --pid=65536 --format /dev/osd0
The --format is optional if not specified no OSD_FORMAT will be
preformed and a clean file system will be created in the specified pid,
in the available space of the target. (Use --format=size_in_meg to limit
the total LUN space available)
If pid already exist it will be deleted and a new one will be created in it's
place. Be careful.
An exofs lives inside a single OSD partition. You can create multiple exofs
filesystems on the same device using multiple pids.
(run mkfs.exofs without any parameters for usage help message)
6. Mount the file system.
For example, to mount /dev/osd0, partition ID 0x10000 on /mnt/exofs:
mount -t exofs -o pid=65536 /dev/osd0 /mnt/exofs/
7. For reference (See do-exofs example script):
do-exofs start - an example of how to perform the above steps.
do-exofs stop - an example of how to unmount the file system.
do-exofs format - an example of how to format and mkfs a new exofs.
8. Extra compilation flags (uncomment in fs/exofs/Kbuild):
CONFIG_EXOFS_DEBUG - for debug messages and extra checks.
===============================================================================
exofs mount options
===============================================================================
Similar to any mount command:
mount -t exofs -o exofs_options /dev/osdX mount_exofs_directory
Where:
-t exofs: specifies the exofs file system
/dev/osdX: X is a decimal number. /dev/osdX was created after a successful
login into an OSD target.
mount_exofs_directory: The directory to mount the file system on
exofs specific options: Options are separated by commas (,)
pid=<integer> - The partition number to mount/create as
container of the filesystem.
This option is mandatory
to=<integer> - Timeout in ticks for a single command
default is (60 * HZ) [for debugging only]
===============================================================================
DESIGN
===============================================================================
* The file system control block (AKA on-disk superblock) resides in an object
with a special ID (defined in common.h).
Information included in the file system control block is used to fill the
in-memory superblock structure at mount time. This object is created before
the file system is used by mkexofs.c It contains information such as:
- The file system's magic number
- The next inode number to be allocated
* Each file resides in its own object and contains the data (and it will be
possible to extend the file over multiple objects, though this has not been
implemented yet).
* A directory is treated as a file, and essentially contains a list of <file
name, inode #> pairs for files that are found in that directory. The object
IDs correspond to the files' inode numbers and will be allocated according to
a bitmap (stored in a separate object). Now they are allocated using a
counter.
* Each file's control block (AKA on-disk inode) is stored in its object's
attributes. This applies to both regular files and other types (directories,
device files, symlinks, etc.).
* Credentials are generated per object (inode and superblock) when they is
created in memory (read off disk or created). The credential works for all
operations and is used as long as the object remains in memory.
* Async OSD operations are used whenever possible, but the target may execute
them out of order. The operations that concern us are create, delete,
readpage, writepage, update_inode, and truncate. The following pairs of
operations should execute in the order written, and we need to prevent them
from executing in reverse order:
- The following are handled with the OBJ_CREATED and OBJ_2BCREATED
flags. OBJ_CREATED is set when we know the object exists on the OSD -
in create's callback function, and when we successfully do a read_inode.
OBJ_2BCREATED is set in the beginning of the create function, so we
know that we should wait.
- create/delete: delete should wait until the object is created
on the OSD.
- create/readpage: readpage should be able to return a page
full of zeroes in this case. If there was a write already
en-route (i.e. create, writepage, readpage) then the page
would be locked, and so it would really be the same as
create/writepage.
- create/writepage: if writepage is called for a sync write, it
should wait until the object is created on the OSD.
Otherwise, it should just return.
- create/truncate: truncate should wait until the object is
created on the OSD.
- create/update_inode: update_inode should wait until the
object is created on the OSD.
- Handled by VFS locks:
- readpage/delete: shouldn't happen because of page lock.
- writepage/delete: shouldn't happen because of page lock.
- readpage/writepage: shouldn't happen because of page lock.
===============================================================================
LICENSE/COPYRIGHT
===============================================================================
The exofs file system is based on ext2 v0.5b (distributed with the Linux kernel
version 2.6.10). All files include the original copyrights, and the license
is GPL version 2 (only version 2, as is true for the Linux kernel). The
Linux kernel can be downloaded from www.kernel.org.
......@@ -169,6 +169,8 @@ source "fs/romfs/Kconfig"
source "fs/sysv/Kconfig"
source "fs/ufs/Kconfig"
source "fs/exofs/Kconfig"
endif # MISC_FILESYSTEMS
menuconfig NETWORK_FILESYSTEMS
......
......@@ -120,3 +120,4 @@ obj-$(CONFIG_DEBUG_FS) += debugfs/
obj-$(CONFIG_OCFS2_FS) += ocfs2/
obj-$(CONFIG_BTRFS_FS) += btrfs/
obj-$(CONFIG_GFS2_FS) += gfs2/
obj-$(CONFIG_EXOFS_FS) += exofs/
- Out-of-space may cause a severe problem if the object (and directory entry)
were written, but the inode attributes failed. Then if the filesystem was
unmounted and mounted the kernel can get into an endless loop doing a readdir.
#
# Kbuild for the EXOFS module
#
# Copyright (C) 2008 Panasas Inc. All rights reserved.
#
# Authors:
# Boaz Harrosh <bharrosh@panasas.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
#
# Kbuild - Gets included from the Kernels Makefile and build system
#
exofs-y := osd.o inode.o file.o symlink.o namei.o dir.o super.o
obj-$(CONFIG_EXOFS_FS) += exofs.o
config EXOFS_FS
tristate "exofs: OSD based file system support"
depends on SCSI_OSD_ULD
help
EXOFS is a file system that uses an OSD storage device,
as its backing storage.
# Debugging-related stuff
config EXOFS_DEBUG
bool "Enable debugging"
depends on EXOFS_FS
help
This option enables EXOFS debug prints.
/*
* common.h - Common definitions for both Kernel and user-mode utilities
*
* Copyright (C) 2005, 2006
* Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
* Copyright (C) 2005, 2006
* International Business Machines
* Copyright (C) 2008, 2009
* Boaz Harrosh <bharrosh@panasas.com>
*
* Copyrights for code taken from ext2:
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* from
* linux/fs/minix/inode.c
* Copyright (C) 1991, 1992 Linus Torvalds
*
* This file is part of exofs.
*
* exofs 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. Since it is based on ext2, and the only
* valid version of GPL for the Linux kernel is version 2, the only valid
* version of GPL for exofs is version 2.
*
* exofs 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 exofs; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __EXOFS_COM_H__
#define __EXOFS_COM_H__
#include <linux/types.h>
#include <scsi/osd_attributes.h>
#include <scsi/osd_initiator.h>
#include <scsi/osd_sec.h>
/****************************************************************************
* Object ID related defines
* NOTE: inode# = object ID - EXOFS_OBJ_OFF
****************************************************************************/
#define EXOFS_MIN_PID 0x10000 /* Smallest partition ID */
#define EXOFS_OBJ_OFF 0x10000 /* offset for objects */
#define EXOFS_SUPER_ID 0x10000 /* object ID for on-disk superblock */
#define EXOFS_ROOT_ID 0x10002 /* object ID for root directory */
/* exofs Application specific page/attribute */
# define EXOFS_APAGE_FS_DATA (OSD_APAGE_APP_DEFINED_FIRST + 3)
# define EXOFS_ATTR_INODE_DATA 1
/*
* The maximum number of files we can have is limited by the size of the
* inode number. This is the largest object ID that the file system supports.
* Object IDs 0, 1, and 2 are always in use (see above defines).
*/
enum {
EXOFS_MAX_INO_ID = (sizeof(ino_t) * 8 == 64) ? ULLONG_MAX :
(1ULL << (sizeof(ino_t) * 8ULL - 1ULL)),
EXOFS_MAX_ID = (EXOFS_MAX_INO_ID - 1 - EXOFS_OBJ_OFF),
};
/****************************************************************************
* Misc.
****************************************************************************/
#define EXOFS_BLKSHIFT 12
#define EXOFS_BLKSIZE (1UL << EXOFS_BLKSHIFT)
/****************************************************************************
* superblock-related things
****************************************************************************/
#define EXOFS_SUPER_MAGIC 0x5DF5
/*
* The file system control block - stored in an object's data (mainly, the one
* with ID EXOFS_SUPER_ID). This is where the in-memory superblock is stored
* on disk. Right now it just has a magic value, which is basically a sanity
* check on our ability to communicate with the object store.
*/
struct exofs_fscb {
__le64 s_nextid; /* Highest object ID used */
__le32 s_numfiles; /* Number of files on fs */
__le16 s_magic; /* Magic signature */
__le16 s_newfs; /* Non-zero if this is a new fs */
};
/****************************************************************************
* inode-related things
****************************************************************************/
#define EXOFS_IDATA 5
/*
* The file control block - stored in an object's attributes. This is where
* the in-memory inode is stored on disk.
*/
struct exofs_fcb {
__le64 i_size; /* Size of the file */
__le16 i_mode; /* File mode */
__le16 i_links_count; /* Links count */
__le32 i_uid; /* Owner Uid */
__le32 i_gid; /* Group Id */
__le32 i_atime; /* Access time */
__le32 i_ctime; /* Creation time */
__le32 i_mtime; /* Modification time */
__le32 i_flags; /* File flags (unused for now)*/
__le32 i_generation; /* File version (for NFS) */
__le32 i_data[EXOFS_IDATA]; /* Short symlink names and device #s */
};
#define EXOFS_INO_ATTR_SIZE sizeof(struct exofs_fcb)
/* This is the Attribute the fcb is stored in */
static const struct __weak osd_attr g_attr_inode_data = ATTR_DEF(
EXOFS_APAGE_FS_DATA,
EXOFS_ATTR_INODE_DATA,
EXOFS_INO_ATTR_SIZE);
/****************************************************************************
* dentry-related things
****************************************************************************/
#define EXOFS_NAME_LEN 255
/*
* The on-disk directory entry
*/
struct exofs_dir_entry {
__le64 inode_no; /* inode number */
__le16 rec_len; /* directory entry length */
u8 name_len; /* name length */
u8 file_type; /* umm...file type */
char name[EXOFS_NAME_LEN]; /* file name */
};
enum {
EXOFS_FT_UNKNOWN,
EXOFS_FT_REG_FILE,
EXOFS_FT_DIR,
EXOFS_FT_CHRDEV,
EXOFS_FT_BLKDEV,
EXOFS_FT_FIFO,
EXOFS_FT_SOCK,
EXOFS_FT_SYMLINK,
EXOFS_FT_MAX
};
#define EXOFS_DIR_PAD 4
#define EXOFS_DIR_ROUND (EXOFS_DIR_PAD - 1)
#define EXOFS_DIR_REC_LEN(name_len) \
(((name_len) + offsetof(struct exofs_dir_entry, name) + \
EXOFS_DIR_ROUND) & ~EXOFS_DIR_ROUND)
/*************************
* function declarations *
*************************/
/* osd.c */
void exofs_make_credential(u8 cred_a[OSD_CAP_LEN],
const struct osd_obj_id *obj);
int exofs_check_ok_resid(struct osd_request *or, u64 *in_resid, u64 *out_resid);
static inline int exofs_check_ok(struct osd_request *or)
{
return exofs_check_ok_resid(or, NULL, NULL);
}
int exofs_sync_op(struct osd_request *or, int timeout, u8 *cred);
int exofs_async_op(struct osd_request *or,
osd_req_done_fn *async_done, void *caller_context, u8 *cred);
int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr);
int osd_req_read_kern(struct osd_request *or,
const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
int osd_req_write_kern(struct osd_request *or,
const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
#endif /*ifndef __EXOFS_COM_H__*/
This diff is collapsed.
/*
* Copyright (C) 2005, 2006
* Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
* Copyright (C) 2005, 2006
* International Business Machines
* Copyright (C) 2008, 2009
* Boaz Harrosh <bharrosh@panasas.com>
*
* Copyrights for code taken from ext2:
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* from
* linux/fs/minix/inode.c
* Copyright (C) 1991, 1992 Linus Torvalds
*
* This file is part of exofs.
*
* exofs 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. Since it is based on ext2, and the only
* valid version of GPL for the Linux kernel is version 2, the only valid
* version of GPL for exofs is version 2.
*
* exofs 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 exofs; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/fs.h>
#include <linux/time.h>
#include "common.h"
#ifndef __EXOFS_H__
#define __EXOFS_H__
#define EXOFS_ERR(fmt, a...) printk(KERN_ERR "exofs: " fmt, ##a)
#ifdef CONFIG_EXOFS_DEBUG
#define EXOFS_DBGMSG(fmt, a...) \
printk(KERN_NOTICE "exofs @%s:%d: " fmt, __func__, __LINE__, ##a)
#else
#define EXOFS_DBGMSG(fmt, a...) \
do { if (0) printk(fmt, ##a); } while (0)
#endif
/* u64 has problems with printk this will cast it to unsigned long long */
#define _LLU(x) (unsigned long long)(x)
/*
* our extension to the in-memory superblock
*/
struct exofs_sb_info {
struct osd_dev *s_dev; /* returned by get_osd_dev */
osd_id s_pid; /* partition ID of file system*/
int s_timeout; /* timeout for OSD operations */
uint64_t s_nextid; /* highest object ID used */
uint32_t s_numfiles; /* number of files on fs */
spinlock_t s_next_gen_lock; /* spinlock for gen # update */
u32 s_next_generation; /* next gen # to use */
atomic_t s_curr_pending; /* number of pending commands */
uint8_t s_cred[OSD_CAP_LEN]; /* all-powerful credential */
};
/*
* our extension to the in-memory inode
*/
struct exofs_i_info {
unsigned long i_flags; /* various atomic flags */
uint32_t i_data[EXOFS_IDATA];/*short symlink names and device #s*/
uint32_t i_dir_start_lookup; /* which page to start lookup */
wait_queue_head_t i_wq; /* wait queue for inode */
uint64_t i_commit_size; /* the object's written length */
uint8_t i_cred[OSD_CAP_LEN];/* all-powerful credential */
struct inode vfs_inode; /* normal in-memory inode */
};
/*
* our inode flags
*/
#define OBJ_2BCREATED 0 /* object will be created soon*/
#define OBJ_CREATED 1 /* object has been created on the osd*/
static inline int obj_2bcreated(struct exofs_i_info *oi)
{
return test_bit(OBJ_2BCREATED, &oi->i_flags);
}
static inline void set_obj_2bcreated(struct exofs_i_info *oi)
{
set_bit(OBJ_2BCREATED, &oi->i_flags);
}
static inline int obj_created(struct exofs_i_info *oi)
{
return test_bit(OBJ_CREATED, &oi->i_flags);
}
static inline void set_obj_created(struct exofs_i_info *oi)
{
set_bit(OBJ_CREATED, &oi->i_flags);
}
int __exofs_wait_obj_created(struct exofs_i_info *oi);
static inline int wait_obj_created(struct exofs_i_info *oi)
{
if (likely(obj_created(oi)))
return 0;
return __exofs_wait_obj_created(oi);
}
/*
* get to our inode from the vfs inode
*/
static inline struct exofs_i_info *exofs_i(struct inode *inode)
{
return container_of(inode, struct exofs_i_info, vfs_inode);
}
/*
* Maximum count of links to a file
*/
#define EXOFS_LINK_MAX 32000
/*************************
* function declarations *
*************************/
/* inode.c */
void exofs_truncate(struct inode *inode);
int exofs_setattr(struct dentry *, struct iattr *);
int exofs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata);
extern struct inode *exofs_iget(struct super_block *, unsigned long);
struct inode *exofs_new_inode(struct inode *, int);
extern int exofs_write_inode(struct inode *, int);
extern void exofs_delete_inode(struct inode *);
/* dir.c: */
int exofs_add_link(struct dentry *, struct inode *);
ino_t exofs_inode_by_name(struct inode *, struct dentry *);
int exofs_delete_entry(struct exofs_dir_entry *, struct page *);
int exofs_make_empty(struct inode *, struct inode *);
struct exofs_dir_entry *exofs_find_entry(struct inode *, struct dentry *,
struct page **);
int exofs_empty_dir(struct inode *);
struct exofs_dir_entry *exofs_dotdot(struct inode *, struct page **);
ino_t exofs_parent_ino(struct dentry *child);
int exofs_set_link(struct inode *, struct exofs_dir_entry *, struct page *,
struct inode *);
/*********************
* operation vectors *
*********************/
/* dir.c: */
extern const struct file_operations exofs_dir_operations;
/* file.c */
extern const struct inode_operations exofs_file_inode_operations;
extern const struct file_operations exofs_file_operations;
/* inode.c */
extern const struct address_space_operations exofs_aops;
/* namei.c */
extern const struct inode_operations exofs_dir_inode_operations;
extern const struct inode_operations exofs_special_inode_operations;
/* symlink.c */
extern const struct inode_operations exofs_symlink_inode_operations;
extern const struct inode_operations exofs_fast_symlink_inode_operations;
#endif
/*
* Copyright (C) 2005, 2006
* Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
* Copyright (C) 2005, 2006
* International Business Machines
* Copyright (C) 2008, 2009
* Boaz Harrosh <bharrosh@panasas.com>
*
* Copyrights for code taken from ext2:
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* from
* linux/fs/minix/inode.c
* Copyright (C) 1991, 1992 Linus Torvalds
*
* This file is part of exofs.
*
* exofs 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. Since it is based on ext2, and the only
* valid version of GPL for the Linux kernel is version 2, the only valid
* version of GPL for exofs is version 2.
*
* exofs 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 exofs; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/buffer_head.h>
#include "exofs.h"
static int exofs_release_file(struct inode *inode, struct file *filp)
{
return 0;
}
static int exofs_file_fsync(struct file *filp, struct dentry *dentry,
int datasync)
{
int ret;
struct address_space *mapping = filp->f_mapping;
ret = filemap_write_and_wait(mapping);
if (ret)
return ret;
/*Note: file_fsync below also calles sync_blockdev, which is a no-op
* for exofs, but other then that it does sync_inode and
* sync_superblock which is what we need here.
*/
return file_fsync(filp, dentry, datasync);
}
static int exofs_flush(struct file *file, fl_owner_t id)
{
exofs_file_fsync(file, file->f_path.dentry, 1);
/* TODO: Flush the OSD target */
return 0;
}
const struct file_operations exofs_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.open = generic_file_open,
.release = exofs_release_file,
.fsync = exofs_file_fsync,
.flush = exofs_flush,
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
};
const struct inode_operations exofs_file_inode_operations = {
.truncate = exofs_truncate,
.setattr = exofs_setattr,
};
This diff is collapsed.
/*
* Copyright (C) 2005, 2006
* Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
* Copyright (C) 2005, 2006
* International Business Machines
* Copyright (C) 2008, 2009
* Boaz Harrosh <bharrosh@panasas.com>
*
* Copyrights for code taken from ext2:
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* from
* linux/fs/minix/inode.c
* Copyright (C) 1991, 1992 Linus Torvalds
*
* This file is part of exofs.
*
* exofs 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. Since it is based on ext2, and the only
* valid version of GPL for the Linux kernel is version 2, the only valid
* version of GPL for exofs is version 2.
*
* exofs 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 exofs; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "exofs.h"
static inline int exofs_add_nondir(struct dentry *dentry, struct inode *inode)
{
int err = exofs_add_link(dentry, inode);
if (!err) {
d_instantiate(dentry, inode);
return 0;
}
inode_dec_link_count(inode);
iput(inode);
return err;
}
static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
struct inode *inode;
ino_t ino;
if (dentry->d_name.len > EXOFS_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
ino = exofs_inode_by_name(dir, dentry);
inode = NULL;
if (ino) {
inode = exofs_iget(dir->i_sb, ino);
if (IS_ERR(inode))
return ERR_CAST(inode);
}
return d_splice_alias(inode, dentry);
}
static int exofs_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *nd)
{
struct inode *inode = exofs_new_inode(dir, mode);
int err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
inode->i_op = &exofs_file_inode_operations;
inode->i_fop = &exofs_file_operations;
inode->i_mapping->a_ops = &exofs_aops;
mark_inode_dirty(inode);
err = exofs_add_nondir(dentry, inode);
}
return err;
}
static int exofs_mknod(struct inode *dir, struct dentry *dentry, int mode,
dev_t rdev)
{
struct inode *inode;
int err;
if (!new_valid_dev(rdev))
return -EINVAL;
inode = exofs_new_inode(dir, mode);
err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
init_special_inode(inode, inode->i_mode, rdev);
mark_inode_dirty(inode);
err = exofs_add_nondir(dentry, inode);
}
return err;
}
static int exofs_symlink(struct inode *dir, struct dentry *dentry,
const char *symname)
{
struct super_block *sb = dir->i_sb;
int err = -ENAMETOOLONG;
unsigned l = strlen(symname)+1;
struct inode *inode;
struct exofs_i_info *oi;
if (l > sb->s_blocksize)
goto out;
inode = exofs_new_inode(dir, S_IFLNK | S_IRWXUGO);
err = PTR_ERR(inode);
if (IS_ERR(inode))
goto out;
oi = exofs_i(inode);
if (l > sizeof(oi->i_data)) {
/* slow symlink */
inode->i_op = &exofs_symlink_inode_operations;
inode->i_mapping->a_ops = &exofs_aops;
memset(oi->i_data, 0, sizeof(oi->i_data));
err = page_symlink(inode, symname, l);
if (err)
goto out_fail;
} else {
/* fast symlink */
inode->i_op = &exofs_fast_symlink_inode_operations;
memcpy(oi->i_data, symname, l);
inode->i_size = l-1;
}
mark_inode_dirty(inode);
err = exofs_add_nondir(dentry, inode);
out:
return err;
out_fail:
inode_dec_link_count(inode);
iput(inode);
goto out;
}
static int exofs_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
if (inode->i_nlink >= EXOFS_LINK_MAX)
return -EMLINK;
inode->i_ctime = CURRENT_TIME;
inode_inc_link_count(inode);
atomic_inc(&inode->i_count);
return exofs_add_nondir(dentry, inode);
}
static int exofs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct inode *inode;
int err = -EMLINK;
if (dir->i_nlink >= EXOFS_LINK_MAX)
goto out;
inode_inc_link_count(dir);
inode = exofs_new_inode(dir, S_IFDIR | mode);
err = PTR_ERR(inode);
if (IS_ERR(inode))
goto out_dir;
inode->i_op = &exofs_dir_inode_operations;
inode->i_fop = &exofs_dir_operations;
inode->i_mapping->a_ops = &exofs_aops;
inode_inc_link_count(inode);
err = exofs_make_empty(inode, dir);
if (err)
goto out_fail;
err = exofs_add_link(dentry, inode);
if (err)
goto out_fail;
d_instantiate(dentry, inode);
out:
return err;
out_fail:
inode_dec_link_count(inode);
inode_dec_link_count(inode);
iput(inode);
out_dir:
inode_dec_link_count(dir);
goto out;
}
static int exofs_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
struct exofs_dir_entry *de;
struct page *page;
int err = -ENOENT;
de = exofs_find_entry(dir, dentry, &page);
if (!de)
goto out;
err = exofs_delete_entry(de, page);
if (err)
goto out;
inode->i_ctime = dir->i_ctime;
inode_dec_link_count(inode);
err = 0;
out:
return err;
}
static int exofs_rmdir(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
int err = -ENOTEMPTY;
if (exofs_empty_dir(inode)) {
err = exofs_unlink(dir, dentry);
if (!err) {
inode->i_size = 0;
inode_dec_link_count(inode);
inode_dec_link_count(dir);
}
}
return err;
}
static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
struct inode *old_inode = old_dentry->d_inode;
struct inode *new_inode = new_dentry->d_inode;
struct page *dir_page = NULL;
struct exofs_dir_entry *dir_de = NULL;
struct page *old_page;
struct exofs_dir_entry *old_de;
int err = -ENOENT;
old_de = exofs_find_entry(old_dir, old_dentry, &old_page);
if (!old_de)
goto out;
if (S_ISDIR(old_inode->i_mode)) {
err = -EIO;
dir_de = exofs_dotdot(old_inode, &dir_page);
if (!dir_de)
goto out_old;
}
if (new_inode) {
struct page *new_page;
struct exofs_dir_entry *new_de;
err = -ENOTEMPTY;
if (dir_de && !exofs_empty_dir(new_inode))
goto out_dir;
err = -ENOENT;
new_de = exofs_find_entry(new_dir, new_dentry, &new_page);
if (!new_de)
goto out_dir;
inode_inc_link_count(old_inode);
err = exofs_set_link(new_dir, new_de, new_page, old_inode);
new_inode->i_ctime = CURRENT_TIME;
if (dir_de)
drop_nlink(new_inode);
inode_dec_link_count(new_inode);
if (err)
goto out_dir;
} else {
if (dir_de) {
err = -EMLINK;
if (new_dir->i_nlink >= EXOFS_LINK_MAX)
goto out_dir;
}
inode_inc_link_count(old_inode);
err = exofs_add_link(new_dentry, old_inode);
if (err) {
inode_dec_link_count(old_inode);
goto out_dir;
}
if (dir_de)
inode_inc_link_count(new_dir);
}
old_inode->i_ctime = CURRENT_TIME;
exofs_delete_entry(old_de, old_page);
inode_dec_link_count(old_inode);
if (dir_de) {
err = exofs_set_link(old_inode, dir_de, dir_page, new_dir);
inode_dec_link_count(old_dir);
if (err)
goto out_dir;
}
return 0;
out_dir:
if (dir_de) {
kunmap(dir_page);
page_cache_release(dir_page);
}
out_old:
kunmap(old_page);
page_cache_release(old_page);
out:
return err;
}
const struct inode_operations exofs_dir_inode_operations = {
.create = exofs_create,
.lookup = exofs_lookup,
.link = exofs_link,
.unlink = exofs_unlink,
.symlink = exofs_symlink,
.mkdir = exofs_mkdir,
.rmdir = exofs_rmdir,
.mknod = exofs_mknod,
.rename = exofs_rename,
.setattr = exofs_setattr,
};
const struct inode_operations exofs_special_inode_operations = {
.setattr = exofs_setattr,
};
/*
* Copyright (C) 2005, 2006
* Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
* Copyright (C) 2005, 2006
* International Business Machines
* Copyright (C) 2008, 2009
* Boaz Harrosh <bharrosh@panasas.com>
*
* This file is part of exofs.
*
* exofs 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. Since it is based on ext2, and the only
* valid version of GPL for the Linux kernel is version 2, the only valid
* version of GPL for exofs is version 2.
*
* exofs 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 exofs; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <scsi/scsi_device.h>
#include <scsi/osd_sense.h>
#include "exofs.h"
int exofs_check_ok_resid(struct osd_request *or, u64 *in_resid, u64 *out_resid)
{
struct osd_sense_info osi;
int ret = osd_req_decode_sense(or, &osi);
if (ret) { /* translate to Linux codes */
if (osi.additional_code == scsi_invalid_field_in_cdb) {
if (osi.cdb_field_offset == OSD_CFO_STARTING_BYTE)
ret = -EFAULT;
if (osi.cdb_field_offset == OSD_CFO_OBJECT_ID)
ret = -ENOENT;
else
ret = -EINVAL;
} else if (osi.additional_code == osd_quota_error)
ret = -ENOSPC;
else
ret = -EIO;
}
/* FIXME: should be include in osd_sense_info */
if (in_resid)
*in_resid = or->in.req ? or->in.req->data_len : 0;
if (out_resid)
*out_resid = or->out.req ? or->out.req->data_len : 0;
return ret;
}
void exofs_make_credential(u8 cred_a[OSD_CAP_LEN], const struct osd_obj_id *obj)
{
osd_sec_init_nosec_doall_caps(cred_a, obj, false, true);
}
/*
* Perform a synchronous OSD operation.
*/
int exofs_sync_op(struct osd_request *or, int timeout, uint8_t *credential)
{
int ret;
or->timeout = timeout;
ret = osd_finalize_request(or, 0, credential, NULL);
if (ret) {
EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret);
return ret;
}
ret = osd_execute_request(or);
if (ret)
EXOFS_DBGMSG("osd_execute_request() => %d\n", ret);
/* osd_req_decode_sense(or, ret); */
return ret;
}
/*
* Perform an asynchronous OSD operation.
*/
int exofs_async_op(struct osd_request *or, osd_req_done_fn *async_done,
void *caller_context, u8 *cred)
{
int ret;
ret = osd_finalize_request(or, 0, cred, NULL);
if (ret) {
EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret);
return ret;
}
ret = osd_execute_request_async(or, async_done, caller_context);
if (ret)
EXOFS_DBGMSG("osd_execute_request_async() => %d\n", ret);
return ret;
}
int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr)
{
struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */
void *iter = NULL;
int nelem;
do {
nelem = 1;
osd_req_decode_get_attr_list(or, &cur_attr, &nelem, &iter);
if ((cur_attr.attr_page == attr->attr_page) &&
(cur_attr.attr_id == attr->attr_id)) {
attr->len = cur_attr.len;
attr->val_ptr = cur_attr.val_ptr;
return 0;
}
} while (iter);
return -EIO;
}
int osd_req_read_kern(struct osd_request *or,
const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
{
struct request_queue *req_q = or->osd_dev->scsi_device->request_queue;
struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
if (!bio)
return -ENOMEM;
osd_req_read(or, obj, bio, offset);
return 0;
}
int osd_req_write_kern(struct osd_request *or,
const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
{
struct request_queue *req_q = or->osd_dev->scsi_device->request_queue;
struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
if (!bio)
return -ENOMEM;
osd_req_write(or, obj, bio, offset);
return 0;
}
This diff is collapsed.
/*
* Copyright (C) 2005, 2006
* Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
* Copyright (C) 2005, 2006
* International Business Machines
* Copyright (C) 2008, 2009
* Boaz Harrosh <bharrosh@panasas.com>
*
* Copyrights for code taken from ext2:
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* from
* linux/fs/minix/inode.c
* Copyright (C) 1991, 1992 Linus Torvalds
*
* This file is part of exofs.
*
* exofs 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. Since it is based on ext2, and the only
* valid version of GPL for the Linux kernel is version 2, the only valid
* version of GPL for exofs is version 2.
*
* exofs 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 exofs; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/namei.h>
#include "exofs.h"
static void *exofs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct exofs_i_info *oi = exofs_i(dentry->d_inode);
nd_set_link(nd, (char *)oi->i_data);
return NULL;
}
const struct inode_operations exofs_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = page_follow_link_light,
.put_link = page_put_link,
};
const struct inode_operations exofs_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = exofs_follow_link,
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment