]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - fs/nfs/pnfs_dev.c
bf05189a7cbf6543e6d9d08e613a61c4a132f51f
[karo-tx-linux.git] / fs / nfs / pnfs_dev.c
1 /*
2  *  Device operations for the pnfs client.
3  *
4  *  Copyright (c) 2002
5  *  The Regents of the University of Michigan
6  *  All Rights Reserved
7  *
8  *  Dean Hildebrand <dhildebz@umich.edu>
9  *  Garth Goodson   <Garth.Goodson@netapp.com>
10  *
11  *  Permission is granted to use, copy, create derivative works, and
12  *  redistribute this software and such derivative works for any purpose,
13  *  so long as the name of the University of Michigan is not used in
14  *  any advertising or publicity pertaining to the use or distribution
15  *  of this software without specific, written prior authorization. If
16  *  the above copyright notice or any other identification of the
17  *  University of Michigan is included in any copy of any portion of
18  *  this software, then the disclaimer below must also be included.
19  *
20  *  This software is provided as is, without representation or warranty
21  *  of any kind either express or implied, including without limitation
22  *  the implied warranties of merchantability, fitness for a particular
23  *  purpose, or noninfringement.  The Regents of the University of
24  *  Michigan shall not be liable for any damages, including special,
25  *  indirect, incidental, or consequential damages, with respect to any
26  *  claim arising out of or in connection with the use of the software,
27  *  even if it has been or is hereafter advised of the possibility of
28  *  such damages.
29  */
30
31 #include "pnfs.h"
32
33 #define NFSDBG_FACILITY         NFSDBG_PNFS
34
35 /*
36  * Device ID RCU cache. A device ID is unique per server and layout type.
37  */
38 #define NFS4_DEVICE_ID_HASH_BITS        5
39 #define NFS4_DEVICE_ID_HASH_SIZE        (1 << NFS4_DEVICE_ID_HASH_BITS)
40 #define NFS4_DEVICE_ID_HASH_MASK        (NFS4_DEVICE_ID_HASH_SIZE - 1)
41
42 static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE];
43 static DEFINE_SPINLOCK(nfs4_deviceid_lock);
44
45 void
46 nfs4_print_deviceid(const struct nfs4_deviceid *id)
47 {
48         u32 *p = (u32 *)id;
49
50         dprintk("%s: device id= [%x%x%x%x]\n", __func__,
51                 p[0], p[1], p[2], p[3]);
52 }
53 EXPORT_SYMBOL_GPL(nfs4_print_deviceid);
54
55 static inline u32
56 nfs4_deviceid_hash(const struct nfs4_deviceid *id)
57 {
58         unsigned char *cptr = (unsigned char *)id->data;
59         unsigned int nbytes = NFS4_DEVICEID4_SIZE;
60         u32 x = 0;
61
62         while (nbytes--) {
63                 x *= 37;
64                 x += *cptr++;
65         }
66         return x & NFS4_DEVICE_ID_HASH_MASK;
67 }
68
69 /*
70  * Lookup a deviceid in cache and get a reference count on it if found
71  *
72  * @clp nfs_client associated with deviceid
73  * @id deviceid to look up
74  */
75 struct nfs4_deviceid_node *
76 nfs4_find_get_deviceid(const struct nfs_client *clp, const struct nfs4_deviceid *id)
77 {
78         struct nfs4_deviceid_node *d;
79         struct hlist_node *n;
80         long hash = nfs4_deviceid_hash(id);
81
82         rcu_read_lock();
83         hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[hash], node) {
84                 if (d->nfs_client == clp && !memcmp(&d->deviceid, id, sizeof(*id))) {
85                         if (!atomic_inc_not_zero(&d->ref))
86                                 goto fail;
87                         rcu_read_unlock();
88                         return d;
89                 }
90         }
91 fail:
92         rcu_read_unlock();
93         return NULL;
94 }
95 EXPORT_SYMBOL_GPL(nfs4_find_get_deviceid);
96
97 void
98 nfs4_init_deviceid_node(struct nfs4_deviceid_node *d,
99                         const struct nfs_client *nfs_client,
100                         const struct nfs4_deviceid *id)
101 {
102         d->nfs_client = nfs_client;
103         d->deviceid = *id;
104 }
105 EXPORT_SYMBOL_GPL(nfs4_init_deviceid_node);
106
107 /*
108  * Uniquely initialize and insert a deviceid node into cache
109  *
110  * @new new deviceid node
111  *      Note that the caller must set up new->nfs_client and new->deviceid
112  *
113  * @ret the inserted node, if none found, otherwise, the found entry.
114  */
115 struct nfs4_deviceid_node *
116 nfs4_insert_deviceid_node(struct nfs4_deviceid_node *new)
117 {
118         struct nfs4_deviceid_node *d;
119         long hash;
120
121         spin_lock(&nfs4_deviceid_lock);
122         d = nfs4_find_get_deviceid(new->nfs_client, &new->deviceid);
123         if (d) {
124                 spin_unlock(&nfs4_deviceid_lock);
125                 return d;
126         }
127
128         INIT_HLIST_NODE(&new->node);
129         atomic_set(&new->ref, 1);
130         hash = nfs4_deviceid_hash(&new->deviceid);
131         hlist_add_head_rcu(&new->node, &nfs4_deviceid_cache[hash]);
132         spin_unlock(&nfs4_deviceid_lock);
133
134         return new;
135 }
136 EXPORT_SYMBOL_GPL(nfs4_insert_deviceid_node);
137
138 /*
139  * Dereference a deviceid node and delete it when its reference count drops
140  * to zero.
141  *
142  * @d deviceid node to put
143  *
144  * @ret true iff the node was deleted
145  */
146 bool
147 nfs4_put_deviceid_node(struct nfs4_deviceid_node *d)
148 {
149         if (!atomic_dec_and_lock(&d->ref, &nfs4_deviceid_lock))
150                 return false;
151         hlist_del_init_rcu(&d->node);
152         spin_unlock(&nfs4_deviceid_lock);
153         synchronize_rcu();
154         return true;
155 }
156 EXPORT_SYMBOL_GPL(nfs4_put_deviceid_node);