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

* 'for-linus' of git://git.open-osd.org/linux-open-osd:
  exofs: Multi-device mirror support
  exofs: Move all operations to an io_engine
  exofs: move osd.c to ios.c
  exofs: statfs blocks is sectors not FS blocks
  exofs: Prints on mount and unmout
  exofs: refactor exofs_i_info initialization into common helper
  exofs: dbg-print less
  exofs: More sane debug print
  trivial: some small fixes in exofs documentation
This commit is contained in:
Linus Torvalds 2009-12-10 09:32:24 -08:00
commit a5eba3f66f
10 changed files with 1107 additions and 457 deletions

View File

@ -36,6 +36,8 @@ dnotify.txt
- info about directory notification in Linux. - info about directory notification in Linux.
ecryptfs.txt ecryptfs.txt
- docs on eCryptfs: stacked cryptographic filesystem for Linux. - docs on eCryptfs: stacked cryptographic filesystem for Linux.
exofs.txt
- info, usage, mount options, design about EXOFS.
ext2.txt ext2.txt
- info, mount options and specifications for the Ext2 filesystem. - info, mount options and specifications for the Ext2 filesystem.
ext3.txt ext3.txt

View File

@ -60,13 +60,13 @@ USAGE
mkfs.exofs --pid=65536 --format /dev/osd0 mkfs.exofs --pid=65536 --format /dev/osd0
The --format is optional if not specified no OSD_FORMAT will be 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, performed 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 in the available space of the target. (Use --format=size_in_meg to limit
the total LUN space available) the total LUN space available)
If pid already exist it will be deleted and a new one will be created in it's If pid already exists, it will be deleted and a new one will be created in
place. Be careful. its place. Be careful.
An exofs lives inside a single OSD partition. You can create multiple exofs An exofs lives inside a single OSD partition. You can create multiple exofs
filesystems on the same device using multiple pids. filesystems on the same device using multiple pids.
@ -81,7 +81,7 @@ USAGE
7. For reference (See do-exofs example script): 7. For reference (See do-exofs example script):
do-exofs start - an example of how to perform the above steps. 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 stop - an example of how to unmount the file system.
do-exofs format - an example of how to format and mkfs a new exofs. do-exofs format - an example of how to format and mkfs a new exofs.
8. Extra compilation flags (uncomment in fs/exofs/Kbuild): 8. Extra compilation flags (uncomment in fs/exofs/Kbuild):
@ -104,8 +104,8 @@ Where:
exofs specific options: Options are separated by commas (,) exofs specific options: Options are separated by commas (,)
pid=<integer> - The partition number to mount/create as pid=<integer> - The partition number to mount/create as
container of the filesystem. container of the filesystem.
This option is mandatory This option is mandatory.
to=<integer> - Timeout in ticks for a single command to=<integer> - Timeout in ticks for a single command.
default is (60 * HZ) [for debugging only] default is (60 * HZ) [for debugging only]
=============================================================================== ===============================================================================
@ -116,7 +116,7 @@ DESIGN
with a special ID (defined in common.h). with a special ID (defined in common.h).
Information included in the file system control block is used to fill the 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 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 is used by mkexofs.c. It contains information such as:
- The file system's magic number - The file system's magic number
- The next inode number to be allocated - The next inode number to be allocated
@ -134,8 +134,8 @@ DESIGN
attributes. This applies to both regular files and other types (directories, attributes. This applies to both regular files and other types (directories,
device files, symlinks, etc.). device files, symlinks, etc.).
* Credentials are generated per object (inode and superblock) when they is * Credentials are generated per object (inode and superblock) when they are
created in memory (read off disk or created). The credential works for all created in memory (read from disk or created). The credential works for all
operations and is used as long as the object remains in memory. operations and is used as long as the object remains in memory.
* Async OSD operations are used whenever possible, but the target may execute * Async OSD operations are used whenever possible, but the target may execute
@ -145,7 +145,8 @@ DESIGN
from executing in reverse order: from executing in reverse order:
- The following are handled with the OBJ_CREATED and OBJ_2BCREATED - 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 - 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. 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 OBJ_2BCREATED is set in the beginning of the create function, so we
know that we should wait. know that we should wait.
- create/delete: delete should wait until the object is created - create/delete: delete should wait until the object is created

View File

@ -12,5 +12,5 @@
# Kbuild - Gets included from the Kernels Makefile and build system # 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 exofs-y := ios.o inode.o file.o symlink.o namei.o dir.o super.o
obj-$(CONFIG_EXOFS_FS) += exofs.o obj-$(CONFIG_EXOFS_FS) += exofs.o

View File

@ -49,6 +49,7 @@
#define EXOFS_MIN_PID 0x10000 /* Smallest partition ID */ #define EXOFS_MIN_PID 0x10000 /* Smallest partition ID */
#define EXOFS_OBJ_OFF 0x10000 /* offset for objects */ #define EXOFS_OBJ_OFF 0x10000 /* offset for objects */
#define EXOFS_SUPER_ID 0x10000 /* object ID for on-disk superblock */ #define EXOFS_SUPER_ID 0x10000 /* object ID for on-disk superblock */
#define EXOFS_DEVTABLE_ID 0x10001 /* object ID for on-disk device table */
#define EXOFS_ROOT_ID 0x10002 /* object ID for root directory */ #define EXOFS_ROOT_ID 0x10002 /* object ID for root directory */
/* exofs Application specific page/attribute */ /* exofs Application specific page/attribute */
@ -78,17 +79,67 @@ enum {
#define EXOFS_SUPER_MAGIC 0x5DF5 #define EXOFS_SUPER_MAGIC 0x5DF5
/* /*
* The file system control block - stored in an object's data (mainly, the one * The file system control block - stored in object EXOFS_SUPER_ID's data.
* with ID EXOFS_SUPER_ID). This is where the in-memory superblock is stored * This is where the in-memory superblock is stored on disk.
* 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.
*/ */
enum {EXOFS_FSCB_VER = 1, EXOFS_DT_VER = 1};
struct exofs_fscb { struct exofs_fscb {
__le64 s_nextid; /* Highest object ID used */ __le64 s_nextid; /* Highest object ID used */
__le32 s_numfiles; /* Number of files on fs */ __le64 s_numfiles; /* Number of files on fs */
__le32 s_version; /* == EXOFS_FSCB_VER */
__le16 s_magic; /* Magic signature */ __le16 s_magic; /* Magic signature */
__le16 s_newfs; /* Non-zero if this is a new fs */ __le16 s_newfs; /* Non-zero if this is a new fs */
};
/* From here on it's a static part, only written by mkexofs */
__le64 s_dev_table_oid; /* Resurved, not used */
__le64 s_dev_table_count; /* == 0 means no dev_table */
} __packed;
/*
* Describes the raid used in the FS. It is part of the device table.
* This here is taken from the pNFS-objects definition. In exofs we
* use one raid policy through-out the filesystem. (NOTE: the funny
* alignment at begining. We take care of it at exofs_device_table.
*/
struct exofs_dt_data_map {
__le32 cb_num_comps;
__le64 cb_stripe_unit;
__le32 cb_group_width;
__le32 cb_group_depth;
__le32 cb_mirror_cnt;
__le32 cb_raid_algorithm;
} __packed;
/*
* This is an osd device information descriptor. It is a single entry in
* the exofs device table. It describes an osd target lun which
* contains data belonging to this FS. (Same partition_id on all devices)
*/
struct exofs_dt_device_info {
__le32 systemid_len;
u8 systemid[OSD_SYSTEMID_LEN];
__le64 long_name_offset; /* If !0 then offset-in-file */
__le32 osdname_len; /* */
u8 osdname[44]; /* Embbeded, Ususally an asci uuid */
} __packed;
/*
* The EXOFS device table - stored in object EXOFS_DEVTABLE_ID's data.
* It contains the raid used for this multy-device FS and an array of
* participating devices.
*/
struct exofs_device_table {
__le32 dt_version; /* == EXOFS_DT_VER */
struct exofs_dt_data_map dt_data_map; /* Raid policy to use */
/* Resurved space For future use. Total includeing this:
* (8 * sizeof(le64))
*/
__le64 __Resurved[4];
__le64 dt_num_devices; /* Array size */
struct exofs_dt_device_info dt_dev_table[]; /* Array of devices */
} __packed;
/**************************************************************************** /****************************************************************************
* inode-related things * inode-related things
@ -155,22 +206,4 @@ enum {
(((name_len) + offsetof(struct exofs_dir_entry, name) + \ (((name_len) + offsetof(struct exofs_dir_entry, name) + \
EXOFS_DIR_ROUND) & ~EXOFS_DIR_ROUND) 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);
#endif /*ifndef __EXOFS_COM_H__*/ #endif /*ifndef __EXOFS_COM_H__*/

View File

@ -30,13 +30,17 @@
* along with exofs; if not, write to the Free Software * along with exofs; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef __EXOFS_H__
#define __EXOFS_H__
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/time.h> #include <linux/time.h>
#include "common.h" #include "common.h"
#ifndef __EXOFS_H__ /* FIXME: Remove once pnfs hits mainline
#define __EXOFS_H__ * #include <linux/exportfs/pnfs_osd_xdr.h>
*/
#include "pnfs.h"
#define EXOFS_ERR(fmt, a...) printk(KERN_ERR "exofs: " fmt, ##a) #define EXOFS_ERR(fmt, a...) printk(KERN_ERR "exofs: " fmt, ##a)
@ -55,7 +59,7 @@
* our extension to the in-memory superblock * our extension to the in-memory superblock
*/ */
struct exofs_sb_info { struct exofs_sb_info {
struct osd_dev *s_dev; /* returned by get_osd_dev */ struct exofs_fscb s_fscb; /* Written often, pre-allocate*/
osd_id s_pid; /* partition ID of file system*/ osd_id s_pid; /* partition ID of file system*/
int s_timeout; /* timeout for OSD operations */ int s_timeout; /* timeout for OSD operations */
uint64_t s_nextid; /* highest object ID used */ uint64_t s_nextid; /* highest object ID used */
@ -63,7 +67,11 @@ struct exofs_sb_info {
spinlock_t s_next_gen_lock; /* spinlock for gen # update */ spinlock_t s_next_gen_lock; /* spinlock for gen # update */
u32 s_next_generation; /* next gen # to use */ u32 s_next_generation; /* next gen # to use */
atomic_t s_curr_pending; /* number of pending commands */ atomic_t s_curr_pending; /* number of pending commands */
uint8_t s_cred[OSD_CAP_LEN]; /* all-powerful credential */ uint8_t s_cred[OSD_CAP_LEN]; /* credential for the fscb */
struct pnfs_osd_data_map data_map; /* Default raid to use */
unsigned s_numdevs; /* Num of devices in array */
struct osd_dev *s_ods[1]; /* Variable length, minimum 1 */
}; };
/* /*
@ -79,6 +87,50 @@ struct exofs_i_info {
struct inode vfs_inode; /* normal in-memory inode */ struct inode vfs_inode; /* normal in-memory inode */
}; };
static inline osd_id exofs_oi_objno(struct exofs_i_info *oi)
{
return oi->vfs_inode.i_ino + EXOFS_OBJ_OFF;
}
struct exofs_io_state;
typedef void (*exofs_io_done_fn)(struct exofs_io_state *or, void *private);
struct exofs_io_state {
struct kref kref;
void *private;
exofs_io_done_fn done;
struct exofs_sb_info *sbi;
struct osd_obj_id obj;
u8 *cred;
/* Global read/write IO*/
loff_t offset;
unsigned long length;
void *kern_buff;
struct bio *bio;
/* Attributes */
unsigned in_attr_len;
struct osd_attr *in_attr;
unsigned out_attr_len;
struct osd_attr *out_attr;
/* Variable array of size numdevs */
unsigned numdevs;
struct exofs_per_dev_state {
struct osd_request *or;
struct bio *bio;
} per_dev[];
};
static inline unsigned exofs_io_state_size(unsigned numdevs)
{
return sizeof(struct exofs_io_state) +
sizeof(struct exofs_per_dev_state) * numdevs;
}
/* /*
* our inode flags * our inode flags
*/ */
@ -130,6 +182,42 @@ static inline struct exofs_i_info *exofs_i(struct inode *inode)
/************************* /*************************
* function declarations * * function declarations *
*************************/ *************************/
/* ios.c */
void exofs_make_credential(u8 cred_a[OSD_CAP_LEN],
const struct osd_obj_id *obj);
int exofs_read_kern(struct osd_dev *od, u8 *cred, struct osd_obj_id *obj,
u64 offset, void *p, unsigned length);
int exofs_get_io_state(struct exofs_sb_info *sbi, struct exofs_io_state** ios);
void exofs_put_io_state(struct exofs_io_state *ios);
int exofs_check_io(struct exofs_io_state *ios, u64 *resid);
int exofs_sbi_create(struct exofs_io_state *ios);
int exofs_sbi_remove(struct exofs_io_state *ios);
int exofs_sbi_write(struct exofs_io_state *ios);
int exofs_sbi_read(struct exofs_io_state *ios);
int extract_attr_from_ios(struct exofs_io_state *ios, struct osd_attr *attr);
int exofs_oi_truncate(struct exofs_i_info *oi, u64 new_len);
static inline int exofs_oi_write(struct exofs_i_info *oi,
struct exofs_io_state *ios)
{
ios->obj.id = exofs_oi_objno(oi);
ios->cred = oi->i_cred;
return exofs_sbi_write(ios);
}
static inline int exofs_oi_read(struct exofs_i_info *oi,
struct exofs_io_state *ios)
{
ios->obj.id = exofs_oi_objno(oi);
ios->cred = oi->i_cred;
return exofs_sbi_read(ios);
}
/* inode.c */ /* inode.c */
void exofs_truncate(struct inode *inode); void exofs_truncate(struct inode *inode);
int exofs_setattr(struct dentry *, struct iattr *); int exofs_setattr(struct dentry *, struct iattr *);
@ -169,6 +257,7 @@ extern const struct file_operations exofs_file_operations;
/* inode.c */ /* inode.c */
extern const struct address_space_operations exofs_aops; extern const struct address_space_operations exofs_aops;
extern const struct osd_attr g_attr_logical_length;
/* namei.c */ /* namei.c */
extern const struct inode_operations exofs_dir_inode_operations; extern const struct inode_operations exofs_dir_inode_operations;

