The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/intermezzo/replicator.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
    2  * vim:expandtab:shiftwidth=8:tabstop=8:
    3  *
    4  * Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
    5  * Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
    6  *
    7  *   This file is part of InterMezzo, http://www.inter-mezzo.org.
    8  *
    9  *   InterMezzo is free software; you can redistribute it and/or
   10  *   modify it under the terms of version 2 of the GNU General Public
   11  *   License as published by the Free Software Foundation.
   12  *
   13  *   InterMezzo is distributed in the hope that it will be useful,
   14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16  *   GNU General Public License for more details.
   17  *
   18  *   You should have received a copy of the GNU General Public License
   19  *   along with InterMezzo; if not, write to the Free Software
   20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   21  *
   22  * Manage RCVD records for clients in the kernel
   23  *
   24  */
   25 
   26 #define __NO_VERSION__
   27 #include <linux/module.h>
   28 #include <stdarg.h>
   29 #include <asm/uaccess.h>
   30 
   31 #include <linux/errno.h>
   32 
   33 #include <linux/intermezzo_fs.h>
   34 
   35 /*
   36  * this file contains a hash table of replicators/clients for a
   37  * fileset. It allows fast lookup and update of reintegration status
   38  */
   39 
   40 struct izo_offset_rec {
   41         struct list_head or_list;
   42         char             or_uuid[16];
   43         loff_t           or_offset;
   44 };
   45 
   46 #define RCACHE_BITS 8
   47 #define RCACHE_SIZE (1 << RCACHE_BITS)
   48 #define RCACHE_MASK (RCACHE_SIZE - 1)
   49 
   50 static struct list_head *
   51 izo_rep_cache(void)
   52 {
   53         int i;
   54         struct list_head *cache;
   55         PRESTO_ALLOC(cache, sizeof(struct list_head) * RCACHE_SIZE);
   56         if (cache == NULL) {
   57                 CERROR("intermezzo-fatal: no memory for replicator cache\n");
   58                 return NULL;
   59         }
   60         memset(cache, 0, sizeof(struct list_head) * RCACHE_SIZE);
   61         for (i = 0; i < RCACHE_SIZE; i++)
   62                 INIT_LIST_HEAD(&cache[i]);
   63 
   64         return cache;
   65 }
   66 
   67 static struct list_head *
   68 izo_rep_hash(struct list_head *cache, char *uuid)
   69 {
   70         return &cache[(RCACHE_MASK & uuid[1])];
   71 }
   72 
   73 static void
   74 izo_rep_cache_clean(struct presto_file_set *fset)
   75 {
   76         int i;
   77         struct list_head *bucket;
   78         struct list_head *tmp;
   79 
   80         if (fset->fset_clients == NULL)
   81                 return;
   82         for (i = 0; i < RCACHE_SIZE; i++) {
   83                 tmp = bucket = &fset->fset_clients[i];
   84 
   85                 tmp = tmp->next;
   86                 while (tmp != bucket) {
   87                         struct izo_offset_rec *offrec;
   88                         tmp = tmp->next;
   89                         list_del(tmp);
   90                         offrec = list_entry(tmp, struct izo_offset_rec,
   91                                             or_list);
   92                         PRESTO_FREE(offrec, sizeof(struct izo_offset_rec));
   93                 }
   94         }
   95 }
   96 
   97 struct izo_offset_rec *
   98 izo_rep_cache_find(struct presto_file_set *fset, char *uuid)
   99 {
  100         struct list_head *buck = izo_rep_hash(fset->fset_clients, uuid);
  101         struct list_head *tmp = buck;
  102         struct izo_offset_rec *rec = NULL;
  103 
  104         while ( (tmp = tmp->next) != buck ) {
  105                 rec = list_entry(tmp, struct izo_offset_rec, or_list);
  106                 if ( memcmp(rec->or_uuid, uuid, sizeof(rec->or_uuid)) == 0 )
  107                         return rec;
  108         }
  109 
  110         return NULL;
  111 }
  112 
  113 static int
  114 izo_rep_cache_add(struct presto_file_set *fset, struct izo_rcvd_rec *rec,
  115                   loff_t offset)
  116 {
  117         struct izo_offset_rec *offrec;
  118 
  119         if (izo_rep_cache_find(fset, rec->lr_uuid)) {
  120                 CERROR("izo: duplicate client entry %s off %Ld\n",
  121                        fset->fset_name, offset);
  122                 return -EINVAL;
  123         }
  124 
  125         PRESTO_ALLOC(offrec, sizeof(*offrec));
  126         if (offrec == NULL) {
  127                 CERROR("izo: cannot allocate offrec\n");
  128                 return -ENOMEM;
  129         }
  130 
  131         memcpy(offrec->or_uuid, rec->lr_uuid, sizeof(rec->lr_uuid));
  132         offrec->or_offset = offset;
  133 
  134         list_add(&offrec->or_list,
  135                  izo_rep_hash(fset->fset_clients, rec->lr_uuid));
  136         return 0;
  137 }
  138 
  139 int
  140 izo_rep_cache_init(struct presto_file_set *fset)
  141 {
  142         struct izo_rcvd_rec rec;
  143         loff_t offset = 0, last_offset = 0;
  144 
  145         fset->fset_clients = izo_rep_cache();
  146         if (fset->fset_clients == NULL) {
  147                 CERROR("Error initializing client cache\n");
  148                 return -ENOMEM;
  149         }
  150 
  151         while ( presto_fread(fset->fset_rcvd.fd_file, (char *)&rec,
  152                              sizeof(rec), &offset) == sizeof(rec) ) {
  153                 int rc;
  154 
  155                 if ((rc = izo_rep_cache_add(fset, &rec, last_offset)) < 0) {
  156                         izo_rep_cache_clean(fset);
  157                         return rc;
  158                 }
  159 
  160                 last_offset = offset;
  161         }
  162 
  163         return 0;
  164 }
  165 
  166 /*
  167  * Return local last_rcvd record for the client. Update or create 
  168  * if necessary.
  169  *
  170  * XXX: After this call, any -EINVAL from izo_rcvd_get is a real error.
  171  */
  172 int
  173 izo_repstatus(struct presto_file_set *fset,  __u64 client_kmlsize, 
  174               struct izo_rcvd_rec *lr_client, struct izo_rcvd_rec *lr_server)
  175 {
  176         int rc;
  177         rc = izo_rcvd_get(lr_server, fset, lr_client->lr_uuid);
  178         if (rc < 0 && rc != -EINVAL) {
  179                 return rc;
  180         }
  181 
  182         /* client is new or has been reset. */
  183         if (rc < 0 || (client_kmlsize == 0 && lr_client->lr_remote_offset == 0)) {
  184                 memset(lr_server, 0, sizeof(*lr_server));
  185                 memcpy(lr_server->lr_uuid, lr_client->lr_uuid, sizeof(lr_server->lr_uuid));
  186                 rc = izo_rcvd_write(fset, lr_server);
  187                 if (rc < 0)
  188                         return rc;
  189         }
  190 
  191         /* update intersync */
  192         rc = izo_upc_repstatus(presto_f2m(fset), fset->fset_name, lr_server);
  193         return rc;
  194 }
  195 
  196 loff_t
  197 izo_rcvd_get(struct izo_rcvd_rec *rec, struct presto_file_set *fset, char *uuid)
  198 {
  199         struct izo_offset_rec *offrec;
  200         struct izo_rcvd_rec tmprec;
  201         loff_t offset;
  202 
  203         offrec = izo_rep_cache_find(fset, uuid);
  204         if (offrec == NULL) {
  205                 CDEBUG(D_SPECIAL, "izo_get_rcvd: uuid not in hash.\n");
  206                 return -EINVAL;
  207         }
  208         offset = offrec->or_offset;
  209 
  210         if (rec == NULL)
  211                 return offset;
  212 
  213         if (presto_fread(fset->fset_rcvd.fd_file, (char *)&tmprec,
  214                          sizeof(tmprec), &offset) != sizeof(tmprec)) {
  215                 CERROR("izo_get_rcvd: Unable to read from last_rcvd file offset "
  216                        "%Lu\n", offset);
  217                 return -EIO;
  218         }
  219 
  220         memcpy(rec->lr_uuid, tmprec.lr_uuid, sizeof(tmprec.lr_uuid));
  221         rec->lr_remote_recno = le64_to_cpu(tmprec.lr_remote_recno);
  222         rec->lr_remote_offset = le64_to_cpu(tmprec.lr_remote_offset);
  223         rec->lr_local_recno = le64_to_cpu(tmprec.lr_local_recno);
  224         rec->lr_local_offset = le64_to_cpu(tmprec.lr_local_offset);
  225         rec->lr_last_ctime = le64_to_cpu(tmprec.lr_last_ctime);
  226 
  227         return offrec->or_offset;
  228 }
  229 
  230 /* Try to lookup the UUID in the hash.  Insert it if it isn't found.  Write the
  231  * data to the file.
  232  *
  233  * Returns the offset of the beginning of the record in the last_rcvd file. */
  234 loff_t
  235 izo_rcvd_write(struct presto_file_set *fset, struct izo_rcvd_rec *rec)
  236 {
  237         struct izo_offset_rec *offrec;
  238         loff_t offset, rc;
  239 
  240         ENTRY;
  241 
  242         offrec = izo_rep_cache_find(fset, rec->lr_uuid);
  243         if (offrec == NULL) {
  244                 /* I don't think it should be possible for an entry to be not in
  245                  * the hash table without also having an invalid offset, but we
  246                  * handle it gracefully regardless. */
  247                 write_lock(&fset->fset_rcvd.fd_lock);
  248                 offset = fset->fset_rcvd.fd_offset;
  249                 fset->fset_rcvd.fd_offset += sizeof(*rec);
  250                 write_unlock(&fset->fset_rcvd.fd_lock);
  251 
  252                 rc = izo_rep_cache_add(fset, rec, offset);
  253                 if (rc < 0) {
  254                         EXIT;
  255                         return rc;
  256                 }
  257         } else
  258                 offset = offrec->or_offset;
  259         
  260 
  261         rc = presto_fwrite(fset->fset_rcvd.fd_file, (char *)rec, sizeof(*rec),
  262                            &offset);
  263         if (rc == sizeof(*rec))
  264                 /* presto_fwrite() advances 'offset' */
  265                 rc = offset - sizeof(*rec);
  266 
  267         EXIT;
  268         return rc;
  269 }
  270 
  271 loff_t
  272 izo_rcvd_upd_remote(struct presto_file_set *fset, char * uuid,  __u64 remote_recno, 
  273                     __u64 remote_offset)
  274 {
  275         struct izo_rcvd_rec rec;
  276         
  277         loff_t rc;
  278 
  279         ENTRY;
  280         rc = izo_rcvd_get(&rec, fset, uuid);
  281         if (rc < 0)
  282                 return rc;
  283         rec.lr_remote_recno = remote_recno;
  284         rec.lr_remote_offset = remote_offset;
  285 
  286         rc = izo_rcvd_write(fset, &rec);
  287         EXIT;
  288         if (rc < 0)
  289                 return rc;
  290         return 0;
  291 }

Cache object: b6755fdf8580ca5ee128f0f150b086b6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.