Whamcloud - gitweb
LU-15593 mdt: Add option to disable use of SOM
[fs/lustre-release.git] / lustre / mdt / mdt_som.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) 2017, Intel Corporation.
24  */
25 /*
26  * lustre/mdt/mdt_som.c
27  *
28  * Size on MDS revival
29  *
30  * Author: Jinshan Xiong <jinshan.xiong@intel.com>
31  * Author: Yingjin Qian <qian@ddn.com>
32  */
33
34 #define DEBUG_SUBSYSTEM S_MDS
35
36 #include "mdt_internal.h"
37
38 /*
39  * Swab and extract SOM attributes from on-disk xattr.
40  *
41  * \param buf - is a buffer containing the on-disk LSOM extended attribute.
42  * \param rc  - is the SOM xattr stored in \a buf
43  * \param ms  - is the md_som structure where to extract SOM attributes.
44  */
45 int lustre_buf2som(void *buf, int rc, struct md_som *ms)
46 {
47         struct lustre_som_attrs *attrs = (struct lustre_som_attrs *)buf;
48         ENTRY;
49
50         if (rc == 0 || rc == -ENODATA)
51                 /* no LSOM attributes */
52                 RETURN(-ENODATA);
53
54         if (rc < 0)
55                 /* error hit while fetching xattr */
56                 RETURN(rc);
57
58         /* unpack LSOM attributes */
59         lustre_som_swab(attrs);
60
61         /* fill in-memory md_som structure */
62         ms->ms_valid = attrs->lsa_valid;
63         ms->ms_size = attrs->lsa_size;
64         ms->ms_blocks = attrs->lsa_blocks;
65
66         RETURN(0);
67 }
68
69 int mdt_get_som(struct mdt_thread_info *info, struct mdt_object *obj,
70                 struct md_attr *ma)
71 {
72         struct lu_buf *buf = &info->mti_buf;
73         struct lu_attr *attr = &ma->ma_attr;
74         int rc;
75
76         buf->lb_buf = info->mti_xattr_buf;
77         buf->lb_len = sizeof(info->mti_xattr_buf);
78         BUILD_BUG_ON(sizeof(struct lustre_som_attrs) >
79                      sizeof(info->mti_xattr_buf));
80         rc = mo_xattr_get(info->mti_env, mdt_object_child(obj), buf,
81                           XATTR_NAME_SOM);
82         rc = lustre_buf2som(info->mti_xattr_buf, rc, &ma->ma_som);
83         if (rc == 0) {
84                 struct md_som *som = &ma->ma_som;
85
86                 ma->ma_valid |= MA_SOM;
87
88                 CDEBUG(D_INODE, DFID": Reading som attrs: "
89                        "valid: %x, size: %lld, blocks: %lld\n",
90                        PFID(mdt_object_fid(obj)), som->ms_valid,
91                        som->ms_size, som->ms_blocks);
92
93                 if (som->ms_valid & SOM_FL_STRICT) {
94                         attr->la_valid |= LA_SIZE | LA_BLOCKS;
95
96                         /*
97                          * Size on MDS is valid and could be returned
98                          * to client.
99                          */
100                         attr->la_size = som->ms_size;
101                         attr->la_blocks = som->ms_blocks;
102                         info->mti_som_strict = 1;
103                 } else if (!obj->mot_lsom_inited &&
104                            (som->ms_valid & SOM_FL_LAZY) &&
105                            !mutex_is_locked(&obj->mot_som_mutex)) {
106                         mutex_lock(&obj->mot_som_mutex);
107                         obj->mot_lsom_size = som->ms_size;
108                         obj->mot_lsom_blocks = som->ms_blocks;
109                         obj->mot_lsom_inited = true;
110                         mutex_unlock(&obj->mot_som_mutex);
111                 }
112         } else if (rc == -ENODATA) {
113                 rc = 0;
114         }
115
116         return rc;
117 }
118
119 /**
120  * Update SOM on-disk attributes.
121  */
122 int mdt_set_som(struct mdt_thread_info *info, struct mdt_object *obj,
123                 enum lustre_som_flags flag, __u64 size, __u64 blocks)
124 {
125         struct md_object *next = mdt_object_child(obj);
126         struct lu_buf *buf = &info->mti_buf;
127         struct lustre_som_attrs *som;
128         int rc;
129
130         ENTRY;
131
132         CDEBUG(D_INODE,
133                DFID": Set SOM attrs S/B/F: %lld/%lld/%x.\n",
134                PFID(mdt_object_fid(obj)), size, blocks, flag);
135
136         som = (struct lustre_som_attrs *)info->mti_xattr_buf;
137         BUILD_BUG_ON(sizeof(info->mti_xattr_buf) < sizeof(*som));
138
139         som->lsa_valid = flag;
140         som->lsa_size = size;
141         som->lsa_blocks = blocks;
142         memset(&som->lsa_reserved, 0, sizeof(som->lsa_reserved));
143         lustre_som_swab(som);
144
145         /* update SOM attributes */
146         buf->lb_buf = som;
147         buf->lb_len = sizeof(*som);
148         rc = mo_xattr_set(info->mti_env, next, buf, XATTR_NAME_SOM, 0);
149         if (!rc && flag == SOM_FL_LAZY) {
150                 obj->mot_lsom_size = size;
151                 obj->mot_lsom_blocks = blocks;
152                 obj->mot_lsom_inited = true;
153         }
154         RETURN(rc);
155 }
156
157 /**
158  * SOM state transition from STRICT to STALE,
159  */
160 int mdt_lsom_downgrade(struct mdt_thread_info *info, struct mdt_object *o)
161 {
162         struct md_attr *tmp_ma;
163         int rc;
164
165         ENTRY;
166
167         mutex_lock(&o->mot_som_mutex);
168         tmp_ma = &info->mti_u.som.attr;
169         tmp_ma->ma_need = MA_SOM;
170         tmp_ma->ma_valid = 0;
171
172         rc = mdt_get_som(info, o, tmp_ma);
173         if (rc < 0)
174                 GOTO(out_lock, rc);
175
176         if (tmp_ma->ma_valid & MA_SOM) {
177                 struct md_som *som = &tmp_ma->ma_som;
178
179                 info->mti_som_strict = 0;
180                 /* The size and blocks info should be still correct. */
181                 if (som->ms_valid & SOM_FL_STRICT)
182                         rc = mdt_set_som(info, o, SOM_FL_STALE,
183                                          som->ms_size, som->ms_blocks);
184         }
185 out_lock:
186         mutex_unlock(&o->mot_som_mutex);
187         RETURN(rc);
188 }
189
190 int mdt_lsom_update(struct mdt_thread_info *info,
191                     struct mdt_object *o, bool truncate)
192 {
193         struct md_attr *ma, *tmp_ma;
194         struct lu_attr *la;
195         int rc = 0;
196
197         ENTRY;
198
199         ma = &info->mti_attr;
200         la = &ma->ma_attr;
201
202         if (!(la->la_valid & (LA_SIZE | LA_LSIZE) &&
203               o->mot_lsom_size < la->la_size) &&
204             !(la->la_valid & (LA_BLOCKS | LA_LBLOCKS) &&
205               o->mot_lsom_blocks < la->la_blocks) && !truncate &&
206             o->mot_lsom_inited)
207                 RETURN(0);
208
209         tmp_ma = &info->mti_u.som.attr;
210         tmp_ma->ma_need = MA_INODE | MA_SOM;
211         tmp_ma->ma_valid = 0;
212
213         rc = mdt_attr_get_complex(info, o, tmp_ma);
214         if (rc)
215                 RETURN(rc);
216
217         /**
218          * If mti_big_lmm_used is set, it indicates that mti_big_lmm
219          * should contain valid LOV EA data, and can be used directly.
220          */
221         if (!info->mti_big_lmm_used) {
222                 rc = mdt_big_xattr_get(info, o, XATTR_NAME_LOV);
223                 if (rc < 0 && rc != -ENODATA)
224                         RETURN(rc);
225
226                 /* No LOV EA */
227                 if (rc == -ENODATA)
228                         RETURN(0);
229
230                 rc = 0;
231         }
232
233         /**
234          * Check if a Lazy Size-on-MDS update is needed. Skip the
235          * file with no LOV EA, unlink files or DoM-only file.
236          * MDS only updates LSOM of the file if the size or block
237          * size is being increased or the file is being truncated.
238          */
239         if (!mdt_lmm_dom_only(info->mti_big_lmm) &&
240             !(tmp_ma->ma_valid & MA_INODE && tmp_ma->ma_attr.la_nlink == 0)) {
241                 __u64 size;
242                 __u64 blocks;
243                 bool changed = false;
244                 struct md_som *som = &tmp_ma->ma_som;
245
246                 if (truncate) {
247                         size = la->la_size;
248                         if (size == 0) {
249                                 blocks = 0;
250                         } else if (!(tmp_ma->ma_valid & MA_SOM) ||
251                                     size < som->ms_size) {
252                                 /* We cannot rely to blocks after
253                                  * truncate especially for spare file,
254                                  * and the truncate operation is usually
255                                  * followed with a close, so just set blocks
256                                  * to 1 here, and the following close will
257                                  * update it accordingly.
258                                  */
259                                 blocks = 1;
260                         } else {
261                                 blocks = som->ms_blocks;
262                         }
263                 } else {
264                         if (!(tmp_ma->ma_valid & MA_SOM)) {
265                                 /* Only set initial SOM Xattr data when both
266                                  * size and blocks are valid.
267                                  */
268                                 if (la->la_valid & (LA_SIZE | LA_LSIZE) &&
269                                     la->la_valid & (LA_BLOCKS | LA_LBLOCKS)) {
270                                         changed = true;
271                                         size = la->la_size;
272                                         blocks = la->la_blocks;
273                                 }
274                         } else {
275                                 /* Double check whether it is already set
276                                  * to SOM_FL_STRICT in mdt_mfd_close.
277                                  * If file is in SOM_FL_STALE state, and
278                                  * the close indicates there is no data
279                                  * modified, skip to transimit to LAZY
280                                  * state.
281                                  */
282                                 if (som->ms_valid & SOM_FL_STRICT ||
283                                     (som->ms_valid & SOM_FL_STALE &&
284                                      !(ma->ma_attr_flags & MDS_DATA_MODIFIED)))
285                                         RETURN(rc);
286
287                                 size = som->ms_size;
288                                 blocks = som->ms_blocks;
289                                 if (la->la_valid & (LA_SIZE | LA_LSIZE) &&
290                                     la->la_size > som->ms_size) {
291                                         changed = true;
292                                         size = la->la_size;
293                                 }
294                                 if (la->la_valid & (LA_BLOCKS | LA_LBLOCKS) &&
295                                     la->la_blocks > som->ms_blocks) {
296                                         changed = true;
297                                         blocks = la->la_blocks;
298                                 }
299                         }
300                 }
301                 if (truncate || changed) {
302                         mutex_lock(&o->mot_som_mutex);
303                         if (size <= o->mot_lsom_size &&
304                             blocks <= o->mot_lsom_blocks && !truncate &&
305                             o->mot_lsom_inited) {
306                                 mutex_unlock(&o->mot_som_mutex);
307                                 RETURN(0);
308                         }
309                         if (!truncate && size < o->mot_lsom_size)
310                                 size = o->mot_lsom_size;
311                         if (!truncate && blocks < o->mot_lsom_blocks)
312                                 blocks = o->mot_lsom_blocks;
313                         rc = mdt_set_som(info, o, SOM_FL_LAZY, size, blocks);
314                         mutex_unlock(&o->mot_som_mutex);
315                 }
316         }
317
318         RETURN(rc);
319 }