]> git.karo-electronics.de Git - karo-tx-linux.git/blob - fs/ext4/inline.c
ext4: add the basic function for inline data support
[karo-tx-linux.git] / fs / ext4 / inline.c
1 /*
2  * Copyright (c) 2012 Taobao.
3  * Written by Tao Ma <boyu.mt@taobao.com>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2.1 of the GNU Lesser General Public License
7  * as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14 #include "ext4_jbd2.h"
15 #include "ext4.h"
16 #include "xattr.h"
17
18 #define EXT4_XATTR_SYSTEM_DATA  "data"
19 #define EXT4_MIN_INLINE_DATA_SIZE       ((sizeof(__le32) * EXT4_N_BLOCKS))
20
21 int ext4_get_inline_size(struct inode *inode)
22 {
23         if (EXT4_I(inode)->i_inline_off)
24                 return EXT4_I(inode)->i_inline_size;
25
26         return 0;
27 }
28
29 static int get_max_inline_xattr_value_size(struct inode *inode,
30                                            struct ext4_iloc *iloc)
31 {
32         struct ext4_xattr_ibody_header *header;
33         struct ext4_xattr_entry *entry;
34         struct ext4_inode *raw_inode;
35         int free, min_offs;
36
37         min_offs = EXT4_SB(inode->i_sb)->s_inode_size -
38                         EXT4_GOOD_OLD_INODE_SIZE -
39                         EXT4_I(inode)->i_extra_isize -
40                         sizeof(struct ext4_xattr_ibody_header);
41
42         /*
43          * We need to subtract another sizeof(__u32) since an in-inode xattr
44          * needs an empty 4 bytes to indicate the gap between the xattr entry
45          * and the name/value pair.
46          */
47         if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR))
48                 return EXT4_XATTR_SIZE(min_offs -
49                         EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA)) -
50                         EXT4_XATTR_ROUND - sizeof(__u32));
51
52         raw_inode = ext4_raw_inode(iloc);
53         header = IHDR(inode, raw_inode);
54         entry = IFIRST(header);
55
56         /* Compute min_offs. */
57         for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
58                 if (!entry->e_value_block && entry->e_value_size) {
59                         size_t offs = le16_to_cpu(entry->e_value_offs);
60                         if (offs < min_offs)
61                                 min_offs = offs;
62                 }
63         }
64         free = min_offs -
65                 ((void *)entry - (void *)IFIRST(header)) - sizeof(__u32);
66
67         if (EXT4_I(inode)->i_inline_off) {
68                 entry = (struct ext4_xattr_entry *)
69                         ((void *)raw_inode + EXT4_I(inode)->i_inline_off);
70
71                 free += le32_to_cpu(entry->e_value_size);
72                 goto out;
73         }
74
75         free -= EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA));
76
77         if (free > EXT4_XATTR_ROUND)
78                 free = EXT4_XATTR_SIZE(free - EXT4_XATTR_ROUND);
79         else
80                 free = 0;
81
82 out:
83         return free;
84 }
85
86 /*
87  * Get the maximum size we now can store in an inode.
88  * If we can't find the space for a xattr entry, don't use the space
89  * of the extents since we have no space to indicate the inline data.
90  */
91 int ext4_get_max_inline_size(struct inode *inode)
92 {
93         int error, max_inline_size;
94         struct ext4_iloc iloc;
95
96         if (EXT4_I(inode)->i_extra_isize == 0)
97                 return 0;
98
99         error = ext4_get_inode_loc(inode, &iloc);
100         if (error) {
101                 ext4_error_inode(inode, __func__, __LINE__, 0,
102                                  "can't get inode location %lu",
103                                  inode->i_ino);
104                 return 0;
105         }
106
107         down_read(&EXT4_I(inode)->xattr_sem);
108         max_inline_size = get_max_inline_xattr_value_size(inode, &iloc);
109         up_read(&EXT4_I(inode)->xattr_sem);
110
111         brelse(iloc.bh);
112
113         if (!max_inline_size)
114                 return 0;
115
116         return max_inline_size + EXT4_MIN_INLINE_DATA_SIZE;
117 }
118
119 int ext4_has_inline_data(struct inode *inode)
120 {
121         return ext4_test_inode_flag(inode, EXT4_INODE_INLINE_DATA) &&
122                EXT4_I(inode)->i_inline_off;
123 }
124
125 /*
126  * this function does not take xattr_sem, which is OK because it is
127  * currently only used in a code path coming form ext4_iget, before
128  * the new inode has been unlocked
129  */
130 int ext4_find_inline_data_nolock(struct inode *inode)
131 {
132         struct ext4_xattr_ibody_find is = {
133                 .s = { .not_found = -ENODATA, },
134         };
135         struct ext4_xattr_info i = {
136                 .name_index = EXT4_XATTR_INDEX_SYSTEM,
137                 .name = EXT4_XATTR_SYSTEM_DATA,
138         };
139         int error;
140
141         if (EXT4_I(inode)->i_extra_isize == 0)
142                 return 0;
143
144         error = ext4_get_inode_loc(inode, &is.iloc);
145         if (error)
146                 return error;
147
148         error = ext4_xattr_ibody_find(inode, &i, &is);
149         if (error)
150                 goto out;
151
152         if (!is.s.not_found) {
153                 EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here -
154                                         (void *)ext4_raw_inode(&is.iloc));
155                 EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE +
156                                 le32_to_cpu(is.s.here->e_value_size);
157                 ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
158         }
159 out:
160         brelse(is.iloc.bh);
161         return error;
162 }
163
164 static int ext4_read_inline_data(struct inode *inode, void *buffer,
165                                  unsigned int len,
166                                  struct ext4_iloc *iloc)
167 {
168         struct ext4_xattr_entry *entry;
169         struct ext4_xattr_ibody_header *header;
170         int cp_len = 0;
171         struct ext4_inode *raw_inode;
172
173         if (!len)
174                 return 0;
175
176         BUG_ON(len > EXT4_I(inode)->i_inline_size);
177
178         cp_len = len < EXT4_MIN_INLINE_DATA_SIZE ?
179                         len : EXT4_MIN_INLINE_DATA_SIZE;
180
181         raw_inode = ext4_raw_inode(iloc);
182         memcpy(buffer, (void *)(raw_inode->i_block), cp_len);
183
184         len -= cp_len;
185         buffer += cp_len;
186
187         if (!len)
188                 goto out;
189
190         header = IHDR(inode, raw_inode);
191         entry = (struct ext4_xattr_entry *)((void *)raw_inode +
192                                             EXT4_I(inode)->i_inline_off);
193         len = min_t(unsigned int, len,
194                     (unsigned int)le32_to_cpu(entry->e_value_size));
195
196         memcpy(buffer,
197                (void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs), len);
198         cp_len += len;
199
200 out:
201         return cp_len;
202 }
203
204 /*
205  * write the buffer to the inline inode.
206  * If 'create' is set, we don't need to do the extra copy in the xattr
207  * value since it is already handled by ext4_xattr_ibody_set. That saves
208  * us one memcpy.
209  */
210 void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc,
211                             void *buffer, loff_t pos, unsigned int len)
212 {
213         struct ext4_xattr_entry *entry;
214         struct ext4_xattr_ibody_header *header;
215         struct ext4_inode *raw_inode;
216         int cp_len = 0;
217
218         BUG_ON(!EXT4_I(inode)->i_inline_off);
219         BUG_ON(pos + len > EXT4_I(inode)->i_inline_size);
220
221         raw_inode = ext4_raw_inode(iloc);
222         buffer += pos;
223
224         if (pos < EXT4_MIN_INLINE_DATA_SIZE) {
225                 cp_len = pos + len > EXT4_MIN_INLINE_DATA_SIZE ?
226                          EXT4_MIN_INLINE_DATA_SIZE - pos : len;
227                 memcpy((void *)raw_inode->i_block + pos, buffer, cp_len);
228
229                 len -= cp_len;
230                 buffer += cp_len;
231                 pos += cp_len;
232         }
233
234         if (!len)
235                 return;
236
237         pos -= EXT4_MIN_INLINE_DATA_SIZE;
238         header = IHDR(inode, raw_inode);
239         entry = (struct ext4_xattr_entry *)((void *)raw_inode +
240                                             EXT4_I(inode)->i_inline_off);
241
242         memcpy((void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs) + pos,
243                buffer, len);
244 }
245
246 static int ext4_create_inline_data(handle_t *handle,
247                                    struct inode *inode, unsigned len)
248 {
249         int error;
250         void *value = NULL;
251         struct ext4_xattr_ibody_find is = {
252                 .s = { .not_found = -ENODATA, },
253         };
254         struct ext4_xattr_info i = {
255                 .name_index = EXT4_XATTR_INDEX_SYSTEM,
256                 .name = EXT4_XATTR_SYSTEM_DATA,
257         };
258
259         error = ext4_get_inode_loc(inode, &is.iloc);
260         if (error)
261                 return error;
262
263         error = ext4_journal_get_write_access(handle, is.iloc.bh);
264         if (error)
265                 goto out;
266
267         if (len > EXT4_MIN_INLINE_DATA_SIZE) {
268                 value = (void *)empty_zero_page;
269                 len -= EXT4_MIN_INLINE_DATA_SIZE;
270         } else {
271                 value = "";
272                 len = 0;
273         }
274
275         /* Insert the the xttr entry. */
276         i.value = value;
277         i.value_len = len;
278
279         error = ext4_xattr_ibody_find(inode, &i, &is);
280         if (error)
281                 goto out;
282
283         BUG_ON(!is.s.not_found);
284
285         error = ext4_xattr_ibody_set(handle, inode, &i, &is);
286         if (error) {
287                 if (error == -ENOSPC)
288                         ext4_clear_inode_state(inode,
289                                                EXT4_STATE_MAY_INLINE_DATA);
290                 goto out;
291         }
292
293         memset((void *)ext4_raw_inode(&is.iloc)->i_block,
294                 0, EXT4_MIN_INLINE_DATA_SIZE);
295
296         EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here -
297                                       (void *)ext4_raw_inode(&is.iloc));
298         EXT4_I(inode)->i_inline_size = len + EXT4_MIN_INLINE_DATA_SIZE;
299         ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
300         ext4_set_inode_flag(inode, EXT4_INODE_INLINE_DATA);
301         get_bh(is.iloc.bh);
302         error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
303
304 out:
305         brelse(is.iloc.bh);
306         return error;
307 }
308
309 static int ext4_update_inline_data(handle_t *handle, struct inode *inode,
310                                    unsigned int len)
311 {
312         int error;
313         void *value = NULL;
314         struct ext4_xattr_ibody_find is = {
315                 .s = { .not_found = -ENODATA, },
316         };
317         struct ext4_xattr_info i = {
318                 .name_index = EXT4_XATTR_INDEX_SYSTEM,
319                 .name = EXT4_XATTR_SYSTEM_DATA,
320         };
321
322         /* If the old space is ok, write the data directly. */
323         if (len <= EXT4_I(inode)->i_inline_size)
324                 return 0;
325
326         error = ext4_get_inode_loc(inode, &is.iloc);
327         if (error)
328                 return error;
329
330         error = ext4_xattr_ibody_find(inode, &i, &is);
331         if (error)
332                 goto out;
333
334         BUG_ON(is.s.not_found);
335
336         len -= EXT4_MIN_INLINE_DATA_SIZE;
337         value = kzalloc(len, GFP_NOFS);
338         if (!value)
339                 goto out;
340
341         error = ext4_xattr_ibody_get(inode, i.name_index, i.name,
342                                      value, len);
343         if (error == -ENODATA)
344                 goto out;
345
346         error = ext4_journal_get_write_access(handle, is.iloc.bh);
347         if (error)
348                 goto out;
349
350         /* Update the xttr entry. */
351         i.value = value;
352         i.value_len = len;
353
354         error = ext4_xattr_ibody_set(handle, inode, &i, &is);
355         if (error)
356                 goto out;
357
358         EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here -
359                                       (void *)ext4_raw_inode(&is.iloc));
360         EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE +
361                                 le32_to_cpu(is.s.here->e_value_size);
362         ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
363         get_bh(is.iloc.bh);
364         error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
365
366 out:
367         kfree(value);
368         brelse(is.iloc.bh);
369         return error;
370 }
371
372 int ext4_prepare_inline_data(handle_t *handle, struct inode *inode,
373                              unsigned int len)
374 {
375         int ret, size;
376         struct ext4_inode_info *ei = EXT4_I(inode);
377
378         if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA))
379                 return -ENOSPC;
380
381         size = ext4_get_max_inline_size(inode);
382         if (size < len)
383                 return -ENOSPC;
384
385         down_write(&EXT4_I(inode)->xattr_sem);
386
387         if (ei->i_inline_off)
388                 ret = ext4_update_inline_data(handle, inode, len);
389         else
390                 ret = ext4_create_inline_data(handle, inode, len);
391
392         up_write(&EXT4_I(inode)->xattr_sem);
393
394         return ret;
395 }
396
397 static int ext4_destroy_inline_data_nolock(handle_t *handle,
398                                            struct inode *inode)
399 {
400         struct ext4_inode_info *ei = EXT4_I(inode);
401         struct ext4_xattr_ibody_find is = {
402                 .s = { .not_found = 0, },
403         };
404         struct ext4_xattr_info i = {
405                 .name_index = EXT4_XATTR_INDEX_SYSTEM,
406                 .name = EXT4_XATTR_SYSTEM_DATA,
407                 .value = NULL,
408                 .value_len = 0,
409         };
410         int error;
411
412         if (!ei->i_inline_off)
413                 return 0;
414
415         error = ext4_get_inode_loc(inode, &is.iloc);
416         if (error)
417                 return error;
418
419         error = ext4_xattr_ibody_find(inode, &i, &is);
420         if (error)
421                 goto out;
422
423         error = ext4_journal_get_write_access(handle, is.iloc.bh);
424         if (error)
425                 goto out;
426
427         error = ext4_xattr_ibody_set(handle, inode, &i, &is);
428         if (error)
429                 goto out;
430
431         memset((void *)ext4_raw_inode(&is.iloc)->i_block,
432                 0, EXT4_MIN_INLINE_DATA_SIZE);
433
434         if (EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb,
435                                       EXT4_FEATURE_INCOMPAT_EXTENTS)) {
436                 if (S_ISDIR(inode->i_mode) ||
437                     S_ISREG(inode->i_mode) || S_ISLNK(inode->i_mode)) {
438                         ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
439                         ext4_ext_tree_init(handle, inode);
440                 }
441         }
442         ext4_clear_inode_flag(inode, EXT4_INODE_INLINE_DATA);
443
444         get_bh(is.iloc.bh);
445         error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
446
447         EXT4_I(inode)->i_inline_off = 0;
448         EXT4_I(inode)->i_inline_size = 0;
449         ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
450 out:
451         brelse(is.iloc.bh);
452         if (error == -ENODATA)
453                 error = 0;
454         return error;
455 }
456
457 int ext4_destroy_inline_data(handle_t *handle, struct inode *inode)
458 {
459         int ret;
460
461         down_write(&EXT4_I(inode)->xattr_sem);
462         ret = ext4_destroy_inline_data_nolock(handle, inode);
463         up_write(&EXT4_I(inode)->xattr_sem);
464
465         return ret;
466 }