Whamcloud - gitweb
79c160ec1873f8fe0334ee17d35e35883279d94c
[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  2008 Sun Microsystems, Inc. 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 lu_fid_pack      dti_pack;
64         struct dt_find_hint     dti_dfh;
65 };
66
67 /* context key constructor/destructor: dt_global_key_init, dt_global_key_fini */
68 LU_KEY_INIT(dt_global, struct dt_thread_info);
69 LU_KEY_FINI(dt_global, struct dt_thread_info);
70
71 static struct lu_context_key dt_key = {
72         .lct_tags = LCT_MD_THREAD|LCT_DT_THREAD,
73         .lct_init = dt_global_key_init,
74         .lct_fini = dt_global_key_fini
75 };
76
77 /* no lock is necessary to protect the list, because call-backs
78  * are added during system startup. Please refer to "struct dt_device".
79  */
80 void dt_txn_callback_add(struct dt_device *dev, struct dt_txn_callback *cb)
81 {
82         list_add(&cb->dtc_linkage, &dev->dd_txn_callbacks);
83 }
84 EXPORT_SYMBOL(dt_txn_callback_add);
85
86 void dt_txn_callback_del(struct dt_device *dev, struct dt_txn_callback *cb)
87 {
88         list_del_init(&cb->dtc_linkage);
89 }
90 EXPORT_SYMBOL(dt_txn_callback_del);
91
92 int dt_txn_hook_start(const struct lu_env *env,
93                       struct dt_device *dev, struct txn_param *param)
94 {
95         int result;
96         struct dt_txn_callback *cb;
97
98         result = 0;
99         list_for_each_entry(cb, &dev->dd_txn_callbacks, dtc_linkage) {
100                 if (cb->dtc_txn_start == NULL)
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         list_for_each_entry(cb, &dev->dd_txn_callbacks, dtc_linkage) {
118                 if (cb->dtc_txn_stop == NULL)
119                         continue;
120                 result = cb->dtc_txn_stop(env, txn, cb->dtc_cookie);
121                 if (result < 0)
122                         break;
123         }
124         return result;
125 }
126 EXPORT_SYMBOL(dt_txn_hook_stop);
127
128 int dt_txn_hook_commit(const struct lu_env *env, struct thandle *txn)
129 {
130         struct dt_device       *dev = txn->th_dev;
131         struct dt_txn_callback *cb;
132         int                     result;
133
134         result = 0;
135         list_for_each_entry(cb, &dev->dd_txn_callbacks, dtc_linkage) {
136                 if (cb->dtc_txn_commit == NULL)
137                         continue;
138                 result = cb->dtc_txn_commit(env, txn, cb->dtc_cookie);
139                 if (result < 0)
140                         break;
141         }
142         return result;
143 }
144 EXPORT_SYMBOL(dt_txn_hook_commit);
145
146 int dt_device_init(struct dt_device *dev, struct lu_device_type *t)
147 {
148
149         CFS_INIT_LIST_HEAD(&dev->dd_txn_callbacks);
150         return lu_device_init(&dev->dd_lu_dev, t);
151 }
152 EXPORT_SYMBOL(dt_device_init);
153
154 void dt_device_fini(struct dt_device *dev)
155 {
156         lu_device_fini(&dev->dd_lu_dev);
157 }
158 EXPORT_SYMBOL(dt_device_fini);
159
160 int dt_object_init(struct dt_object *obj,
161                    struct lu_object_header *h, struct lu_device *d)
162
163 {
164         return lu_object_init(&obj->do_lu, h, d);
165 }
166 EXPORT_SYMBOL(dt_object_init);
167
168 void dt_object_fini(struct dt_object *obj)
169 {
170         lu_object_fini(&obj->do_lu);
171 }
172 EXPORT_SYMBOL(dt_object_fini);
173
174 int dt_try_as_dir(const struct lu_env *env, struct dt_object *obj)
175 {
176         if (obj->do_index_ops == NULL)
177                 obj->do_ops->do_index_try(env, obj, &dt_directory_features);
178         return obj->do_index_ops != NULL;
179 }
180 EXPORT_SYMBOL(dt_try_as_dir);
181
182 enum dt_format_type dt_mode_to_dft(__u32 mode)
183 {
184         enum dt_format_type result;
185
186         switch (mode & S_IFMT) {
187         case S_IFDIR:
188                 result = DFT_DIR;
189                 break;
190         case S_IFREG:
191                 result = DFT_REGULAR;
192                 break;
193         case S_IFLNK:
194                 result = DFT_SYM;
195                 break;
196         case S_IFCHR:
197         case S_IFBLK:
198         case S_IFIFO:
199         case S_IFSOCK:
200                 result = DFT_NODE;
201                 break;
202         default:
203                 LBUG();
204                 break;
205         }
206         return result;
207 }
208
209 EXPORT_SYMBOL(dt_mode_to_dft);
210 /**
211  * lookup fid for object named \a name in directory \a dir.
212  */
213
214 static int dt_lookup(const struct lu_env *env, struct dt_object *dir,
215                      const char *name, struct lu_fid *fid)
216 {
217         struct dt_thread_info *info = lu_context_key_get(&env->le_ctx,
218                                                          &dt_key);
219         struct lu_fid_pack *pack = &info->dti_pack;
220         struct dt_rec       *rec = (struct dt_rec *)pack;
221         const struct dt_key *key = (const struct dt_key *)name;
222         int result;
223
224         if (dt_try_as_dir(env, dir)) {
225                 result = dir->do_index_ops->dio_lookup(env, dir, rec, key,
226                                                        BYPASS_CAPA);
227                 if (result > 0)
228                         result = fid_unpack(pack, fid);
229                 else if (result == 0)
230                         result = -ENOENT;
231         } else
232                 result = -ENOTDIR;
233         return result;
234 }
235
236 /**
237  * get object for given \a fid.
238  */
239 struct dt_object *dt_locate(const struct lu_env *env,
240                             struct dt_device *dev,
241                             const struct lu_fid *fid)
242 {
243         struct lu_object *obj;
244         struct dt_object *dt;
245
246         obj = lu_object_find(env, &dev->dd_lu_dev, fid, NULL);
247         if (!IS_ERR(obj)) {
248                 obj = lu_object_locate(obj->lo_header, dev->dd_lu_dev.ld_type);
249                 LASSERT(obj != NULL);
250                 dt = container_of(obj, struct dt_object, do_lu);
251         } else
252                 dt = (struct dt_object *)obj;
253         return dt;
254 }
255 EXPORT_SYMBOL(dt_locate);
256
257 /**
258  * find a object named \a entry in given \a dfh->dfh_o directory.
259  */
260 static int dt_find_entry(const struct lu_env *env, const char *entry, void *data)
261 {
262         struct dt_find_hint  *dfh = data;
263         struct dt_device     *dt = dfh->dfh_dt;
264         struct lu_fid        *fid = dfh->dfh_fid;
265         struct dt_object     *obj = dfh->dfh_o;
266         int                   result;
267
268         result = dt_lookup(env, obj, entry, fid);
269         lu_object_put(env, &obj->do_lu);
270         if (result == 0) {
271                 obj = dt_locate(env, dt, fid);
272                 if (IS_ERR(obj))
273                         result = PTR_ERR(obj);
274         }
275         dfh->dfh_o = obj;
276         return result;
277 }
278
279 /**
280  * Abstract function which parses path name. This function feeds
281  * path component to \a entry_func.
282  */
283 int dt_path_parser(const struct lu_env *env,
284                    char *path, dt_entry_func_t entry_func,
285                    void *data)
286 {
287         char *e;
288         int rc = 0;
289
290         while (1) {
291                 e = strsep(&path, "/");
292                 if (e == NULL)
293                         break;
294
295                 if (e[0] == 0) {
296                         if (!path || path[0] == '\0')
297                                 break;
298                         continue;
299                 }
300                 rc = entry_func(env, e, data);
301                 if (rc)
302                         break;
303         }
304
305         return rc;
306 }
307
308 static struct dt_object *dt_store_resolve(const struct lu_env *env,
309                                           struct dt_device *dt,
310                                           const char *path,
311                                           struct lu_fid *fid)
312 {
313         struct dt_thread_info *info = lu_context_key_get(&env->le_ctx,
314                                                          &dt_key);
315         struct dt_find_hint *dfh = &info->dti_dfh;
316         struct dt_object     *obj;
317         char *local = info->dti_buf;
318         int result;
319
320         dfh->dfh_dt = dt;
321         dfh->dfh_fid = fid;
322
323         strncpy(local, path, DT_MAX_PATH);
324         local[DT_MAX_PATH - 1] = '\0';
325
326         result = dt->dd_ops->dt_root_get(env, dt, fid);
327         if (result == 0) {
328                 obj = dt_locate(env, dt, fid);
329                 if (!IS_ERR(obj)) {
330                         dfh->dfh_o = obj;
331                         result = dt_path_parser(env, local, dt_find_entry, dfh);
332                         if (result != 0)
333                                 obj = ERR_PTR(result);
334                         else
335                                 obj = dfh->dfh_o;
336                 }
337         } else {
338                 obj = ERR_PTR(result);
339         }
340         return obj;
341 }
342
343 static struct dt_object *dt_reg_open(const struct lu_env *env,
344                                      struct dt_device *dt,
345                                      struct dt_object *p,
346                                      const char *name,
347                                      struct lu_fid *fid)
348 {
349         struct dt_object *o;
350         int result;
351
352         result = dt_lookup(env, p, name, fid);
353         if (result == 0){
354                 o = dt_locate(env, dt, fid);
355         }
356         else
357                 o = ERR_PTR(result);
358
359         return o;
360 }
361
362 /**
363  * Open dt object named \a filename from \a dirname directory.
364  *      \param  dt      dt device
365  *      \param  fid     on success, object fid is stored in *fid
366  */
367 struct dt_object *dt_store_open(const struct lu_env *env,
368                                 struct dt_device *dt,
369                                 const char *dirname,
370                                 const char *filename,
371                                 struct lu_fid *fid)
372 {
373         struct dt_object *file;
374         struct dt_object *dir;
375
376         dir = dt_store_resolve(env, dt, dirname, fid);
377         if (!IS_ERR(dir)) {
378                 file = dt_reg_open(env, dt, dir,
379                                    filename, fid);
380                 lu_object_put(env, &dir->do_lu);
381         } else {
382                 file = dir;
383         }
384         return file;
385 }
386 EXPORT_SYMBOL(dt_store_open);
387
388 /* dt class init function. */
389 int dt_global_init(void)
390 {
391         int result;
392
393         LU_CONTEXT_KEY_INIT(&dt_key);
394         result = lu_context_key_register(&dt_key);
395         return result;
396 }
397
398 void dt_global_fini(void)
399 {
400         lu_context_key_degister(&dt_key);
401 }
402
403 const struct dt_index_features dt_directory_features;
404 EXPORT_SYMBOL(dt_directory_features);