Whamcloud - gitweb
LU-5971 llite: rename ccc_object to vvp_object
[fs/lustre-release.git] / lustre / llite / vvp_dev.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2012, 2014, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * cl_device and cl_device_type implementation for VVP layer.
37  *
38  *   Author: Nikita Danilov <nikita.danilov@sun.com>
39  *   Author: Jinshan Xiong <jinshan.xiong@intel.com>
40  */
41
42 #define DEBUG_SUBSYSTEM S_LLITE
43
44
45 #include <obd.h>
46 #include "llite_internal.h"
47 #include "vvp_internal.h"
48
49 /*****************************************************************************
50  *
51  * Vvp device and device type functions.
52  *
53  */
54
55 /*
56  * vvp_ prefix stands for "Vfs Vm Posix". It corresponds to historical
57  * "llite_" (var. "ll_") prefix.
58  */
59
60 struct kmem_cache *vvp_object_kmem;
61 static struct kmem_cache *vvp_thread_kmem;
62 static struct kmem_cache *vvp_session_kmem;
63 static struct lu_kmem_descr vvp_caches[] = {
64         {
65                 .ckd_cache = &vvp_object_kmem,
66                 .ckd_name  = "vvp_object_kmem",
67                 .ckd_size  = sizeof(struct vvp_object),
68         },
69         {
70                 .ckd_cache = &vvp_thread_kmem,
71                 .ckd_name  = "vvp_thread_kmem",
72                 .ckd_size  = sizeof (struct vvp_thread_info),
73         },
74         {
75                 .ckd_cache = &vvp_session_kmem,
76                 .ckd_name  = "vvp_session_kmem",
77                 .ckd_size  = sizeof (struct vvp_session)
78         },
79         {
80                 .ckd_cache = NULL
81         }
82 };
83
84 static void *vvp_key_init(const struct lu_context *ctx,
85                           struct lu_context_key *key)
86 {
87         struct vvp_thread_info *info;
88
89         OBD_SLAB_ALLOC_PTR_GFP(info, vvp_thread_kmem, GFP_NOFS);
90         if (info == NULL)
91                 info = ERR_PTR(-ENOMEM);
92         return info;
93 }
94
95 static void vvp_key_fini(const struct lu_context *ctx,
96                          struct lu_context_key *key, void *data)
97 {
98         struct vvp_thread_info *info = data;
99         OBD_SLAB_FREE_PTR(info, vvp_thread_kmem);
100 }
101
102 static void *vvp_session_key_init(const struct lu_context *ctx,
103                                   struct lu_context_key *key)
104 {
105         struct vvp_session *session;
106
107         OBD_SLAB_ALLOC_PTR_GFP(session, vvp_session_kmem, GFP_NOFS);
108         if (session == NULL)
109                 session = ERR_PTR(-ENOMEM);
110         return session;
111 }
112
113 static void vvp_session_key_fini(const struct lu_context *ctx,
114                                  struct lu_context_key *key, void *data)
115 {
116         struct vvp_session *session = data;
117         OBD_SLAB_FREE_PTR(session, vvp_session_kmem);
118 }
119
120
121 struct lu_context_key vvp_key = {
122         .lct_tags = LCT_CL_THREAD,
123         .lct_init = vvp_key_init,
124         .lct_fini = vvp_key_fini
125 };
126
127 struct lu_context_key vvp_session_key = {
128         .lct_tags = LCT_SESSION,
129         .lct_init = vvp_session_key_init,
130         .lct_fini = vvp_session_key_fini
131 };
132
133 /* type constructor/destructor: vvp_type_{init,fini,start,stop}(). */
134 LU_TYPE_INIT_FINI(vvp, &ccc_key, &ccc_session_key, &vvp_key, &vvp_session_key);
135
136 static const struct lu_device_operations vvp_lu_ops = {
137         .ldo_object_alloc      = vvp_object_alloc
138 };
139
140 static const struct cl_device_operations vvp_cl_ops = {
141         .cdo_req_init = ccc_req_init
142 };
143
144 static struct lu_device *vvp_device_free(const struct lu_env *env,
145                                          struct lu_device *d)
146 {
147         struct vvp_device *vdv  = lu2vvp_dev(d);
148         struct cl_site    *site = lu2cl_site(d->ld_site);
149         struct lu_device  *next = cl2lu_dev(vdv->vdv_next);
150
151         if (d->ld_site != NULL) {
152                 cl_site_fini(site);
153                 OBD_FREE_PTR(site);
154         }
155
156         cl_device_fini(lu2cl_dev(d));
157         OBD_FREE_PTR(vdv);
158         return next;
159 }
160
161 static struct lu_device *vvp_device_alloc(const struct lu_env *env,
162                                           struct lu_device_type *t,
163                                           struct lustre_cfg *cfg)
164 {
165         struct vvp_device *vdv;
166         struct lu_device *lud;
167         struct cl_site *site;
168         int rc;
169         ENTRY;
170
171         OBD_ALLOC_PTR(vdv);
172         if (vdv == NULL)
173                 RETURN(ERR_PTR(-ENOMEM));
174
175         lud = &vdv->vdv_cl.cd_lu_dev;
176         cl_device_init(&vdv->vdv_cl, t);
177         vvp2lu_dev(vdv)->ld_ops = &vvp_lu_ops;
178         vdv->vdv_cl.cd_ops = &vvp_cl_ops;
179
180         OBD_ALLOC_PTR(site);
181         if (site != NULL) {
182                 rc = cl_site_init(site, &vdv->vdv_cl);
183                 if (rc == 0)
184                         rc = lu_site_init_finish(&site->cs_lu);
185                 else {
186                         LASSERT(lud->ld_site == NULL);
187                         CERROR("Cannot init lu_site, rc %d.\n", rc);
188                         OBD_FREE_PTR(site);
189                 }
190         } else
191                 rc = -ENOMEM;
192         if (rc != 0) {
193                 vvp_device_free(env, lud);
194                 lud = ERR_PTR(rc);
195         }
196         RETURN(lud);
197 }
198
199 static int vvp_device_init(const struct lu_env *env, struct lu_device *d,
200                            const char *name, struct lu_device *next)
201 {
202         struct vvp_device  *vdv;
203         int rc;
204         ENTRY;
205
206         vdv = lu2vvp_dev(d);
207         vdv->vdv_next = lu2cl_dev(next);
208
209         LASSERT(d->ld_site != NULL && next->ld_type != NULL);
210         next->ld_site = d->ld_site;
211         rc = next->ld_type->ldt_ops->ldto_device_init(
212                 env, next, next->ld_type->ldt_name, NULL);
213         if (rc == 0) {
214                 lu_device_get(next);
215                 lu_ref_add(&next->ld_reference, "lu-stack", &lu_site_init);
216         }
217         RETURN(rc);
218 }
219
220 static struct lu_device *vvp_device_fini(const struct lu_env *env,
221                                          struct lu_device *d)
222 {
223         return cl2lu_dev(lu2vvp_dev(d)->vdv_next);
224 }
225
226 static const struct lu_device_type_operations vvp_device_type_ops = {
227         .ldto_init = vvp_type_init,
228         .ldto_fini = vvp_type_fini,
229
230         .ldto_start = vvp_type_start,
231         .ldto_stop  = vvp_type_stop,
232
233         .ldto_device_alloc      = vvp_device_alloc,
234         .ldto_device_free       = vvp_device_free,
235         .ldto_device_init       = vvp_device_init,
236         .ldto_device_fini       = vvp_device_fini,
237 };
238
239 struct lu_device_type vvp_device_type = {
240         .ldt_tags     = LU_DEVICE_CL,
241         .ldt_name     = LUSTRE_VVP_NAME,
242         .ldt_ops      = &vvp_device_type_ops,
243         .ldt_ctx_tags = LCT_CL_THREAD
244 };
245
246 /**
247  * A mutex serializing calls to vvp_inode_fini() under extreme memory
248  * pressure, when environments cannot be allocated.
249  */
250 int vvp_global_init(void)
251 {
252         int result;
253
254         result = lu_kmem_init(vvp_caches);
255         if (result == 0) {
256                 result = ccc_global_init(&vvp_device_type);
257                 if (result != 0)
258                         lu_kmem_fini(vvp_caches);
259         }
260         return result;
261 }
262
263 void vvp_global_fini(void)
264 {
265         ccc_global_fini(&vvp_device_type);
266         lu_kmem_fini(vvp_caches);
267 }
268
269
270 /*****************************************************************************
271  *
272  * mirror obd-devices into cl devices.
273  *
274  */
275
276 int cl_sb_init(struct super_block *sb)
277 {
278         struct ll_sb_info *sbi;
279         struct cl_device  *cl;
280         struct lu_env     *env;
281         int rc = 0;
282         int refcheck;
283
284         sbi  = ll_s2sbi(sb);
285         env = cl_env_get(&refcheck);
286         if (!IS_ERR(env)) {
287                 cl = cl_type_setup(env, NULL, &vvp_device_type,
288                                    sbi->ll_dt_exp->exp_obd->obd_lu_dev);
289                 if (!IS_ERR(cl)) {
290                         cl2vvp_dev(cl)->vdv_sb = sb;
291                         sbi->ll_cl = cl;
292                         sbi->ll_site = cl2lu_dev(cl)->ld_site;
293                 }
294                 cl_env_put(env, &refcheck);
295         } else
296                 rc = PTR_ERR(env);
297         RETURN(rc);
298 }
299
300 int cl_sb_fini(struct super_block *sb)
301 {
302         struct ll_sb_info *sbi;
303         struct lu_env     *env;
304         struct cl_device  *cld;
305         int                refcheck;
306         int                result;
307
308         ENTRY;
309         sbi = ll_s2sbi(sb);
310         env = cl_env_get(&refcheck);
311         if (!IS_ERR(env)) {
312                 cld = sbi->ll_cl;
313
314                 if (cld != NULL) {
315                         cl_stack_fini(env, cld);
316                         sbi->ll_cl = NULL;
317                         sbi->ll_site = NULL;
318                 }
319                 cl_env_put(env, &refcheck);
320                 result = 0;
321         } else {
322                 CERROR("Cannot cleanup cl-stack due to memory shortage.\n");
323                 result = PTR_ERR(env);
324         }
325
326         RETURN(result);
327 }
328
329 /****************************************************************************
330  *
331  * /proc/fs/lustre/llite/$MNT/dump_page_cache
332  *
333  ****************************************************************************/
334
335 /*
336  * To represent contents of a page cache as a byte stream, following
337  * information if encoded in 64bit offset:
338  *
339  *       - file hash bucket in lu_site::ls_hash[]       28bits
340  *
341  *       - how far file is from bucket head              4bits
342  *
343  *       - page index                                   32bits
344  *
345  * First two data identify a file in the cache uniquely.
346  */
347
348 #define PGC_OBJ_SHIFT (32 + 4)
349 #define PGC_DEPTH_SHIFT (32)
350
351 struct vvp_pgcache_id {
352         unsigned                 vpi_bucket;
353         unsigned                 vpi_depth;
354         uint32_t                 vpi_index;
355
356         unsigned                 vpi_curdep;
357         struct lu_object_header *vpi_obj;
358 };
359
360 static void vvp_pgcache_id_unpack(loff_t pos, struct vvp_pgcache_id *id)
361 {
362         CLASSERT(sizeof(pos) == sizeof(__u64));
363
364         id->vpi_index  = pos & 0xffffffff;
365         id->vpi_depth  = (pos >> PGC_DEPTH_SHIFT) & 0xf;
366         id->vpi_bucket = ((unsigned long long)pos >> PGC_OBJ_SHIFT);
367 }
368
369 static loff_t vvp_pgcache_id_pack(struct vvp_pgcache_id *id)
370 {
371         return
372                 ((__u64)id->vpi_index) |
373                 ((__u64)id->vpi_depth  << PGC_DEPTH_SHIFT) |
374                 ((__u64)id->vpi_bucket << PGC_OBJ_SHIFT);
375 }
376
377 static int vvp_pgcache_obj_get(cfs_hash_t *hs, cfs_hash_bd_t *bd,
378                                struct hlist_node *hnode, void *data)
379 {
380         struct vvp_pgcache_id   *id  = data;
381         struct lu_object_header *hdr = cfs_hash_object(hs, hnode);
382
383         if (id->vpi_curdep-- > 0)
384                 return 0; /* continue */
385
386         if (lu_object_is_dying(hdr))
387                 return 1;
388
389         cfs_hash_get(hs, hnode);
390         id->vpi_obj = hdr;
391         return 1;
392 }
393
394 static struct cl_object *vvp_pgcache_obj(const struct lu_env *env,
395                                          struct lu_device *dev,
396                                          struct vvp_pgcache_id *id)
397 {
398         LASSERT(lu_device_is_cl(dev));
399
400         id->vpi_depth &= 0xf;
401         id->vpi_obj    = NULL;
402         id->vpi_curdep = id->vpi_depth;
403
404         cfs_hash_hlist_for_each(dev->ld_site->ls_obj_hash, id->vpi_bucket,
405                                 vvp_pgcache_obj_get, id);
406         if (id->vpi_obj != NULL) {
407                 struct lu_object *lu_obj;
408
409                 lu_obj = lu_object_locate(id->vpi_obj, dev->ld_type);
410                 if (lu_obj != NULL) {
411                         lu_object_ref_add(lu_obj, "dump", current);
412                         return lu2cl(lu_obj);
413                 }
414                 lu_object_put(env, lu_object_top(id->vpi_obj));
415
416         } else if (id->vpi_curdep > 0) {
417                 id->vpi_depth = 0xf;
418         }
419         return NULL;
420 }
421
422 static loff_t vvp_pgcache_find(const struct lu_env *env,
423                                struct lu_device *dev, loff_t pos)
424 {
425         struct cl_object     *clob;
426         struct lu_site       *site;
427         struct vvp_pgcache_id id;
428
429         site = dev->ld_site;
430         vvp_pgcache_id_unpack(pos, &id);
431
432         while (1) {
433                 if (id.vpi_bucket >= CFS_HASH_NHLIST(site->ls_obj_hash))
434                         return ~0ULL;
435                 clob = vvp_pgcache_obj(env, dev, &id);
436                 if (clob != NULL) {
437                         struct inode *inode = vvp_object_inode(clob);
438                         struct page *vmpage;
439                         int nr;
440
441                         nr = find_get_pages_contig(inode->i_mapping,
442                                                    id.vpi_index, 1, &vmpage);
443                         if (nr > 0) {
444                                 id.vpi_index = vmpage->index;
445                                 /* Cant support over 16T file */
446                                 nr = !(vmpage->index > 0xffffffff);
447                                 page_cache_release(vmpage);
448                         }
449
450                         lu_object_ref_del(&clob->co_lu, "dump", current);
451                         cl_object_put(env, clob);
452                         if (nr > 0)
453                                 return vvp_pgcache_id_pack(&id);
454                 }
455                 /* to the next object. */
456                 ++id.vpi_depth;
457                 id.vpi_depth &= 0xf;
458                 if (id.vpi_depth == 0 && ++id.vpi_bucket == 0)
459                         return ~0ULL;
460                 id.vpi_index = 0;
461         }
462 }
463
464 #define seq_page_flag(seq, page, flag, has_flags) do {                  \
465         if (test_bit(PG_##flag, &(page)->flags)) {                  \
466                 seq_printf(seq, "%s"#flag, has_flags ? "|" : "");       \
467                 has_flags = 1;                                          \
468         }                                                               \
469 } while(0)
470
471 static void vvp_pgcache_page_show(const struct lu_env *env,
472                                   struct seq_file *seq, struct cl_page *page)
473 {
474         struct ccc_page *cpg;
475         struct page      *vmpage;
476         int              has_flags;
477
478         cpg = cl2ccc_page(cl_page_at(page, &vvp_device_type));
479         vmpage = cpg->cpg_page;
480         seq_printf(seq, " %5i | %p %p %s %s %s %s | %p "DFID"(%p) %lu %u [",
481                    0 /* gen */,
482                    cpg, page,
483                    "none",
484                    cpg->cpg_write_queued ? "wq" : "- ",
485                    cpg->cpg_defer_uptodate ? "du" : "- ",
486                    PageWriteback(vmpage) ? "wb" : "-",
487                    vmpage,
488                    PFID(ll_inode2fid(vmpage->mapping->host)),
489                    vmpage->mapping->host, vmpage->index,
490                    page_count(vmpage));
491         has_flags = 0;
492         seq_page_flag(seq, vmpage, locked, has_flags);
493         seq_page_flag(seq, vmpage, error, has_flags);
494         seq_page_flag(seq, vmpage, referenced, has_flags);
495         seq_page_flag(seq, vmpage, uptodate, has_flags);
496         seq_page_flag(seq, vmpage, dirty, has_flags);
497         seq_page_flag(seq, vmpage, writeback, has_flags);
498         seq_printf(seq, "%s]\n", has_flags ? "" : "-");
499 }
500
501 static int vvp_pgcache_show(struct seq_file *f, void *v)
502 {
503         loff_t                   pos;
504         struct ll_sb_info       *sbi;
505         struct cl_object        *clob;
506         struct lu_env           *env;
507         struct vvp_pgcache_id    id;
508         int                      refcheck;
509         int                      result;
510
511         env = cl_env_get(&refcheck);
512         if (!IS_ERR(env)) {
513                 pos = *(loff_t *) v;
514                 vvp_pgcache_id_unpack(pos, &id);
515                 sbi = f->private;
516                 clob = vvp_pgcache_obj(env, &sbi->ll_cl->cd_lu_dev, &id);
517                 if (clob != NULL) {
518                         struct inode *inode = vvp_object_inode(clob);
519                         struct cl_page *page = NULL;
520                         struct page *vmpage;
521
522                         result = find_get_pages_contig(inode->i_mapping,
523                                                       id.vpi_index, 1, &vmpage);
524                         if (result > 0) {
525                                 lock_page(vmpage);
526                                 page = cl_vmpage_page(vmpage, clob);
527                                 unlock_page(vmpage);
528
529                                 page_cache_release(vmpage);
530                         }
531
532                         seq_printf(f, "%8x@"DFID": ", id.vpi_index,
533                                    PFID(lu_object_fid(&clob->co_lu)));
534                         if (page != NULL) {
535                                 vvp_pgcache_page_show(env, f, page);
536                                 cl_page_put(env, page);
537                         } else
538                                 seq_puts(f, "missing\n");
539                         lu_object_ref_del(&clob->co_lu, "dump", current);
540                         cl_object_put(env, clob);
541                 } else
542                         seq_printf(f, "%llx missing\n", pos);
543                 cl_env_put(env, &refcheck);
544                 result = 0;
545         } else
546                 result = PTR_ERR(env);
547         return result;
548 }
549
550 static void *vvp_pgcache_start(struct seq_file *f, loff_t *pos)
551 {
552         struct ll_sb_info *sbi;
553         struct lu_env     *env;
554         int                refcheck;
555
556         sbi = f->private;
557
558         env = cl_env_get(&refcheck);
559         if (!IS_ERR(env)) {
560                 sbi = f->private;
561                 if (sbi->ll_site->ls_obj_hash->hs_cur_bits > 64 - PGC_OBJ_SHIFT)
562                         pos = ERR_PTR(-EFBIG);
563                 else {
564                         *pos = vvp_pgcache_find(env, &sbi->ll_cl->cd_lu_dev,
565                                                 *pos);
566                         if (*pos == ~0ULL)
567                                 pos = NULL;
568                 }
569                 cl_env_put(env, &refcheck);
570         }
571         return pos;
572 }
573
574 static void *vvp_pgcache_next(struct seq_file *f, void *v, loff_t *pos)
575 {
576         struct ll_sb_info *sbi;
577         struct lu_env     *env;
578         int                refcheck;
579
580         env = cl_env_get(&refcheck);
581         if (!IS_ERR(env)) {
582                 sbi = f->private;
583                 *pos = vvp_pgcache_find(env, &sbi->ll_cl->cd_lu_dev, *pos + 1);
584                 if (*pos == ~0ULL)
585                         pos = NULL;
586                 cl_env_put(env, &refcheck);
587         }
588         return pos;
589 }
590
591 static void vvp_pgcache_stop(struct seq_file *f, void *v)
592 {
593         /* Nothing to do */
594 }
595
596 static struct seq_operations vvp_pgcache_ops = {
597         .start = vvp_pgcache_start,
598         .next  = vvp_pgcache_next,
599         .stop  = vvp_pgcache_stop,
600         .show  = vvp_pgcache_show
601 };
602
603 static int vvp_dump_pgcache_seq_open(struct inode *inode, struct file *filp)
604 {
605         struct ll_sb_info       *sbi = PDE_DATA(inode);
606         struct seq_file         *seq;
607         int                     result;
608
609         result = seq_open(filp, &vvp_pgcache_ops);
610         if (result == 0) {
611                 seq = filp->private_data;
612                 seq->private = sbi;
613         }
614         return result;
615 }
616
617 const struct file_operations vvp_dump_pgcache_file_ops = {
618         .owner   = THIS_MODULE,
619         .open    = vvp_dump_pgcache_seq_open,
620         .read    = seq_read,
621         .llseek  = seq_lseek,
622         .release = seq_release,
623 };