Whamcloud - gitweb
Don't update your trees yet..... Brian and I are trying to get our
[fs/lustre-release.git] / lustre / obdclass / genops.c
1 /*
2  *  linux/fs/ext2_obd/sim_obd.c
3  * Copyright (C) 2001  Cluster File Systems, Inc.
4  *
5  * This code is issued under the GNU General Public License.
6  * See the file COPYING in this distribution
7  *
8  * These are the only exported functions; they provide the simulated object-
9  * oriented disk.
10  *
11  */
12
13 #define DEBUG_SUBSYSTEM S_CLASS
14
15 #include <linux/obd_class.h>
16 #include <linux/random.h>
17 #include <linux/slab.h>
18
19 extern struct obd_device obd_dev[MAX_OBD_DEVICES];
20 kmem_cache_t *obdo_cachep = NULL;
21 kmem_cache_t *export_cachep = NULL;
22 kmem_cache_t *import_cachep = NULL;
23
24 void obd_cleanup_caches(void)
25 {
26         int rc;
27         ENTRY;
28         if (obdo_cachep) { 
29                 rc = kmem_cache_destroy(obdo_cachep);
30                 if (rc)
31                         CERROR("Cannot destory obdo_cachep\n");
32                 obdo_cachep = NULL;
33         }
34         if (import_cachep) { 
35                 rc = kmem_cache_destroy(import_cachep);
36                 if (rc)
37                         CERROR("Cannot destory import_cachep\n");
38                 import_cachep = NULL;
39         }
40         if (export_cachep) { 
41                 rc = kmem_cache_destroy(export_cachep);
42                 if (rc)
43                         CERROR("Cannot destory import_cachep\n");
44                 export_cachep = NULL;
45         }
46         EXIT;
47 }
48
49 int obd_init_caches(void)
50 {
51         ENTRY;
52         if (obdo_cachep == NULL) {
53                 obdo_cachep = kmem_cache_create("obdo_cache",
54                                                 sizeof(struct obdo),
55                                                 0, SLAB_HWCACHE_ALIGN,
56                                                 NULL, NULL);
57                 if (obdo_cachep == NULL)
58                         GOTO(out, -ENOMEM);
59         }
60
61         if (export_cachep == NULL) {
62                 export_cachep = kmem_cache_create("export_cache",
63                                                 sizeof(struct obd_export),
64                                                 0, SLAB_HWCACHE_ALIGN,
65                                                 NULL, NULL);
66                 if (export_cachep == NULL)
67                         GOTO(out, -ENOMEM);
68         }
69
70         if (import_cachep == NULL) {
71                 import_cachep = kmem_cache_create("import_cache",
72                                                 sizeof(struct obd_import),
73                                                 0, SLAB_HWCACHE_ALIGN,
74                                                 NULL, NULL);
75                 if (import_cachep == NULL)
76                         GOTO(out, -ENOMEM);
77         }
78         RETURN(0);
79  out:
80         obd_cleanup_caches();
81         RETURN(-ENOMEM);
82
83 }
84
85
86 /* map connection to client */
87 struct obd_export *gen_client(struct obd_conn *conn)
88 {
89         struct obd_export * export;
90
91         if (!conn)
92                 RETURN(NULL);
93
94         if (!conn->addr || conn->addr == -1 ) { 
95                 fixme();
96                 RETURN(NULL);
97         }
98               
99         export = (struct obd_export *) (unsigned long)conn->addr;
100         if (!kmem_cache_validate(export_cachep, (void *)export))
101                 RETURN(NULL);
102
103         if (export->export_cookie != conn->cookie)
104                 return NULL;
105         return export;
106 } /* gen_client */
107
108 struct obd_device *gen_conn2obd(struct obd_conn *conn)
109 {
110         struct obd_export *export;
111         export = gen_client(conn); 
112         if (export) 
113                 return export->export_obd;
114         fixme();
115         return NULL;
116 }
117
118 /* a connection defines a context in which preallocation can be managed. */
119 int gen_connect (struct obd_conn *conn, struct obd_device *obd)
120 {
121         struct obd_export * export;
122
123         export = kmem_cache_alloc(export_cachep, GFP_KERNEL); 
124         if ( !export ) {
125                 CERROR("no memory! (minor %d)\n", obd->obd_minor);
126                 return -ENOMEM;
127         }
128
129         memset(export, 0, sizeof(*export));
130         get_random_bytes(&export->export_cookie, sizeof(__u64));
131         /* XXX this should probably spinlocked? */
132         export->export_id = ++obd->obd_gen_last_id;
133         export->export_obd = obd; 
134         export->export_import.addr = conn->addr;
135         export->export_import.cookie = conn->cookie;
136         
137         list_add(&(export->export_chain), export->export_obd->obd_exports.prev);
138
139         CDEBUG(D_INFO, "connect: new ID %u\n", export->export_id);
140         conn->oc_id = export->export_id;
141         conn->addr = (__u64) (unsigned long)export;
142         conn->cookie = export->export_cookie;
143         return 0;
144 } /* gen_connect */
145
146
147 int gen_disconnect(struct obd_conn *conn)
148 {
149         struct obd_export * export;
150         ENTRY;
151
152         if (!(export = gen_client(conn))) {
153                 fixme();
154                 CDEBUG(D_IOCTL, "disconnect: attempting to free "
155                        "nonexistent client %u\n", conn->oc_id);
156                 RETURN(-EINVAL);
157         }
158         list_del(&export->export_chain);
159         kmem_cache_free(export_cachep, export);
160
161         CDEBUG(D_INFO, "disconnect: ID %u\n", conn->oc_id);
162
163         RETURN(0);
164 } /* gen_obd_disconnect */
165
166 /* FIXME: Data is a space- or comma-separated list of device IDs.  This will
167  * have to change. */
168 int gen_multi_setup(struct obd_device *obddev, uint32_t len, void *data)
169 {
170         int count, rc;
171         char *p;
172         ENTRY;
173
174         for (p = data, count = 0; p < (char *)data + len; count++) {
175                 char *end;
176                 int tmp = simple_strtoul(p, &end, 0);
177
178                 if (p == end) {
179                         CERROR("invalid device ID starting at: %s\n", p);
180                         GOTO(err_disconnect, rc = -EINVAL);
181                 }
182                 
183                 if (tmp < 0 || tmp >= MAX_OBD_DEVICES) { 
184                         CERROR("Trying to sub dev %d  - dev no too large\n", 
185                                tmp);
186                         GOTO(err_disconnect, rc); 
187                 }
188
189                 rc = obd_connect(&obddev->obd_multi_conn[count], &obd_dev[tmp]);
190                 if (rc) {
191                         CERROR("cannot connect to device %d: rc = %d\n", tmp,
192                                rc);
193                         GOTO(err_disconnect, rc);
194                 }
195
196                 CDEBUG(D_INFO, "target OBD %d is of type %s\n", count,
197                        obd_dev[tmp].obd_type->typ_name);
198
199                 p = end + 1;
200         }
201
202         obddev->obd_multi_count = count;
203
204         RETURN(0);
205
206  err_disconnect:
207         for (count--; count >= 0; count--)
208                 obd_disconnect(&obddev->obd_multi_conn[count]);
209         return rc;
210 }
211
212 /*
213  *    remove all connections to this device
214  *    close all connections to lower devices
215  *    needed for forced unloads of OBD client drivers
216  */
217 int gen_multi_cleanup(struct obd_device *obddev)
218 {
219         int i;
220
221         for (i = 0; i < obddev->obd_multi_count; i++) {
222                 int rc;
223                 struct obd_device *obd = gen_conn2obd(&obddev->obd_multi_conn[i]);
224
225                 if (!obd) { 
226                         CERROR("no such device [i %d]\n", i); 
227                         RETURN(-EINVAL);
228                 }
229
230                 rc = obd_disconnect(&obddev->obd_multi_conn[i]);
231                 if (rc)
232                         CERROR("disconnect failure %d\n", obd->obd_minor);
233         }
234         return 0;
235 }
236
237
238 /*
239  *    forced cleanup of the device:
240  *    - remove connections from the device
241  *    - cleanup the device afterwards
242  */
243 int gen_cleanup(struct obd_device * obddev)
244 {
245         struct list_head * lh, * tmp;
246         struct obd_export * export;
247
248         ENTRY;
249
250         lh = tmp = &obddev->obd_exports;
251         while ((tmp = tmp->next) != lh) {
252                 export = list_entry(tmp, struct obd_export, export_chain);
253                 CDEBUG(D_INFO, "Disconnecting obd_connection %d, at %p\n",
254                        export->export_id, export);
255         }
256         return 0;
257 } /* sim_cleanup_device */
258
259 void lck_page(struct page *page)
260 {
261         while (TryLockPage(page))
262                 ___wait_on_page(page);
263 }
264
265 int gen_copy_data(struct obd_conn *dst_conn, struct obdo *dst,
266                   struct obd_conn *src_conn, struct obdo *src,
267                   obd_size count, obd_off offset)
268 {
269         struct page *page;
270         unsigned long index = 0;
271         int err = 0;
272
273         ENTRY;
274         CDEBUG(D_INFO, "src: ino %Ld blocks %Ld, size %Ld, dst: ino %Ld\n",
275                (unsigned long long)src->o_id, (unsigned long long)src->o_blocks,
276                (unsigned long long)src->o_size, (unsigned long long)dst->o_id);
277         page = alloc_page(GFP_USER);
278         if (page == NULL)
279                 RETURN(-ENOMEM);
280
281         lck_page(page);
282
283         /* XXX with brw vector I/O, we could batch up reads and writes here,
284          *     all we need to do is allocate multiple pages to handle the I/Os
285          *     and arrays to handle the request parameters.
286          */
287         while (index < ((src->o_size + PAGE_SIZE - 1) >> PAGE_SHIFT)) {
288                 obd_count        num_oa = 1;
289                 obd_count        num_buf = 1;
290                 obd_size         brw_count = PAGE_SIZE;
291                 obd_off          brw_offset = (page->index) << PAGE_SHIFT;
292                 obd_flag         flagr = 0;
293                 obd_flag         flagw = OBD_BRW_CREATE;
294
295                 page->index = index;
296                 err = obd_brw(OBD_BRW_READ, src_conn, num_oa, &src, &num_buf,
297                               &page, &brw_count, &brw_offset, &flagr, NULL);
298
299                 if ( err ) {
300                         EXIT;
301                         break;
302                 }
303                 CDEBUG(D_INFO, "Read page %ld ...\n", page->index);
304
305                 err = obd_brw(OBD_BRW_WRITE, dst_conn, num_oa, &dst, &num_buf,
306                               &page, &brw_count, &brw_offset, &flagw, NULL);
307
308                 /* XXX should handle dst->o_size, dst->o_blocks here */
309                 if ( err ) {
310                         EXIT;
311                         break;
312                 }
313
314                 CDEBUG(D_INFO, "Wrote page %ld ...\n", page->index);
315
316                 index++;
317         }
318         dst->o_size = src->o_size;
319         dst->o_blocks = src->o_blocks;
320         dst->o_valid |= (OBD_MD_FLSIZE | OBD_MD_FLBLOCKS);
321         UnlockPage(page);
322         __free_page(page);
323
324         RETURN(err);
325 }