Whamcloud - gitweb
LU-5519 lfsck: LFSCK code framework adjustment (2)
[fs/lustre-release.git] / lustre / lfsck / lfsck_striped_dir.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,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License version 2 for more details.  A copy is
14  * included in the COPYING file that accompanied this code.
15
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2014, Intel Corporation.
24  */
25 /*
26  * lustre/lfsck/lfsck_striped_dir.c
27  *
28  * Author: Fan, Yong <fan.yong@intel.com>
29  */
30
31 #define DEBUG_SUBSYSTEM S_LFSCK
32
33 #include <lustre/lustre_idl.h>
34 #include <lu_object.h>
35 #include <dt_object.h>
36 #include <md_object.h>
37 #include <lustre_fid.h>
38 #include <lustre_lib.h>
39 #include <lustre_net.h>
40 #include <lustre_lmv.h>
41 #include <lustre/lustre_user.h>
42
43 #include "lfsck_internal.h"
44
45 void lfsck_lmv_put(const struct lu_env *env, struct lfsck_lmv *llmv)
46 {
47         if (llmv != NULL && atomic_dec_and_test(&llmv->ll_ref)) {
48                 if (llmv->ll_lslr != NULL)
49                         OBD_FREE_LARGE(llmv->ll_lslr,
50                                 sizeof(struct lfsck_slave_lmv_rec) *
51                                 llmv->ll_stripes_allocated);
52
53                 OBD_FREE_PTR(llmv);
54         }
55 }
56
57 static inline bool lfsck_is_valid_slave_lmv(struct lmv_mds_md_v1 *lmv)
58 {
59         return lmv->lmv_stripe_count >= 1 &&
60                lmv->lmv_stripe_count <= LFSCK_LMV_MAX_STRIPES &&
61                lmv->lmv_stripe_count > lmv->lmv_master_mdt_index &&
62                lmv_is_known_hash_type(lmv->lmv_hash_type);
63 }
64
65 int lfsck_read_stripe_lmv(const struct lu_env *env, struct dt_object *obj,
66                           struct lmv_mds_md_v1 *lmv)
67 {
68         struct dt_object *bottom;
69         int               rc;
70
71         /* Currently, we only store the LMV header on disk. It is the LOD's
72          * duty to iterate the master MDT-object's directory to compose the
73          * integrated LMV EA. But here, we only want to load the LMV header,
74          * so we need to bypass LOD to avoid unnecessary iteration in LOD. */
75         bottom = lu2dt(container_of0(obj->do_lu.lo_header->loh_layers.prev,
76                                      struct lu_object, lo_linkage));
77         if (unlikely(bottom == NULL))
78                 return -ENOENT;
79
80         dt_read_lock(env, bottom, 0);
81         rc = dt_xattr_get(env, bottom, lfsck_buf_get(env, lmv, sizeof(*lmv)),
82                           XATTR_NAME_LMV, BYPASS_CAPA);
83         dt_read_unlock(env, bottom);
84         if (rc != sizeof(*lmv))
85                 return rc > 0 ? -EINVAL : rc;
86
87         lfsck_lmv_header_le_to_cpu(lmv, lmv);
88         if ((lmv->lmv_magic == LMV_MAGIC &&
89              !(lmv->lmv_hash_type & LMV_HASH_FLAG_MIGRATION)) ||
90             (lmv->lmv_magic == LMV_MAGIC_STRIPE &&
91              !(lmv->lmv_hash_type & LMV_HASH_FLAG_DEAD)))
92                 return 0;
93
94         return -ENODATA;
95 }
96
97 /**
98  * Parse the shard's index from the given shard name.
99  *
100  * The valid shard name/type should be:
101  * 1) The type must be S_IFDIR
102  * 2) The name should be $FID:$index
103  * 3) the index should within valid range.
104  *
105  * \param[in] env       pointer to the thread context
106  * \param[in] name      the shard name
107  * \param[in] namelen   the name length
108  * \param[in] type      the entry's type
109  * \param[in] fid       the entry's FID
110  *
111  * \retval              zero or positive number for the index from the name
112  * \retval              negative error number on failure
113  */
114 int lfsck_shard_name_to_index(const struct lu_env *env, const char *name,
115                               int namelen, __u16 type, const struct lu_fid *fid)
116 {
117         char    *name2  = lfsck_env_info(env)->lti_tmpbuf2;
118         int      len;
119         int      idx    = 0;
120
121         if (!S_ISDIR(type))
122                 return -ENOTDIR;
123
124         LASSERT(name != name2);
125
126         len = snprintf(name2, sizeof(lfsck_env_info(env)->lti_tmpbuf2),
127                        DFID":", PFID(fid));
128         if (namelen < len + 1 || memcmp(name, name2, len) != 0)
129                 return -EINVAL;
130
131         do {
132                 if (!isdigit(name[len]))
133                         return -EINVAL;
134
135                 idx = idx * 10 + name[len++] - '0';
136         } while (len < namelen);
137
138         if (idx >= LFSCK_LMV_MAX_STRIPES)
139                 return -EINVAL;
140
141         return idx;
142 }
143
144 bool lfsck_is_valid_slave_name_entry(const struct lu_env *env,
145                                      struct lfsck_lmv *llmv,
146                                      const char *name, int namelen)
147 {
148         struct lmv_mds_md_v1    *lmv;
149         int                      idx;
150
151         if (llmv == NULL || !llmv->ll_lmv_slave || !llmv->ll_lmv_verified)
152                 return true;
153
154         lmv = &llmv->ll_lmv;
155         idx = lmv_name_to_stripe_index(lmv->lmv_hash_type,
156                                        lmv->lmv_stripe_count,
157                                        name, namelen);
158         if (unlikely(idx != lmv->lmv_master_mdt_index))
159                 return false;
160
161         return true;
162 }
163
164 /**
165  * Check whether the given name is a valid entry under the @parent.
166  *
167  * If the @parent is a striped directory then the @child should one
168  * shard of the striped directory, its name should be $FID:$index.
169  *
170  * If the @parent is a shard of a striped directory, then the name hash
171  * should match the MDT, otherwise it is invalid.
172  *
173  * \param[in] env       pointer to the thread context
174  * \param[in] parent    the parent directory
175  * \param[in] child     the child object to be checked
176  * \param[in] cname     the name for the @child in the parent directory
177  *
178  * \retval              positive number for invalid name entry
179  * \retval              0 if the name is valid or uncertain
180  * \retval              negative error number on failure
181  */
182 int lfsck_namespace_check_name(const struct lu_env *env,
183                                struct dt_object *parent,
184                                struct dt_object *child,
185                                const struct lu_name *cname)
186 {
187         struct lmv_mds_md_v1    *lmv = &lfsck_env_info(env)->lti_lmv;
188         int                      idx;
189         int                      rc;
190
191         rc = lfsck_read_stripe_lmv(env, parent, lmv);
192         if (rc != 0)
193                 RETURN(rc == -ENODATA ? 0 : rc);
194
195         if (lmv->lmv_magic == LMV_MAGIC_STRIPE) {
196                 if (!lfsck_is_valid_slave_lmv(lmv))
197                         return 0;
198
199                 idx = lmv_name_to_stripe_index(lmv->lmv_hash_type,
200                                                lmv->lmv_stripe_count,
201                                                cname->ln_name,
202                                                cname->ln_namelen);
203                 if (unlikely(idx != lmv->lmv_master_mdt_index))
204                         return 1;
205         } else if (lfsck_shard_name_to_index(env, cname->ln_name,
206                         cname->ln_namelen, lfsck_object_type(child),
207                         lfsck_dto2fid(child)) < 0) {
208                 return 1;
209         }
210
211         return 0;
212 }
213
214 int lfsck_namespace_verify_stripe_slave(const struct lu_env *env,
215                                         struct lfsck_component *com,
216                                         struct dt_object *obj,
217                                         struct lfsck_lmv *llmv)
218 {
219         /* XXX: TBD */
220         return 0;
221 }