us to load MDS even if the extN module is not building properly.
struct ptlrpc_request **);
int mdc_create_client(char *uuid, struct ptlrpc_client *cl);
+extern int mds_client_add(struct mds_obd *mds, struct mds_client_data *mcd,
+ int cl_off);
+
+/* mds/mds_fs.c */
struct mds_fs_operations {
void *(* fs_start)(struct inode *inode, int op);
int (* fs_commit)(struct inode *inode, void *handle);
int (* fs_setattr)(struct dentry *dentry, void *handle,
struct iattr *iattr);
int (* fs_set_objid)(struct inode *inode, void *handle, obd_id id);
- void (* fs_get_objid)(struct inode *inode, obd_id *id);
+ int (* fs_get_objid)(struct inode *inode, obd_id *id);
ssize_t (* fs_readpage)(struct file *file, char *buf, size_t count,
loff_t *offset);
void (* fs_delete_inode)(struct inode *inode);
int (* fs_set_last_rcvd)(struct mds_obd *mds, void *handle);
};
-#define MDS_FSOP_UNLINK 1
-#define MDS_FSOP_RMDIR 2
-#define MDS_FSOP_RENAME 3
-#define MDS_FSOP_CREATE 4
-#define MDS_FSOP_MKDIR 5
-#define MDS_FSOP_SYMLINK 6
-#define MDS_FSOP_MKNOD 7
-#define MDS_FSOP_SETATTR 8
-#define MDS_FSOP_LINK 9
+extern int mds_register_fs_type(struct mds_fs_operations *op, const char *name);
+extern void mds_unregister_fs_type(const char *name);
+extern int mds_fs_setup(struct mds_obd *mds, struct vfsmount *mnt);
+extern void mds_fs_cleanup(struct mds_obd *mds);
static inline void *mds_fs_start(struct mds_obd *mds, struct inode *inode,
int op)
return mds->mds_fsops->fs_set_objid(inode, handle, id);
}
-static inline void mds_fs_get_objid(struct mds_obd *mds, struct inode *inode,
+static inline int mds_fs_get_objid(struct mds_obd *mds, struct inode *inode,
__u64 *id)
{
- mds->mds_fsops->fs_get_objid(inode, id);
+ return mds->mds_fsops->fs_get_objid(inode, id);
}
static inline ssize_t mds_fs_readpage(struct mds_obd *mds, struct file *file,
return mds->mds_fsops->fs_journal_data(file);
}
-extern struct mds_fs_operations mds_ext2_fs_ops;
-extern struct mds_fs_operations mds_ext3_fs_ops;
-extern struct mds_fs_operations mds_extN_fs_ops;
+#define MDS_FSOP_UNLINK 1
+#define MDS_FSOP_RMDIR 2
+#define MDS_FSOP_RENAME 3
+#define MDS_FSOP_CREATE 4
+#define MDS_FSOP_MKDIR 5
+#define MDS_FSOP_SYMLINK 6
+#define MDS_FSOP_MKNOD 7
+#define MDS_FSOP_SETATTR 8
+#define MDS_FSOP_LINK 9
#endif /* __KERNEL__ */
DEFS:=
MODULE = mds
-modulefs_DATA = mds.o
-EXTRA_PROGRAMS = mds
+modulefs_DATA = mds.o mds_ext2.o mds_ext3.o mds_extN.o
+EXTRA_PROGRAMS = mds mds_ext2 mds_ext3 mds_extN
LINX=mds_updates.c simple.c
mds_updates.c:
simple.c:
test -e simple.c || ln -sf $(top_srcdir)/lib/simple.c
-mds_SOURCES = handler.c mds_reint.c mds_ext2.c mds_ext3.c $(LINX)
+mds_SOURCES = handler.c mds_reint.c mds_fs.c $(LINX)
dist-hook:
list='$(LINX)'; for f in $$list; do rm -f $(distdir)/$$f; done
#include <linux/module.h>
#include <linux/lustre_mds.h>
+static
int mds_sendpage(struct ptlrpc_request *req, struct file *file, __u64 offset)
{
int rc = 0;
return result;
}
-#define MDS_MAX_CLIENTS 1024
-#define MDS_MAX_CLIENT_WORDS (MDS_MAX_CLIENTS / sizeof(unsigned long))
-
-static unsigned long last_rcvd_slots[MDS_MAX_CLIENT_WORDS];
-
-/* Add client data to the MDS. The in-memory storage will be a hash at some
- * point. We use a bitmap to locate a free space in the last_rcvd file if
- * cl_off is -1 (i.e. a new client). Otherwise, we have just read the data
- * from the last_rcvd file and we know its offset.
- */
-int mds_client_add(struct mds_obd *mds, struct mds_client_data *mcd, int cl_off)
-{
- struct mds_client_info *mci;
-
- OBD_ALLOC(mci, sizeof(*mci));
- if (!mci) {
- CERROR("no memory for MDS client info\n");
- RETURN(-ENOMEM);
- }
- INIT_LIST_HEAD(&mci->mci_open_head);
-
- CDEBUG(D_INFO, "client at offset %d with UUID '%s' added\n",
- cl_off, mcd->mcd_uuid);
-
- if (cl_off == -1) {
- unsigned long *word;
- int bit;
-
- repeat:
- word = last_rcvd_slots;
- while(*word == ~0UL)
- ++word;
- if (word - last_rcvd_slots >= MDS_MAX_CLIENT_WORDS) {
- CERROR("no room in client MDS bitmap - fix code\n");
- return -ENOMEM;
- }
- bit = ffz(*word);
- if (test_and_set_bit(bit, word)) {
- CERROR("found bit %d set for word %d - fix code\n",
- bit, word - last_rcvd_slots);
- goto repeat;
- }
- cl_off = word - last_rcvd_slots + bit;
- } else {
- if (test_and_set_bit(cl_off, last_rcvd_slots)) {
- CERROR("bit %d already set in bitmap - bad bad\n",
- cl_off);
- LBUG();
- }
- }
-
- mci->mci_mcd = mcd;
- mci->mci_off = cl_off;
-
- /* For now we just put the clients in a list, not a hashed list */
- list_add_tail(&mci->mci_list, &mds->mds_client_info);
-
- mds->mds_client_count++;
-
- return 0;
-}
-
-void mds_client_del(struct mds_obd *mds, struct mds_client_info *mci)
-{
- unsigned long *word;
- int bit;
-
- word = last_rcvd_slots + mci->mci_off / sizeof(unsigned long);
- bit = mci->mci_off % sizeof(unsigned long);
-
- if (!test_and_clear_bit(bit, word)) {
- CERROR("bit %d already clear in word %d - bad bad\n",
- bit, word - last_rcvd_slots);
- LBUG();
- }
-
- --mds->mds_client_count;
- list_del(&mci->mci_list);
- OBD_FREE(mci->mci_mcd, sizeof(*mci->mci_mcd));
- OBD_FREE(mci, sizeof (*mci));
-}
-
-int mds_client_free_all(struct mds_obd *mds)
-{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &mds->mds_client_info) {
- struct mds_client_info *mci;
-
- mci = list_entry(p, struct mds_client_info, mci_list);
- mds_client_del(mds, mci);
- }
-
- return 0;
-}
-
-int mds_server_free_data(struct mds_obd *mds)
-{
- OBD_FREE(mds->mds_server_data, sizeof(*mds->mds_server_data));
- mds->mds_server_data = NULL;
-
- return 0;
-}
-
+static
int mds_connect(struct ptlrpc_request *req)
{
struct mds_body *body;
RETURN(0);
}
+static
int mds_getattr(struct ptlrpc_request *req)
{
struct dentry *de;
if (rc < 0) {
req->rq_status = rc;
- CERROR("readlink failed: %d\n", req->rq_status);
+ CERROR("readlink failed: %d\n", rc);
GOTO(out, 0);
}
}
body->size = inode->i_size;
body->mode = inode->i_mode;
body->nlink = inode->i_nlink;
- body->valid = ~0;
- mds_fs_get_objid(mds, inode, &body->objid);
+ if (S_ISREG(inode->i_mode)) {
+ rc = mds_fs_get_objid(mds, inode, &body->objid);
+ if (rc < 0) {
+ req->rq_status = rc;
+ CERROR("readlink failed: %d\n", rc);
+ GOTO(out, 0);
+ }
+ }
+ body->valid = ~0; /* FIXME: should be more selective */
out:
l_dput(de);
RETURN(0);
}
+static
int mds_open(struct ptlrpc_request *req)
{
struct mds_obd *mds = &req->rq_obd->u.mds;
RETURN(0);
}
+static
int mds_close(struct ptlrpc_request *req)
{
struct dentry *de;
return 0;
}
-/* This will be a hash table at some point. */
-int mds_init_client_data(struct mds_obd *mds)
-{
- INIT_LIST_HEAD(&mds->mds_client_info);
- return 0;
-}
-
-#define LAST_RCVD "last_rcvd"
-
-int mds_read_last_rcvd(struct mds_obd *mds, struct file *f)
-{
- struct mds_server_data *msd;
- struct mds_client_data *mcd = NULL;
- loff_t fsize = f->f_dentry->d_inode->i_size;
- loff_t off = 0;
- int cl_off;
- __u64 last_rcvd = 0;
- __u64 last_mount;
- int rc = 0;
-
- OBD_ALLOC(msd, sizeof(*msd));
- if (!msd)
- RETURN(-ENOMEM);
- rc = lustre_fread(f, (char *)msd, sizeof(*msd), &off);
-
- mds->mds_server_data = msd;
- if (rc == 0) {
- CERROR("empty MDS %s, new MDS?\n", LAST_RCVD);
- RETURN(0);
- } else if (rc != sizeof(*msd)) {
- CERROR("error reading MDS %s: rc = %d\n", LAST_RCVD, rc);
- if (rc > 0) {
- rc = -EIO;
- }
- GOTO(err_msd, rc);
- }
-
- /*
- * When we do a clean MDS shutdown, we save the last_rcvd into
- * the header. If we find clients with higher last_rcvd values
- * then those clients may need recovery done.
- */
- last_rcvd = le64_to_cpu(msd->msd_last_rcvd);
- mds->mds_last_rcvd = last_rcvd;
- CDEBUG(D_INODE, "got %Lu for server last_rcvd value\n",
- (unsigned long long)last_rcvd);
-
- last_mount = le64_to_cpu(msd->msd_mount_count);
- mds->mds_mount_count = last_mount;
- CDEBUG(D_INODE, "got %Lu for server last_mount value\n",
- (unsigned long long)last_mount);
-
- for (off = MDS_LR_CLIENT, cl_off = 0, rc = sizeof(*mcd);
- off <= fsize - sizeof(*mcd) && rc == sizeof(*mcd);
- off = MDS_LR_CLIENT + ++cl_off * MDS_LR_SIZE) {
- if (!mcd)
- OBD_ALLOC(mcd, sizeof(*mcd));
- if (!mcd)
- GOTO(err_msd, rc = -ENOMEM);
-
- rc = lustre_fread(f, (char *)mcd, sizeof(*mcd), &off);
- if (rc != sizeof(*mcd)) {
- CERROR("error reading MDS %s offset %d: rc = %d\n",
- LAST_RCVD, cl_off, rc);
- if (rc > 0)
- rc = -EIO;
- break;
- }
-
- last_rcvd = le64_to_cpu(mcd->mcd_last_rcvd);
- last_mount = le64_to_cpu(mcd->mcd_mount_count);
-
- if (last_rcvd &&
- last_mount - mcd->mcd_mount_count < MDS_MOUNT_RECOV) {
- rc = mds_client_add(mds, mcd, cl_off);
- if (rc) {
- rc = 0;
- break;
- }
- mcd = NULL;
- } else {
- CDEBUG(D_INFO,
- "client at offset %d with UUID '%s' ignored\n",
- cl_off, mcd->mcd_uuid);
- }
-
- if (last_rcvd > mds->mds_last_rcvd) {
- CDEBUG(D_OTHER,
- "client at offset %d has last_rcvd = %Lu\n",
- cl_off, (unsigned long long)last_rcvd);
- mds->mds_last_rcvd = last_rcvd;
- }
- }
- CDEBUG(D_INODE, "got %Lu for highest last_rcvd value, %d clients\n",
- (unsigned long long)mds->mds_last_rcvd, mds->mds_client_count);
-
- /* After recovery, there can be no local uncommitted transactions */
- mds->mds_last_committed = mds->mds_last_rcvd;
-
- return 0;
-
-err_msd:
- mds_server_free_data(mds);
- return rc;
-}
-
-static int mds_prep(struct obd_device *obddev)
-{
- struct obd_run_ctxt saved;
- struct mds_obd *mds = &obddev->u.mds;
- struct super_operations *s_ops;
- struct dentry *dentry;
- struct file *f;
- int rc;
-
- push_ctxt(&saved, &mds->mds_ctxt);
- dentry = simple_mkdir(current->fs->pwd, "ROOT", 0700);
- if (IS_ERR(dentry)) {
- rc = PTR_ERR(dentry);
- CERROR("cannot create ROOT directory: rc = %d\n", rc);
- GOTO(err_pop, rc);
- }
- /* XXX probably want to hold on to this later... */
- dput(dentry);
- f = filp_open("ROOT", O_RDONLY, 0);
- if (IS_ERR(f)) {
- rc = PTR_ERR(f);
- CERROR("cannot open ROOT: rc = %d\n", rc);
- LBUG();
- GOTO(err_pop, rc);
- }
-
- mds->mds_rootfid.id = f->f_dentry->d_inode->i_ino;
- mds->mds_rootfid.generation = f->f_dentry->d_inode->i_generation;
- mds->mds_rootfid.f_type = S_IFDIR;
-
- rc = filp_close(f, 0);
- if (rc) {
- CERROR("cannot close ROOT: rc = %d\n", rc);
- LBUG();
- }
-
- dentry = simple_mkdir(current->fs->pwd, "FH", 0700);
- if (IS_ERR(dentry)) {
- rc = PTR_ERR(dentry);
- CERROR("cannot create FH directory: rc = %d\n", rc);
- GOTO(err_pop, rc);
- }
- /* XXX probably want to hold on to this later... */
- dput(dentry);
-
- rc = mds_init_client_data(mds);
- if (rc)
- GOTO(err_pop, rc);
-
- f = filp_open(LAST_RCVD, O_RDWR | O_CREAT, 0644);
- if (IS_ERR(f)) {
- rc = PTR_ERR(f);
- CERROR("cannot open/create %s file: rc = %d\n", LAST_RCVD, rc);
- GOTO(err_pop, rc = PTR_ERR(f));
- }
- if (!S_ISREG(f->f_dentry->d_inode->i_mode)) {
- CERROR("%s is not a regular file!: mode = %o\n", LAST_RCVD,
- f->f_dentry->d_inode->i_mode);
- GOTO(err_pop, rc = -ENOENT);
- }
-
- rc = mds_fs_journal_data(mds, f);
- if (rc) {
- CERROR("cannot journal data on %s: rc = %d\n", LAST_RCVD, rc);
- GOTO(err_filp, rc);
- }
-
- rc = mds_read_last_rcvd(mds, f);
- if (rc) {
- CERROR("cannot read %s: rc = %d\n", LAST_RCVD, rc);
- GOTO(err_client, rc);
- }
- mds->mds_rcvd_filp = f;
- pop_ctxt(&saved);
-
- /*
- * Replace the client filesystem delete_inode method with our own,
- * so that we can clear the object ID before the inode is deleted.
- * The fs_delete_inode method will call cl_delete_inode for us.
- *
- * We need to do this for the MDS superblock only, hence we install
- * a modified copy of the original superblock method table.
- *
- * We still assume that there is only a single MDS client filesystem
- * type, as we don't have access to the mds struct in delete_inode
- * and store the client delete_inode method in a global table. This
- * will only become a problem when multiple MDSs are running on a
- * single host with different client filesystems.
- */
- OBD_ALLOC(s_ops, sizeof(*s_ops));
- if (!s_ops)
- GOTO(err_filp, rc = -ENOMEM);
-
- memcpy(s_ops, mds->mds_sb->s_op, sizeof(*s_ops));
- mds->mds_fsops->cl_delete_inode = s_ops->delete_inode;
- s_ops->delete_inode = mds->mds_fsops->fs_delete_inode;
- mds->mds_sb->s_op = s_ops;
-
- mds->mds_service = ptlrpc_init_svc(128 * 1024,
- MDS_REQUEST_PORTAL, MDC_REPLY_PORTAL,
- "self", mds_handle);
-
- if (!mds->mds_service) {
- CERROR("failed to start service\n");
- GOTO(err_filp, rc = -EINVAL);
- }
-
- rc = ptlrpc_start_thread(obddev, mds->mds_service, "lustre_mds");
- if (rc) {
- CERROR("cannot start thread: rc = %d\n", rc);
- GOTO(err_svc, rc);
- }
-
- RETURN(0);
-
-err_svc:
- rpc_unregister_service(mds->mds_service);
- OBD_FREE(mds->mds_service, sizeof(*mds->mds_service));
-err_client:
- mds_client_free_all(mds);
-err_filp:
- if (filp_close(f, 0))
- CERROR("can't close %s after error\n", LAST_RCVD);
-err_pop:
- pop_ctxt(&saved);
-
- return rc;
-}
-
/* Update the server data on disk. This stores the new mount_count and
* also the last_rcvd value to disk. If we don't have a clean shutdown,
* then the server last_rcvd value may be less than that of the clients.
* This will alert us that we may need to do client recovery.
*/
+static
int mds_update_server_data(struct mds_obd *mds)
{
struct obd_run_ctxt saved;
return rc;
}
-static int mds_cleanup(struct obd_device *obddev);
-
/* mount the file system (secretly) */
static int mds_setup(struct obd_device *obddev, obd_count len, void *buf)
{
int rc = 0;
ENTRY;
+ MOD_INC_USE_COUNT;
#ifdef CONFIG_DEV_RDONLY
dev_clear_rdonly(2);
#endif
if (!data->ioc_inlbuf1 || !data->ioc_inlbuf2)
- RETURN(-EINVAL);
+ GOTO(err_dec, rc = -EINVAL);
mds->mds_fstype = strdup(data->ioc_inlbuf2);
- if (!strcmp(mds->mds_fstype, "extN"))
- mds->mds_fsops = &mds_extN_fs_ops;
- else if (!strcmp(mds->mds_fstype, "ext3"))
- mds->mds_fsops = &mds_ext3_fs_ops;
- else if (!strcmp(mds->mds_fstype, "ext2"))
- mds->mds_fsops = &mds_ext2_fs_ops;
- else {
- CERROR("unsupported MDS filesystem type %s\n", mds->mds_fstype);
- GOTO(err_kfree, rc = -EPERM);
- }
-
- MOD_INC_USE_COUNT;
mnt = do_kern_mount(mds->mds_fstype, 0, data->ioc_inlbuf1, NULL);
if (IS_ERR(mnt)) {
rc = PTR_ERR(mnt);
CERROR("do_kern_mount failed: rc = %d\n", rc);
- GOTO(err_dec, rc);
+ GOTO(err_kfree, rc);
}
mds->mds_sb = mnt->mnt_root->d_inode->i_sb;
if (!mds->mds_sb)
GOTO(err_put, rc = -ENODEV);
- mds->mds_vfsmnt = mnt;
- mds->mds_ctxt.pwdmnt = mnt;
- mds->mds_ctxt.pwd = mnt->mnt_root;
- mds->mds_ctxt.fs = KERNEL_DS;
-
- rc = mds_prep(obddev);
- if (rc)
+ rc = mds_fs_setup(mds, mnt);
+ if (rc) {
+ CERROR("MDS filesystem method init failed: rc = %d\n", rc);
GOTO(err_put, rc);
+ }
- rc = mds_recover(obddev);
+ mds->mds_service = ptlrpc_init_svc(128 * 1024,
+ MDS_REQUEST_PORTAL, MDC_REPLY_PORTAL, "self", mds_handle);
+ if (!mds->mds_service) {
+ CERROR("failed to start service\n");
+ GOTO(err_fs, rc = -EINVAL);
+ }
+
+ rc = ptlrpc_start_thread(obddev, mds->mds_service, "lustre_mds");
if (rc) {
- mds_cleanup(obddev);
- RETURN(rc);
+ CERROR("cannot start thread: rc = %d\n", rc);
+ GOTO(err_svc, rc);
}
+ rc = mds_recover(obddev);
+ if (rc)
+ GOTO(err_thread, rc);
+
RETURN(0);
+err_thread:
+ ptlrpc_stop_all_threads(mds->mds_service);
+err_svc:
+ rpc_unregister_service(mds->mds_service);
+ OBD_FREE(mds->mds_service, sizeof(*mds->mds_service));
+err_fs:
+ mds_fs_cleanup(mds);
err_put:
unlock_kernel();
mntput(mds->mds_vfsmnt);
mds->mds_sb = 0;
lock_kernel();
-err_dec:
- MOD_DEC_USE_COUNT;
err_kfree:
kfree(mds->mds_fstype);
+err_dec:
+ MOD_DEC_USE_COUNT;
return rc;
}
static int mds_cleanup(struct obd_device * obddev)
{
- struct super_operations *s_ops = NULL;
struct super_block *sb;
struct mds_obd *mds = &obddev->u.mds;
if (!mds->mds_sb)
RETURN(0);
- mds_client_free_all(mds);
mds_update_server_data(mds);
- mds_server_free_data(mds);
if (mds->mds_rcvd_filp) {
int rc = filp_close(mds->mds_rcvd_filp, 0);
if (rc)
CERROR("last_rcvd file won't close, rc=%d\n", rc);
}
- s_ops = sb->s_op;
unlock_kernel();
mntput(mds->mds_vfsmnt);
#ifdef CONFIG_DEV_RDONLY
dev_clear_rdonly(2);
#endif
- OBD_FREE(s_ops, sizeof(*s_ops));
+ mds_fs_cleanup(mds);
MOD_DEC_USE_COUNT;
RETURN(0);
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/lustre_mds.h>
+#include <linux/module.h>
static void *mds_ext2_start(struct inode *inode, int nblocks)
{
return 0;
}
-static void mds_ext2_get_objid(struct inode *inode, obd_id *id)
+static int mds_ext2_get_objid(struct inode *inode, obd_id *id)
{
*id = le64_to_cpu(inode->u.ext2_i.i_data[0]);
+
+ return 0;
}
static ssize_t mds_ext2_readpage(struct file *file, char *buf, size_t count,
return generic_file_read(file, buf, count, offset);
}
-struct mds_fs_operations mds_ext2_fs_ops;
+static struct mds_fs_operations mds_ext2_fs_ops;
static void mds_ext2_delete_inode(struct inode *inode)
{
return 0;
}
-struct mds_fs_operations mds_ext2_fs_ops = {
+static struct mds_fs_operations mds_ext2_fs_ops = {
fs_start: mds_ext2_start,
fs_commit: mds_ext2_stop,
fs_setattr: mds_ext2_setattr,
fs_journal_data:mds_ext2_journal_data,
fs_set_last_rcvd:mds_ext2_set_last_rcvd,
};
+
+static int __init mds_ext2_init(void)
+{
+ return mds_register_fs_type(&mds_ext2_fs_ops, "ext2");
+}
+
+static void __exit mds_ext2_exit(void)
+{
+ mds_unregister_fs_type("ext2");
+}
+
+MODULE_AUTHOR("Cluster File Systems, Inc. <adilger@clusterfs.com>");
+MODULE_DESCRIPTION("Lustre MDS ext2 Filesystem Helper v0.1");
+MODULE_LICENSE("GPL");
+
+module_init(mds_ext2_init);
+module_exit(mds_ext2_exit);
#include <linux/jbd.h>
#include <linux/ext3_fs.h>
#include <linux/ext3_jbd.h>
-#include <linux/extN_fs.h>
#include <linux/lustre_mds.h>
+#include <linux/module.h>
+
+static struct mds_fs_operations mds_ext3_fs_ops;
+static kmem_cache_t *jcb_cache;
+static int jcb_cache_count;
+
+struct mds_cb_data {
+ struct journal_callback cb_jcb;
+ struct mds_obd *cb_mds;
+ __u64 cb_last_rcvd;
+};
/*
* We don't currently need any additional blocks for rmdir and
switch(op) {
case MDS_FSOP_RMDIR:
case MDS_FSOP_UNLINK:
- nblocks += EXT3_DELETE_TRANS_BLOCKS; break;
+ nblocks += EXT3_DELETE_TRANS_BLOCKS;
+ break;
case MDS_FSOP_RENAME:
+ /* We may be modifying two directories */
nblocks += EXT3_DATA_TRANS_BLOCKS;
+ case MDS_FSOP_SYMLINK:
+ /* Possible new block + block bitmap + GDT for long symlink */
+ nblocks += 3;
case MDS_FSOP_CREATE:
- // FIXME: when we store oa_id in an EA we need more blocks
- // nblocks += 0;
case MDS_FSOP_MKDIR:
- case MDS_FSOP_SYMLINK:
- /* Create new directory or symlink (more data blocks) */
- nblocks += 2;
case MDS_FSOP_MKNOD:
- /* Change parent directory + setattr on new inode */
- nblocks += EXT3_DATA_TRANS_BLOCKS + 3;
+ /* New inode + block bitmap + GDT for new file */
+ nblocks += 3;
+ case MDS_FSOP_LINK:
+ /* Change parent directory */
+ nblocks += EXT3_DATA_TRANS_BLOCKS;
+ break;
+ case MDS_FSOP_SETATTR:
+ /* Setattr on inode */
+ nblocks += 1;
+ break;
+ default: CERROR("unknown transaction start op %d\n", op);
+ LBUG();
}
return journal_start(EXT3_JOURNAL(inode), nblocks);
return 0;
}
-static void mds_ext3_get_objid(struct inode *inode, obd_id *id)
+static int mds_ext3_get_objid(struct inode *inode, obd_id *id)
{
*id = le64_to_cpu(EXT3_I(inode)->i_data[0]);
+
+ return 0;
}
static ssize_t mds_ext3_readpage(struct file *file, char *buf, size_t count,
return rc;
}
-static ssize_t mds_extN_readpage(struct file *file, char *buf, size_t count,
- loff_t *offset)
-{
- struct inode *inode = file->f_dentry->d_inode;
- int rc = 0;
-
- if (S_ISREG(inode->i_mode))
- rc = file->f_op->read(file, buf, count, offset);
- else {
- struct buffer_head *bh;
-
- /* FIXME: this assumes the blocksize == count, but the calling
- * function will detect this as an error for now */
- bh = extN_bread(NULL, inode,
- *offset >> inode->i_sb->s_blocksize_bits,
- 0, &rc);
-
- if (bh) {
- memcpy(buf, bh->b_data, inode->i_blksize);
- brelse(bh);
- rc = inode->i_blksize;
- }
- }
-
- return rc;
-}
-
-struct mds_fs_operations mds_ext3_fs_ops;
-struct mds_fs_operations mds_extN_fs_ops;
-
static void mds_ext3_delete_inode(struct inode *inode)
{
if (S_ISREG(inode->i_mode)) {
mds_ext3_fs_ops.cl_delete_inode(inode);
}
-static void mds_extN_delete_inode(struct inode *inode)
-{
- if (S_ISREG(inode->i_mode)) {
- void *handle = mds_ext3_start(inode, MDS_FSOP_UNLINK);
-
- if (IS_ERR(handle)) {
- CERROR("unable to start transaction");
- EXIT;
- return;
- }
- if (mds_ext3_set_objid(inode, handle, 0))
- CERROR("error clearing objid on %ld\n", inode->i_ino);
-
- if (mds_extN_fs_ops.cl_delete_inode)
- mds_extN_fs_ops.cl_delete_inode(inode);
-
- if (mds_ext3_commit(inode, handle))
- CERROR("error closing handle on %ld\n", inode->i_ino);
- } else
- mds_extN_fs_ops.cl_delete_inode(inode);
-}
-
-struct mds_cb_data {
- struct journal_callback cb_jcb;
- struct mds_obd *cb_mds;
- __u64 cb_last_rcvd;
-};
-
static void mds_ext3_callback_status(struct journal_callback *jcb, int error)
{
struct mds_cb_data *mcb = (struct mds_cb_data *)jcb;
if (!error && mcb->cb_last_rcvd > mcb->cb_mds->mds_last_committed)
mcb->cb_mds->mds_last_committed = mcb->cb_last_rcvd;
- OBD_FREE(mcb, sizeof(*mcb));
+ kmem_cache_free(jcb_cache, mcb);
+ --jcb_cache_count;
}
#ifdef HAVE_JOURNAL_CALLBACK
{
struct mds_cb_data *mcb;
- OBD_ALLOC(mcb, sizeof(*mcb));
+ mcb = kmem_cache_alloc(jcb_cache, GFP_NOFS);
if (!mcb)
RETURN(-ENOMEM);
+ ++jcb_cache_count;
mcb->cb_mds = mds;
mcb->cb_last_rcvd = mds->mds_last_rcvd;
return 0;
}
-struct mds_fs_operations mds_ext3_fs_ops = {
+static struct mds_fs_operations mds_ext3_fs_ops = {
fs_start: mds_ext3_start,
fs_commit: mds_ext3_commit,
fs_setattr: mds_ext3_setattr,
fs_set_last_rcvd:mds_ext3_set_last_rcvd,
};
-struct mds_fs_operations mds_extN_fs_ops = {
- fs_start: mds_ext3_start,
- fs_commit: mds_ext3_commit,
- fs_setattr: mds_ext3_setattr,
- fs_set_objid: mds_ext3_set_objid,
- fs_get_objid: mds_ext3_get_objid,
- fs_readpage: mds_extN_readpage,
- fs_delete_inode:mds_extN_delete_inode,
- cl_delete_inode:clear_inode,
- fs_journal_data:mds_ext3_journal_data,
- fs_set_last_rcvd:mds_ext3_set_last_rcvd,
-};
+static int __init mds_ext3_init(void)
+{
+ int rc;
+
+ jcb_cache = kmem_cache_create("mds_ext3_jcb",
+ sizeof(struct mds_cb_data), 0,
+ SLAB_POISON, NULL, NULL);
+ if (!jcb_cache) {
+ CERROR("error allocating MDS journal callback cache\n");
+ GOTO(out, rc = -ENOMEM);
+ }
+
+ rc = mds_register_fs_type(&mds_ext3_fs_ops, "ext3");
+
+ if (rc)
+ kmem_cache_destroy(jcb_cache);
+out:
+ return rc;
+}
+
+static void __exit mds_ext3_exit(void)
+{
+ int rc;
+
+ mds_unregister_fs_type("ext3");
+ rc = kmem_cache_destroy(jcb_cache);
+
+ if (rc || jcb_cache_count) {
+ CERROR("can't free MDS callback cache: count %d, rc = %d\n",
+ jcb_cache_count, rc);
+ }
+}
+
+MODULE_AUTHOR("Cluster File Systems, Inc. <adilger@clusterfs.com>");
+MODULE_DESCRIPTION("Lustre MDS ext3 Filesystem Helper v0.1");
+MODULE_LICENSE("GPL");
+
+module_init(mds_ext3_init);
+module_exit(mds_ext3_exit);
#include <linux/extN_jbd.h>
#include <linux/extN_xattr.h>
#include <linux/lustre_mds.h>
+#include <linux/module.h>
-struct mds_fs_operations mds_extN_fs_ops;
+static struct mds_fs_operations mds_extN_fs_ops;
static kmem_cache_t *jcb_cache;
static int jcb_cache_count;
#define XATTR_MDS_MO_MAGIC 0x4711
-int mds_extN_init(struct mds_obd *mds)
-{
- int rc;
-
- /*
- * Replace the client filesystem delete_inode method with our own,
- * so that we can clear the object ID before the inode is deleted.
- * The fs_delete_inode method will call cl_delete_inode for us.
- *
- * We need to do this for the MDS superblock only, hence we install
- * a modified copy of the original superblock method table.
- *
- * We still assume that there is only a single MDS client filesystem
- * type, as we don't have access to the mds struct in delete_inode
- * and store the client delete_inode method in a global table. This
- * will only become a problem when multiple MDSs are running on a
- * single host with different client filesystems.
- */
- OBD_ALLOC(mds->mds_sop, sizeof(*mds->mds_sop));
- if (!mds->mds_sop)
- GOTO(out, rc = -ENOMEM);
-
- memcpy(mds->mds_sop, mds->mds_sb->s_op, sizeof(*mds->mds_sop));
- mds_extN_fs_ops.cl_delete_inode = mds->mds_sop->delete_inode;
- mds->mds_sop->delete_inode = mds_extN_fs_ops.fs_delete_inode;
- mds->mds_sb->s_op = mds->mds_sop;
-
- //rc = extN_xattr_register();
- jcb_cache = kmem_cache_create("mds_extN_jcb",
- sizeof(struct mds_cb_data), 0,
- SLAB_POISON, NULL, NULL);
- if (!jcb_cache) {
- CERROR("error allocating MDS journal callback cache\n");
- GOTO(out_sop, rc = -ENOMEM);
- }
-
- return 0;
-
-out_sop:
- OBD_FREE(mds->mds_sop, sizeof(*mds->mds_sop));
-out:
- return rc;
-}
-
-int mds_extN_exit(struct mds_obd *mds)
-{
- int rc;
-
- rc = kmem_cache_destroy(jcb_cache);
-
- if (rc || jcb_cache_count) {
- CERROR("can't free MDS callback cache: count %d, rc = %d\n",
- jcb_cache_count, rc);
- }
-
- //rc = extN_xattr_unregister();
- OBD_FREE(mds->mds_sop, sizeof(*mds->mds_sop));
- return rc;
-}
-
/*
* We don't currently need any additional blocks for rmdir and
* unlink transactions because we are storing the OST oa_id inside
return 0;
}
-struct mds_fs_operations mds_extN_fs_ops = {
- fs_init: mds_extN_init,
- fs_exit: mds_extN_exit,
- fs_start: mds_extN_start,
- fs_commit: mds_extN_commit,
- fs_setattr: mds_extN_setattr,
- fs_set_objid: mds_extN_set_objid,
- fs_get_objid: mds_extN_get_objid,
- fs_readpage: mds_extN_readpage,
- fs_delete_inode:mds_extN_delete_inode,
- cl_delete_inode:clear_inode,
- fs_journal_data:mds_extN_journal_data,
- fs_set_last_rcvd:mds_extN_set_last_rcvd,
+static struct mds_fs_operations mds_extN_fs_ops = {
+ fs_start: mds_extN_start,
+ fs_commit: mds_extN_commit,
+ fs_setattr: mds_extN_setattr,
+ fs_set_objid: mds_extN_set_objid,
+ fs_get_objid: mds_extN_get_objid,
+ fs_readpage: mds_extN_readpage,
+ fs_delete_inode: mds_extN_delete_inode,
+ cl_delete_inode: clear_inode,
+ fs_journal_data: mds_extN_journal_data,
+ fs_set_last_rcvd: mds_extN_set_last_rcvd,
};
+
+static int __init mds_extN_init(void)
+{
+ int rc;
+
+ //rc = extN_xattr_register();
+ jcb_cache = kmem_cache_create("mds_extN_jcb",
+ sizeof(struct mds_cb_data), 0,
+ SLAB_POISON, NULL, NULL);
+ if (!jcb_cache) {
+ CERROR("error allocating MDS journal callback cache\n");
+ GOTO(out, rc = -ENOMEM);
+ }
+ rc = mds_register_fs_type(&mds_extN_fs_ops, "extN");
+
+ if (rc)
+ kmem_cache_destroy(jcb_cache);
+out:
+ return rc;
+}
+
+static void __exit mds_extN_exit(void)
+{
+ int rc;
+
+ mds_unregister_fs_type("extN");
+ rc = kmem_cache_destroy(jcb_cache);
+
+ if (rc || jcb_cache_count) {
+ CERROR("can't free MDS callback cache: count %d, rc = %d\n",
+ jcb_cache_count, rc);
+ }
+
+ //rc = extN_xattr_unregister();
+}
+
+MODULE_AUTHOR("Cluster File Systems, Inc. <adilger@clusterfs.com>");
+MODULE_DESCRIPTION("Lustre MDS extN Filesystem Helper v0.1");
+MODULE_LICENSE("GPL");
+
+module_init(mds_extN_init);
+module_exit(mds_extN_exit);