View File

@ -37,15 +37,18 @@
#include "exofs.h" #include "exofs.h"
#ifdef CONFIG_EXOFS_DEBUG #define EXOFS_DBGMSG2(M...) do {} while (0)
# define EXOFS_DEBUG_OBJ_ISIZE 1
#endif enum { BIO_MAX_PAGES_KMALLOC =
(PAGE_SIZE - sizeof(struct bio)) / sizeof(struct bio_vec),
};
struct page_collect { struct page_collect {
struct exofs_sb_info *sbi; struct exofs_sb_info *sbi;
struct request_queue *req_q; struct request_queue *req_q;
struct inode *inode; struct inode *inode;
unsigned expected_pages; unsigned expected_pages;
struct exofs_io_state *ios;
struct bio *bio; struct bio *bio;
unsigned nr_pages; unsigned nr_pages;
@ -54,22 +57,23 @@ struct page_collect {
}; };
static void _pcol_init(struct page_collect *pcol, unsigned expected_pages, static void _pcol_init(struct page_collect *pcol, unsigned expected_pages,
struct inode *inode) struct inode *inode)
{ {
struct exofs_sb_info *sbi = inode->i_sb->s_fs_info; struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
pcol->sbi = sbi; pcol->sbi = sbi;
pcol->req_q = osd_request_queue(sbi->s_dev); /* Create master bios on first Q, later on cloning, each clone will be
* allocated on it's destination Q
*/
pcol->req_q = osd_request_queue(sbi->s_ods[0]);
pcol->inode = inode; pcol->inode = inode;
pcol->expected_pages = expected_pages; pcol->expected_pages = expected_pages;
pcol->ios = NULL;
pcol->bio = NULL; pcol->bio = NULL;
pcol->nr_pages = 0; pcol->nr_pages = 0;
pcol->length = 0; pcol->length = 0;
pcol->pg_first = -1; pcol->pg_first = -1;
EXOFS_DBGMSG("_pcol_init ino=0x%lx expected_pages=%u\n", inode->i_ino,
expected_pages);
} }
static void _pcol_reset(struct page_collect *pcol) static void _pcol_reset(struct page_collect *pcol)
@ -80,35 +84,49 @@ static void _pcol_reset(struct page_collect *pcol)
pcol->nr_pages = 0; pcol->nr_pages = 0;
pcol->length = 0; pcol->length = 0;
pcol->pg_first = -1; pcol->pg_first = -1;
EXOFS_DBGMSG("_pcol_reset ino=0x%lx expected_pages=%u\n", pcol->ios = NULL;
pcol->inode->i_ino, pcol->expected_pages);
/* this is probably the end of the loop but in writes /* this is probably the end of the loop but in writes
* it might not end here. don't be left with nothing * it might not end here. don't be left with nothing
*/ */
if (!pcol->expected_pages) if (!pcol->expected_pages)
pcol->expected_pages = 128; pcol->expected_pages = BIO_MAX_PAGES_KMALLOC;
} }
static int pcol_try_alloc(struct page_collect *pcol) static int pcol_try_alloc(struct page_collect *pcol)
{ {
int pages = min_t(unsigned, pcol->expected_pages, BIO_MAX_PAGES); int pages = min_t(unsigned, pcol->expected_pages,
BIO_MAX_PAGES_KMALLOC);
if (!pcol->ios) { /* First time allocate io_state */
int ret = exofs_get_io_state(pcol->sbi, &pcol->ios);
if (ret)
return ret;
}
for (; pages; pages >>= 1) { for (; pages; pages >>= 1) {
pcol->bio = bio_alloc(GFP_KERNEL, pages); pcol->bio = bio_kmalloc(GFP_KERNEL, pages);
if (likely(pcol->bio)) if (likely(pcol->bio))
return 0; return 0;
} }
EXOFS_ERR("Failed to kcalloc expected_pages=%u\n", EXOFS_ERR("Failed to bio_kmalloc expected_pages=%u\n",
pcol->expected_pages); pcol->expected_pages);
return -ENOMEM; return -ENOMEM;
} }
static void pcol_free(struct page_collect *pcol) static void pcol_free(struct page_collect *pcol)
{ {
bio_put(pcol->bio); if (pcol->bio) {
pcol->bio = NULL; bio_put(pcol->bio);
pcol->bio = NULL;
}
if (pcol->ios) {
exofs_put_io_state(pcol->ios);
pcol->ios = NULL;
}
} }
static int pcol_add_page(struct page_collect *pcol, struct page *page, static int pcol_add_page(struct page_collect *pcol, struct page *page,
@ -161,22 +179,17 @@ static void update_write_page(struct page *page, int ret)
/* Called at the end of reads, to optionally unlock pages and update their /* Called at the end of reads, to optionally unlock pages and update their
* status. * status.
*/ */
static int __readpages_done(struct osd_request *or, struct page_collect *pcol, static int __readpages_done(struct page_collect *pcol, bool do_unlock)
bool do_unlock)
{ {
struct bio_vec *bvec; struct bio_vec *bvec;
int i; int i;
u64 resid; u64 resid;
u64 good_bytes; u64 good_bytes;
u64 length = 0; u64 length = 0;
int ret = exofs_check_ok_resid(or, &resid, NULL); int ret = exofs_check_io(pcol->ios, &resid);
osd_end_request(or);
if (likely(!ret)) if (likely(!ret))
good_bytes = pcol->length; good_bytes = pcol->length;
else if (!resid)
good_bytes = 0;
else else
good_bytes = pcol->length - resid; good_bytes = pcol->length - resid;
@ -198,7 +211,7 @@ static int __readpages_done(struct osd_request *or, struct page_collect *pcol,
else else
page_stat = ret; page_stat = ret;
EXOFS_DBGMSG(" readpages_done(0x%lx, 0x%lx) %s\n", EXOFS_DBGMSG2(" readpages_done(0x%lx, 0x%lx) %s\n",
inode->i_ino, page->index, inode->i_ino, page->index,
page_stat ? "bad_bytes" : "good_bytes"); page_stat ? "bad_bytes" : "good_bytes");
@ -214,13 +227,13 @@ static int __readpages_done(struct osd_request *or, struct page_collect *pcol,
} }
/* callback of async reads */ /* callback of async reads */
static void readpages_done(struct osd_request *or, void *p) static void readpages_done(struct exofs_io_state *ios, void *p)
{ {
struct page_collect *pcol = p; struct page_collect *pcol = p;
__readpages_done(or, pcol, true); __readpages_done(pcol, true);
atomic_dec(&pcol->sbi->s_curr_pending); atomic_dec(&pcol->sbi->s_curr_pending);
kfree(p); kfree(pcol);
} }
static void _unlock_pcol_pages(struct page_collect *pcol, int ret, int rw) static void _unlock_pcol_pages(struct page_collect *pcol, int ret, int rw)
@ -238,17 +251,13 @@ static void _unlock_pcol_pages(struct page_collect *pcol, int ret, int rw)
unlock_page(page); unlock_page(page);
} }
pcol_free(pcol);
} }
static int read_exec(struct page_collect *pcol, bool is_sync) static int read_exec(struct page_collect *pcol, bool is_sync)
{ {
struct exofs_i_info *oi = exofs_i(pcol->inode); struct exofs_i_info *oi = exofs_i(pcol->inode);
struct osd_obj_id obj = {pcol->sbi->s_pid, struct exofs_io_state *ios = pcol->ios;
pcol->inode->i_ino + EXOFS_OBJ_OFF};
struct osd_request *or = NULL;
struct page_collect *pcol_copy = NULL; struct page_collect *pcol_copy = NULL;
loff_t i_start = pcol->pg_first << PAGE_CACHE_SHIFT;
int ret; int ret;
if (!pcol->bio) if (!pcol->bio)
@ -257,17 +266,13 @@ static int read_exec(struct page_collect *pcol, bool is_sync)
/* see comment in _readpage() about sync reads */ /* see comment in _readpage() about sync reads */
WARN_ON(is_sync && (pcol->nr_pages != 1)); WARN_ON(is_sync && (pcol->nr_pages != 1));
or = osd_start_request(pcol->sbi->s_dev, GFP_KERNEL); ios->bio = pcol->bio;
if (unlikely(!or)) { ios->length = pcol->length;
ret = -ENOMEM; ios->offset = pcol->pg_first << PAGE_CACHE_SHIFT;
goto err;
}
osd_req_read(or, &obj, i_start, pcol->bio, pcol->length);
if (is_sync) { if (is_sync) {
exofs_sync_op(or, pcol->sbi->s_timeout, oi->i_cred); exofs_oi_read(oi, pcol->ios);
return __readpages_done(or, pcol, false); return __readpages_done(pcol, false);
} }
pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL); pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL);
@ -277,14 +282,16 @@ static int read_exec(struct page_collect *pcol, bool is_sync)
} }
*pcol_copy = *pcol; *pcol_copy = *pcol;
ret = exofs_async_op(or, readpages_done, pcol_copy, oi->i_cred); ios->done = readpages_done;
ios->private = pcol_copy;
ret = exofs_oi_read(oi, ios);
if (unlikely(ret)) if (unlikely(ret))
goto err; goto err;
atomic_inc(&pcol->sbi->s_curr_pending); atomic_inc(&pcol->sbi->s_curr_pending);
EXOFS_DBGMSG("read_exec obj=0x%llx start=0x%llx length=0x%lx\n", EXOFS_DBGMSG("read_exec obj=0x%llx start=0x%llx length=0x%lx\n",
obj.id, _LLU(i_start), pcol->length); ios->obj.id, _LLU(ios->offset), pcol->length);
/* pages ownership was passed to pcol_copy */ /* pages ownership was passed to pcol_copy */
_pcol_reset(pcol); _pcol_reset(pcol);
@ -293,12 +300,10 @@ static int read_exec(struct page_collect *pcol, bool is_sync)
err: err:
if (!is_sync) if (!is_sync)
_unlock_pcol_pages(pcol, ret, READ); _unlock_pcol_pages(pcol, ret, READ);
else /* Pages unlocked by caller in sync mode only free bio */
pcol_free(pcol); pcol_free(pcol);
kfree(pcol_copy); kfree(pcol_copy);
if (or)
osd_end_request(or);
return ret; return ret;
} }
@ -370,12 +375,12 @@ try_again:
if (len != PAGE_CACHE_SIZE) if (len != PAGE_CACHE_SIZE)
zero_user(page, len, PAGE_CACHE_SIZE - len); zero_user(page, len, PAGE_CACHE_SIZE - len);
EXOFS_DBGMSG(" readpage_strip(0x%lx, 0x%lx) len=0x%zx\n", EXOFS_DBGMSG2(" readpage_strip(0x%lx, 0x%lx) len=0x%zx\n",
inode->i_ino, page->index, len); inode->i_ino, page->index, len);
ret = pcol_add_page(pcol, page, len); ret = pcol_add_page(pcol, page, len);
if (ret) { if (ret) {
EXOFS_DBGMSG("Failed pcol_add_page pages[i]=%p " EXOFS_DBGMSG2("Failed pcol_add_page pages[i]=%p "
"this_len=0x%zx nr_pages=%u length=0x%lx\n", "this_len=0x%zx nr_pages=%u length=0x%lx\n",
page, len, pcol->nr_pages, pcol->length); page, len, pcol->nr_pages, pcol->length);
@ -419,9 +424,8 @@ static int _readpage(struct page *page, bool is_sync)
_pcol_init(&pcol, 1, page->mapping->host); _pcol_init(&pcol, 1, page->mapping->host);
/* readpage_strip might call read_exec(,async) inside at several places /* readpage_strip might call read_exec(,is_sync==false) at several
* but this is safe for is_async=0 since read_exec will not do anything * places but not if we have a single page.
* when we have a single page.
*/ */
ret = readpage_strip(&pcol, page); ret = readpage_strip(&pcol, page);
if (ret) { if (ret) {
@ -440,8 +444,8 @@ static int exofs_readpage(struct file *file, struct page *page)
return _readpage(page, false); return _readpage(page, false);
} }
/* Callback for osd_write. All writes are asynchronouse */ /* Callback for osd_write. All writes are asynchronous */
static void writepages_done(struct osd_request *or, void *p) static void writepages_done(struct exofs_io_state *ios, void *p)
{ {
struct page_collect *pcol = p; struct page_collect *pcol = p;
struct bio_vec *bvec; struct bio_vec *bvec;
@ -449,16 +453,12 @@ static void writepages_done(struct osd_request *or, void *p)
u64 resid; u64 resid;
u64 good_bytes; u64 good_bytes;
u64 length = 0; u64 length = 0;
int ret = exofs_check_io(ios, &resid);
int ret = exofs_check_ok_resid(or, NULL, &resid);
osd_end_request(or);
atomic_dec(&pcol->sbi->s_curr_pending); atomic_dec(&pcol->sbi->s_curr_pending);
if (likely(!ret)) if (likely(!ret))
good_bytes = pcol->length; good_bytes = pcol->length;
else if (!resid)
good_bytes = 0;
else else
good_bytes = pcol->length - resid; good_bytes = pcol->length - resid;
@ -482,7 +482,7 @@ static void writepages_done(struct osd_request *or, void *p)
update_write_page(page, page_stat); update_write_page(page, page_stat);
unlock_page(page); unlock_page(page);
EXOFS_DBGMSG(" writepages_done(0x%lx, 0x%lx) status=%d\n", EXOFS_DBGMSG2(" writepages_done(0x%lx, 0x%lx) status=%d\n",
inode->i_ino, page->index, page_stat); inode->i_ino, page->index, page_stat);
length += bvec->bv_len; length += bvec->bv_len;
@ -496,23 +496,13 @@ static void writepages_done(struct osd_request *or, void *p)
static int write_exec(struct page_collect *pcol) static int write_exec(struct page_collect *pcol)
{ {
struct exofs_i_info *oi = exofs_i(pcol->inode); struct exofs_i_info *oi = exofs_i(pcol->inode);
struct osd_obj_id obj = {pcol->sbi->s_pid, struct exofs_io_state *ios = pcol->ios;
pcol->inode->i_ino + EXOFS_OBJ_OFF};
struct osd_request *or = NULL;
struct page_collect *pcol_copy = NULL; struct page_collect *pcol_copy = NULL;
loff_t i_start = pcol->pg_first << PAGE_CACHE_SHIFT;
int ret; int ret;
if (!pcol->bio) if (!pcol->bio)
return 0; return 0;
or = osd_start_request(pcol->sbi->s_dev, GFP_KERNEL);
if (unlikely(!or)) {
EXOFS_ERR("write_exec: Faild to osd_start_request()\n");
ret = -ENOMEM;
goto err;
}
pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL); pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL);
if (!pcol_copy) { if (!pcol_copy) {
EXOFS_ERR("write_exec: Faild to kmalloc(pcol)\n"); EXOFS_ERR("write_exec: Faild to kmalloc(pcol)\n");
@ -523,16 +513,22 @@ static int write_exec(struct page_collect *pcol)
*pcol_copy = *pcol; *pcol_copy = *pcol;
pcol_copy->bio->bi_rw |= (1 << BIO_RW); /* FIXME: bio_set_dir() */ pcol_copy->bio->bi_rw |= (1 << BIO_RW); /* FIXME: bio_set_dir() */
osd_req_write(or, &obj, i_start, pcol_copy->bio, pcol_copy->length);
ret = exofs_async_op(or, writepages_done, pcol_copy, oi->i_cred); ios->bio = pcol_copy->bio;
ios->offset = pcol_copy->pg_first << PAGE_CACHE_SHIFT;
ios->length = pcol_copy->length;
ios->done = writepages_done;
ios->private = pcol_copy;
ret = exofs_oi_write(oi, ios);
if (unlikely(ret)) { if (unlikely(ret)) {
EXOFS_ERR("write_exec: exofs_async_op() Faild\n"); EXOFS_ERR("write_exec: exofs_oi_write() Faild\n");
goto err; goto err;
} }
atomic_inc(&pcol->sbi->s_curr_pending); atomic_inc(&pcol->sbi->s_curr_pending);
EXOFS_DBGMSG("write_exec(0x%lx, 0x%llx) start=0x%llx length=0x%lx\n", EXOFS_DBGMSG("write_exec(0x%lx, 0x%llx) start=0x%llx length=0x%lx\n",
pcol->inode->i_ino, pcol->pg_first, _LLU(i_start), pcol->inode->i_ino, pcol->pg_first, _LLU(ios->offset),
pcol->length); pcol->length);
/* pages ownership was passed to pcol_copy */ /* pages ownership was passed to pcol_copy */
_pcol_reset(pcol); _pcol_reset(pcol);
@ -540,9 +536,9 @@ static int write_exec(struct page_collect *pcol)
err: err:
_unlock_pcol_pages(pcol, ret, WRITE); _unlock_pcol_pages(pcol, ret, WRITE);
pcol_free(pcol);
kfree(pcol_copy); kfree(pcol_copy);
if (or)
osd_end_request(or);
return ret; return ret;
} }
@ -586,6 +582,9 @@ static int writepage_strip(struct page *page,
if (PageError(page)) if (PageError(page))
ClearPageError(page); ClearPageError(page);
unlock_page(page); unlock_page(page);
EXOFS_DBGMSG("writepage_strip(0x%lx, 0x%lx) "
"outside the limits\n",
inode->i_ino, page->index);
return 0; return 0;
} }
} }
@ -600,6 +599,9 @@ try_again:
ret = write_exec(pcol); ret = write_exec(pcol);
if (unlikely(ret)) if (unlikely(ret))
goto fail; goto fail;
EXOFS_DBGMSG("writepage_strip(0x%lx, 0x%lx) Discontinuity\n",
inode->i_ino, page->index);
goto try_again; goto try_again;
} }
@ -609,7 +611,7 @@ try_again:
goto fail; goto fail;
} }
EXOFS_DBGMSG(" writepage_strip(0x%lx, 0x%lx) len=0x%zx\n", EXOFS_DBGMSG2(" writepage_strip(0x%lx, 0x%lx) len=0x%zx\n",
inode->i_ino, page->index, len); inode->i_ino, page->index, len);
ret = pcol_add_page(pcol, page, len); ret = pcol_add_page(pcol, page, len);
@ -634,6 +636,8 @@ try_again:
return 0; return 0;
fail: fail:
EXOFS_DBGMSG("Error: writepage_strip(0x%lx, 0x%lx)=>%d\n",
inode->i_ino, page->index, ret);
set_bit(AS_EIO, &page->mapping->flags); set_bit(AS_EIO, &page->mapping->flags);
unlock_page(page); unlock_page(page);
return ret; return ret;
@ -652,14 +656,17 @@ static int exofs_writepages(struct address_space *mapping,
wbc->range_end >> PAGE_CACHE_SHIFT; wbc->range_end >> PAGE_CACHE_SHIFT;
if (start || end) if (start || end)
expected_pages = min(end - start + 1, 32L); expected_pages = end - start + 1;
else else
expected_pages = mapping->nrpages; expected_pages = mapping->nrpages;
EXOFS_DBGMSG("inode(0x%lx) wbc->start=0x%llx wbc->end=0x%llx" if (expected_pages < 32L)
" m->nrpages=%lu start=0x%lx end=0x%lx\n", expected_pages = 32L;
EXOFS_DBGMSG("inode(0x%lx) wbc->start=0x%llx wbc->end=0x%llx "
"nrpages=%lu start=0x%lx end=0x%lx expected_pages=%ld\n",
mapping->host->i_ino, wbc->range_start, wbc->range_end, mapping->host->i_ino, wbc->range_start, wbc->range_end,
mapping->nrpages, start, end); mapping->nrpages, start, end, expected_pages);
_pcol_init(&pcol, expected_pages, mapping->host); _pcol_init(&pcol, expected_pages, mapping->host);
@ -771,19 +778,28 @@ static int exofs_get_block(struct inode *inode, sector_t iblock,
const struct osd_attr g_attr_logical_length = ATTR_DEF( const struct osd_attr g_attr_logical_length = ATTR_DEF(
OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8); OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8);
static int _do_truncate(struct inode *inode)
{
struct exofs_i_info *oi = exofs_i(inode);
loff_t isize = i_size_read(inode);
int ret;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
nobh_truncate_page(inode->i_mapping, isize, exofs_get_block);
ret = exofs_oi_truncate(oi, (u64)isize);
EXOFS_DBGMSG("(0x%lx) size=0x%llx\n", inode->i_ino, isize);
return ret;
}
/* /*
* Truncate a file to the specified size - all we have to do is set the size * Truncate a file to the specified size - all we have to do is set the size
* attribute. We make sure the object exists first. * attribute. We make sure the object exists first.
*/ */
void exofs_truncate(struct inode *inode) void exofs_truncate(struct inode *inode)
{ {
struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
struct exofs_i_info *oi = exofs_i(inode); struct exofs_i_info *oi = exofs_i(inode);
struct osd_obj_id obj = {sbi->s_pid, inode->i_ino + EXOFS_OBJ_OFF};
struct osd_request *or;
struct osd_attr attr;
loff_t isize = i_size_read(inode);
__be64 newsize;
int ret; int ret;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
@ -793,22 +809,6 @@ void exofs_truncate(struct inode *inode)
return; return;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return; return;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
nobh_truncate_page(inode->i_mapping, isize, exofs_get_block);
or = osd_start_request(sbi->s_dev, GFP_KERNEL);
if (unlikely(!or)) {
EXOFS_ERR("ERROR: exofs_truncate: osd_start_request failed\n");
goto fail;
}
osd_req_set_attributes(or, &obj);
newsize = cpu_to_be64((u64)isize);
attr = g_attr_logical_length;
attr.val_ptr = &newsize;
osd_req_add_set_attr_list(or, &attr, 1);
/* if we are about to truncate an object, and it hasn't been /* if we are about to truncate an object, and it hasn't been
* created yet, wait * created yet, wait
@ -816,8 +816,7 @@ void exofs_truncate(struct inode *inode)
if (unlikely(wait_obj_created(oi))) if (unlikely(wait_obj_created(oi)))
goto fail; goto fail;
ret = exofs_sync_op(or, sbi->s_timeout, oi->i_cred); ret = _do_truncate(inode);
osd_end_request(or);
if (ret) if (ret)
goto fail; goto fail;
@ -847,65 +846,62 @@ int exofs_setattr(struct dentry *dentry, struct iattr *iattr)
/* /*
* Read an inode from the OSD, and return it as is. We also return the size * Read an inode from the OSD, and return it as is. We also return the size
* attribute in the 'sanity' argument if we got compiled with debugging turned * attribute in the 'obj_size' argument.
* on.
*/ */
static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi, static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi,
struct exofs_fcb *inode, uint64_t *sanity) struct exofs_fcb *inode, uint64_t *obj_size)
{ {
struct exofs_sb_info *sbi = sb->s_fs_info; struct exofs_sb_info *sbi = sb->s_fs_info;
struct osd_request *or; struct osd_attr attrs[2];
struct osd_attr attr; struct exofs_io_state *ios;
struct osd_obj_id obj = {sbi->s_pid,
oi->vfs_inode.i_ino + EXOFS_OBJ_OFF};
int ret; int ret;
exofs_make_credential(oi->i_cred, &obj); *obj_size = ~0;
ret = exofs_get_io_state(sbi, &ios);
or = osd_start_request(sbi->s_dev, GFP_KERNEL); if (unlikely(ret)) {
if (unlikely(!or)) { EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__);
EXOFS_ERR("exofs_get_inode: osd_start_request failed.\n"); return ret;
return -ENOMEM;
} }
osd_req_get_attributes(or, &obj);
/* we need the inode attribute */ ios->obj.id = exofs_oi_objno(oi);
osd_req_add_get_attr_list(or, &g_attr_inode_data, 1); exofs_make_credential(oi->i_cred, &ios->obj);
ios->cred = oi->i_cred;
#ifdef EXOFS_DEBUG_OBJ_ISIZE attrs[0] = g_attr_inode_data;
/* we get the size attributes to do a sanity check */ attrs[1] = g_attr_logical_length;
osd_req_add_get_attr_list(or, &g_attr_logical_length, 1); ios->in_attr = attrs;
#endif ios->in_attr_len = ARRAY_SIZE(attrs);
ret = exofs_sync_op(or, sbi->s_timeout, oi->i_cred); ret = exofs_sbi_read(ios);
if (ret) if (ret)
goto out; goto out;
attr = g_attr_inode_data; ret = extract_attr_from_ios(ios, &attrs[0]);
ret = extract_attr_from_req(or, &attr);
if (ret) { if (ret) {
EXOFS_ERR("exofs_get_inode: extract_attr_from_req failed\n"); EXOFS_ERR("%s: extract_attr of inode_data failed\n", __func__);
goto out; goto out;
} }
WARN_ON(attrs[0].len != EXOFS_INO_ATTR_SIZE);
memcpy(inode, attrs[0].val_ptr, EXOFS_INO_ATTR_SIZE);
WARN_ON(attr.len != EXOFS_INO_ATTR_SIZE); ret = extract_attr_from_ios(ios, &attrs[1]);
memcpy(inode, attr.val_ptr, EXOFS_INO_ATTR_SIZE);
#ifdef EXOFS_DEBUG_OBJ_ISIZE
attr = g_attr_logical_length;
ret = extract_attr_from_req(or, &attr);
if (ret) { if (ret) {
EXOFS_ERR("ERROR: extract attr from or failed\n"); EXOFS_ERR("%s: extract_attr of logical_length failed\n",
__func__);
goto out; goto out;
} }
*sanity = get_unaligned_be64(attr.val_ptr); *obj_size = get_unaligned_be64(attrs[1].val_ptr);
#endif
out: out:
osd_end_request(or); exofs_put_io_state(ios);
return ret; return ret;
} }
static void __oi_init(struct exofs_i_info *oi)
{
init_waitqueue_head(&oi->i_wq);
oi->i_flags = 0;
}
/* /*
* Fill in an inode read from the OSD and set it up for use * Fill in an inode read from the OSD and set it up for use
*/ */
@ -914,7 +910,7 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
struct exofs_i_info *oi; struct exofs_i_info *oi;
struct exofs_fcb fcb; struct exofs_fcb fcb;
struct inode *inode; struct inode *inode;
uint64_t uninitialized_var(sanity); uint64_t obj_size;
int ret; int ret;
inode = iget_locked(sb, ino); inode = iget_locked(sb, ino);
@ -923,13 +919,13 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
if (!(inode->i_state & I_NEW)) if (!(inode->i_state & I_NEW))
return inode; return inode;
oi = exofs_i(inode); oi = exofs_i(inode);
__oi_init(oi);
/* read the inode from the osd */ /* read the inode from the osd */
ret = exofs_get_inode(sb, oi, &fcb, &sanity); ret = exofs_get_inode(sb, oi, &fcb, &obj_size);
if (ret) if (ret)
goto bad_inode; goto bad_inode;
init_waitqueue_head(&oi->i_wq);
set_obj_created(oi); set_obj_created(oi);
/* copy stuff from on-disk struct to in-memory struct */ /* copy stuff from on-disk struct to in-memory struct */
@ -947,14 +943,12 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
inode->i_blkbits = EXOFS_BLKSHIFT; inode->i_blkbits = EXOFS_BLKSHIFT;
inode->i_generation = le32_to_cpu(fcb.i_generation); inode->i_generation = le32_to_cpu(fcb.i_generation);
#ifdef EXOFS_DEBUG_OBJ_ISIZE if ((inode->i_size != obj_size) &&
if ((inode->i_size != sanity) &&
(!exofs_inode_is_fast_symlink(inode))) { (!exofs_inode_is_fast_symlink(inode))) {
EXOFS_ERR("WARNING: Size of object from inode and " EXOFS_ERR("WARNING: Size of inode=%llu != object=%llu\n",
"attributes differ (%lld != %llu)\n", inode->i_size, _LLU(obj_size));
inode->i_size, _LLU(sanity)); /* FIXME: call exofs_inode_recovery() */
} }
#endif
oi->i_dir_start_lookup = 0; oi->i_dir_start_lookup = 0;
@ -1020,23 +1014,30 @@ int __exofs_wait_obj_created(struct exofs_i_info *oi)
* set the obj_created flag so that other methods know that the object exists on * set the obj_created flag so that other methods know that the object exists on
* the OSD. * the OSD.
*/ */
static void create_done(struct osd_request *or, void *p) static void create_done(struct exofs_io_state *ios, void *p)
{ {
struct inode *inode = p; struct inode *inode = p;
struct exofs_i_info *oi = exofs_i(inode); struct exofs_i_info *oi = exofs_i(inode);
struct exofs_sb_info *sbi = inode->i_sb->s_fs_info; struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
int ret; int ret;
ret = exofs_check_ok(or); ret = exofs_check_io(ios, NULL);
osd_end_request(or); exofs_put_io_state(ios);
atomic_dec(&sbi->s_curr_pending); atomic_dec(&sbi->s_curr_pending);
if (unlikely(ret)) { if (unlikely(ret)) {
EXOFS_ERR("object=0x%llx creation faild in pid=0x%llx", EXOFS_ERR("object=0x%llx creation faild in pid=0x%llx",
_LLU(sbi->s_pid), _LLU(inode->i_ino + EXOFS_OBJ_OFF)); _LLU(exofs_oi_objno(oi)), _LLU(sbi->s_pid));
make_bad_inode(inode); /*TODO: When FS is corrupted creation can fail, object already
} else * exist. Get rid of this asynchronous creation, if exist
set_obj_created(oi); * increment the obj counter and try the next object. Until we
* succeed. All these dangling objects will be made into lost
* files by chkfs.exofs
*/
}
set_obj_created(oi);
atomic_dec(&inode->i_count); atomic_dec(&inode->i_count);
wake_up(&oi->i_wq); wake_up(&oi->i_wq);
@ -1051,8 +1052,7 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
struct inode *inode; struct inode *inode;
struct exofs_i_info *oi; struct exofs_i_info *oi;
struct exofs_sb_info *sbi; struct exofs_sb_info *sbi;
struct osd_request *or; struct exofs_io_state *ios;
struct osd_obj_id obj;
int ret; int ret;
sb = dir->i_sb; sb = dir->i_sb;
@ -1061,8 +1061,8 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
oi = exofs_i(inode); oi = exofs_i(inode);
__oi_init(oi);
init_waitqueue_head(&oi->i_wq);
set_obj_2bcreated(oi); set_obj_2bcreated(oi);
sbi = sb->s_fs_info; sbi = sb->s_fs_info;
@ -1089,28 +1089,28 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
mark_inode_dirty(inode); mark_inode_dirty(inode);
obj.partition = sbi->s_pid; ret = exofs_get_io_state(sbi, &ios);
obj.id = inode->i_ino + EXOFS_OBJ_OFF; if (unlikely(ret)) {
exofs_make_credential(oi->i_cred, &obj); EXOFS_ERR("exofs_new_inode: exofs_get_io_state failed\n");
return ERR_PTR(ret);
or = osd_start_request(sbi->s_dev, GFP_KERNEL);
if (unlikely(!or)) {
EXOFS_ERR("exofs_new_inode: osd_start_request failed\n");
return ERR_PTR(-ENOMEM);
} }
osd_req_create_object(or, &obj); ios->obj.id = exofs_oi_objno(oi);
exofs_make_credential(oi->i_cred, &ios->obj);
/* increment the refcount so that the inode will still be around when we /* increment the refcount so that the inode will still be around when we
* reach the callback * reach the callback
*/ */
atomic_inc(&inode->i_count); atomic_inc(&inode->i_count);
ret = exofs_async_op(or, create_done, inode, oi->i_cred); ios->done = create_done;
ios->private = inode;
ios->cred = oi->i_cred;
ret = exofs_sbi_create(ios);
if (ret) { if (ret) {
atomic_dec(&inode->i_count); atomic_dec(&inode->i_count);
osd_end_request(or); exofs_put_io_state(ios);
return ERR_PTR(-EIO); return ERR_PTR(ret);
} }
atomic_inc(&sbi->s_curr_pending); atomic_inc(&sbi->s_curr_pending);
@ -1128,11 +1128,11 @@ struct updatei_args {
/* /*
* Callback function from exofs_update_inode(). * Callback function from exofs_update_inode().
*/ */
static void updatei_done(struct osd_request *or, void *p) static void updatei_done(struct exofs_io_state *ios, void *p)
{ {
struct updatei_args *args = p; struct updatei_args *args = p;
osd_end_request(or); exofs_put_io_state(ios);
atomic_dec(&args->sbi->s_curr_pending); atomic_dec(&args->sbi->s_curr_pending);
@ -1148,8 +1148,7 @@ static int exofs_update_inode(struct inode *inode, int do_sync)
struct exofs_i_info *oi = exofs_i(inode); struct exofs_i_info *oi = exofs_i(inode);
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct exofs_sb_info *sbi = sb->s_fs_info; struct exofs_sb_info *sbi = sb->s_fs_info;
struct osd_obj_id obj = {sbi->s_pid, inode->i_ino + EXOFS_OBJ_OFF}; struct exofs_io_state *ios;
struct osd_request *or;
struct osd_attr attr; struct osd_attr attr;
struct exofs_fcb *fcb; struct exofs_fcb *fcb;
struct updatei_args *args; struct updatei_args *args;
@ -1186,18 +1185,16 @@ static int exofs_update_inode(struct inode *inode, int do_sync)
} else } else
memcpy(fcb->i_data, oi->i_data, sizeof(fcb->i_data)); memcpy(fcb->i_data, oi->i_data, sizeof(fcb->i_data));
or = osd_start_request(sbi->s_dev, GFP_KERNEL); ret = exofs_get_io_state(sbi, &ios);
if (unlikely(!or)) { if (unlikely(ret)) {
EXOFS_ERR("exofs_update_inode: osd_start_request failed.\n"); EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__);
ret = -ENOMEM;
goto free_args; goto free_args;
} }
osd_req_set_attributes(or, &obj);
attr = g_attr_inode_data; attr = g_attr_inode_data;
attr.val_ptr = fcb; attr.val_ptr = fcb;
osd_req_add_set_attr_list(or, &attr, 1); ios->out_attr_len = 1;
ios->out_attr = &attr;
if (!obj_created(oi)) { if (!obj_created(oi)) {
EXOFS_DBGMSG("!obj_created\n"); EXOFS_DBGMSG("!obj_created\n");
@ -1206,22 +1203,19 @@ static int exofs_update_inode(struct inode *inode, int do_sync)
EXOFS_DBGMSG("wait_event done\n"); EXOFS_DBGMSG("wait_event done\n");
} }
if (do_sync) { if (!do_sync) {
ret = exofs_sync_op(or, sbi->s_timeout, oi->i_cred);
osd_end_request(or);
goto free_args;
} else {
args->sbi = sbi; args->sbi = sbi;
ios->done = updatei_done;
ios->private = args;
}
ret = exofs_async_op(or, updatei_done, args, oi->i_cred); ret = exofs_oi_write(oi, ios);
if (ret) { if (!do_sync && !ret) {
osd_end_request(or);
goto free_args;
}
atomic_inc(&sbi->s_curr_pending); atomic_inc(&sbi->s_curr_pending);
goto out; /* deallocation in updatei_done */ goto out; /* deallocation in updatei_done */
} }
exofs_put_io_state(ios);
free_args: free_args:
kfree(args); kfree(args);
out: out:
@ -1238,11 +1232,12 @@ int exofs_write_inode(struct inode *inode, int wait)
* Callback function from exofs_delete_inode() - don't have much cleaning up to * Callback function from exofs_delete_inode() - don't have much cleaning up to
* do. * do.
*/ */
static void delete_done(struct osd_request *or, void *p) static void delete_done(struct exofs_io_state *ios, void *p)
{ {
struct exofs_sb_info *sbi; struct exofs_sb_info *sbi = p;
osd_end_request(or);
sbi = p; exofs_put_io_state(ios);
atomic_dec(&sbi->s_curr_pending); atomic_dec(&sbi->s_curr_pending);
} }
@ -1256,8 +1251,7 @@ void exofs_delete_inode(struct inode *inode)
struct exofs_i_info *oi = exofs_i(inode); struct exofs_i_info *oi = exofs_i(inode);
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct exofs_sb_info *sbi = sb->s_fs_info; struct exofs_sb_info *sbi = sb->s_fs_info;
struct osd_obj_id obj = {sbi->s_pid, inode->i_ino + EXOFS_OBJ_OFF}; struct exofs_io_state *ios;
struct osd_request *or;
int ret; int ret;
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
@ -1274,25 +1268,26 @@ void exofs_delete_inode(struct inode *inode)
clear_inode(inode); clear_inode(inode);
or = osd_start_request(sbi->s_dev, GFP_KERNEL); ret = exofs_get_io_state(sbi, &ios);
if (unlikely(!or)) { if (unlikely(ret)) {
EXOFS_ERR("exofs_delete_inode: osd_start_request failed\n"); EXOFS_ERR("%s: exofs_get_io_state failed\n", __func__);
return; return;
} }
osd_req_remove_object(or, &obj);
/* if we are deleting an obj that hasn't been created yet, wait */ /* if we are deleting an obj that hasn't been created yet, wait */
if (!obj_created(oi)) { if (!obj_created(oi)) {
BUG_ON(!obj_2bcreated(oi)); BUG_ON(!obj_2bcreated(oi));
wait_event(oi->i_wq, obj_created(oi)); wait_event(oi->i_wq, obj_created(oi));
} }
ret = exofs_async_op(or, delete_done, sbi, oi->i_cred); ios->obj.id = exofs_oi_objno(oi);
ios->done = delete_done;
ios->private = sbi;
ios->cred = oi->i_cred;
ret = exofs_sbi_remove(ios);
if (ret) { if (ret) {
EXOFS_ERR( EXOFS_ERR("%s: exofs_sbi_remove failed\n", __func__);
"ERROR: @exofs_delete_inode exofs_async_op failed\n"); exofs_put_io_state(ios);
osd_end_request(or);
return; return;
} }
atomic_inc(&sbi->s_curr_pending); atomic_inc(&sbi->s_curr_pending);

421
fs/exofs/ios.c Normal file
View File

@ -0,0 +1,421 @@
/*
* Copyright (C) 2005, 2006
* Avishay Traeger (avishay@gmail.com)
* 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 "exofs.h"
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);
}
int exofs_read_kern(struct osd_dev *od, u8 *cred, struct osd_obj_id *obj,
u64 offset, void *p, unsigned length)
{
struct osd_request *or = osd_start_request(od, GFP_KERNEL);
/* struct osd_sense_info osi = {.key = 0};*/
int ret;
if (unlikely(!or)) {
EXOFS_DBGMSG("%s: osd_start_request failed.\n", __func__);
return -ENOMEM;
}
ret = osd_req_read_kern(or, obj, offset, p, length);
if (unlikely(ret)) {
EXOFS_DBGMSG("%s: osd_req_read_kern failed.\n", __func__);
goto out;
}
ret = osd_finalize_request(or, 0, cred, NULL);
if (unlikely(ret)) {
EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret);
goto out;
}
ret = osd_execute_request(or);
if (unlikely(ret))
EXOFS_DBGMSG("osd_execute_request() => %d\n", ret);
/* osd_req_decode_sense(or, ret); */
out:
osd_end_request(or);
return ret;
}
int exofs_get_io_state(struct exofs_sb_info *sbi, struct exofs_io_state** pios)
{
struct exofs_io_state *ios;
/*TODO: Maybe use kmem_cach per sbi of size
* exofs_io_state_size(sbi->s_numdevs)
*/
ios = kzalloc(exofs_io_state_size(sbi->s_numdevs), GFP_KERNEL);
if (unlikely(!ios)) {
*pios = NULL;
return -ENOMEM;
}
ios->sbi = sbi;
ios->obj.partition = sbi->s_pid;
*pios = ios;
return 0;
}
void exofs_put_io_state(struct exofs_io_state *ios)
{
if (ios) {
unsigned i;
for (i = 0; i < ios->numdevs; i++) {
struct exofs_per_dev_state *per_dev = &ios->per_dev[i];
if (per_dev->or)
osd_end_request(per_dev->or);
if (per_dev->bio)
bio_put(per_dev->bio);
}
kfree(ios);
}
}
static void _sync_done(struct exofs_io_state *ios, void *p)
{
struct completion *waiting = p;
complete(waiting);
}
static void _last_io(struct kref *kref)
{
struct exofs_io_state *ios = container_of(
kref, struct exofs_io_state, kref);
ios->done(ios, ios->private);
}
static void _done_io(struct osd_request *or, void *p)
{
struct exofs_io_state *ios = p;
kref_put(&ios->kref, _last_io);
}
static int exofs_io_execute(struct exofs_io_state *ios)
{
DECLARE_COMPLETION_ONSTACK(wait);
bool sync = (ios->done == NULL);
int i, ret;
if (sync) {
ios->done = _sync_done;
ios->private = &wait;
}
for (i = 0; i < ios->numdevs; i++) {
struct osd_request *or = ios->per_dev[i].or;
if (unlikely(!or))
continue;
ret = osd_finalize_request(or, 0, ios->cred, NULL);
if (unlikely(ret)) {
EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n",
ret);
return ret;
}
}
kref_init(&ios->kref);
for (i = 0; i < ios->numdevs; i++) {
struct osd_request *or = ios->per_dev[i].or;
if (unlikely(!or))
continue;
kref_get(&ios->kref);
osd_execute_request_async(or, _done_io, ios);
}
kref_put(&ios->kref, _last_io);
ret = 0;
if (sync) {
wait_for_completion(&wait);
ret = exofs_check_io(ios, NULL);
}
return ret;
}
int exofs_check_io(struct exofs_io_state *ios, u64 *resid)
{
enum osd_err_priority acumulated_osd_err = 0;
int acumulated_lin_err = 0;
int i;
for (i = 0; i < ios->numdevs; i++) {
struct osd_sense_info osi;
int ret = osd_req_decode_sense(ios->per_dev[i].or, &osi);
if (likely(!ret))
continue;
if (unlikely(ret == -EFAULT)) {
EXOFS_DBGMSG("%s: EFAULT Need page clear\n", __func__);
/*FIXME: All the pages in this device range should:
* clear_highpage(page);
*/
}
if (osi.osd_err_pri >= acumulated_osd_err) {
acumulated_osd_err = osi.osd_err_pri;
acumulated_lin_err = ret;
}
}
/* TODO: raid specific residual calculations */
if (resid) {
if (likely(!acumulated_lin_err))
*resid = 0;
else
*resid = ios->length;
}
return acumulated_lin_err;
}
int exofs_sbi_create(struct exofs_io_state *ios)
{
int i, ret;
for (i = 0; i < ios->sbi->s_numdevs; i++) {
struct osd_request *or;
or = osd_start_request(ios->sbi->s_ods[i], GFP_KERNEL);
if (unlikely(!or)) {
EXOFS_ERR("%s: osd_start_request failed\n", __func__);
ret = -ENOMEM;
goto out;
}
ios->per_dev[i].or = or;
ios->numdevs++;
osd_req_create_object(or, &ios->obj);
}
ret = exofs_io_execute(ios);
out:
return ret;
}
int exofs_sbi_remove(struct exofs_io_state *ios)
{
int i, ret;
for (i = 0; i < ios->sbi->s_numdevs; i++) {
struct osd_request *or;
or = osd_start_request(ios->sbi->s_ods[i], GFP_KERNEL);
if (unlikely(!or)) {
EXOFS_ERR("%s: osd_start_request failed\n", __func__);
ret = -ENOMEM;
goto out;
}
ios->per_dev[i].or = or;
ios->numdevs++;
osd_req_remove_object(or, &ios->obj);
}
ret = exofs_io_execute(ios);
out:
return ret;
}
int exofs_sbi_write(struct exofs_io_state *ios)
{
int i, ret;
for (i = 0; i < ios->sbi->s_numdevs; i++) {
struct osd_request *or;
or = osd_start_request(ios->sbi->s_ods[i], GFP_KERNEL);
if (unlikely(!or)) {
EXOFS_ERR("%s: osd_start_request failed\n", __func__);
ret = -ENOMEM;
goto out;
}
ios->per_dev[i].or = or;
ios->numdevs++;
if (ios->bio) {
struct bio *bio;
if (i != 0) {
bio = bio_kmalloc(GFP_KERNEL,
ios->bio->bi_max_vecs);
if (unlikely(!bio)) {
ret = -ENOMEM;
goto out;
}
__bio_clone(bio, ios->bio);
bio->bi_bdev = NULL;
bio->bi_next = NULL;
ios->per_dev[i].bio = bio;
} else {
bio = ios->bio;
}
osd_req_write(or, &ios->obj, ios->offset, bio,
ios->length);
/* EXOFS_DBGMSG("write sync=%d\n", sync);*/
} else if (ios->kern_buff) {
osd_req_write_kern(or, &ios->obj, ios->offset,
ios->kern_buff, ios->length);
/* EXOFS_DBGMSG("write_kern sync=%d\n", sync);*/
} else {
osd_req_set_attributes(or, &ios->obj);
/* EXOFS_DBGMSG("set_attributes sync=%d\n", sync);*/
}
if (ios->out_attr)
osd_req_add_set_attr_list(or, ios->out_attr,
ios->out_attr_len);
if (ios->in_attr)
osd_req_add_get_attr_list(or, ios->in_attr,
ios->in_attr_len);
}
ret = exofs_io_execute(ios);
out:
return ret;
}
int exofs_sbi_read(struct exofs_io_state *ios)
{
int i, ret;
for (i = 0; i < 1; i++) {
struct osd_request *or;
unsigned first_dev = (unsigned)ios->obj.id;
first_dev %= ios->sbi->s_numdevs;
or = osd_start_request(ios->sbi->s_ods[first_dev], GFP_KERNEL);
if (unlikely(!or)) {
EXOFS_ERR("%s: osd_start_request failed\n", __func__);
ret = -ENOMEM;
goto out;
}
ios->per_dev[i].or = or;
ios->numdevs++;
if (ios->bio) {
osd_req_read(or, &ios->obj, ios->offset, ios->bio,
ios->length);
/* EXOFS_DBGMSG("read sync=%d\n", sync);*/
} else if (ios->kern_buff) {
osd_req_read_kern(or, &ios->obj, ios->offset,
ios->kern_buff, ios->length);
/* EXOFS_DBGMSG("read_kern sync=%d\n", sync);*/
} else {
osd_req_get_attributes(or, &ios->obj);
/* EXOFS_DBGMSG("get_attributes sync=%d\n", sync);*/
}
if (ios->out_attr)
osd_req_add_set_attr_list(or, ios->out_attr,
ios->out_attr_len);
if (ios->in_attr)
osd_req_add_get_attr_list(or, ios->in_attr,
ios->in_attr_len);
}
ret = exofs_io_execute(ios);
out:
return ret;
}
int extract_attr_from_ios(struct exofs_io_state *ios, 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(ios->per_dev[0].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 exofs_oi_truncate(struct exofs_i_info *oi, u64 size)
{
struct exofs_sb_info *sbi = oi->vfs_inode.i_sb->s_fs_info;
struct exofs_io_state *ios;
struct osd_attr attr;
__be64 newsize;
int i, ret;
if (exofs_get_io_state(sbi, &ios))
return -ENOMEM;
ios->obj.id = exofs_oi_objno(oi);
ios->cred = oi->i_cred;
newsize = cpu_to_be64(size);
attr = g_attr_logical_length;
attr.val_ptr = &newsize;
for (i = 0; i < sbi->s_numdevs; i++) {
struct osd_request *or;
or = osd_start_request(sbi->s_ods[i], GFP_KERNEL);
if (unlikely(!or)) {
EXOFS_ERR("%s: osd_start_request failed\n", __func__);
ret = -ENOMEM;
goto out;
}
ios->per_dev[i].or = or;
ios->numdevs++;
osd_req_set_attributes(or, &ios->obj);
osd_req_add_set_attr_list(or, &attr, 1);
}
ret = exofs_io_execute(ios);
out:
exofs_put_io_state(ios);
return ret;
}

View File

@ -1,125 +0,0 @@
/*
* Copyright (C) 2005, 2006
* Avishay Traeger (avishay@gmail.com)
* 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->resid_len : 0;
if (out_resid)
*out_resid = or->out.req ? or->out.req->resid_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;
}

51
fs/exofs/pnfs.h Normal file
View File

@ -0,0 +1,51 @@
/*
* 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 version 2 as published by the Free
* Software Foundation.
*
*/
/* FIXME: Remove this file once pnfs hits mainline */
#ifndef __EXOFS_PNFS_H__
#define __EXOFS_PNFS_H__
#if defined(CONFIG_PNFS)
/* FIXME: move this file to: linux/exportfs/pnfs_osd_xdr.h */
#include "../nfs/objlayout/pnfs_osd_xdr.h"
#else /* defined(CONFIG_PNFS) */
enum pnfs_iomode {
IOMODE_READ = 1,
IOMODE_RW = 2,
IOMODE_ANY = 3,
};
/* Layout Structure */
enum pnfs_osd_raid_algorithm4 {
PNFS_OSD_RAID_0 = 1,
PNFS_OSD_RAID_4 = 2,
PNFS_OSD_RAID_5 = 3,
PNFS_OSD_RAID_PQ = 4 /* Reed-Solomon P+Q */
};
struct pnfs_osd_data_map {
u32 odm_num_comps;
u64 odm_stripe_unit;
u32 odm_group_width;
u32 odm_group_depth;
u32 odm_mirror_cnt;
u32 odm_raid_algorithm;
};
#endif /* else defined(CONFIG_PNFS) */
#endif /* __EXOFS_PNFS_H__ */

View File

@ -203,49 +203,45 @@ int exofs_sync_fs(struct super_block *sb, int wait)
{ {
struct exofs_sb_info *sbi; struct exofs_sb_info *sbi;
struct exofs_fscb *fscb; struct exofs_fscb *fscb;
struct osd_request *or; struct exofs_io_state *ios;
struct osd_obj_id obj;
int ret = -ENOMEM; int ret = -ENOMEM;
fscb = kzalloc(sizeof(struct exofs_fscb), GFP_KERNEL);
if (!fscb) {
EXOFS_ERR("exofs_write_super: memory allocation failed.\n");
return -ENOMEM;
}
lock_super(sb); lock_super(sb);
sbi = sb->s_fs_info; sbi = sb->s_fs_info;
fscb = &sbi->s_fscb;
ret = exofs_get_io_state(sbi, &ios);
if (ret)
goto out;
/* Note: We only write the changing part of the fscb. .i.e upto the
* the fscb->s_dev_table_oid member. There is no read-modify-write
* here.
*/
ios->length = offsetof(struct exofs_fscb, s_dev_table_oid);
memset(fscb, 0, ios->length);
fscb->s_nextid = cpu_to_le64(sbi->s_nextid); fscb->s_nextid = cpu_to_le64(sbi->s_nextid);
fscb->s_numfiles = cpu_to_le32(sbi->s_numfiles); fscb->s_numfiles = cpu_to_le32(sbi->s_numfiles);
fscb->s_magic = cpu_to_le16(sb->s_magic); fscb->s_magic = cpu_to_le16(sb->s_magic);
fscb->s_newfs = 0; fscb->s_newfs = 0;
fscb->s_version = EXOFS_FSCB_VER;
or = osd_start_request(sbi->s_dev, GFP_KERNEL); ios->obj.id = EXOFS_SUPER_ID;
if (unlikely(!or)) { ios->offset = 0;
EXOFS_ERR("exofs_write_super: osd_start_request failed.\n"); ios->kern_buff = fscb;
goto out; ios->cred = sbi->s_cred;
}
obj.partition = sbi->s_pid; ret = exofs_sbi_write(ios);
obj.id = EXOFS_SUPER_ID;
ret = osd_req_write_kern(or, &obj, 0, fscb, sizeof(*fscb));
if (unlikely(ret)) { if (unlikely(ret)) {
EXOFS_ERR("exofs_write_super: osd_req_write_kern failed.\n"); EXOFS_ERR("%s: exofs_sbi_write failed.\n", __func__);
goto out;
}
ret = exofs_sync_op(or, sbi->s_timeout, sbi->s_cred);
if (unlikely(ret)) {
EXOFS_ERR("exofs_write_super: exofs_sync_op failed.\n");
goto out; goto out;
} }
sb->s_dirt = 0; sb->s_dirt = 0;
out: out:
if (or) EXOFS_DBGMSG("s_nextid=0x%llx ret=%d\n", _LLU(sbi->s_nextid), ret);
osd_end_request(or); exofs_put_io_state(ios);
unlock_super(sb); unlock_super(sb);
kfree(fscb);
return ret; return ret;
} }
@ -257,6 +253,29 @@ static void exofs_write_super(struct super_block *sb)
sb->s_dirt = 0; sb->s_dirt = 0;
} }
static void _exofs_print_device(const char *msg, const char *dev_path,
struct osd_dev *od, u64 pid)
{
const struct osd_dev_info *odi = osduld_device_info(od);
printk(KERN_NOTICE "exofs: %s %s osd_name-%s pid-0x%llx\n",
msg, dev_path ?: "", odi->osdname, _LLU(pid));
}
void exofs_free_sbi(struct exofs_sb_info *sbi)
{
while (sbi->s_numdevs) {
int i = --sbi->s_numdevs;
struct osd_dev *od = sbi->s_ods[i];
if (od) {
sbi->s_ods[i] = NULL;
osduld_put_device(od);
}
}
kfree(sbi);
}
/* /*
* This function is called when the vfs is freeing the superblock. We just * This function is called when the vfs is freeing the superblock. We just
* need to free our own part. * need to free our own part.
@ -279,11 +298,182 @@ static void exofs_put_super(struct super_block *sb)
msecs_to_jiffies(100)); msecs_to_jiffies(100));
} }
osduld_put_device(sbi->s_dev); _exofs_print_device("Unmounting", NULL, sbi->s_ods[0], sbi->s_pid);
kfree(sb->s_fs_info);
exofs_free_sbi(sbi);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
} }
static int _read_and_match_data_map(struct exofs_sb_info *sbi, unsigned numdevs,
struct exofs_device_table *dt)
{
sbi->data_map.odm_num_comps =
le32_to_cpu(dt->dt_data_map.cb_num_comps);
sbi->data_map.odm_stripe_unit =
le64_to_cpu(dt->dt_data_map.cb_stripe_unit);
sbi->data_map.odm_group_width =
le32_to_cpu(dt->dt_data_map.cb_group_width);
sbi->data_map.odm_group_depth =
le32_to_cpu(dt->dt_data_map.cb_group_depth);
sbi->data_map.odm_mirror_cnt =
le32_to_cpu(dt->dt_data_map.cb_mirror_cnt);
sbi->data_map.odm_raid_algorithm =
le32_to_cpu(dt->dt_data_map.cb_raid_algorithm);
/* FIXME: Hard coded mirror only for now. if not so do not mount */
if ((sbi->data_map.odm_num_comps != numdevs) ||
(sbi->data_map.odm_stripe_unit != EXOFS_BLKSIZE) ||
(sbi->data_map.odm_raid_algorithm != PNFS_OSD_RAID_0) ||
(sbi->data_map.odm_mirror_cnt != (numdevs - 1)))
return -EINVAL;
else
return 0;
}
/* @odi is valid only as long as @fscb_dev is valid */
static int exofs_devs_2_odi(struct exofs_dt_device_info *dt_dev,
struct osd_dev_info *odi)
{
odi->systemid_len = le32_to_cpu(dt_dev->systemid_len);
memcpy(odi->systemid, dt_dev->systemid, odi->systemid_len);
odi->osdname_len = le32_to_cpu(dt_dev->osdname_len);
odi->osdname = dt_dev->osdname;
/* FIXME support long names. Will need a _put function */
if (dt_dev->long_name_offset)
return -EINVAL;
/* Make sure osdname is printable!
* mkexofs should give us space for a null-terminator else the
* device-table is invalid.
*/
if (unlikely(odi->osdname_len >= sizeof(dt_dev->osdname)))
odi->osdname_len = sizeof(dt_dev->osdname) - 1;
dt_dev->osdname[odi->osdname_len] = 0;
/* If it's all zeros something is bad we read past end-of-obj */
return !(odi->systemid_len || odi->osdname_len);
}
static int exofs_read_lookup_dev_table(struct exofs_sb_info **psbi,
unsigned table_count)
{
struct exofs_sb_info *sbi = *psbi;
struct osd_dev *fscb_od;
struct osd_obj_id obj = {.partition = sbi->s_pid,
.id = EXOFS_DEVTABLE_ID};
struct exofs_device_table *dt;
unsigned table_bytes = table_count * sizeof(dt->dt_dev_table[0]) +
sizeof(*dt);
unsigned numdevs, i;
int ret;
dt = kmalloc(table_bytes, GFP_KERNEL);
if (unlikely(!dt)) {
EXOFS_ERR("ERROR: allocating %x bytes for device table\n",
table_bytes);
return -ENOMEM;
}
fscb_od = sbi->s_ods[0];
sbi->s_ods[0] = NULL;
sbi->s_numdevs = 0;
ret = exofs_read_kern(fscb_od, sbi->s_cred, &obj, 0, dt, table_bytes);
if (unlikely(ret)) {
EXOFS_ERR("ERROR: reading device table\n");
goto out;
}
numdevs = le64_to_cpu(dt->dt_num_devices);
if (unlikely(!numdevs)) {
ret = -EINVAL;
goto out;
}
WARN_ON(table_count != numdevs);
ret = _read_and_match_data_map(sbi, numdevs, dt);
if (unlikely(ret))
goto out;
if (likely(numdevs > 1)) {
unsigned size = numdevs * sizeof(sbi->s_ods[0]);
sbi = krealloc(sbi, sizeof(*sbi) + size, GFP_KERNEL);
if (unlikely(!sbi)) {
ret = -ENOMEM;
goto out;
}
memset(&sbi->s_ods[1], 0, size - sizeof(sbi->s_ods[0]));
*psbi = sbi;
}
for (i = 0; i < numdevs; i++) {
struct exofs_fscb fscb;
struct osd_dev_info odi;
struct osd_dev *od;
if (exofs_devs_2_odi(&dt->dt_dev_table[i], &odi)) {
EXOFS_ERR("ERROR: Read all-zeros device entry\n");
ret = -EINVAL;
goto out;
}
printk(KERN_NOTICE "Add device[%d]: osd_name-%s\n",
i, odi.osdname);
/* On all devices the device table is identical. The user can
* specify any one of the participating devices on the command
* line. We always keep them in device-table order.
*/
if (fscb_od && osduld_device_same(fscb_od, &odi)) {
sbi->s_ods[i] = fscb_od;
++sbi->s_numdevs;
fscb_od = NULL;
continue;
}
od = osduld_info_lookup(&odi);
if (unlikely(IS_ERR(od))) {
ret = PTR_ERR(od);
EXOFS_ERR("ERROR: device requested is not found "
"osd_name-%s =>%d\n", odi.osdname, ret);
goto out;
}
sbi->s_ods[i] = od;
++sbi->s_numdevs;
/* Read the fscb of the other devices to make sure the FS
* partition is there.
*/
ret = exofs_read_kern(od, sbi->s_cred, &obj, 0, &fscb,
sizeof(fscb));
if (unlikely(ret)) {
EXOFS_ERR("ERROR: Malformed participating device "
"error reading fscb osd_name-%s\n",
odi.osdname);
goto out;
}
/* TODO: verify other information is correct and FS-uuid
* matches. Benny what did you say about device table
* generation and old devices?
*/
}
out:
kfree(dt);
if (unlikely(!ret && fscb_od)) {
EXOFS_ERR(
"ERROR: Bad device-table container device not present\n");
osduld_put_device(fscb_od);
ret = -EINVAL;
}
return ret;
}
/* /*
* Read the superblock from the OSD and fill in the fields * Read the superblock from the OSD and fill in the fields
*/ */
@ -292,24 +482,25 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
struct inode *root; struct inode *root;
struct exofs_mountopt *opts = data; struct exofs_mountopt *opts = data;
struct exofs_sb_info *sbi; /*extended info */ struct exofs_sb_info *sbi; /*extended info */
struct osd_dev *od; /* Master device */
struct exofs_fscb fscb; /*on-disk superblock info */ struct exofs_fscb fscb; /*on-disk superblock info */
struct osd_request *or = NULL;
struct osd_obj_id obj; struct osd_obj_id obj;
unsigned table_count;
int ret; int ret;
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi) if (!sbi)
return -ENOMEM; return -ENOMEM;
sb->s_fs_info = sbi;
/* use mount options to fill superblock */ /* use mount options to fill superblock */
sbi->s_dev = osduld_path_lookup(opts->dev_name); od = osduld_path_lookup(opts->dev_name);
if (IS_ERR(sbi->s_dev)) { if (IS_ERR(od)) {
ret = PTR_ERR(sbi->s_dev); ret = PTR_ERR(od);
sbi->s_dev = NULL;
goto free_sbi; goto free_sbi;
} }
sbi->s_ods[0] = od;
sbi->s_numdevs = 1;
sbi->s_pid = opts->pid; sbi->s_pid = opts->pid;
sbi->s_timeout = opts->timeout; sbi->s_timeout = opts->timeout;
@ -323,35 +514,13 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_bdev = NULL; sb->s_bdev = NULL;
sb->s_dev = 0; sb->s_dev = 0;
/* read data from on-disk superblock object */
obj.partition = sbi->s_pid; obj.partition = sbi->s_pid;
obj.id = EXOFS_SUPER_ID; obj.id = EXOFS_SUPER_ID;
exofs_make_credential(sbi->s_cred, &obj); exofs_make_credential(sbi->s_cred, &obj);
or = osd_start_request(sbi->s_dev, GFP_KERNEL); ret = exofs_read_kern(od, sbi->s_cred, &obj, 0, &fscb, sizeof(fscb));
if (unlikely(!or)) { if (unlikely(ret))
if (!silent)
EXOFS_ERR(
"exofs_fill_super: osd_start_request failed.\n");
ret = -ENOMEM;
goto free_sbi; goto free_sbi;
}
ret = osd_req_read_kern(or, &obj, 0, &fscb, sizeof(fscb));
if (unlikely(ret)) {
if (!silent)
EXOFS_ERR(
"exofs_fill_super: osd_req_read_kern failed.\n");
ret = -ENOMEM;
goto free_sbi;
}
ret = exofs_sync_op(or, sbi->s_timeout, sbi->s_cred);
if (unlikely(ret)) {
if (!silent)
EXOFS_ERR("exofs_fill_super: exofs_sync_op failed.\n");
ret = -EIO;
goto free_sbi;
}
sb->s_magic = le16_to_cpu(fscb.s_magic); sb->s_magic = le16_to_cpu(fscb.s_magic);
sbi->s_nextid = le64_to_cpu(fscb.s_nextid); sbi->s_nextid = le64_to_cpu(fscb.s_nextid);
@ -364,12 +533,26 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
ret = -EINVAL; ret = -EINVAL;
goto free_sbi; goto free_sbi;
} }
if (le32_to_cpu(fscb.s_version) != EXOFS_FSCB_VER) {
EXOFS_ERR("ERROR: Bad FSCB version expected-%d got-%d\n",
EXOFS_FSCB_VER, le32_to_cpu(fscb.s_version));
ret = -EINVAL;
goto free_sbi;
}
/* start generation numbers from a random point */ /* start generation numbers from a random point */
get_random_bytes(&sbi->s_next_generation, sizeof(u32)); get_random_bytes(&sbi->s_next_generation, sizeof(u32));
spin_lock_init(&sbi->s_next_gen_lock); spin_lock_init(&sbi->s_next_gen_lock);
table_count = le64_to_cpu(fscb.s_dev_table_count);
if (table_count) {
ret = exofs_read_lookup_dev_table(&sbi, table_count);
if (unlikely(ret))
goto free_sbi;
}
/* set up operation vectors */ /* set up operation vectors */
sb->s_fs_info = sbi;
sb->s_op = &exofs_sops; sb->s_op = &exofs_sops;
sb->s_export_op = &exofs_export_ops; sb->s_export_op = &exofs_export_ops;
root = exofs_iget(sb, EXOFS_ROOT_ID - EXOFS_OBJ_OFF); root = exofs_iget(sb, EXOFS_ROOT_ID - EXOFS_OBJ_OFF);
@ -395,16 +578,15 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
goto free_sbi; goto free_sbi;
} }
ret = 0; _exofs_print_device("Mounting", opts->dev_name, sbi->s_ods[0],
out: sbi->s_pid);
if (or) return 0;
osd_end_request(or);
return ret;
free_sbi: free_sbi:
osduld_put_device(sbi->s_dev); /* NULL safe */ EXOFS_ERR("Unable to mount exofs on %s pid=0x%llx err=%d\n",
kfree(sbi); opts->dev_name, sbi->s_pid, ret);
goto out; exofs_free_sbi(sbi);
return ret;
} }
/* /*
@ -433,7 +615,7 @@ static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf)
{ {
struct super_block *sb = dentry->d_sb; struct super_block *sb = dentry->d_sb;
struct exofs_sb_info *sbi = sb->s_fs_info; struct exofs_sb_info *sbi = sb->s_fs_info;
struct osd_obj_id obj = {sbi->s_pid, 0}; struct exofs_io_state *ios;
struct osd_attr attrs[] = { struct osd_attr attrs[] = {
ATTR_DEF(OSD_APAGE_PARTITION_QUOTAS, ATTR_DEF(OSD_APAGE_PARTITION_QUOTAS,
OSD_ATTR_PQ_CAPACITY_QUOTA, sizeof(__be64)), OSD_ATTR_PQ_CAPACITY_QUOTA, sizeof(__be64)),
@ -442,32 +624,33 @@ static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf)
}; };
uint64_t capacity = ULLONG_MAX; uint64_t capacity = ULLONG_MAX;
uint64_t used = ULLONG_MAX; uint64_t used = ULLONG_MAX;
struct osd_request *or;
uint8_t cred_a[OSD_CAP_LEN]; uint8_t cred_a[OSD_CAP_LEN];
int ret; int ret;
/* get used/capacity attributes */ ret = exofs_get_io_state(sbi, &ios);
exofs_make_credential(cred_a, &obj); if (ret) {
EXOFS_DBGMSG("exofs_get_io_state failed.\n");
or = osd_start_request(sbi->s_dev, GFP_KERNEL); return ret;
if (unlikely(!or)) {
EXOFS_DBGMSG("exofs_statfs: osd_start_request failed.\n");
return -ENOMEM;
} }
osd_req_get_attributes(or, &obj); exofs_make_credential(cred_a, &ios->obj);
osd_req_add_get_attr_list(or, attrs, ARRAY_SIZE(attrs)); ios->cred = sbi->s_cred;
ret = exofs_sync_op(or, sbi->s_timeout, cred_a); ios->in_attr = attrs;
ios->in_attr_len = ARRAY_SIZE(attrs);
ret = exofs_sbi_read(ios);
if (unlikely(ret)) if (unlikely(ret))
goto out; goto out;
ret = extract_attr_from_req(or, &attrs[0]); ret = extract_attr_from_ios(ios, &attrs[0]);
if (likely(!ret)) if (likely(!ret)) {
capacity = get_unaligned_be64(attrs[0].val_ptr); capacity = get_unaligned_be64(attrs[0].val_ptr);
else if (unlikely(!capacity))
capacity = ULLONG_MAX;
} else
EXOFS_DBGMSG("exofs_statfs: get capacity failed.\n"); EXOFS_DBGMSG("exofs_statfs: get capacity failed.\n");
ret = extract_attr_from_req(or, &attrs[1]); ret = extract_attr_from_ios(ios, &attrs[1]);
if (likely(!ret)) if (likely(!ret))
used = get_unaligned_be64(attrs[1].val_ptr); used = get_unaligned_be64(attrs[1].val_ptr);
else else
@ -476,15 +659,15 @@ static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf)
/* fill in the stats buffer */ /* fill in the stats buffer */
buf->f_type = EXOFS_SUPER_MAGIC; buf->f_type = EXOFS_SUPER_MAGIC;
buf->f_bsize = EXOFS_BLKSIZE; buf->f_bsize = EXOFS_BLKSIZE;
buf->f_blocks = (capacity >> EXOFS_BLKSHIFT); buf->f_blocks = capacity >> 9;
buf->f_bfree = ((capacity - used) >> EXOFS_BLKSHIFT); buf->f_bfree = (capacity - used) >> 9;
buf->f_bavail = buf->f_bfree; buf->f_bavail = buf->f_bfree;
buf->f_files = sbi->s_numfiles; buf->f_files = sbi->s_numfiles;
buf->f_ffree = EXOFS_MAX_ID - sbi->s_numfiles; buf->f_ffree = EXOFS_MAX_ID - sbi->s_numfiles;
buf->f_namelen = EXOFS_NAME_LEN; buf->f_namelen = EXOFS_NAME_LEN;
out: out:
osd_end_request(or); exofs_put_io_state(ios);
return ret; return ret;
} }