patch-2.4.20 linux-2.4.20/fs/intermezzo/replicator.c
Next file: linux-2.4.20/fs/intermezzo/super.c
Previous file: linux-2.4.20/fs/intermezzo/psdev.c
Back to the patch index
Back to the overall index
- Lines: 292
- Date:
Thu Nov 28 15:53:15 2002
- Orig file:
linux-2.4.19/fs/intermezzo/replicator.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -urN linux-2.4.19/fs/intermezzo/replicator.c linux-2.4.20/fs/intermezzo/replicator.c
@@ -0,0 +1,291 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ * Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ * This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ * InterMezzo is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * InterMezzo is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with InterMezzo; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Manage RCVD records for clients in the kernel
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <stdarg.h>
+#include <asm/uaccess.h>
+
+#include <linux/errno.h>
+
+#include <linux/intermezzo_fs.h>
+
+/*
+ * this file contains a hash table of replicators/clients for a
+ * fileset. It allows fast lookup and update of reintegration status
+ */
+
+struct izo_offset_rec {
+ struct list_head or_list;
+ char or_uuid[16];
+ loff_t or_offset;
+};
+
+#define RCACHE_BITS 8
+#define RCACHE_SIZE (1 << RCACHE_BITS)
+#define RCACHE_MASK (RCACHE_SIZE - 1)
+
+static struct list_head *
+izo_rep_cache(void)
+{
+ int i;
+ struct list_head *cache;
+ PRESTO_ALLOC(cache, sizeof(struct list_head) * RCACHE_SIZE);
+ if (cache == NULL) {
+ CERROR("intermezzo-fatal: no memory for replicator cache\n");
+ return NULL;
+ }
+ memset(cache, 0, sizeof(struct list_head) * RCACHE_SIZE);
+ for (i = 0; i < RCACHE_SIZE; i++)
+ INIT_LIST_HEAD(&cache[i]);
+
+ return cache;
+}
+
+static struct list_head *
+izo_rep_hash(struct list_head *cache, char *uuid)
+{
+ return &cache[(RCACHE_MASK & uuid[1])];
+}
+
+static void
+izo_rep_cache_clean(struct presto_file_set *fset)
+{
+ int i;
+ struct list_head *bucket;
+ struct list_head *tmp;
+
+ if (fset->fset_clients == NULL)
+ return;
+ for (i = 0; i < RCACHE_SIZE; i++) {
+ tmp = bucket = &fset->fset_clients[i];
+
+ tmp = tmp->next;
+ while (tmp != bucket) {
+ struct izo_offset_rec *offrec;
+ tmp = tmp->next;
+ list_del(tmp);
+ offrec = list_entry(tmp, struct izo_offset_rec,
+ or_list);
+ PRESTO_FREE(offrec, sizeof(struct izo_offset_rec));
+ }
+ }
+}
+
+struct izo_offset_rec *
+izo_rep_cache_find(struct presto_file_set *fset, char *uuid)
+{
+ struct list_head *buck = izo_rep_hash(fset->fset_clients, uuid);
+ struct list_head *tmp = buck;
+ struct izo_offset_rec *rec = NULL;
+
+ while ( (tmp = tmp->next) != buck ) {
+ rec = list_entry(tmp, struct izo_offset_rec, or_list);
+ if ( memcmp(rec->or_uuid, uuid, sizeof(rec->or_uuid)) == 0 )
+ return rec;
+ }
+
+ return NULL;
+}
+
+static int
+izo_rep_cache_add(struct presto_file_set *fset, struct izo_rcvd_rec *rec,
+ loff_t offset)
+{
+ struct izo_offset_rec *offrec;
+
+ if (izo_rep_cache_find(fset, rec->lr_uuid)) {
+ CERROR("izo: duplicate client entry %s off %Ld\n",
+ fset->fset_name, offset);
+ return -EINVAL;
+ }
+
+ PRESTO_ALLOC(offrec, sizeof(*offrec));
+ if (offrec == NULL) {
+ CERROR("izo: cannot allocate offrec\n");
+ return -ENOMEM;
+ }
+
+ memcpy(offrec->or_uuid, rec->lr_uuid, sizeof(rec->lr_uuid));
+ offrec->or_offset = offset;
+
+ list_add(&offrec->or_list,
+ izo_rep_hash(fset->fset_clients, rec->lr_uuid));
+ return 0;
+}
+
+int
+izo_rep_cache_init(struct presto_file_set *fset)
+{
+ struct izo_rcvd_rec rec;
+ loff_t offset = 0, last_offset = 0;
+
+ fset->fset_clients = izo_rep_cache();
+ if (fset->fset_clients == NULL) {
+ CERROR("Error initializing client cache\n");
+ return -ENOMEM;
+ }
+
+ while ( presto_fread(fset->fset_rcvd.fd_file, (char *)&rec,
+ sizeof(rec), &offset) == sizeof(rec) ) {
+ int rc;
+
+ if ((rc = izo_rep_cache_add(fset, &rec, last_offset)) < 0) {
+ izo_rep_cache_clean(fset);
+ return rc;
+ }
+
+ last_offset = offset;
+ }
+
+ return 0;
+}
+
+/*
+ * Return local last_rcvd record for the client. Update or create
+ * if necessary.
+ *
+ * XXX: After this call, any -EINVAL from izo_rcvd_get is a real error.
+ */
+int
+izo_repstatus(struct presto_file_set *fset, __u64 client_kmlsize,
+ struct izo_rcvd_rec *lr_client, struct izo_rcvd_rec *lr_server)
+{
+ int rc;
+ rc = izo_rcvd_get(lr_server, fset, lr_client->lr_uuid);
+ if (rc < 0 && rc != -EINVAL) {
+ return rc;
+ }
+
+ /* client is new or has been reset. */
+ if (rc < 0 || (client_kmlsize == 0 && lr_client->lr_remote_offset == 0)) {
+ memset(lr_server, 0, sizeof(*lr_server));
+ memcpy(lr_server->lr_uuid, lr_client->lr_uuid, sizeof(lr_server->lr_uuid));
+ rc = izo_rcvd_write(fset, lr_server);
+ if (rc < 0)
+ return rc;
+ }
+
+ /* update intersync */
+ rc = izo_upc_repstatus(presto_f2m(fset), fset->fset_name, lr_server);
+ return rc;
+}
+
+loff_t
+izo_rcvd_get(struct izo_rcvd_rec *rec, struct presto_file_set *fset, char *uuid)
+{
+ struct izo_offset_rec *offrec;
+ struct izo_rcvd_rec tmprec;
+ loff_t offset;
+
+ offrec = izo_rep_cache_find(fset, uuid);
+ if (offrec == NULL) {
+ CDEBUG(D_SPECIAL, "izo_get_rcvd: uuid not in hash.\n");
+ return -EINVAL;
+ }
+ offset = offrec->or_offset;
+
+ if (rec == NULL)
+ return offset;
+
+ if (presto_fread(fset->fset_rcvd.fd_file, (char *)&tmprec,
+ sizeof(tmprec), &offset) != sizeof(tmprec)) {
+ CERROR("izo_get_rcvd: Unable to read from last_rcvd file offset "
+ "%Lu\n", offset);
+ return -EIO;
+ }
+
+ memcpy(rec->lr_uuid, tmprec.lr_uuid, sizeof(tmprec.lr_uuid));
+ rec->lr_remote_recno = le64_to_cpu(tmprec.lr_remote_recno);
+ rec->lr_remote_offset = le64_to_cpu(tmprec.lr_remote_offset);
+ rec->lr_local_recno = le64_to_cpu(tmprec.lr_local_recno);
+ rec->lr_local_offset = le64_to_cpu(tmprec.lr_local_offset);
+ rec->lr_last_ctime = le64_to_cpu(tmprec.lr_last_ctime);
+
+ return offrec->or_offset;
+}
+
+/* Try to lookup the UUID in the hash. Insert it if it isn't found. Write the
+ * data to the file.
+ *
+ * Returns the offset of the beginning of the record in the last_rcvd file. */
+loff_t
+izo_rcvd_write(struct presto_file_set *fset, struct izo_rcvd_rec *rec)
+{
+ struct izo_offset_rec *offrec;
+ loff_t offset, rc;
+
+ ENTRY;
+
+ offrec = izo_rep_cache_find(fset, rec->lr_uuid);
+ if (offrec == NULL) {
+ /* I don't think it should be possible for an entry to be not in
+ * the hash table without also having an invalid offset, but we
+ * handle it gracefully regardless. */
+ write_lock(&fset->fset_rcvd.fd_lock);
+ offset = fset->fset_rcvd.fd_offset;
+ fset->fset_rcvd.fd_offset += sizeof(*rec);
+ write_unlock(&fset->fset_rcvd.fd_lock);
+
+ rc = izo_rep_cache_add(fset, rec, offset);
+ if (rc < 0) {
+ EXIT;
+ return rc;
+ }
+ } else
+ offset = offrec->or_offset;
+
+
+ rc = presto_fwrite(fset->fset_rcvd.fd_file, (char *)rec, sizeof(*rec),
+ &offset);
+ if (rc == sizeof(*rec))
+ /* presto_fwrite() advances 'offset' */
+ rc = offset - sizeof(*rec);
+
+ EXIT;
+ return rc;
+}
+
+loff_t
+izo_rcvd_upd_remote(struct presto_file_set *fset, char * uuid, __u64 remote_recno,
+ __u64 remote_offset)
+{
+ struct izo_rcvd_rec rec;
+
+ loff_t rc;
+
+ ENTRY;
+ rc = izo_rcvd_get(&rec, fset, uuid);
+ if (rc < 0)
+ return rc;
+ rec.lr_remote_recno = remote_recno;
+ rec.lr_remote_offset = remote_offset;
+
+ rc = izo_rcvd_write(fset, &rec);
+ EXIT;
+ if (rc < 0)
+ return rc;
+ return 0;
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)