Whamcloud - gitweb
Minor bug fixes to get export handles used by the DLM. I believe the
[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->addr = (__u64) (unsigned long)export;
141         conn->cookie = export->export_cookie;
142         return 0;
143 } /* gen_connect */
144
145
146 int gen_disconnect(struct obd_conn *conn)
147 {
148         struct obd_export * export;
149         ENTRY;
150
151         if (!(export = gen_client(conn))) {
152                 fixme();
153                 CDEBUG(D_IOCTL, "disconnect: attempting to free "
154                        "nonexistent client %Lx\n", conn->addr);
155                 RETURN(-EINVAL);
156         }
157         list_del(&export->export_chain);
158         kmem_cache_free(export_cachep, export);
159
160         RETURN(0);
161 } /* gen_obd_disconnect */
162
163 /* FIXME: Data is a space- or comma-separated list of device IDs.  This will
164  * have to change. */
165 int gen_multi_setup(struct obd_device *obddev, uint32_t len, void *data)
166 {
167         int count, rc;
168         char *p;
169         ENTRY;
170
171         for (p = data, count = 0; p < (char *)data + len; count++) {
172                 char *end;
173                 int tmp = simple_strtoul(p, &end, 0);
174
175                 if (p == end) {
176                         CERROR("invalid device ID starting at: %s\n", p);
177                         GOTO(err_disconnect, rc = -EINVAL);
178                 }
179                 
180                 if (tmp < 0 || tmp >= MAX_OBD_DEVICES) { 
181                         CERROR("Trying to sub dev %d  - dev no too large\n", 
182                                tmp);
183                         GOTO(err_disconnect, rc); 
184                 }
185
186                 rc = obd_connect(&obddev->obd_multi_conn[count], &obd_dev[tmp]);
187                 if (rc) {
188                         CERROR("cannot connect to device %d: rc = %d\n", tmp,
189                                rc);
190                         GOTO(err_disconnect, rc);
191                 }
192
193                 CDEBUG(D_INFO, "target OBD %d is of type %s\n", count,
194                        obd_dev[tmp].obd_type->typ_name);
195
196                 p = end + 1;
197         }
198
199         obddev->obd_multi_count = count;
200
201         RETURN(0);
202
203  err_disconnect:
204         for (count--; count >= 0; count--)
205                 obd_disconnect(&obddev->obd_multi_conn[count]);
206         return rc;
207 }
208
209 /*
210  *    remove all connections to this device
211  *    close all connections to lower devices
212  *    needed for forced unloads of OBD client drivers
213  */
214 int gen_multi_cleanup(struct obd_device *obddev)
215 {
216         int i;
217
218         for (i = 0; i < obddev->obd_multi_count; i++) {
219                 int rc;
220                 struct obd_device *obd = gen_conn2obd(&obddev->obd_multi_conn[i]);
221
222                 if (!obd) { 
223                         CERROR("no such device [i %d]\n", i); 
224                         RETURN(-EINVAL);
225                 }
226
227                 rc = obd_disconnect(&obddev->obd_multi_conn[i]);
228                 if (rc)
229                         CERROR("disconnect failure %d\n", obd->obd_minor);
230         }
231         return 0;
232 }
233
234
235 /*
236  *    forced cleanup of the device:
237  *    - remove connections from the device
238  *    - cleanup the device afterwards
239  */
240 int gen_cleanup(struct obd_device * obddev)
241 {
242         struct list_head * lh, * tmp;
243         struct obd_export * export;
244
245         ENTRY;
246
247         lh = tmp = &obddev->obd_exports;
248         while ((tmp = tmp->next) != lh) {
249                 export = list_entry(tmp, struct obd_export, export_chain);
250                 CDEBUG(D_INFO, "Disconnecting obd_connection %d, at %p\n",
251                        export->export_id, export);
252         }
253         return 0;
254 } /* sim_cleanup_device */
255
256 void lck_page(struct page *page)
257 {
258         while (TryLockPage(page))
259                 ___wait_on_page(page);
260 }
261
262 int gen_copy_data(struct obd_conn *dst_conn, struct obdo *dst,
263                   struct obd_conn *src_conn, struct obdo *src,
264                   obd_size count, obd_off offset)
265 {
266         struct page *page;
267         unsigned long index = 0;
268         int err = 0;
269
270         ENTRY;
271         CDEBUG(D_INFO, "src: ino %Ld blocks %Ld, size %Ld, dst: ino %Ld\n",
272                (unsigned long long)src->o_id, (unsigned long long)src->o_blocks,
273                (unsigned long long)src->o_size, (unsigned long long)dst->o_id);
274         page = alloc_page(GFP_USER);
275         if (page == NULL)
276                 RETURN(-ENOMEM);
277
278         lck_page(page);
279
280         /* XXX with brw vector I/O, we could batch up reads and writes here,
281          *     all we need to do is allocate multiple pages to handle the I/Os
282          *     and arrays to handle the request parameters.
283          */
284         while (index < ((src->o_size + PAGE_SIZE - 1) >> PAGE_SHIFT)) {
285                 obd_count        num_oa = 1;
286                 obd_count        num_buf = 1;
287                 obd_size         brw_count = PAGE_SIZE;
288                 obd_off          brw_offset = (page->index) << PAGE_SHIFT;
289                 obd_flag         flagr = 0;
290                 obd_flag         flagw = OBD_BRW_CREATE;
291
292                 page->index = index;
293                 err = obd_brw(OBD_BRW_READ, src_conn, num_oa, &src, &num_buf,
294                               &page, &brw_count, &brw_offset, &flagr, NULL);
295
296                 if ( err ) {
297                         EXIT;
298                         break;
299                 }
300                 CDEBUG(D_INFO, "Read page %ld ...\n", page->index);
301
302                 err = obd_brw(OBD_BRW_WRITE, dst_conn, num_oa, &dst, &num_buf,
303                               &page, &brw_count, &brw_offset, &flagw, NULL);
304
305                 /* XXX should handle dst->o_size, dst->o_blocks here */
306                 if ( err ) {
307                         EXIT;
308                         break;
309                 }
310
311                 CDEBUG(D_INFO, "Wrote page %ld ...\n", page->index);
312
313                 index++;
314         }
315         dst->o_size = src->o_size;
316         dst->o_blocks = src->o_blocks;
317         dst->o_valid |= (OBD_MD_FLSIZE | OBD_MD_FLBLOCKS);
318         UnlockPage(page);
319         __free_page(page);
320
321         RETURN(err);
322 }