* Copyright (C) 2001-2003 Cluster File Systems, Inc.
* Author: Andreas Dilger <adilger@clusterfs.com>
*
- * This file is part of Lustre, http://www.lustre.org.
+ * This file is part of the Lustre file system, http://www.lustre.org
+ * Lustre is a trademark of Cluster File Systems, Inc.
*
- * Lustre is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
+ * You may have signed or agreed to another license before downloading
+ * this software. If so, you are bound by the terms and conditions
+ * of that agreement, and the following does not apply to you. See the
+ * LICENSE file included with this distribution for more information.
*
- * Lustre 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.
+ * If you did not agree to a different license, then this copy of Lustre
+ * is open source software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
*
- * You should have received a copy of the GNU General Public License
- * along with Lustre; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * In either case, Lustre 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
+ * license text for more details.
*
* OST<->MDS recovery logging infrastructure.
*
#define EXPORT_SYMTAB
#endif
-#ifdef __KERNEL__
-#include <linux/fs.h>
-#else
+#ifndef __KERNEL__
#include <liblustre.h>
#endif
-#include <linux/obd.h>
-#include <linux/obd_class.h>
-#include <linux/lustre_log.h>
-#include <linux/obd_ost.h>
-#include <portals/list.h>
-#include <linux/lvfs.h>
-#include <linux/lustre_fsfilt.h>
+#include <obd.h>
+#include <obd_class.h>
+#include <lustre_log.h>
+#include <obd_ost.h>
+#include <libcfs/list.h>
+#include <lvfs.h>
+#include <lustre_fsfilt.h>
+#include <lustre_disk.h>
#include "llog_internal.h"
-#ifdef __KERNEL__
+#if defined(__KERNEL__) && defined(LLOG_LVFS)
static int llog_lvfs_pad(struct obd_device *obd, struct l_file *file,
int len, int index)
tail.lrt_len = rec.lrh_len = len;
tail.lrt_index = rec.lrh_index = index;
- rec.lrh_type = 0;
+ rec.lrh_type = LLOG_PAD_MAGIC;
rc = fsfilt_write_record(obd, file, &rec, sizeof(rec), &file->f_pos, 0);
if (rc) {
int buflen = rec->lrh_len;
ENTRY;
+
file->f_pos = off;
+ if (buflen == 0)
+ CWARN("0-length record\n");
+
if (!buf) {
rc = fsfilt_write_record(obd, file, rec, buflen,&file->f_pos,0);
if (rc) {
obd = handle->lgh_ctxt->loc_exp->exp_obd;
- if (handle->lgh_file->f_dentry->d_inode->i_size == 0) {
+ if (i_size_read(handle->lgh_file->f_dentry->d_inode) == 0) {
CDEBUG(D_HA, "not reading header from 0-byte log\n");
RETURN(LLOG_EEMPTY);
}
rc = llog_lvfs_read_blob(obd, handle->lgh_file, handle->lgh_hdr,
LLOG_CHUNK_SIZE, 0);
if (rc) {
- CERROR("error reading log header from %*s\n",
+ CERROR("error reading log header from %.*s\n",
handle->lgh_file->f_dentry->d_name.len,
handle->lgh_file->f_dentry->d_name.name);
} else {
struct llog_rec_hdr *llh_hdr = &handle->lgh_hdr->llh_hdr;
- /*
- * These need to be fixed for bug 1987
- */
+
+ if (LLOG_REC_HDR_NEEDS_SWABBING(llh_hdr))
+ lustre_swab_llog_hdr(handle->lgh_hdr);
+
if (llh_hdr->lrh_type != LLOG_HDR_MAGIC) {
- CERROR("bad log %*s header magic: %#x (expected %#x)\n",
+ CERROR("bad log %.*s header magic: %#x (expected %#x)\n",
handle->lgh_file->f_dentry->d_name.len,
handle->lgh_file->f_dentry->d_name.name,
llh_hdr->lrh_type, LLOG_HDR_MAGIC);
rc = -EIO;
} else if (llh_hdr->lrh_len != LLOG_CHUNK_SIZE) {
- CERROR("incorrectly sized log %*s header: %#x "
+ CERROR("incorrectly sized log %.*s header: %#x "
"(expected %#x)\n",
handle->lgh_file->f_dentry->d_name.len,
handle->lgh_file->f_dentry->d_name.name,
}
handle->lgh_last_idx = handle->lgh_hdr->llh_tail.lrt_index;
- handle->lgh_file->f_pos = handle->lgh_file->f_dentry->d_inode->i_size;
+ handle->lgh_file->f_pos = i_size_read(handle->lgh_file->f_dentry->d_inode);
RETURN(rc);
}
if (rc)
RETURN(rc);
+ if (buf)
+ /* write_blob adds header and tail to lrh_len. */
+ reclen = sizeof(*rec) + rec->lrh_len +
+ sizeof(struct llog_rec_tail);
+
if (idx != -1) {
loff_t saved_offset;
/* no header: only allowed to insert record 1 */
- if (idx != 1 && !file->f_dentry->d_inode->i_size) {
+ if (idx != 1 && !i_size_read(file->f_dentry->d_inode)) {
CERROR("idx != -1 in empty log\n");
LBUG();
}
- if (idx && llh->llh_size && llh->llh_size != reclen)
+ if (idx && llh->llh_size && llh->llh_size != rec->lrh_len)
RETURN(-EINVAL);
+ if (!ext2_test_bit(idx, llh->llh_bitmap))
+ CERROR("Modify unset record %u\n", idx);
+ if (idx != rec->lrh_index)
+ CERROR("Index mismatch %d %u\n", idx, rec->lrh_index);
+
rc = llog_lvfs_write_blob(obd, file, &llh->llh_hdr, NULL, 0);
/* we are done if we only write the header or on error */
if (rc || idx == 0)
RETURN(rc);
- saved_offset = sizeof(*llh) + (idx-1)*rec->lrh_len;
+ /* Assumes constant lrh_len */
+ saved_offset = sizeof(*llh) + (idx - 1) * reclen;
+
+ if (buf) {
+ struct llog_rec_hdr check;
+
+ /* We assume that caller has set lgh_cur_* */
+ saved_offset = loghandle->lgh_cur_offset;
+ CDEBUG(D_OTHER,
+ "modify record "LPX64": idx:%d/%u/%d, len:%u "
+ "offset %llu\n",
+ loghandle->lgh_id.lgl_oid, idx, rec->lrh_index,
+ loghandle->lgh_cur_idx, rec->lrh_len,
+ (long long)(saved_offset - sizeof(*llh)));
+ if (rec->lrh_index != loghandle->lgh_cur_idx) {
+ CERROR("modify idx mismatch %u/%d\n",
+ idx, loghandle->lgh_cur_idx);
+ RETURN(-EFAULT);
+ }
+#if 1 /* FIXME remove this safety check at some point */
+ /* Verify that the record we're modifying is the
+ right one. */
+ rc = llog_lvfs_read_blob(obd, file, &check,
+ sizeof(check), saved_offset);
+ if (check.lrh_index != idx || check.lrh_len != reclen) {
+ CERROR("Bad modify idx %u/%u size %u/%u (%d)\n",
+ idx, check.lrh_index, reclen,
+ check.lrh_len, rc);
+ RETURN(-EFAULT);
+ }
+#endif
+ }
+
rc = llog_lvfs_write_blob(obd, file, rec, buf, saved_offset);
if (rc == 0 && reccookie) {
reccookie->lgc_lgl = loghandle->lgh_id;
* big enough to hold reclen, so all we care about is padding here.
*/
left = LLOG_CHUNK_SIZE - (file->f_pos & (LLOG_CHUNK_SIZE - 1));
- if (buf)
- reclen = sizeof(*rec) + rec->lrh_len +
- sizeof(struct llog_rec_tail);
/* NOTE: padding is a record, but no bit is set */
if (left != 0 && left != reclen &&
left < (reclen + LLOG_MIN_REC_SIZE)) {
- int bitmap_size = sizeof(llh->llh_bitmap) * 8;
loghandle->lgh_last_idx++;
rc = llog_lvfs_pad(obd, file, left, loghandle->lgh_last_idx);
if (rc)
RETURN(rc);
/* if it's the last idx in log file, then return -ENOSPC */
- if (loghandle->lgh_last_idx == bitmap_size - 1)
+ if (loghandle->lgh_last_idx == LLOG_BITMAP_SIZE(llh) - 1)
RETURN(-ENOSPC);
}
loghandle->lgh_last_idx++;
index = loghandle->lgh_last_idx;
+ LASSERT(index < LLOG_BITMAP_SIZE(llh));
rec->lrh_index = index;
if (buf == NULL) {
lrt = (struct llog_rec_tail *)
if (rc)
RETURN(rc);
- CDEBUG(D_HA, "added record "LPX64": idx: %u, %u bytes\n",
+ CDEBUG(D_RPCTRACE, "added record "LPX64": idx: %u, %u bytes\n",
loghandle->lgh_id.lgl_oid, index, rec->lrh_len);
if (rc == 0 && reccookie) {
reccookie->lgc_lgl = loghandle->lgh_id;
reccookie->lgc_index = index;
- if (rec->lrh_type == MDS_UNLINK_REC)
- reccookie->lgc_subsys = LLOG_UNLINK_ORIG_CTXT;
+ if ((rec->lrh_type == MDS_UNLINK_REC) ||
+ (rec->lrh_type == MDS_SETATTR_REC))
+ reccookie->lgc_subsys = LLOG_MDS_OST_ORIG_CTXT;
else if (rec->lrh_type == OST_SZ_REC)
reccookie->lgc_subsys = LLOG_SIZE_ORIG_CTXT;
else if (rec->lrh_type == OST_RAID1_REC)
CDEBUG(D_OTHER, "looking for log index %u (cur idx %u off "LPU64")\n",
next_idx, *cur_idx, *cur_offset);
- while (*cur_offset < loghandle->lgh_file->f_dentry->d_inode->i_size) {
+ while (*cur_offset < i_size_read(loghandle->lgh_file->f_dentry->d_inode)) {
struct llog_rec_hdr *rec;
struct llog_rec_tail *tail;
loff_t ppos;
rc = fsfilt_read_record(loghandle->lgh_ctxt->loc_exp->exp_obd,
loghandle->lgh_file, buf, len,
&ppos);
-
if (rc) {
CERROR("Cant read llog block at log id "LPU64
"/%u offset "LPU64"\n",
rc = ppos - *cur_offset;
*cur_offset = ppos;
+ if (rc < len) {
+ /* signal the end of the valid buffer to llog_process */
+ memset(buf + rc, 0, len - rc);
+ }
+
if (rc == 0) /* end of file, nothing to do */
RETURN(0);
RETURN(-EINVAL);
}
- tail = buf + rc - sizeof(struct llog_rec_tail);
+ rec = buf;
+ tail = (struct llog_rec_tail *)((char *)buf + rc -
+ sizeof(struct llog_rec_tail));
+
+ if (LLOG_REC_HDR_NEEDS_SWABBING(rec)) {
+ lustre_swab_llog_rec(rec, tail);
+ }
+
*cur_idx = tail->lrt_index;
/* this shouldn't happen */
/* sanity check that the start of the new buffer is no farther
* than the record that we wanted. This shouldn't happen. */
- rec = buf;
if (rec->lrh_index > next_idx) {
CERROR("missed desired record? %u > %u\n",
rec->lrh_index, next_idx);
RETURN(-EIO);
}
-static struct file *llog_filp_open(char *name, int flags, int mode)
+static int llog_lvfs_prev_block(struct llog_handle *loghandle,
+ int prev_idx, void *buf, int len)
+{
+ __u64 cur_offset;
+ int rc;
+ ENTRY;
+
+ if (len == 0 || len & (LLOG_CHUNK_SIZE - 1))
+ RETURN(-EINVAL);
+
+ CDEBUG(D_OTHER, "looking for log index %u\n", prev_idx);
+
+ cur_offset = LLOG_CHUNK_SIZE;
+ llog_skip_over(&cur_offset, 0, prev_idx);
+
+ while (cur_offset < i_size_read(loghandle->lgh_file->f_dentry->d_inode)) {
+ struct llog_rec_hdr *rec;
+ struct llog_rec_tail *tail;
+ loff_t ppos;
+
+ ppos = cur_offset;
+
+ rc = fsfilt_read_record(loghandle->lgh_ctxt->loc_exp->exp_obd,
+ loghandle->lgh_file, buf, len,
+ &ppos);
+ if (rc) {
+ CERROR("Cant read llog block at log id "LPU64
+ "/%u offset "LPU64"\n",
+ loghandle->lgh_id.lgl_oid,
+ loghandle->lgh_id.lgl_ogen,
+ cur_offset);
+ RETURN(rc);
+ }
+
+ /* put number of bytes read into rc to make code simpler */
+ rc = ppos - cur_offset;
+ cur_offset = ppos;
+
+ if (rc == 0) /* end of file, nothing to do */
+ RETURN(0);
+
+ if (rc < sizeof(*tail)) {
+ CERROR("Invalid llog block at log id "LPU64"/%u offset "
+ LPU64"\n", loghandle->lgh_id.lgl_oid,
+ loghandle->lgh_id.lgl_ogen, cur_offset);
+ RETURN(-EINVAL);
+ }
+
+ tail = buf + rc - sizeof(struct llog_rec_tail);
+
+ /* this shouldn't happen */
+ if (tail->lrt_index == 0) {
+ CERROR("Invalid llog tail at log id "LPU64"/%u offset "
+ LPU64"\n", loghandle->lgh_id.lgl_oid,
+ loghandle->lgh_id.lgl_ogen, cur_offset);
+ RETURN(-EINVAL);
+ }
+ if (le32_to_cpu(tail->lrt_index) < prev_idx)
+ continue;
+
+ /* sanity check that the start of the new buffer is no farther
+ * than the record that we wanted. This shouldn't happen. */
+ rec = buf;
+ if (le32_to_cpu(rec->lrh_index) > prev_idx) {
+ CERROR("missed desired record? %u > %u\n",
+ le32_to_cpu(rec->lrh_index), prev_idx);
+ RETURN(-ENOENT);
+ }
+ RETURN(0);
+ }
+ RETURN(-EIO);
+}
+
+static struct file *llog_filp_open(char *dir, char *name, int flags, int mode)
{
char *logname;
struct file *filp;
if (logname == NULL)
return ERR_PTR(-ENOMEM);
- len = snprintf(logname, PATH_MAX, "LOGS/%s", name);
+ len = snprintf(logname, PATH_MAX, "%s/%s", dir, name);
if (len >= PATH_MAX - 1) {
filp = ERR_PTR(-ENAMETOOLONG);
} else {
CERROR("logfile creation %s: %ld\n", logname,
PTR_ERR(filp));
}
-
OBD_FREE(logname, PATH_MAX);
return filp;
}
GOTO(cleanup, rc);
}
- handle->lgh_file = l_dentry_open(&obd->obd_ctxt, dchild,
+ handle->lgh_file = l_dentry_open(&obd->obd_lvfs_ctxt, dchild,
O_RDWR | O_LARGEFILE);
if (IS_ERR(handle->lgh_file)) {
rc = PTR_ERR(handle->lgh_file);
handle->lgh_id = *logid;
} else if (name) {
- handle->lgh_file = llog_filp_open(name, open_flags, 0644);
+ /* COMPAT_146 */
+ if (strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME) == 0) {
+ handle->lgh_file = llog_filp_open(MDT_LOGS_DIR, name,
+ open_flags, 0644);
+ } else {
+ /* end COMPAT_146 */
+ handle->lgh_file = llog_filp_open(MOUNT_CONFIGS_DIR,
+ name, open_flags,
+ 0644);
+ }
if (IS_ERR(handle->lgh_file))
GOTO(cleanup, rc = PTR_ERR(handle->lgh_file));
handle->lgh_id.lgl_ogen =
handle->lgh_file->f_dentry->d_inode->i_generation;
} else {
- oa = obdo_alloc();
+ OBDO_ALLOC(oa);
if (oa == NULL)
GOTO(cleanup, rc = -ENOMEM);
- /* XXX get some filter group constants */
- oa->o_gr = 1;
+
+ oa->o_gr = FILTER_GROUP_LLOG;
oa->o_valid = OBD_MD_FLGENER | OBD_MD_FLGROUP;
+
rc = obd_create(ctxt->loc_exp, oa, NULL, NULL);
if (rc)
GOTO(cleanup, rc);
if (IS_ERR(dchild))
GOTO(cleanup, rc = PTR_ERR(dchild));
cleanup_phase = 2;
- handle->lgh_file = l_dentry_open(&obd->obd_ctxt, dchild,
+ handle->lgh_file = l_dentry_open(&obd->obd_lvfs_ctxt, dchild,
open_flags);
if (IS_ERR(handle->lgh_file))
GOTO(cleanup, rc = PTR_ERR(handle->lgh_file));
handle->lgh_ctxt = ctxt;
finish:
if (oa)
- obdo_free(oa);
+ OBDO_FREE(oa);
RETURN(rc);
cleanup:
switch (cleanup_phase) {
{
struct dentry *fdentry;
struct obdo *oa;
+ struct obd_device *obd = handle->lgh_ctxt->loc_exp->exp_obd;
+ char *dir;
int rc;
ENTRY;
+ /* COMPAT_146 */
+ if (strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME) == 0)
+ dir = MDT_LOGS_DIR;
+ else
+ /* end COMPAT_146 */
+ dir = MOUNT_CONFIGS_DIR;
+
fdentry = handle->lgh_file->f_dentry;
- if (!strcmp(fdentry->d_parent->d_name.name, "LOGS")) {
- struct obd_device *obd = handle->lgh_ctxt->loc_exp->exp_obd;
+ if (strcmp(fdentry->d_parent->d_name.name, dir) == 0) {
struct inode *inode = fdentry->d_parent->d_inode;
- struct obd_run_ctxt saved;
+ struct lvfs_run_ctxt saved;
- push_ctxt(&saved, &obd->obd_ctxt, NULL);
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
dget(fdentry);
rc = llog_lvfs_close(handle);
if (rc == 0) {
- down(&inode->i_sem);
+ LOCK_INODE_MUTEX(inode);
rc = vfs_unlink(inode, fdentry);
- up(&inode->i_sem);
+ UNLOCK_INODE_MUTEX(inode);
}
dput(fdentry);
- pop_ctxt(&saved, &obd->obd_ctxt, NULL);
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
RETURN(rc);
}
- oa = obdo_alloc();
+ OBDO_ALLOC(oa);
if (oa == NULL)
RETURN(-ENOMEM);
if (rc)
GOTO(out, rc);
- rc = obd_destroy(handle->lgh_ctxt->loc_exp, oa, NULL, NULL);
+ rc = obd_destroy(handle->lgh_ctxt->loc_exp, oa, NULL, NULL, NULL);
out:
- obdo_free(oa);
+ OBDO_FREE(oa);
RETURN(rc);
}
int llog_get_cat_list(struct obd_device *obd, struct obd_device *disk_obd,
char *name, int count, struct llog_catid *idarray)
{
- struct obd_run_ctxt saved;
+ struct lvfs_run_ctxt saved;
struct l_file *file;
int rc;
int size = sizeof(*idarray) * count;
loff_t off = 0;
+ ENTRY;
- LASSERT(count);
+ if (!count)
+ RETURN(0);
- push_ctxt(&saved, &obd->obd_ctxt, NULL);
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
file = filp_open(name, O_RDWR | O_CREAT | O_LARGEFILE, 0700);
if (!file || IS_ERR(file)) {
rc = PTR_ERR(file);
name, rc);
GOTO(out, rc);
}
-
+
if (!S_ISREG(file->f_dentry->d_inode->i_mode)) {
CERROR("%s is not a regular file!: mode = %o\n", name,
file->f_dentry->d_inode->i_mode);
GOTO(out, rc = -ENOENT);
}
+ CDEBUG(D_CONFIG, "cat list: disk size=%d, read=%d\n",
+ (int)i_size_read(file->f_dentry->d_inode), size);
+
rc = fsfilt_read_record(disk_obd, file, idarray, size, &off);
if (rc) {
- CDEBUG(D_INODE,"OBD filter: error reading %s: rc %d\n",
- name, rc);
+ CERROR("OBD filter: error reading %s: rc %d\n", name, rc);
GOTO(out, rc);
}
+ EXIT;
out:
- pop_ctxt(&saved, &obd->obd_ctxt, NULL);
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
if (file && !IS_ERR(file))
rc = filp_close(file, 0);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_get_cat_list);
int llog_put_cat_list(struct obd_device *obd, struct obd_device *disk_obd,
char *name, int count, struct llog_catid *idarray)
{
- struct obd_run_ctxt saved;
+ struct lvfs_run_ctxt saved;
struct l_file *file;
int rc;
int size = sizeof(*idarray) * count;
loff_t off = 0;
- LASSERT(count);
+ if (!count)
+ return (0);
- push_ctxt(&saved, &obd->obd_ctxt, NULL);
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
file = filp_open(name, O_RDWR | O_CREAT | O_LARGEFILE, 0700);
if (!file || IS_ERR(file)) {
rc = PTR_ERR(file);
}
out:
- pop_ctxt(&saved, &obd->obd_ctxt, NULL);
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
if (file && !IS_ERR(file))
rc = filp_close(file, 0);
RETURN(rc);
struct llog_operations llog_lvfs_ops = {
lop_write_rec: llog_lvfs_write_rec,
lop_next_block: llog_lvfs_next_block,
+ lop_prev_block: llog_lvfs_prev_block,
lop_read_header: llog_lvfs_read_header,
lop_create: llog_lvfs_create,
lop_destroy: llog_lvfs_destroy,
return 0;
}
+static int llog_lvfs_prev_block(struct llog_handle *loghandle,
+ int prev_idx, void *buf, int len)
+{
+ LBUG();
+ return 0;
+}
+
static int llog_lvfs_create(struct llog_ctxt *ctxt, struct llog_handle **res,
struct llog_logid *logid, char *name)
{
}
int llog_get_cat_list(struct obd_device *obd, struct obd_device *disk_obd,
- char *name, int count, struct llog_logid *idarray)
+ char *name, int count, struct llog_catid *idarray)
{
LBUG();
return 0;
}
int llog_put_cat_list(struct obd_device *obd, struct obd_device *disk_obd,
- char *name, int count, struct llog_logid *idarray)
+ char *name, int count, struct llog_catid *idarray)
{
LBUG();
return 0;
struct llog_operations llog_lvfs_ops = {
lop_write_rec: llog_lvfs_write_rec,
lop_next_block: llog_lvfs_next_block,
+ lop_prev_block: llog_lvfs_prev_block,
lop_read_header: llog_lvfs_read_header,
lop_create: llog_lvfs_create,
lop_destroy: llog_lvfs_destroy,