2 * linux/fs/ext2_obd/sim_obd.c
3 * Copyright (C) 2001 Cluster File Systems, Inc.
5 * This code is issued under the GNU General Public License.
6 * See the file COPYING in this distribution
8 * These are the only exported functions; they provide the simulated object-
13 #define DEBUG_SUBSYSTEM S_CLASS
15 #include <linux/obd_class.h>
16 #include <linux/random.h>
17 #include <linux/slab.h>
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;
24 void obd_cleanup_caches(void)
29 rc = kmem_cache_destroy(obdo_cachep);
31 CERROR("Cannot destory obdo_cachep\n");
35 rc = kmem_cache_destroy(import_cachep);
37 CERROR("Cannot destory import_cachep\n");
41 rc = kmem_cache_destroy(export_cachep);
43 CERROR("Cannot destory import_cachep\n");
49 int obd_init_caches(void)
52 if (obdo_cachep == NULL) {
53 obdo_cachep = kmem_cache_create("obdo_cache",
55 0, SLAB_HWCACHE_ALIGN,
57 if (obdo_cachep == NULL)
61 if (export_cachep == NULL) {
62 export_cachep = kmem_cache_create("export_cache",
63 sizeof(struct obd_export),
64 0, SLAB_HWCACHE_ALIGN,
66 if (export_cachep == NULL)
70 if (import_cachep == NULL) {
71 import_cachep = kmem_cache_create("import_cache",
72 sizeof(struct obd_import),
73 0, SLAB_HWCACHE_ALIGN,
75 if (import_cachep == NULL)
86 /* map connection to client */
87 struct obd_export *gen_client(struct obd_conn *conn)
89 struct obd_export * export;
94 if (!conn->addr || conn->addr == -1 ) {
99 export = (struct obd_export *) (unsigned long)conn->addr;
100 if (!kmem_cache_validate(export_cachep, (void *)export))
103 if (export->export_cookie != conn->cookie)
108 struct obd_device *gen_conn2obd(struct obd_conn *conn)
110 struct obd_export *export;
111 export = gen_client(conn);
113 return export->export_obd;
118 /* a connection defines a context in which preallocation can be managed. */
119 int gen_connect (struct obd_conn *conn, struct obd_device *obd)
121 struct obd_export * export;
123 export = kmem_cache_alloc(export_cachep, GFP_KERNEL);
125 CERROR("no memory! (minor %d)\n", obd->obd_minor);
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;
137 list_add(&(export->export_chain), export->export_obd->obd_exports.prev);
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;
147 int gen_disconnect(struct obd_conn *conn)
149 struct obd_export * export;
152 if (!(export = gen_client(conn))) {
154 CDEBUG(D_IOCTL, "disconnect: attempting to free "
155 "nonexistent client %u\n", conn->oc_id);
158 list_del(&export->export_chain);
159 kmem_cache_free(export_cachep, export);
161 CDEBUG(D_INFO, "disconnect: ID %u\n", conn->oc_id);
164 } /* gen_obd_disconnect */
166 /* FIXME: Data is a space- or comma-separated list of device IDs. This will
168 int gen_multi_setup(struct obd_device *obddev, uint32_t len, void *data)
174 for (p = data, count = 0; p < (char *)data + len; count++) {
176 int tmp = simple_strtoul(p, &end, 0);
179 CERROR("invalid device ID starting at: %s\n", p);
180 GOTO(err_disconnect, rc = -EINVAL);
183 if (tmp < 0 || tmp >= MAX_OBD_DEVICES) {
184 CERROR("Trying to sub dev %d - dev no too large\n",
186 GOTO(err_disconnect, rc);
189 rc = obd_connect(&obddev->obd_multi_conn[count], &obd_dev[tmp]);
191 CERROR("cannot connect to device %d: rc = %d\n", tmp,
193 GOTO(err_disconnect, rc);
196 CDEBUG(D_INFO, "target OBD %d is of type %s\n", count,
197 obd_dev[tmp].obd_type->typ_name);
202 obddev->obd_multi_count = count;
207 for (count--; count >= 0; count--)
208 obd_disconnect(&obddev->obd_multi_conn[count]);
213 * remove all connections to this device
214 * close all connections to lower devices
215 * needed for forced unloads of OBD client drivers
217 int gen_multi_cleanup(struct obd_device *obddev)
221 for (i = 0; i < obddev->obd_multi_count; i++) {
223 struct obd_device *obd = gen_conn2obd(&obddev->obd_multi_conn[i]);
226 CERROR("no such device [i %d]\n", i);
230 rc = obd_disconnect(&obddev->obd_multi_conn[i]);
232 CERROR("disconnect failure %d\n", obd->obd_minor);
239 * forced cleanup of the device:
240 * - remove connections from the device
241 * - cleanup the device afterwards
243 int gen_cleanup(struct obd_device * obddev)
245 struct list_head * lh, * tmp;
246 struct obd_export * export;
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);
257 } /* sim_cleanup_device */
259 void lck_page(struct page *page)
261 while (TryLockPage(page))
262 ___wait_on_page(page);
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)
270 unsigned long index = 0;
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);
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.
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;
293 obd_flag flagw = OBD_BRW_CREATE;
296 err = obd_brw(OBD_BRW_READ, src_conn, num_oa, &src, &num_buf,
297 &page, &brw_count, &brw_offset, &flagr, NULL);
303 CDEBUG(D_INFO, "Read page %ld ...\n", page->index);
305 err = obd_brw(OBD_BRW_WRITE, dst_conn, num_oa, &dst, &num_buf,
306 &page, &brw_count, &brw_offset, &flagw, NULL);
308 /* XXX should handle dst->o_size, dst->o_blocks here */
314 CDEBUG(D_INFO, "Wrote page %ld ...\n", page->index);
318 dst->o_size = src->o_size;
319 dst->o_blocks = src->o_blocks;
320 dst->o_valid |= (OBD_MD_FLSIZE | OBD_MD_FLBLOCKS);