Whamcloud - gitweb
Mass conversion of all copyright messages to Oracle.
[fs/lustre-release.git] / lustre / obdclass / dt_object.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/obdclass/dt_object.c
37  *
38  * Dt Object.
39  * Generic functions from dt_object.h
40  *
41  * Author: Nikita Danilov <nikita@clusterfs.com>
42  */
43
44 #define DEBUG_SUBSYSTEM S_CLASS
45 #ifndef EXPORT_SYMTAB
46 # define EXPORT_SYMTAB
47 #endif
48
49 #include <obd.h>
50 #include <dt_object.h>
51 #include <libcfs/list.h>
52 /* fid_be_to_cpu() */
53 #include <lustre_fid.h>
54
55 struct dt_find_hint {
56         struct lu_fid        *dfh_fid;
57         struct dt_device     *dfh_dt;
58         struct dt_object     *dfh_o;
59 };
60
61 struct dt_thread_info {
62         char                    dti_buf[DT_MAX_PATH];
63         struct dt_find_hint     dti_dfh;
64 };
65
66 /* context key constructor/destructor: dt_global_key_init, dt_global_key_fini */
67 LU_KEY_INIT(dt_global, struct dt_thread_info);
68 LU_KEY_FINI(dt_global, struct dt_thread_info);
69
70 static struct lu_context_key dt_key = {
71         .lct_tags = LCT_MD_THREAD|LCT_DT_THREAD,
72         .lct_init = dt_global_key_init,
73         .lct_fini = dt_global_key_fini
74 };
75
76 /* no lock is necessary to protect the list, because call-backs
77  * are added during system startup. Please refer to "struct dt_device".
78  */
79 void dt_txn_callback_add(struct dt_device *dev, struct dt_txn_callback *cb)
80 {
81         cfs_list_add(&cb->dtc_linkage, &dev->dd_txn_callbacks);
82 }
83 EXPORT_SYMBOL(dt_txn_callback_add);
84
85 void dt_txn_callback_del(struct dt_device *dev, struct dt_txn_callback *cb)
86 {
87         cfs_list_del_init(&cb->dtc_linkage);
88 }
89 EXPORT_SYMBOL(dt_txn_callback_del);
90
91 int dt_txn_hook_start(const struct lu_env *env,
92                       struct dt_device *dev, struct txn_param *param)
93 {
94         int result;
95         struct dt_txn_callback *cb;
96
97         result = 0;
98         cfs_list_for_each_entry(cb, &dev->dd_txn_callbacks, dtc_linkage) {
99                 if (cb->dtc_txn_start == NULL ||
100                     !(cb->dtc_tag & env->le_ctx.lc_tags))
101                         continue;
102                 result = cb->dtc_txn_start(env, param, cb->dtc_cookie);
103                 if (result < 0)
104                         break;
105         }
106         return result;
107 }
108 EXPORT_SYMBOL(dt_txn_hook_start);
109
110 int dt_txn_hook_stop(const struct lu_env *env, struct thandle *txn)
111 {
112         struct dt_device       *dev = txn->th_dev;
113         struct dt_txn_callback *cb;
114         int                     result;
115
116         result = 0;
117         cfs_list_for_each_entry(cb, &dev->dd_txn_callbacks, dtc_linkage) {
118                 if (cb->dtc_txn_stop == NULL ||
119                     !(cb->dtc_tag & env->le_ctx.lc_tags))
120                         continue;
121                 result = cb->dtc_txn_stop(env, txn, cb->dtc_cookie);
122                 if (result < 0)
123                         break;
124         }
125         return result;
126 }
127 EXPORT_SYMBOL(dt_txn_hook_stop);
128
129 int dt_txn_hook_commit(const struct lu_env *env, struct thandle *txn)
130 {
131         struct dt_device       *dev = txn->th_dev;
132         struct dt_txn_callback *cb;
133         int                     result;
134
135         result = 0;
136         cfs_list_for_each_entry(cb, &dev->dd_txn_callbacks, dtc_linkage) {
137                 if (cb->dtc_txn_commit == NULL ||
138                     !(cb->dtc_tag & env->le_ctx.lc_tags))
139                         continue;
140                 result = cb->dtc_txn_commit(env, txn, cb->dtc_cookie);
141                 if (result < 0)
142                         break;
143         }
144         return result;
145 }
146 EXPORT_SYMBOL(dt_txn_hook_commit);
147
148 int dt_device_init(struct dt_device *dev, struct lu_device_type *t)
149 {
150
151         CFS_INIT_LIST_HEAD(&dev->dd_txn_callbacks);
152         return lu_device_init(&dev->dd_lu_dev, t);
153 }
154 EXPORT_SYMBOL(dt_device_init);
155
156 void dt_device_fini(struct dt_device *dev)
157 {
158         lu_device_fini(&dev->dd_lu_dev);
159 }
160 EXPORT_SYMBOL(dt_device_fini);
161
162 int dt_object_init(struct dt_object *obj,
163                    struct lu_object_header *h, struct lu_device *d)
164
165 {
166         return lu_object_init(&obj->do_lu, h, d);
167 }
168 EXPORT_SYMBOL(dt_object_init);
169
170 void dt_object_fini(struct dt_object *obj)
171 {
172         lu_object_fini(&obj->do_lu);
173 }
174 EXPORT_SYMBOL(dt_object_fini);
175
176 int dt_try_as_dir(const struct lu_env *env, struct dt_object *obj)
177 {
178         if (obj->do_index_ops == NULL)
179                 obj->do_ops->do_index_try(env, obj, &dt_directory_features);
180         return obj->do_index_ops != NULL;
181 }
182 EXPORT_SYMBOL(dt_try_as_dir);
183
184 enum dt_format_type dt_mode_to_dft(__u32 mode)
185 {
186         enum dt_format_type result;
187
188         switch (mode & S_IFMT) {
189         case S_IFDIR:
190                 result = DFT_DIR;
191                 break;
192         case S_IFREG:
193                 result = DFT_REGULAR;
194                 break;
195         case S_IFLNK:
196                 result = DFT_SYM;
197                 break;
198         case S_IFCHR:
199         case S_IFBLK:
200         case S_IFIFO:
201         case S_IFSOCK:
202                 result = DFT_NODE;
203                 break;
204         default:
205                 LBUG();
206                 break;
207         }
208         return result;
209 }
210
211 EXPORT_SYMBOL(dt_mode_to_dft);
212 /**
213  * lookup fid for object named \a name in directory \a dir.
214  */
215
216 static int dt_lookup(const struct lu_env *env, struct dt_object *dir,
217                      const char *name, struct lu_fid *fid)
218 {
219         struct dt_rec       *rec = (struct dt_rec *)fid;
220         const struct dt_key *key = (const struct dt_key *)name;
221         int result;
222
223         if (dt_try_as_dir(env, dir)) {
224                 result = dir->do_index_ops->dio_lookup(env, dir, rec, key,
225                                                        BYPASS_CAPA);
226                 if (result > 0)
227                         result = 0;
228                 else if (result == 0)
229                         result = -ENOENT;
230         } else
231                 result = -ENOTDIR;
232         return result;
233 }
234
235 /**
236  * get object for given \a fid.
237  */
238 struct dt_object *dt_locate(const struct lu_env *env,
239                             struct dt_device *dev,
240                             const struct lu_fid *fid)
241 {
242         struct lu_object *obj;
243         struct dt_object *dt;
244
245         obj = lu_object_find(env, &dev->dd_lu_dev, fid, NULL);
246         if (!IS_ERR(obj)) {
247                 obj = lu_object_locate(obj->lo_header, dev->dd_lu_dev.ld_type);
248                 LASSERT(obj != NULL);
249                 dt = container_of(obj, struct dt_object, do_lu);
250         } else
251                 dt = (struct dt_object *)obj;
252         return dt;
253 }
254 EXPORT_SYMBOL(dt_locate);
255
256 /**
257  * find a object named \a entry in given \a dfh->dfh_o directory.
258  */
259 static int dt_find_entry(const struct lu_env *env, const char *entry, void *data)
260 {
261         struct dt_find_hint  *dfh = data;
262         struct dt_device     *dt = dfh->dfh_dt;
263         struct lu_fid        *fid = dfh->dfh_fid;
264         struct dt_object     *obj = dfh->dfh_o;
265         int                   result;
266
267         result = dt_lookup(env, obj, entry, fid);
268         lu_object_put(env, &obj->do_lu);
269         if (result == 0) {
270                 obj = dt_locate(env, dt, fid);
271                 if (IS_ERR(obj))
272                         result = PTR_ERR(obj);
273         }
274         dfh->dfh_o = obj;
275         return result;
276 }
277
278 /**
279  * Abstract function which parses path name. This function feeds
280  * path component to \a entry_func.
281  */
282 int dt_path_parser(const struct lu_env *env,
283                    char *path, dt_entry_func_t entry_func,
284                    void *data)
285 {
286         char *e;
287         int rc = 0;
288
289         while (1) {
290                 e = strsep(&path, "/");
291                 if (e == NULL)
292                         break;
293
294                 if (e[0] == 0) {
295                         if (!path || path[0] == '\0')
296                                 break;
297                         continue;
298                 }
299                 rc = entry_func(env, e, data);
300                 if (rc)
301                         break;
302         }
303
304         return rc;
305 }
306
307 static struct dt_object *dt_store_resolve(const struct lu_env *env,
308                                           struct dt_device *dt,
309                                           const char *path,
310                                           struct lu_fid *fid)
311 {
312         struct dt_thread_info *info = lu_context_key_get(&env->le_ctx,
313                                                          &dt_key);
314         struct dt_find_hint *dfh = &info->dti_dfh;
315         struct dt_object     *obj;
316         char *local = info->dti_buf;
317         int result;
318
319         dfh->dfh_dt = dt;
320         dfh->dfh_fid = fid;
321
322         strncpy(local, path, DT_MAX_PATH);
323         local[DT_MAX_PATH - 1] = '\0';
324
325         result = dt->dd_ops->dt_root_get(env, dt, fid);
326         if (result == 0) {
327                 obj = dt_locate(env, dt, fid);
328                 if (!IS_ERR(obj)) {
329                         dfh->dfh_o = obj;
330                         result = dt_path_parser(env, local, dt_find_entry, dfh);
331                         if (result != 0)
332                                 obj = ERR_PTR(result);
333                         else
334                                 obj = dfh->dfh_o;
335                 }
336         } else {
337                 obj = ERR_PTR(result);
338         }
339         return obj;
340 }
341
342 static struct dt_object *dt_reg_open(const struct lu_env *env,
343                                      struct dt_device *dt,
344                                      struct dt_object *p,
345                                      const char *name,
346                                      struct lu_fid *fid)
347 {
348         struct dt_object *o;
349         int result;
350
351         result = dt_lookup(env, p, name, fid);
352         if (result == 0){
353                 o = dt_locate(env, dt, fid);
354         }
355         else
356                 o = ERR_PTR(result);
357
358         return o;
359 }
360
361 /**
362  * Open dt object named \a filename from \a dirname directory.
363  *      \param  dt      dt device
364  *      \param  fid     on success, object fid is stored in *fid
365  */
366 struct dt_object *dt_store_open(const struct lu_env *env,
367                                 struct dt_device *dt,
368                                 const char *dirname,
369                                 const char *filename,
370                                 struct lu_fid *fid)
371 {
372         struct dt_object *file;
373         struct dt_object *dir;
374
375         dir = dt_store_resolve(env, dt, dirname, fid);
376         if (!IS_ERR(dir)) {
377                 file = dt_reg_open(env, dt, dir,
378                                    filename, fid);
379                 lu_object_put(env, &dir->do_lu);
380         } else {
381                 file = dir;
382         }
383         return file;
384 }
385 EXPORT_SYMBOL(dt_store_open);
386
387 /* dt class init function. */
388 int dt_global_init(void)
389 {
390         int result;
391
392         LU_CONTEXT_KEY_INIT(&dt_key);
393         result = lu_context_key_register(&dt_key);
394         return result;
395 }
396
397 void dt_global_fini(void)
398 {
399         lu_context_key_degister(&dt_key);
400 }
401
402 int dt_record_read(const struct lu_env *env, struct dt_object *dt,
403                    struct lu_buf *buf, loff_t *pos)
404 {
405         int rc;
406
407         LASSERTF(dt != NULL, "dt is NULL when we want to read record\n");
408
409         rc = dt->do_body_ops->dbo_read(env, dt, buf, pos, BYPASS_CAPA);
410
411         if (rc == buf->lb_len)
412                 rc = 0;
413         else if (rc >= 0)
414                 rc = -EFAULT;
415         return rc;
416 }
417 EXPORT_SYMBOL(dt_record_read);
418
419 int dt_record_write(const struct lu_env *env, struct dt_object *dt,
420                     const struct lu_buf *buf, loff_t *pos, struct thandle *th)
421 {
422         int rc;
423
424         LASSERTF(dt != NULL, "dt is NULL when we want to write record\n");
425         LASSERT(th != NULL);
426         rc = dt->do_body_ops->dbo_write(env, dt, buf, pos, th, BYPASS_CAPA, 1);
427         if (rc == buf->lb_len)
428                 rc = 0;
429         else if (rc >= 0)
430                 rc = -EFAULT;
431         return rc;
432 }
433 EXPORT_SYMBOL(dt_record_write);
434
435 const struct dt_index_features dt_directory_features;
436 EXPORT_SYMBOL(dt_directory_features);