Whamcloud - gitweb
LU-17662 osd-zfs: Support for ZFS 2.2.3
[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 static 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         CDEBUG(D_INODE,
203                "valid %llx, lsom init %d lsom size %llu size %llu lsom blocks %llu blocks %llu truncate %d\n",
204                la->la_valid, o->mot_lsom_inited, o->mot_lsom_size, la->la_size,
205                o->mot_lsom_blocks, la->la_blocks, truncate);
206         if (!(la->la_valid & (LA_SIZE | LA_LSIZE) &&
207               o->mot_lsom_size < la->la_size) &&
208             !(la->la_valid & (LA_BLOCKS | LA_LBLOCKS) &&
209               o->mot_lsom_blocks < la->la_blocks) && !truncate &&
210             o->mot_lsom_inited)
211                 RETURN(0);
212
213         tmp_ma = &info->mti_u.som.attr;
214         tmp_ma->ma_need = MA_INODE | MA_SOM;
215         tmp_ma->ma_valid = 0;
216
217         rc = mdt_attr_get_complex(info, o, tmp_ma);
218         if (rc)
219                 RETURN(rc);
220
221         /**
222          * If mti_big_lmm_used is set, it indicates that mti_big_lmm
223          * should contain valid LOV EA data, and can be used directly.
224          */
225         if (!info->mti_big_lmm_used) {
226                 rc = mdt_big_xattr_get(info, o, XATTR_NAME_LOV);
227                 if (rc < 0 && rc != -ENODATA)
228                         RETURN(rc);
229
230                 /* No LOV EA */
231                 if (rc == -ENODATA)
232                         RETURN(0);
233
234                 rc = 0;
235         }
236
237         /**
238          * Check if a Lazy Size-on-MDS update is needed. Skip the
239          * file with no LOV EA, unlink files or DoM-only file.
240          * MDS only updates LSOM of the file if the size or block
241          * size is being increased or the file is being truncated.
242          */
243         if (!mdt_lmm_dom_only(info->mti_big_lmm) &&
244             !(tmp_ma->ma_valid & MA_INODE && tmp_ma->ma_attr.la_nlink == 0)) {
245                 __u64 size;
246                 __u64 blocks;
247                 bool changed = false;
248                 struct md_som *som = &tmp_ma->ma_som;
249
250                 if (truncate) {
251                         size = la->la_size;
252                         if (size == 0) {
253                                 blocks = 0;
254                         } else if (!(tmp_ma->ma_valid & MA_SOM) ||
255                                     size < som->ms_size) {
256                                 /* We cannot rely to blocks after
257                                  * truncate especially for spare file,
258                                  * and the truncate operation is usually
259                                  * followed with a close, so just set blocks
260                                  * to 1 here, and the following close will
261                                  * update it accordingly.
262                                  */
263                                 blocks = 1;
264                         } else {
265                                 blocks = som->ms_blocks;
266                         }
267                 } else {
268                         if (!(tmp_ma->ma_valid & MA_SOM)) {
269                                 /* Only set initial SOM Xattr data when both
270                                  * size and blocks are valid.
271                                  */
272                                 if (la->la_valid & (LA_SIZE | LA_LSIZE) &&
273                                     la->la_valid & (LA_BLOCKS | LA_LBLOCKS)) {
274                                         changed = true;
275                                         size = la->la_size;
276                                         blocks = la->la_blocks;
277                                 }
278                         } else {
279                                 /* Double check whether it is already set
280                                  * to SOM_FL_STRICT in mdt_mfd_close.
281                                  * If file is in SOM_FL_STALE state, and
282                                  * the close indicates there is no data
283                                  * modified, skip to transimit to LAZY
284                                  * state.
285                                  */
286                                 if (som->ms_valid & SOM_FL_STRICT ||
287                                     (som->ms_valid & SOM_FL_STALE &&
288                                      !(ma->ma_attr_flags & MDS_DATA_MODIFIED)))
289                                         RETURN(rc);
290
291                                 size = som->ms_size;
292                                 blocks = som->ms_blocks;
293                                 if (la->la_valid & (LA_SIZE | LA_LSIZE) &&
294                                     la->la_size > som->ms_size) {
295                                         changed = true;
296                                         size = la->la_size;
297                                 }
298                                 if (la->la_valid & (LA_BLOCKS | LA_LBLOCKS) &&
299                                     la->la_blocks > som->ms_blocks) {
300                                         changed = true;
301                                         blocks = la->la_blocks;
302                                 }
303                         }
304                 }
305                 if (truncate || changed) {
306                         mutex_lock(&o->mot_som_mutex);
307                         if (size <= o->mot_lsom_size &&
308                             blocks <= o->mot_lsom_blocks && !truncate &&
309                             o->mot_lsom_inited) {
310                                 mutex_unlock(&o->mot_som_mutex);
311                                 RETURN(0);
312                         }
313                         if (!truncate && size < o->mot_lsom_size)
314                                 size = o->mot_lsom_size;
315                         if (!truncate && blocks < o->mot_lsom_blocks)
316                                 blocks = o->mot_lsom_blocks;
317                         rc = mdt_set_som(info, o, SOM_FL_LAZY, size, blocks);
318                         mutex_unlock(&o->mot_som_mutex);
319                 }
320         }
321
322         RETURN(rc);
323 }