inline.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  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. #define EXT4_XATTR_SYSTEM_DATA "data"
  18. #define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__le32) * EXT4_N_BLOCKS))
  19. int ext4_get_inline_size(struct inode *inode)
  20. {
  21. if (EXT4_I(inode)->i_inline_off)
  22. return EXT4_I(inode)->i_inline_size;
  23. return 0;
  24. }
  25. static int get_max_inline_xattr_value_size(struct inode *inode,
  26. struct ext4_iloc *iloc)
  27. {
  28. struct ext4_xattr_ibody_header *header;
  29. struct ext4_xattr_entry *entry;
  30. struct ext4_inode *raw_inode;
  31. int free, min_offs;
  32. min_offs = EXT4_SB(inode->i_sb)->s_inode_size -
  33. EXT4_GOOD_OLD_INODE_SIZE -
  34. EXT4_I(inode)->i_extra_isize -
  35. sizeof(struct ext4_xattr_ibody_header);
  36. /*
  37. * We need to subtract another sizeof(__u32) since an in-inode xattr
  38. * needs an empty 4 bytes to indicate the gap between the xattr entry
  39. * and the name/value pair.
  40. */
  41. if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR))
  42. return EXT4_XATTR_SIZE(min_offs -
  43. EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA)) -
  44. EXT4_XATTR_ROUND - sizeof(__u32));
  45. raw_inode = ext4_raw_inode(iloc);
  46. header = IHDR(inode, raw_inode);
  47. entry = IFIRST(header);
  48. /* Compute min_offs. */
  49. for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
  50. if (!entry->e_value_block && entry->e_value_size) {
  51. size_t offs = le16_to_cpu(entry->e_value_offs);
  52. if (offs < min_offs)
  53. min_offs = offs;
  54. }
  55. }
  56. free = min_offs -
  57. ((void *)entry - (void *)IFIRST(header)) - sizeof(__u32);
  58. if (EXT4_I(inode)->i_inline_off) {
  59. entry = (struct ext4_xattr_entry *)
  60. ((void *)raw_inode + EXT4_I(inode)->i_inline_off);
  61. free += le32_to_cpu(entry->e_value_size);
  62. goto out;
  63. }
  64. free -= EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA));
  65. if (free > EXT4_XATTR_ROUND)
  66. free = EXT4_XATTR_SIZE(free - EXT4_XATTR_ROUND);
  67. else
  68. free = 0;
  69. out:
  70. return free;
  71. }
  72. /*
  73. * Get the maximum size we now can store in an inode.
  74. * If we can't find the space for a xattr entry, don't use the space
  75. * of the extents since we have no space to indicate the inline data.
  76. */
  77. int ext4_get_max_inline_size(struct inode *inode)
  78. {
  79. int error, max_inline_size;
  80. struct ext4_iloc iloc;
  81. if (EXT4_I(inode)->i_extra_isize == 0)
  82. return 0;
  83. error = ext4_get_inode_loc(inode, &iloc);
  84. if (error) {
  85. ext4_error_inode(inode, __func__, __LINE__, 0,
  86. "can't get inode location %lu",
  87. inode->i_ino);
  88. return 0;
  89. }
  90. down_read(&EXT4_I(inode)->xattr_sem);
  91. max_inline_size = get_max_inline_xattr_value_size(inode, &iloc);
  92. up_read(&EXT4_I(inode)->xattr_sem);
  93. brelse(iloc.bh);
  94. if (!max_inline_size)
  95. return 0;
  96. return max_inline_size + EXT4_MIN_INLINE_DATA_SIZE;
  97. }
  98. int ext4_has_inline_data(struct inode *inode)
  99. {
  100. return ext4_test_inode_flag(inode, EXT4_INODE_INLINE_DATA) &&
  101. EXT4_I(inode)->i_inline_off;
  102. }
  103. /*
  104. * this function does not take xattr_sem, which is OK because it is
  105. * currently only used in a code path coming form ext4_iget, before
  106. * the new inode has been unlocked
  107. */
  108. int ext4_find_inline_data_nolock(struct inode *inode)
  109. {
  110. struct ext4_xattr_ibody_find is = {
  111. .s = { .not_found = -ENODATA, },
  112. };
  113. struct ext4_xattr_info i = {
  114. .name_index = EXT4_XATTR_INDEX_SYSTEM,
  115. .name = EXT4_XATTR_SYSTEM_DATA,
  116. };
  117. int error;
  118. if (EXT4_I(inode)->i_extra_isize == 0)
  119. return 0;
  120. error = ext4_get_inode_loc(inode, &is.iloc);
  121. if (error)
  122. return error;
  123. error = ext4_xattr_ibody_find(inode, &i, &is);
  124. if (error)
  125. goto out;
  126. if (!is.s.not_found) {
  127. EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here -
  128. (void *)ext4_raw_inode(&is.iloc));
  129. EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE +
  130. le32_to_cpu(is.s.here->e_value_size);
  131. ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
  132. }
  133. out:
  134. brelse(is.iloc.bh);
  135. return error;
  136. }
  137. static int ext4_read_inline_data(struct inode *inode, void *buffer,
  138. unsigned int len,
  139. struct ext4_iloc *iloc)
  140. {
  141. struct ext4_xattr_entry *entry;
  142. struct ext4_xattr_ibody_header *header;
  143. int cp_len = 0;
  144. struct ext4_inode *raw_inode;
  145. if (!len)
  146. return 0;
  147. BUG_ON(len > EXT4_I(inode)->i_inline_size);
  148. cp_len = len < EXT4_MIN_INLINE_DATA_SIZE ?
  149. len : EXT4_MIN_INLINE_DATA_SIZE;
  150. raw_inode = ext4_raw_inode(iloc);
  151. memcpy(buffer, (void *)(raw_inode->i_block), cp_len);
  152. len -= cp_len;
  153. buffer += cp_len;
  154. if (!len)
  155. goto out;
  156. header = IHDR(inode, raw_inode);
  157. entry = (struct ext4_xattr_entry *)((void *)raw_inode +
  158. EXT4_I(inode)->i_inline_off);
  159. len = min_t(unsigned int, len,
  160. (unsigned int)le32_to_cpu(entry->e_value_size));
  161. memcpy(buffer,
  162. (void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs), len);
  163. cp_len += len;
  164. out:
  165. return cp_len;
  166. }
  167. /*
  168. * write the buffer to the inline inode.
  169. * If 'create' is set, we don't need to do the extra copy in the xattr
  170. * value since it is already handled by ext4_xattr_ibody_set. That saves
  171. * us one memcpy.
  172. */
  173. void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc,
  174. void *buffer, loff_t pos, unsigned int len)
  175. {
  176. struct ext4_xattr_entry *entry;
  177. struct ext4_xattr_ibody_header *header;
  178. struct ext4_inode *raw_inode;
  179. int cp_len = 0;
  180. BUG_ON(!EXT4_I(inode)->i_inline_off);
  181. BUG_ON(pos + len > EXT4_I(inode)->i_inline_size);
  182. raw_inode = ext4_raw_inode(iloc);
  183. buffer += pos;
  184. if (pos < EXT4_MIN_INLINE_DATA_SIZE) {
  185. cp_len = pos + len > EXT4_MIN_INLINE_DATA_SIZE ?
  186. EXT4_MIN_INLINE_DATA_SIZE - pos : len;
  187. memcpy((void *)raw_inode->i_block + pos, buffer, cp_len);
  188. len -= cp_len;
  189. buffer += cp_len;
  190. pos += cp_len;
  191. }
  192. if (!len)
  193. return;
  194. pos -= EXT4_MIN_INLINE_DATA_SIZE;
  195. header = IHDR(inode, raw_inode);
  196. entry = (struct ext4_xattr_entry *)((void *)raw_inode +
  197. EXT4_I(inode)->i_inline_off);
  198. memcpy((void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs) + pos,
  199. buffer, len);
  200. }
  201. static int ext4_create_inline_data(handle_t *handle,
  202. struct inode *inode, unsigned len)
  203. {
  204. int error;
  205. void *value = NULL;
  206. struct ext4_xattr_ibody_find is = {
  207. .s = { .not_found = -ENODATA, },
  208. };
  209. struct ext4_xattr_info i = {
  210. .name_index = EXT4_XATTR_INDEX_SYSTEM,
  211. .name = EXT4_XATTR_SYSTEM_DATA,
  212. };
  213. error = ext4_get_inode_loc(inode, &is.iloc);
  214. if (error)
  215. return error;
  216. error = ext4_journal_get_write_access(handle, is.iloc.bh);
  217. if (error)
  218. goto out;
  219. if (len > EXT4_MIN_INLINE_DATA_SIZE) {
  220. value = (void *)empty_zero_page;
  221. len -= EXT4_MIN_INLINE_DATA_SIZE;
  222. } else {
  223. value = "";
  224. len = 0;
  225. }
  226. /* Insert the the xttr entry. */
  227. i.value = value;
  228. i.value_len = len;
  229. error = ext4_xattr_ibody_find(inode, &i, &is);
  230. if (error)
  231. goto out;
  232. BUG_ON(!is.s.not_found);
  233. error = ext4_xattr_ibody_set(handle, inode, &i, &is);
  234. if (error) {
  235. if (error == -ENOSPC)
  236. ext4_clear_inode_state(inode,
  237. EXT4_STATE_MAY_INLINE_DATA);
  238. goto out;
  239. }
  240. memset((void *)ext4_raw_inode(&is.iloc)->i_block,
  241. 0, EXT4_MIN_INLINE_DATA_SIZE);
  242. EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here -
  243. (void *)ext4_raw_inode(&is.iloc));
  244. EXT4_I(inode)->i_inline_size = len + EXT4_MIN_INLINE_DATA_SIZE;
  245. ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
  246. ext4_set_inode_flag(inode, EXT4_INODE_INLINE_DATA);
  247. get_bh(is.iloc.bh);
  248. error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
  249. out:
  250. brelse(is.iloc.bh);
  251. return error;
  252. }
  253. static int ext4_update_inline_data(handle_t *handle, struct inode *inode,
  254. unsigned int len)
  255. {
  256. int error;
  257. void *value = NULL;
  258. struct ext4_xattr_ibody_find is = {
  259. .s = { .not_found = -ENODATA, },
  260. };
  261. struct ext4_xattr_info i = {
  262. .name_index = EXT4_XATTR_INDEX_SYSTEM,
  263. .name = EXT4_XATTR_SYSTEM_DATA,
  264. };
  265. /* If the old space is ok, write the data directly. */
  266. if (len <= EXT4_I(inode)->i_inline_size)
  267. return 0;
  268. error = ext4_get_inode_loc(inode, &is.iloc);
  269. if (error)
  270. return error;
  271. error = ext4_xattr_ibody_find(inode, &i, &is);
  272. if (error)
  273. goto out;
  274. BUG_ON(is.s.not_found);
  275. len -= EXT4_MIN_INLINE_DATA_SIZE;
  276. value = kzalloc(len, GFP_NOFS);
  277. if (!value)
  278. goto out;
  279. error = ext4_xattr_ibody_get(inode, i.name_index, i.name,
  280. value, len);
  281. if (error == -ENODATA)
  282. goto out;
  283. error = ext4_journal_get_write_access(handle, is.iloc.bh);
  284. if (error)
  285. goto out;
  286. /* Update the xttr entry. */
  287. i.value = value;
  288. i.value_len = len;
  289. error = ext4_xattr_ibody_set(handle, inode, &i, &is);
  290. if (error)
  291. goto out;
  292. EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here -
  293. (void *)ext4_raw_inode(&is.iloc));
  294. EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE +
  295. le32_to_cpu(is.s.here->e_value_size);
  296. ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
  297. get_bh(is.iloc.bh);
  298. error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
  299. out:
  300. kfree(value);
  301. brelse(is.iloc.bh);
  302. return error;
  303. }
  304. int ext4_prepare_inline_data(handle_t *handle, struct inode *inode,
  305. unsigned int len)
  306. {
  307. int ret, size;
  308. struct ext4_inode_info *ei = EXT4_I(inode);
  309. if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA))
  310. return -ENOSPC;
  311. size = ext4_get_max_inline_size(inode);
  312. if (size < len)
  313. return -ENOSPC;
  314. down_write(&EXT4_I(inode)->xattr_sem);
  315. if (ei->i_inline_off)
  316. ret = ext4_update_inline_data(handle, inode, len);
  317. else
  318. ret = ext4_create_inline_data(handle, inode, len);
  319. up_write(&EXT4_I(inode)->xattr_sem);
  320. return ret;
  321. }
  322. static int ext4_destroy_inline_data_nolock(handle_t *handle,
  323. struct inode *inode)
  324. {
  325. struct ext4_inode_info *ei = EXT4_I(inode);
  326. struct ext4_xattr_ibody_find is = {
  327. .s = { .not_found = 0, },
  328. };
  329. struct ext4_xattr_info i = {
  330. .name_index = EXT4_XATTR_INDEX_SYSTEM,
  331. .name = EXT4_XATTR_SYSTEM_DATA,
  332. .value = NULL,
  333. .value_len = 0,
  334. };
  335. int error;
  336. if (!ei->i_inline_off)
  337. return 0;
  338. error = ext4_get_inode_loc(inode, &is.iloc);
  339. if (error)
  340. return error;
  341. error = ext4_xattr_ibody_find(inode, &i, &is);
  342. if (error)
  343. goto out;
  344. error = ext4_journal_get_write_access(handle, is.iloc.bh);
  345. if (error)
  346. goto out;
  347. error = ext4_xattr_ibody_set(handle, inode, &i, &is);
  348. if (error)
  349. goto out;
  350. memset((void *)ext4_raw_inode(&is.iloc)->i_block,
  351. 0, EXT4_MIN_INLINE_DATA_SIZE);
  352. if (EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb,
  353. EXT4_FEATURE_INCOMPAT_EXTENTS)) {
  354. if (S_ISDIR(inode->i_mode) ||
  355. S_ISREG(inode->i_mode) || S_ISLNK(inode->i_mode)) {
  356. ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
  357. ext4_ext_tree_init(handle, inode);
  358. }
  359. }
  360. ext4_clear_inode_flag(inode, EXT4_INODE_INLINE_DATA);
  361. get_bh(is.iloc.bh);
  362. error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
  363. EXT4_I(inode)->i_inline_off = 0;
  364. EXT4_I(inode)->i_inline_size = 0;
  365. ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
  366. out:
  367. brelse(is.iloc.bh);
  368. if (error == -ENODATA)
  369. error = 0;
  370. return error;
  371. }
  372. int ext4_destroy_inline_data(handle_t *handle, struct inode *inode)
  373. {
  374. int ret;
  375. down_write(&EXT4_I(inode)->xattr_sem);
  376. ret = ext4_destroy_inline_data_nolock(handle, inode);
  377. up_write(&EXT4_I(inode)->xattr_sem);
  378. return ret;
  379. }