1*59bfda1fSAndroid Build Coastguard Worker /**
2*59bfda1fSAndroid Build Coastguard Worker * xattr.c
3*59bfda1fSAndroid Build Coastguard Worker *
4*59bfda1fSAndroid Build Coastguard Worker * Many parts of codes are copied from Linux kernel/fs/f2fs.
5*59bfda1fSAndroid Build Coastguard Worker *
6*59bfda1fSAndroid Build Coastguard Worker * Copyright (C) 2015 Huawei Ltd.
7*59bfda1fSAndroid Build Coastguard Worker * Witten by:
8*59bfda1fSAndroid Build Coastguard Worker * Hou Pengyang <[email protected]>
9*59bfda1fSAndroid Build Coastguard Worker * Liu Shuoran <[email protected]>
10*59bfda1fSAndroid Build Coastguard Worker * Jaegeuk Kim <[email protected]>
11*59bfda1fSAndroid Build Coastguard Worker *
12*59bfda1fSAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or modify
13*59bfda1fSAndroid Build Coastguard Worker * it under the terms of the GNU General Public License version 2 as
14*59bfda1fSAndroid Build Coastguard Worker * published by the Free Software Foundation.
15*59bfda1fSAndroid Build Coastguard Worker */
16*59bfda1fSAndroid Build Coastguard Worker #include "fsck.h"
17*59bfda1fSAndroid Build Coastguard Worker #include "node.h"
18*59bfda1fSAndroid Build Coastguard Worker #include "xattr.h"
19*59bfda1fSAndroid Build Coastguard Worker
read_all_xattrs(struct f2fs_sb_info * sbi,struct f2fs_node * inode,bool sanity_check)20*59bfda1fSAndroid Build Coastguard Worker void *read_all_xattrs(struct f2fs_sb_info *sbi, struct f2fs_node *inode,
21*59bfda1fSAndroid Build Coastguard Worker bool sanity_check)
22*59bfda1fSAndroid Build Coastguard Worker {
23*59bfda1fSAndroid Build Coastguard Worker struct f2fs_xattr_header *header;
24*59bfda1fSAndroid Build Coastguard Worker void *txattr_addr;
25*59bfda1fSAndroid Build Coastguard Worker u64 inline_size = inline_xattr_size(&inode->i);
26*59bfda1fSAndroid Build Coastguard Worker nid_t xnid = le32_to_cpu(inode->i.i_xattr_nid);
27*59bfda1fSAndroid Build Coastguard Worker
28*59bfda1fSAndroid Build Coastguard Worker if (c.func == FSCK && xnid && sanity_check) {
29*59bfda1fSAndroid Build Coastguard Worker if (fsck_sanity_check_nid(sbi, xnid, F2FS_FT_XATTR, TYPE_XATTR))
30*59bfda1fSAndroid Build Coastguard Worker return NULL;
31*59bfda1fSAndroid Build Coastguard Worker }
32*59bfda1fSAndroid Build Coastguard Worker
33*59bfda1fSAndroid Build Coastguard Worker txattr_addr = calloc(inline_size + F2FS_BLKSIZE, 1);
34*59bfda1fSAndroid Build Coastguard Worker ASSERT(txattr_addr);
35*59bfda1fSAndroid Build Coastguard Worker
36*59bfda1fSAndroid Build Coastguard Worker if (inline_size)
37*59bfda1fSAndroid Build Coastguard Worker memcpy(txattr_addr, inline_xattr_addr(&inode->i), inline_size);
38*59bfda1fSAndroid Build Coastguard Worker
39*59bfda1fSAndroid Build Coastguard Worker /* Read from xattr node block. */
40*59bfda1fSAndroid Build Coastguard Worker if (xnid) {
41*59bfda1fSAndroid Build Coastguard Worker struct node_info ni;
42*59bfda1fSAndroid Build Coastguard Worker int ret;
43*59bfda1fSAndroid Build Coastguard Worker
44*59bfda1fSAndroid Build Coastguard Worker get_node_info(sbi, xnid, &ni);
45*59bfda1fSAndroid Build Coastguard Worker ret = dev_read_block(txattr_addr + inline_size, ni.blk_addr);
46*59bfda1fSAndroid Build Coastguard Worker ASSERT(ret >= 0);
47*59bfda1fSAndroid Build Coastguard Worker memset(txattr_addr + inline_size + F2FS_BLKSIZE -
48*59bfda1fSAndroid Build Coastguard Worker sizeof(struct node_footer), 0,
49*59bfda1fSAndroid Build Coastguard Worker sizeof(struct node_footer));
50*59bfda1fSAndroid Build Coastguard Worker }
51*59bfda1fSAndroid Build Coastguard Worker
52*59bfda1fSAndroid Build Coastguard Worker header = XATTR_HDR(txattr_addr);
53*59bfda1fSAndroid Build Coastguard Worker
54*59bfda1fSAndroid Build Coastguard Worker /* Never been allocated xattrs */
55*59bfda1fSAndroid Build Coastguard Worker if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) {
56*59bfda1fSAndroid Build Coastguard Worker header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC);
57*59bfda1fSAndroid Build Coastguard Worker header->h_refcount = cpu_to_le32(1);
58*59bfda1fSAndroid Build Coastguard Worker }
59*59bfda1fSAndroid Build Coastguard Worker return txattr_addr;
60*59bfda1fSAndroid Build Coastguard Worker }
61*59bfda1fSAndroid Build Coastguard Worker
__find_xattr(void * base_addr,void * last_base_addr,int index,size_t len,const char * name)62*59bfda1fSAndroid Build Coastguard Worker static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
63*59bfda1fSAndroid Build Coastguard Worker void *last_base_addr, int index,
64*59bfda1fSAndroid Build Coastguard Worker size_t len, const char *name)
65*59bfda1fSAndroid Build Coastguard Worker {
66*59bfda1fSAndroid Build Coastguard Worker struct f2fs_xattr_entry *entry;
67*59bfda1fSAndroid Build Coastguard Worker
68*59bfda1fSAndroid Build Coastguard Worker list_for_each_xattr(entry, base_addr) {
69*59bfda1fSAndroid Build Coastguard Worker if ((void *)(entry) + sizeof(__u32) > last_base_addr ||
70*59bfda1fSAndroid Build Coastguard Worker (void *)XATTR_NEXT_ENTRY(entry) > last_base_addr) {
71*59bfda1fSAndroid Build Coastguard Worker MSG(0, "xattr entry crosses the end of xattr space\n");
72*59bfda1fSAndroid Build Coastguard Worker return NULL;
73*59bfda1fSAndroid Build Coastguard Worker }
74*59bfda1fSAndroid Build Coastguard Worker
75*59bfda1fSAndroid Build Coastguard Worker if (entry->e_name_index != index)
76*59bfda1fSAndroid Build Coastguard Worker continue;
77*59bfda1fSAndroid Build Coastguard Worker if (entry->e_name_len != len)
78*59bfda1fSAndroid Build Coastguard Worker continue;
79*59bfda1fSAndroid Build Coastguard Worker if (!memcmp(entry->e_name, name, len))
80*59bfda1fSAndroid Build Coastguard Worker break;
81*59bfda1fSAndroid Build Coastguard Worker }
82*59bfda1fSAndroid Build Coastguard Worker return entry;
83*59bfda1fSAndroid Build Coastguard Worker }
84*59bfda1fSAndroid Build Coastguard Worker
write_all_xattrs(struct f2fs_sb_info * sbi,struct f2fs_node * inode,__u32 hsize,void * txattr_addr)85*59bfda1fSAndroid Build Coastguard Worker void write_all_xattrs(struct f2fs_sb_info *sbi,
86*59bfda1fSAndroid Build Coastguard Worker struct f2fs_node *inode, __u32 hsize, void *txattr_addr)
87*59bfda1fSAndroid Build Coastguard Worker {
88*59bfda1fSAndroid Build Coastguard Worker void *xattr_addr;
89*59bfda1fSAndroid Build Coastguard Worker struct dnode_of_data dn;
90*59bfda1fSAndroid Build Coastguard Worker struct node_info ni;
91*59bfda1fSAndroid Build Coastguard Worker struct f2fs_node *xattr_node;
92*59bfda1fSAndroid Build Coastguard Worker nid_t new_nid = 0;
93*59bfda1fSAndroid Build Coastguard Worker block_t blkaddr;
94*59bfda1fSAndroid Build Coastguard Worker nid_t xnid = le32_to_cpu(inode->i.i_xattr_nid);
95*59bfda1fSAndroid Build Coastguard Worker u64 inline_size = inline_xattr_size(&inode->i);
96*59bfda1fSAndroid Build Coastguard Worker int ret;
97*59bfda1fSAndroid Build Coastguard Worker bool xattrblk_alloced = false;
98*59bfda1fSAndroid Build Coastguard Worker struct seg_entry *se;
99*59bfda1fSAndroid Build Coastguard Worker
100*59bfda1fSAndroid Build Coastguard Worker memcpy(inline_xattr_addr(&inode->i), txattr_addr, inline_size);
101*59bfda1fSAndroid Build Coastguard Worker
102*59bfda1fSAndroid Build Coastguard Worker if (hsize <= inline_size)
103*59bfda1fSAndroid Build Coastguard Worker return;
104*59bfda1fSAndroid Build Coastguard Worker
105*59bfda1fSAndroid Build Coastguard Worker if (!xnid) {
106*59bfda1fSAndroid Build Coastguard Worker f2fs_alloc_nid(sbi, &new_nid);
107*59bfda1fSAndroid Build Coastguard Worker
108*59bfda1fSAndroid Build Coastguard Worker set_new_dnode(&dn, inode, NULL, new_nid);
109*59bfda1fSAndroid Build Coastguard Worker /* NAT entry would be updated by new_node_page. */
110*59bfda1fSAndroid Build Coastguard Worker blkaddr = new_node_block(sbi, &dn, XATTR_NODE_OFFSET);
111*59bfda1fSAndroid Build Coastguard Worker ASSERT(dn.node_blk);
112*59bfda1fSAndroid Build Coastguard Worker xattr_node = dn.node_blk;
113*59bfda1fSAndroid Build Coastguard Worker inode->i.i_xattr_nid = cpu_to_le32(new_nid);
114*59bfda1fSAndroid Build Coastguard Worker xattrblk_alloced = true;
115*59bfda1fSAndroid Build Coastguard Worker } else {
116*59bfda1fSAndroid Build Coastguard Worker set_new_dnode(&dn, inode, NULL, xnid);
117*59bfda1fSAndroid Build Coastguard Worker get_node_info(sbi, xnid, &ni);
118*59bfda1fSAndroid Build Coastguard Worker blkaddr = ni.blk_addr;
119*59bfda1fSAndroid Build Coastguard Worker xattr_node = calloc(F2FS_BLKSIZE, 1);
120*59bfda1fSAndroid Build Coastguard Worker ASSERT(xattr_node);
121*59bfda1fSAndroid Build Coastguard Worker ret = dev_read_block(xattr_node, ni.blk_addr);
122*59bfda1fSAndroid Build Coastguard Worker if (ret < 0)
123*59bfda1fSAndroid Build Coastguard Worker goto free_xattr_node;
124*59bfda1fSAndroid Build Coastguard Worker }
125*59bfda1fSAndroid Build Coastguard Worker
126*59bfda1fSAndroid Build Coastguard Worker /* write to xattr node block */
127*59bfda1fSAndroid Build Coastguard Worker xattr_addr = (void *)xattr_node;
128*59bfda1fSAndroid Build Coastguard Worker memcpy(xattr_addr, txattr_addr + inline_size,
129*59bfda1fSAndroid Build Coastguard Worker F2FS_BLKSIZE - sizeof(struct node_footer));
130*59bfda1fSAndroid Build Coastguard Worker se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr));
131*59bfda1fSAndroid Build Coastguard Worker ret = xattrblk_alloced ? dev_write_block(xattr_node, blkaddr,
132*59bfda1fSAndroid Build Coastguard Worker f2fs_io_type_to_rw_hint(se->type)) :
133*59bfda1fSAndroid Build Coastguard Worker update_block(sbi, xattr_node, &blkaddr, NULL);
134*59bfda1fSAndroid Build Coastguard Worker
135*59bfda1fSAndroid Build Coastguard Worker free_xattr_node:
136*59bfda1fSAndroid Build Coastguard Worker free(xattr_node);
137*59bfda1fSAndroid Build Coastguard Worker ASSERT(ret >= 0);
138*59bfda1fSAndroid Build Coastguard Worker }
139*59bfda1fSAndroid Build Coastguard Worker
f2fs_setxattr(struct f2fs_sb_info * sbi,nid_t ino,int index,const char * name,const void * value,size_t size,int flags)140*59bfda1fSAndroid Build Coastguard Worker int f2fs_setxattr(struct f2fs_sb_info *sbi, nid_t ino, int index, const char *name,
141*59bfda1fSAndroid Build Coastguard Worker const void *value, size_t size, int flags)
142*59bfda1fSAndroid Build Coastguard Worker {
143*59bfda1fSAndroid Build Coastguard Worker struct f2fs_node *inode;
144*59bfda1fSAndroid Build Coastguard Worker void *base_addr;
145*59bfda1fSAndroid Build Coastguard Worker void *last_base_addr;
146*59bfda1fSAndroid Build Coastguard Worker struct f2fs_xattr_entry *here, *last;
147*59bfda1fSAndroid Build Coastguard Worker struct node_info ni;
148*59bfda1fSAndroid Build Coastguard Worker int error = 0;
149*59bfda1fSAndroid Build Coastguard Worker int len;
150*59bfda1fSAndroid Build Coastguard Worker int found, newsize;
151*59bfda1fSAndroid Build Coastguard Worker __u32 new_hsize;
152*59bfda1fSAndroid Build Coastguard Worker int ret;
153*59bfda1fSAndroid Build Coastguard Worker
154*59bfda1fSAndroid Build Coastguard Worker if (name == NULL)
155*59bfda1fSAndroid Build Coastguard Worker return -EINVAL;
156*59bfda1fSAndroid Build Coastguard Worker
157*59bfda1fSAndroid Build Coastguard Worker if (value == NULL)
158*59bfda1fSAndroid Build Coastguard Worker return -EINVAL;
159*59bfda1fSAndroid Build Coastguard Worker
160*59bfda1fSAndroid Build Coastguard Worker len = strlen(name);
161*59bfda1fSAndroid Build Coastguard Worker
162*59bfda1fSAndroid Build Coastguard Worker if (len > F2FS_NAME_LEN || size > MAX_VALUE_LEN)
163*59bfda1fSAndroid Build Coastguard Worker return -ERANGE;
164*59bfda1fSAndroid Build Coastguard Worker
165*59bfda1fSAndroid Build Coastguard Worker if (ino < 3)
166*59bfda1fSAndroid Build Coastguard Worker return -EINVAL;
167*59bfda1fSAndroid Build Coastguard Worker
168*59bfda1fSAndroid Build Coastguard Worker /* Now We just support selinux */
169*59bfda1fSAndroid Build Coastguard Worker ASSERT(index == F2FS_XATTR_INDEX_SECURITY);
170*59bfda1fSAndroid Build Coastguard Worker
171*59bfda1fSAndroid Build Coastguard Worker get_node_info(sbi, ino, &ni);
172*59bfda1fSAndroid Build Coastguard Worker inode = calloc(F2FS_BLKSIZE, 1);
173*59bfda1fSAndroid Build Coastguard Worker ASSERT(inode);
174*59bfda1fSAndroid Build Coastguard Worker ret = dev_read_block(inode, ni.blk_addr);
175*59bfda1fSAndroid Build Coastguard Worker ASSERT(ret >= 0);
176*59bfda1fSAndroid Build Coastguard Worker
177*59bfda1fSAndroid Build Coastguard Worker base_addr = read_all_xattrs(sbi, inode, true);
178*59bfda1fSAndroid Build Coastguard Worker ASSERT(base_addr);
179*59bfda1fSAndroid Build Coastguard Worker
180*59bfda1fSAndroid Build Coastguard Worker last_base_addr = (void *)base_addr + XATTR_SIZE(&inode->i);
181*59bfda1fSAndroid Build Coastguard Worker
182*59bfda1fSAndroid Build Coastguard Worker here = __find_xattr(base_addr, last_base_addr, index, len, name);
183*59bfda1fSAndroid Build Coastguard Worker if (!here) {
184*59bfda1fSAndroid Build Coastguard Worker MSG(0, "Need to run fsck due to corrupted xattr.\n");
185*59bfda1fSAndroid Build Coastguard Worker error = -EINVAL;
186*59bfda1fSAndroid Build Coastguard Worker goto exit;
187*59bfda1fSAndroid Build Coastguard Worker }
188*59bfda1fSAndroid Build Coastguard Worker
189*59bfda1fSAndroid Build Coastguard Worker found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
190*59bfda1fSAndroid Build Coastguard Worker
191*59bfda1fSAndroid Build Coastguard Worker if ((flags & XATTR_REPLACE) && !found) {
192*59bfda1fSAndroid Build Coastguard Worker error = -ENODATA;
193*59bfda1fSAndroid Build Coastguard Worker goto exit;
194*59bfda1fSAndroid Build Coastguard Worker } else if ((flags & XATTR_CREATE) && found) {
195*59bfda1fSAndroid Build Coastguard Worker error = -EEXIST;
196*59bfda1fSAndroid Build Coastguard Worker goto exit;
197*59bfda1fSAndroid Build Coastguard Worker }
198*59bfda1fSAndroid Build Coastguard Worker
199*59bfda1fSAndroid Build Coastguard Worker last = here;
200*59bfda1fSAndroid Build Coastguard Worker while (!IS_XATTR_LAST_ENTRY(last))
201*59bfda1fSAndroid Build Coastguard Worker last = XATTR_NEXT_ENTRY(last);
202*59bfda1fSAndroid Build Coastguard Worker
203*59bfda1fSAndroid Build Coastguard Worker newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size);
204*59bfda1fSAndroid Build Coastguard Worker
205*59bfda1fSAndroid Build Coastguard Worker /* 1. Check space */
206*59bfda1fSAndroid Build Coastguard Worker if (value) {
207*59bfda1fSAndroid Build Coastguard Worker int free;
208*59bfda1fSAndroid Build Coastguard Worker /*
209*59bfda1fSAndroid Build Coastguard Worker * If value is NULL, it is remove operation.
210*59bfda1fSAndroid Build Coastguard Worker * In case of update operation, we calculate free.
211*59bfda1fSAndroid Build Coastguard Worker */
212*59bfda1fSAndroid Build Coastguard Worker free = MIN_OFFSET - ((char *)last - (char *)base_addr);
213*59bfda1fSAndroid Build Coastguard Worker if (found)
214*59bfda1fSAndroid Build Coastguard Worker free = free + ENTRY_SIZE(here);
215*59bfda1fSAndroid Build Coastguard Worker if (free < newsize) {
216*59bfda1fSAndroid Build Coastguard Worker error = -ENOSPC;
217*59bfda1fSAndroid Build Coastguard Worker goto exit;
218*59bfda1fSAndroid Build Coastguard Worker }
219*59bfda1fSAndroid Build Coastguard Worker }
220*59bfda1fSAndroid Build Coastguard Worker
221*59bfda1fSAndroid Build Coastguard Worker /* 2. Remove old entry */
222*59bfda1fSAndroid Build Coastguard Worker if (found) {
223*59bfda1fSAndroid Build Coastguard Worker /*
224*59bfda1fSAndroid Build Coastguard Worker * If entry if sound, remove old entry.
225*59bfda1fSAndroid Build Coastguard Worker * If not found, remove operation is not needed
226*59bfda1fSAndroid Build Coastguard Worker */
227*59bfda1fSAndroid Build Coastguard Worker struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here);
228*59bfda1fSAndroid Build Coastguard Worker int oldsize = ENTRY_SIZE(here);
229*59bfda1fSAndroid Build Coastguard Worker
230*59bfda1fSAndroid Build Coastguard Worker memmove(here, next, (char *)last - (char *)next);
231*59bfda1fSAndroid Build Coastguard Worker last = (struct f2fs_xattr_entry *)((char *)last - oldsize);
232*59bfda1fSAndroid Build Coastguard Worker memset(last, 0, oldsize);
233*59bfda1fSAndroid Build Coastguard Worker
234*59bfda1fSAndroid Build Coastguard Worker }
235*59bfda1fSAndroid Build Coastguard Worker
236*59bfda1fSAndroid Build Coastguard Worker new_hsize = (char *)last - (char *)base_addr;
237*59bfda1fSAndroid Build Coastguard Worker
238*59bfda1fSAndroid Build Coastguard Worker /* 3. Write new entry */
239*59bfda1fSAndroid Build Coastguard Worker if (value) {
240*59bfda1fSAndroid Build Coastguard Worker char *pval;
241*59bfda1fSAndroid Build Coastguard Worker /*
242*59bfda1fSAndroid Build Coastguard Worker * Before we come here, old entry is removed.
243*59bfda1fSAndroid Build Coastguard Worker * We just write new entry.
244*59bfda1fSAndroid Build Coastguard Worker */
245*59bfda1fSAndroid Build Coastguard Worker memset(last, 0, newsize);
246*59bfda1fSAndroid Build Coastguard Worker last->e_name_index = index;
247*59bfda1fSAndroid Build Coastguard Worker last->e_name_len = len;
248*59bfda1fSAndroid Build Coastguard Worker memcpy(last->e_name, name, len);
249*59bfda1fSAndroid Build Coastguard Worker pval = last->e_name + len;
250*59bfda1fSAndroid Build Coastguard Worker memcpy(pval, value, size);
251*59bfda1fSAndroid Build Coastguard Worker last->e_value_size = cpu_to_le16(size);
252*59bfda1fSAndroid Build Coastguard Worker new_hsize += newsize;
253*59bfda1fSAndroid Build Coastguard Worker }
254*59bfda1fSAndroid Build Coastguard Worker
255*59bfda1fSAndroid Build Coastguard Worker write_all_xattrs(sbi, inode, new_hsize, base_addr);
256*59bfda1fSAndroid Build Coastguard Worker
257*59bfda1fSAndroid Build Coastguard Worker /* inode need update */
258*59bfda1fSAndroid Build Coastguard Worker ASSERT(update_inode(sbi, inode, &ni.blk_addr) >= 0);
259*59bfda1fSAndroid Build Coastguard Worker exit:
260*59bfda1fSAndroid Build Coastguard Worker free(inode);
261*59bfda1fSAndroid Build Coastguard Worker free(base_addr);
262*59bfda1fSAndroid Build Coastguard Worker return error;
263*59bfda1fSAndroid Build Coastguard Worker }
264*59bfda1fSAndroid Build Coastguard Worker
inode_set_selinux(struct f2fs_sb_info * sbi,u32 ino,const char * secon)265*59bfda1fSAndroid Build Coastguard Worker int inode_set_selinux(struct f2fs_sb_info *sbi, u32 ino, const char *secon)
266*59bfda1fSAndroid Build Coastguard Worker {
267*59bfda1fSAndroid Build Coastguard Worker if (!secon)
268*59bfda1fSAndroid Build Coastguard Worker return 0;
269*59bfda1fSAndroid Build Coastguard Worker
270*59bfda1fSAndroid Build Coastguard Worker return f2fs_setxattr(sbi, ino, F2FS_XATTR_INDEX_SECURITY,
271*59bfda1fSAndroid Build Coastguard Worker XATTR_SELINUX_SUFFIX, secon, strlen(secon), 1);
272*59bfda1fSAndroid Build Coastguard Worker }
273