Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / tools / cephfs / PgFiles.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2016 Red Hat
7  *
8  * This is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License version 2.1, as published by the Free Software
11  * Foundation.  See file COPYING.
12  *
13  */
14
15 #include "common/errno.h"
16 #include "osdc/Striper.h"
17
18 #include "PgFiles.h"
19
20
21 #define dout_context g_ceph_context
22 #define dout_subsys ceph_subsys_mds
23 #undef dout_prefix
24 #define dout_prefix *_dout << "pgeffects." << __func__ << ": "
25
26 int PgFiles::init()
27 {
28   int r = ceph_create_with_context(&cmount, g_ceph_context);
29   if (r != 0) {
30     return r;
31   }
32
33   return ceph_init(cmount);
34 }
35
36 PgFiles::PgFiles(Objecter *o, std::set<pg_t> pgs_)
37   : objecter(o), pgs(pgs_)
38 {
39   for (const auto &i : pgs) {
40     pools.insert(i.m_pool);
41   }
42 }
43
44 PgFiles::~PgFiles()
45 {
46   ceph_release(cmount);
47 }
48
49 void PgFiles::hit_dir(std::string const &path)
50 {
51   dout(10) << "entering " << path << dendl;
52
53   ceph_dir_result *dr = nullptr;
54   int r = ceph_opendir(cmount, path.c_str(), &dr);
55   if (r != 0) {
56     derr << "Failed to open path: " << cpp_strerror(r) << dendl;
57     return;
58   }
59
60   struct dirent de;
61   while((r = ceph_readdir_r(cmount, dr, &de)) != 0) {
62     if (r < 0) {
63       derr << "Error reading path " << path << ": " << cpp_strerror(r)
64            << dendl;
65       ceph_closedir(cmount, dr); // best effort, ignore r
66       return;
67     }
68
69     if (std::string(de.d_name) == "." || std::string(de.d_name) == "..") {
70       continue;
71     }
72
73     struct ceph_statx stx;
74     std::string de_path = (path + std::string("/") + de.d_name);
75     r = ceph_statx(cmount, de_path.c_str(), &stx,
76                     CEPH_STATX_INO|CEPH_STATX_SIZE, 0);
77     if (r != 0) {
78       derr << "Failed to stat path " << de_path << ": "
79             << cpp_strerror(r) << dendl;
80       // Don't hold up the whole process for one bad inode
81       continue;
82     }
83
84     if (S_ISREG(stx.stx_mode)) {
85       hit_file(de_path, stx);
86     } else if (S_ISDIR(stx.stx_mode)) {
87       hit_dir(de_path);
88     } else {
89       dout(20) << "Skipping non reg/dir file: " << de_path << dendl;
90     }
91   }
92
93   r = ceph_closedir(cmount, dr);
94   if (r != 0) {
95     derr << "Error closing path " << path << ": " << cpp_strerror(r) << dendl;
96     return;
97   }
98 }
99
100 void PgFiles::hit_file(std::string const &path, const struct ceph_statx &stx)
101 {
102   assert(S_ISREG(stx.stx_mode));
103
104   dout(20) << "Hitting file '" << path << "'" << dendl;
105
106   int l_stripe_unit = 0;
107   int l_stripe_count = 0;
108   int l_object_size = 0;
109   int l_pool_id = 0;
110   int r = ceph_get_path_layout(cmount, path.c_str(), &l_stripe_unit,
111                                &l_stripe_count, &l_object_size,
112                                &l_pool_id);
113   if (r != 0) {
114     derr << "Error reading layout on " << path << ": " << cpp_strerror(r)
115          << dendl;
116     return;
117   }
118
119   struct file_layout_t layout;
120   layout.stripe_unit = l_stripe_unit;
121   layout.stripe_count = l_stripe_count;
122   layout.object_size = l_object_size;
123   layout.pool_id = l_pool_id;
124
125   // Avoid calculating PG if the layout targeted a completely different pool
126   if (pools.count(layout.pool_id) == 0) {
127     dout(20) << "Fast check missed: pool " << layout.pool_id << " not in "
128                 "target set" << dendl;
129     return;
130   }
131
132   auto num_objects = Striper::get_num_objects(layout, stx.stx_size);
133
134   for (uint64_t i = 0; i < num_objects; ++i) {
135     char buf[32];
136     snprintf(buf, sizeof(buf), "%llx.%08llx", (long long unsigned)stx.stx_ino,
137                                               (long long unsigned int)i);
138     dout(20) << "  object " << std::string(buf) << dendl;
139
140     pg_t target;
141     object_t oid;
142     object_locator_t loc;
143     loc.pool = layout.pool_id;
144     loc.key = std::string(buf);
145
146     unsigned pg_num_mask = 0;
147     unsigned pg_num = 0;
148
149     int r = 0;
150     objecter->with_osdmap([&r, oid, loc, &target, &pg_num_mask, &pg_num]
151                           (const OSDMap &osd_map) {
152       r = osd_map.object_locator_to_pg(oid, loc, target);
153       if (r == 0) {
154         auto pool = osd_map.get_pg_pool(loc.pool);
155         pg_num_mask = pool->get_pg_num_mask();
156         pg_num = pool->get_pg_num();
157       }
158     });
159     if (r != 0) {
160       // Can happen if layout pointed to pool not in osdmap, for example
161       continue;
162     }
163
164     target.m_seed = ceph_stable_mod(target.ps(), pg_num, pg_num_mask);
165
166     dout(20) << "  target " << target << dendl;
167
168     if (pgs.count(target)) {
169       std::cout << path << std::endl;
170       return;
171     }
172   }
173   
174 }
175
176 int PgFiles::scan_path(std::string const &path)
177 {
178   int r = ceph_mount(cmount, "/");
179   if (r != 0) {
180     derr << "Failed to mount: " << cpp_strerror(r) << dendl;
181     return r;
182   }
183
184   hit_dir(path);
185
186   r = ceph_unmount(cmount);
187   if (r != 0) {
188     derr << "Failed to unmount: " << cpp_strerror(r) << dendl;
189     return r;
190   }
191
192   return r;
193 }
194