Commit | Line | Data |
---|---|---|
c14dd9d5 | 1 | // SPDX-License-Identifier: GPL-2.0 |
d7e09d03 PT |
2 | /* |
3 | * GPL HEADER START | |
4 | * | |
5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 only, | |
9 | * as published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License version 2 for more details (a copy is included | |
15 | * in the LICENSE file that accompanied this code). | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * version 2 along with this program; If not, see | |
6a5b99a4 | 19 | * http://www.gnu.org/licenses/gpl-2.0.html |
d7e09d03 | 20 | * |
d7e09d03 PT |
21 | * GPL HEADER END |
22 | */ | |
23 | /* | |
24 | * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. | |
25 | * Use is subject to license terms. | |
26 | * | |
1dc563a6 | 27 | * Copyright (c) 2011, 2015, Intel Corporation. |
d7e09d03 PT |
28 | */ |
29 | /* | |
30 | * This file is part of Lustre, http://www.lustre.org/ | |
31 | * Lustre is a trademark of Sun Microsystems, Inc. | |
32 | */ | |
33 | ||
34 | #include <linux/fs.h> | |
35 | #include <linux/sched.h> | |
36 | #include <linux/mm.h> | |
a49c8634 | 37 | #include <linux/xattr.h> |
d7e09d03 PT |
38 | #include <linux/selinux.h> |
39 | ||
40 | #define DEBUG_SUBSYSTEM S_LLITE | |
41 | ||
b2e475b1 JS |
42 | #include <obd_support.h> |
43 | #include <lustre_dlm.h> | |
d7e09d03 PT |
44 | |
45 | #include "llite_internal.h" | |
46 | ||
51cfb8c4 | 47 | const struct xattr_handler *get_xattr_type(const char *name) |
d7e09d03 | 48 | { |
51cfb8c4 | 49 | int i = 0; |
d7e09d03 | 50 | |
51cfb8c4 SB |
51 | while (ll_xattr_handlers[i]) { |
52 | size_t len = strlen(ll_xattr_handlers[i]->prefix); | |
d7e09d03 | 53 | |
51cfb8c4 SB |
54 | if (!strncmp(ll_xattr_handlers[i]->prefix, name, len)) |
55 | return ll_xattr_handlers[i]; | |
56 | i++; | |
57 | } | |
58 | return NULL; | |
d7e09d03 PT |
59 | } |
60 | ||
51cfb8c4 SB |
61 | static int xattr_type_filter(struct ll_sb_info *sbi, |
62 | const struct xattr_handler *handler) | |
d7e09d03 | 63 | { |
51cfb8c4 SB |
64 | /* No handler means XATTR_OTHER_T */ |
65 | if (!handler) | |
66 | return -EOPNOTSUPP; | |
67 | ||
68 | if ((handler->flags == XATTR_ACL_ACCESS_T || | |
69 | handler->flags == XATTR_ACL_DEFAULT_T) && | |
d7e09d03 PT |
70 | !(sbi->ll_flags & LL_SBI_ACL)) |
71 | return -EOPNOTSUPP; | |
72 | ||
51cfb8c4 SB |
73 | if (handler->flags == XATTR_USER_T && |
74 | !(sbi->ll_flags & LL_SBI_USER_XATTR)) | |
d7e09d03 | 75 | return -EOPNOTSUPP; |
51cfb8c4 SB |
76 | |
77 | if (handler->flags == XATTR_TRUSTED_T && | |
78 | !capable(CFS_CAP_SYS_ADMIN)) | |
d7e09d03 | 79 | return -EPERM; |
d7e09d03 PT |
80 | |
81 | return 0; | |
82 | } | |
83 | ||
2c563880 JS |
84 | static int |
85 | ll_xattr_set_common(const struct xattr_handler *handler, | |
86 | struct dentry *dentry, struct inode *inode, | |
87 | const char *name, const void *value, size_t size, | |
88 | int flags) | |
d7e09d03 | 89 | { |
2c563880 | 90 | char fullname[strlen(handler->prefix) + strlen(name) + 1]; |
d7e09d03 | 91 | struct ll_sb_info *sbi = ll_i2sbi(inode); |
7fc1f831 | 92 | struct ptlrpc_request *req = NULL; |
d7e09d03 | 93 | const char *pv = value; |
2c563880 JS |
94 | __u64 valid; |
95 | int rc; | |
d7e09d03 | 96 | |
2c563880 JS |
97 | if (flags == XATTR_REPLACE) { |
98 | ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_REMOVEXATTR, 1); | |
99 | valid = OBD_MD_FLXATTRRM; | |
100 | } else { | |
101 | ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_SETXATTR, 1); | |
102 | valid = OBD_MD_FLXATTR; | |
103 | } | |
104 | ||
51cfb8c4 | 105 | rc = xattr_type_filter(sbi, handler); |
d7e09d03 | 106 | if (rc) |
0a3bdb00 | 107 | return rc; |
d7e09d03 | 108 | |
2c563880 JS |
109 | if ((handler->flags == XATTR_ACL_ACCESS_T || |
110 | handler->flags == XATTR_ACL_DEFAULT_T) && | |
0667dfff LX |
111 | !inode_owner_or_capable(inode)) |
112 | return -EPERM; | |
113 | ||
d7e09d03 | 114 | /* b10667: ignore lustre special xattr for now */ |
bb371b95 AP |
115 | if (!strcmp(name, "hsm") || |
116 | ((handler->flags == XATTR_TRUSTED_T && !strcmp(name, "lov")) || | |
117 | (handler->flags == XATTR_LUSTRE_T && !strcmp(name, "lov")))) | |
0a3bdb00 | 118 | return 0; |
d7e09d03 PT |
119 | |
120 | /* b15587: ignore security.capability xattr for now */ | |
2c563880 JS |
121 | if ((handler->flags == XATTR_SECURITY_T && |
122 | !strcmp(name, "capability"))) | |
0a3bdb00 | 123 | return 0; |
d7e09d03 PT |
124 | |
125 | /* LU-549: Disable security.selinux when selinux is disabled */ | |
2c563880 JS |
126 | if (handler->flags == XATTR_SECURITY_T && !selinux_is_enabled() && |
127 | strcmp(name, "selinux") == 0) | |
0a3bdb00 | 128 | return -EOPNOTSUPP; |
d7e09d03 | 129 | |
115ee9d0 HZ |
130 | /*FIXME: enable IMA when the conditions are ready */ |
131 | if (handler->flags == XATTR_SECURITY_T && | |
132 | (!strcmp(name, "ima") || !strcmp(name, "evm"))) | |
133 | return -EOPNOTSUPP; | |
134 | ||
07b71df1 DE |
135 | /* |
136 | * In user.* namespace, only regular files and directories can have | |
137 | * extended attributes. | |
138 | */ | |
139 | if (handler->flags == XATTR_USER_T) { | |
140 | if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) | |
141 | return -EPERM; | |
142 | } | |
143 | ||
2c563880 | 144 | sprintf(fullname, "%s%s\n", handler->prefix, name); |
ef2e0f55 | 145 | rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), |
2c563880 | 146 | valid, fullname, pv, size, 0, flags, |
a612b007 | 147 | ll_i2suppgid(inode), &req); |
d7e09d03 | 148 | if (rc) { |
2c563880 | 149 | if (rc == -EOPNOTSUPP && handler->flags == XATTR_USER_T) { |
2d00bd17 | 150 | LCONSOLE_INFO("Disabling user_xattr feature because it is not supported on the server\n"); |
d7e09d03 PT |
151 | sbi->ll_flags &= ~LL_SBI_USER_XATTR; |
152 | } | |
0a3bdb00 | 153 | return rc; |
d7e09d03 PT |
154 | } |
155 | ||
156 | ptlrpc_req_finished(req); | |
0a3bdb00 | 157 | return 0; |
d7e09d03 PT |
158 | } |
159 | ||
bb371b95 AP |
160 | static int get_hsm_state(struct inode *inode, u32 *hus_states) |
161 | { | |
162 | struct md_op_data *op_data; | |
163 | struct hsm_user_state *hus; | |
164 | int rc; | |
165 | ||
166 | hus = kzalloc(sizeof(*hus), GFP_NOFS); | |
167 | if (!hus) | |
168 | return -ENOMEM; | |
169 | ||
170 | op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0, | |
171 | LUSTRE_OPC_ANY, hus); | |
172 | if (!IS_ERR(op_data)) { | |
173 | rc = obd_iocontrol(LL_IOC_HSM_STATE_GET, ll_i2mdexp(inode), | |
174 | sizeof(*op_data), op_data, NULL); | |
175 | if (!rc) | |
176 | *hus_states = hus->hus_states; | |
177 | else | |
178 | CDEBUG(D_VFSTRACE, "obd_iocontrol failed. rc = %d\n", | |
179 | rc); | |
180 | ||
181 | ll_finish_md_op_data(op_data); | |
182 | } else { | |
183 | rc = PTR_ERR(op_data); | |
184 | CDEBUG(D_VFSTRACE, "Could not prepare the opdata. rc = %d\n", | |
185 | rc); | |
186 | } | |
187 | kfree(hus); | |
188 | return rc; | |
189 | } | |
190 | ||
2c563880 JS |
191 | static int ll_xattr_set(const struct xattr_handler *handler, |
192 | struct dentry *dentry, struct inode *inode, | |
193 | const char *name, const void *value, size_t size, | |
194 | int flags) | |
d7e09d03 | 195 | { |
d7e09d03 PT |
196 | LASSERT(inode); |
197 | LASSERT(name); | |
198 | ||
1ada25dc | 199 | CDEBUG(D_VFSTRACE, "VFS Op:inode=" DFID "(%p), xattr %s\n", |
97a075cd | 200 | PFID(ll_inode2fid(inode)), inode, name); |
d7e09d03 | 201 | |
2c563880 | 202 | if (!strcmp(name, "lov")) { |
d7e09d03 | 203 | struct lov_user_md *lump = (struct lov_user_md *)value; |
2c563880 JS |
204 | int op_type = flags == XATTR_REPLACE ? LPROC_LL_REMOVEXATTR : |
205 | LPROC_LL_SETXATTR; | |
d7e09d03 PT |
206 | int rc = 0; |
207 | ||
2c563880 JS |
208 | ll_stats_ops_tally(ll_i2sbi(inode), op_type, 1); |
209 | ||
87ebccf9 DC |
210 | if (size != 0 && size < sizeof(struct lov_user_md)) |
211 | return -EINVAL; | |
212 | ||
2c563880 JS |
213 | /* |
214 | * It is possible to set an xattr to a "" value of zero size. | |
215 | * For this case we are going to treat it as a removal. | |
216 | */ | |
217 | if (!size && lump) | |
218 | lump = NULL; | |
219 | ||
d7e09d03 PT |
220 | /* Attributes that are saved via getxattr will always have |
221 | * the stripe_offset as 0. Instead, the MDS should be | |
c0894c6c OD |
222 | * allowed to pick the starting OST index. b=17846 |
223 | */ | |
6e16818b | 224 | if (lump && lump->lmm_stripe_offset == 0) |
d7e09d03 PT |
225 | lump->lmm_stripe_offset = -1; |
226 | ||
bb371b95 AP |
227 | /* Avoid anyone directly setting the RELEASED flag. */ |
228 | if (lump && (lump->lmm_pattern & LOV_PATTERN_F_RELEASED)) { | |
229 | /* Only if we have a released flag check if the file | |
230 | * was indeed archived. | |
231 | */ | |
232 | u32 state = HS_NONE; | |
233 | ||
234 | rc = get_hsm_state(inode, &state); | |
235 | if (rc) | |
236 | return rc; | |
237 | ||
238 | if (!(state & HS_ARCHIVED)) { | |
239 | CDEBUG(D_VFSTRACE, | |
240 | "hus_states state = %x, pattern = %x\n", | |
241 | state, lump->lmm_pattern); | |
242 | /* | |
243 | * Here the state is: real file is not | |
244 | * archived but user is requesting to set | |
245 | * the RELEASED flag so we mask off the | |
246 | * released flag from the request | |
247 | */ | |
248 | lump->lmm_pattern ^= LOV_PATTERN_F_RELEASED; | |
249 | } | |
250 | } | |
251 | ||
6e16818b | 252 | if (lump && S_ISREG(inode->i_mode)) { |
d467220e | 253 | __u64 it_flags = FMODE_WRITE; |
dbf789ce JX |
254 | int lum_size; |
255 | ||
256 | lum_size = ll_lov_user_md_size(lump); | |
257 | if (lum_size < 0 || size < lum_size) | |
258 | return 0; /* b=10667: ignore error */ | |
d7e09d03 | 259 | |
d467220e NY |
260 | rc = ll_lov_setstripe_ea_info(inode, dentry, it_flags, |
261 | lump, lum_size); | |
dbf789ce | 262 | /* b=10667: rc always be 0 here for now */ |
d7e09d03 PT |
263 | rc = 0; |
264 | } else if (S_ISDIR(inode->i_mode)) { | |
265 | rc = ll_dir_setstripe(inode, lump, 0); | |
266 | } | |
267 | ||
268 | return rc; | |
269 | ||
2c563880 JS |
270 | } else if (!strcmp(name, "lma") || !strcmp(name, "link")) { |
271 | ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_SETXATTR, 1); | |
d7e09d03 | 272 | return 0; |
2c563880 | 273 | } |
d7e09d03 | 274 | |
2c563880 JS |
275 | return ll_xattr_set_common(handler, dentry, inode, name, value, size, |
276 | flags); | |
d7e09d03 PT |
277 | } |
278 | ||
a6d879fd | 279 | int |
1e1f9ff4 JS |
280 | ll_xattr_list(struct inode *inode, const char *name, int type, void *buffer, |
281 | size_t size, __u64 valid) | |
d7e09d03 | 282 | { |
1e1f9ff4 | 283 | struct ll_inode_info *lli = ll_i2info(inode); |
d7e09d03 PT |
284 | struct ll_sb_info *sbi = ll_i2sbi(inode); |
285 | struct ptlrpc_request *req = NULL; | |
286 | struct mdt_body *body; | |
d7e09d03 | 287 | void *xdata; |
1e1f9ff4 | 288 | int rc; |
d7e09d03 | 289 | |
51cfb8c4 SB |
290 | if (sbi->ll_xattr_cache_enabled && type != XATTR_ACL_ACCESS_T && |
291 | (type != XATTR_SECURITY_T || strcmp(name, "security.selinux"))) { | |
7fc1f831 | 292 | rc = ll_xattr_cache_get(inode, name, buffer, size, valid); |
e93a3082 AP |
293 | if (rc == -EAGAIN) |
294 | goto getxattr_nocache; | |
7fc1f831 | 295 | if (rc < 0) |
34e1f2bb | 296 | goto out_xattr; |
e93a3082 AP |
297 | |
298 | /* Add "system.posix_acl_access" to the list */ | |
6e16818b | 299 | if (lli->lli_posix_acl && valid & OBD_MD_FLXATTRLS) { |
e93a3082 AP |
300 | if (size == 0) { |
301 | rc += sizeof(XATTR_NAME_ACL_ACCESS); | |
302 | } else if (size - rc >= sizeof(XATTR_NAME_ACL_ACCESS)) { | |
303 | memcpy(buffer + rc, XATTR_NAME_ACL_ACCESS, | |
304 | sizeof(XATTR_NAME_ACL_ACCESS)); | |
305 | rc += sizeof(XATTR_NAME_ACL_ACCESS); | |
306 | } else { | |
34e1f2bb JL |
307 | rc = -ERANGE; |
308 | goto out_xattr; | |
e93a3082 AP |
309 | } |
310 | } | |
7fc1f831 | 311 | } else { |
e93a3082 | 312 | getxattr_nocache: |
ef2e0f55 | 313 | rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), |
341f1f0a | 314 | valid, name, NULL, 0, size, 0, &req); |
7fc1f831 | 315 | if (rc < 0) |
34e1f2bb | 316 | goto out_xattr; |
7fc1f831 AP |
317 | |
318 | body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); | |
319 | LASSERT(body); | |
320 | ||
321 | /* only detect the xattr size */ | |
34e1f2bb | 322 | if (size == 0) { |
2e1b5b8b | 323 | rc = body->mbo_eadatasize; |
34e1f2bb JL |
324 | goto out; |
325 | } | |
7fc1f831 | 326 | |
2e1b5b8b | 327 | if (size < body->mbo_eadatasize) { |
7fc1f831 | 328 | CERROR("server bug: replied size %u > %u\n", |
2e1b5b8b | 329 | body->mbo_eadatasize, (int)size); |
34e1f2bb JL |
330 | rc = -ERANGE; |
331 | goto out; | |
d7e09d03 | 332 | } |
d7e09d03 | 333 | |
2e1b5b8b | 334 | if (body->mbo_eadatasize == 0) { |
34e1f2bb JL |
335 | rc = -ENODATA; |
336 | goto out; | |
337 | } | |
d7e09d03 | 338 | |
7fc1f831 AP |
339 | /* do not need swab xattr data */ |
340 | xdata = req_capsule_server_sized_get(&req->rq_pill, &RMF_EADATA, | |
2e1b5b8b | 341 | body->mbo_eadatasize); |
34e1f2bb JL |
342 | if (!xdata) { |
343 | rc = -EFAULT; | |
344 | goto out; | |
345 | } | |
d7e09d03 | 346 | |
2e1b5b8b JH |
347 | memcpy(buffer, xdata, body->mbo_eadatasize); |
348 | rc = body->mbo_eadatasize; | |
d7e09d03 PT |
349 | } |
350 | ||
7fc1f831 | 351 | out_xattr: |
1e1f9ff4 | 352 | if (rc == -EOPNOTSUPP && type == XATTR_USER_T) { |
7fc1f831 AP |
353 | LCONSOLE_INFO( |
354 | "%s: disabling user_xattr feature because it is not supported on the server: rc = %d\n", | |
355 | ll_get_fsname(inode->i_sb, NULL, 0), rc); | |
356 | sbi->ll_flags &= ~LL_SBI_USER_XATTR; | |
d7e09d03 | 357 | } |
d7e09d03 PT |
358 | out: |
359 | ptlrpc_req_finished(req); | |
360 | return rc; | |
361 | } | |
362 | ||
2c563880 JS |
363 | static int ll_xattr_get_common(const struct xattr_handler *handler, |
364 | struct dentry *dentry, struct inode *inode, | |
365 | const char *name, void *buffer, size_t size) | |
1e1f9ff4 | 366 | { |
2c563880 | 367 | char fullname[strlen(handler->prefix) + strlen(name) + 1]; |
1e1f9ff4 | 368 | struct ll_sb_info *sbi = ll_i2sbi(inode); |
d6a80699 | 369 | #ifdef CONFIG_FS_POSIX_ACL |
1e1f9ff4 | 370 | struct ll_inode_info *lli = ll_i2info(inode); |
d6a80699 | 371 | #endif |
2c563880 | 372 | int rc; |
1e1f9ff4 | 373 | |
1ada25dc | 374 | CDEBUG(D_VFSTRACE, "VFS Op:inode=" DFID "(%p)\n", |
1e1f9ff4 JS |
375 | PFID(ll_inode2fid(inode)), inode); |
376 | ||
2c563880 JS |
377 | ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_GETXATTR, 1); |
378 | ||
51cfb8c4 | 379 | rc = xattr_type_filter(sbi, handler); |
1e1f9ff4 JS |
380 | if (rc) |
381 | return rc; | |
382 | ||
383 | /* b15587: ignore security.capability xattr for now */ | |
2c563880 | 384 | if ((handler->flags == XATTR_SECURITY_T && !strcmp(name, "capability"))) |
1e1f9ff4 JS |
385 | return -ENODATA; |
386 | ||
387 | /* LU-549: Disable security.selinux when selinux is disabled */ | |
2c563880 JS |
388 | if (handler->flags == XATTR_SECURITY_T && !selinux_is_enabled() && |
389 | !strcmp(name, "selinux")) | |
1e1f9ff4 JS |
390 | return -EOPNOTSUPP; |
391 | ||
392 | #ifdef CONFIG_FS_POSIX_ACL | |
393 | /* posix acl is under protection of LOOKUP lock. when calling to this, | |
394 | * we just have path resolution to the target inode, so we have great | |
395 | * chance that cached ACL is uptodate. | |
396 | */ | |
2c563880 | 397 | if (handler->flags == XATTR_ACL_ACCESS_T) { |
1e1f9ff4 JS |
398 | struct posix_acl *acl; |
399 | ||
400 | spin_lock(&lli->lli_lock); | |
401 | acl = posix_acl_dup(lli->lli_posix_acl); | |
402 | spin_unlock(&lli->lli_lock); | |
403 | ||
404 | if (!acl) | |
405 | return -ENODATA; | |
406 | ||
407 | rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); | |
408 | posix_acl_release(acl); | |
409 | return rc; | |
410 | } | |
2c563880 | 411 | if (handler->flags == XATTR_ACL_DEFAULT_T && !S_ISDIR(inode->i_mode)) |
1e1f9ff4 JS |
412 | return -ENODATA; |
413 | #endif | |
2c563880 JS |
414 | sprintf(fullname, "%s%s\n", handler->prefix, name); |
415 | return ll_xattr_list(inode, fullname, handler->flags, buffer, size, | |
1e1f9ff4 JS |
416 | OBD_MD_FLXATTR); |
417 | } | |
418 | ||
55554f31 | 419 | static ssize_t ll_getxattr_lov(struct inode *inode, void *buf, size_t buf_size) |
d7e09d03 | 420 | { |
55554f31 | 421 | ssize_t rc; |
d7e09d03 | 422 | |
55554f31 JH |
423 | if (S_ISREG(inode->i_mode)) { |
424 | struct cl_object *obj = ll_i2info(inode)->lli_clob; | |
425 | struct cl_layout cl = { | |
426 | .cl_buf.lb_buf = buf, | |
427 | .cl_buf.lb_len = buf_size, | |
428 | }; | |
429 | struct lu_env *env; | |
3ee45c7e | 430 | u16 refcheck; |
55554f31 JH |
431 | |
432 | if (!obj) | |
433 | return -ENODATA; | |
d7e09d03 | 434 | |
55554f31 JH |
435 | env = cl_env_get(&refcheck); |
436 | if (IS_ERR(env)) | |
437 | return PTR_ERR(env); | |
2c563880 | 438 | |
55554f31 JH |
439 | rc = cl_object_layout_get(env, obj, &cl); |
440 | if (rc < 0) | |
441 | goto out_env; | |
d7e09d03 | 442 | |
55554f31 JH |
443 | if (!cl.cl_size) { |
444 | rc = -ENODATA; | |
445 | goto out_env; | |
d7e09d03 | 446 | } |
d7e09d03 | 447 | |
55554f31 JH |
448 | rc = cl.cl_size; |
449 | ||
450 | if (!buf_size) | |
451 | goto out_env; | |
452 | ||
453 | LASSERT(buf && rc <= buf_size); | |
454 | ||
455 | /* | |
456 | * Do not return layout gen for getxattr() since | |
457 | * otherwise it would confuse tar --xattr by | |
458 | * recognizing layout gen as stripe offset when the | |
459 | * file is restored. See LU-2809. | |
460 | */ | |
461 | ((struct lov_mds_md *)buf)->lmm_layout_gen = 0; | |
462 | out_env: | |
463 | cl_env_put(env, &refcheck); | |
464 | ||
465 | return rc; | |
466 | } else if (S_ISDIR(inode->i_mode)) { | |
467 | struct ptlrpc_request *req = NULL; | |
468 | struct lov_mds_md *lmm = NULL; | |
469 | int lmm_size = 0; | |
470 | ||
471 | rc = ll_dir_getstripe(inode, (void **)&lmm, &lmm_size, | |
472 | &req, 0); | |
d7e09d03 | 473 | if (rc < 0) |
55554f31 | 474 | goto out_req; |
d7e09d03 | 475 | |
55554f31 JH |
476 | if (!buf_size) { |
477 | rc = lmm_size; | |
478 | goto out_req; | |
d7e09d03 PT |
479 | } |
480 | ||
55554f31 | 481 | if (buf_size < lmm_size) { |
34e1f2bb | 482 | rc = -ERANGE; |
55554f31 | 483 | goto out_req; |
d7e09d03 PT |
484 | } |
485 | ||
55554f31 JH |
486 | memcpy(buf, lmm, lmm_size); |
487 | rc = lmm_size; | |
488 | out_req: | |
489 | if (req) | |
490 | ptlrpc_req_finished(req); | |
d7e09d03 | 491 | |
fbe7c6c7 | 492 | return rc; |
55554f31 JH |
493 | } else { |
494 | return -ENODATA; | |
495 | } | |
496 | } | |
497 | ||
498 | static int ll_xattr_get(const struct xattr_handler *handler, | |
499 | struct dentry *dentry, struct inode *inode, | |
500 | const char *name, void *buffer, size_t size) | |
501 | { | |
502 | LASSERT(inode); | |
503 | LASSERT(name); | |
504 | ||
505 | CDEBUG(D_VFSTRACE, "VFS Op:inode=" DFID "(%p), xattr %s\n", | |
506 | PFID(ll_inode2fid(inode)), inode, name); | |
507 | ||
508 | if (!strcmp(name, "lov")) { | |
509 | ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_GETXATTR, 1); | |
510 | ||
511 | return ll_getxattr_lov(inode, buffer, size); | |
d7e09d03 PT |
512 | } |
513 | ||
2c563880 | 514 | return ll_xattr_get_common(handler, dentry, inode, name, buffer, size); |
d7e09d03 PT |
515 | } |
516 | ||
517 | ssize_t ll_listxattr(struct dentry *dentry, char *buffer, size_t size) | |
518 | { | |
2b0143b5 | 519 | struct inode *inode = d_inode(dentry); |
55554f31 JH |
520 | struct ll_sb_info *sbi = ll_i2sbi(inode); |
521 | char *xattr_name; | |
522 | ssize_t rc, rc2; | |
523 | size_t len, rem; | |
d7e09d03 PT |
524 | |
525 | LASSERT(inode); | |
526 | ||
1ada25dc | 527 | CDEBUG(D_VFSTRACE, "VFS Op:inode=" DFID "(%p)\n", |
97a075cd | 528 | PFID(ll_inode2fid(inode)), inode); |
d7e09d03 PT |
529 | |
530 | ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_LISTXATTR, 1); | |
531 | ||
1e1f9ff4 JS |
532 | rc = ll_xattr_list(inode, NULL, XATTR_OTHER_T, buffer, size, |
533 | OBD_MD_FLXATTRLS); | |
d7e09d03 | 534 | if (rc < 0) |
55554f31 JH |
535 | return rc; |
536 | /* | |
537 | * If we're being called to get the size of the xattr list | |
538 | * (buf_size == 0) then just assume that a lustre.lov xattr | |
539 | * exists. | |
540 | */ | |
541 | if (!size) | |
542 | return rc + sizeof(XATTR_LUSTRE_LOV); | |
543 | ||
544 | xattr_name = buffer; | |
545 | rem = rc; | |
546 | ||
547 | while (rem > 0) { | |
548 | len = strnlen(xattr_name, rem - 1) + 1; | |
549 | rem -= len; | |
550 | if (!xattr_type_filter(sbi, get_xattr_type(xattr_name))) { | |
551 | /* Skip OK xattr type leave it in buffer */ | |
552 | xattr_name += len; | |
553 | continue; | |
d7e09d03 | 554 | } |
55554f31 JH |
555 | |
556 | /* | |
557 | * Move up remaining xattrs in buffer | |
558 | * removing the xattr that is not OK | |
559 | */ | |
560 | memmove(xattr_name, xattr_name + len, rem); | |
561 | rc -= len; | |
d7e09d03 PT |
562 | } |
563 | ||
55554f31 JH |
564 | rc2 = ll_getxattr_lov(inode, NULL, 0); |
565 | if (rc2 == -ENODATA) | |
566 | return rc; | |
cb6a2db6 | 567 | |
55554f31 JH |
568 | if (rc2 < 0) |
569 | return rc2; | |
d7e09d03 | 570 | |
55554f31 JH |
571 | if (size < rc + sizeof(XATTR_LUSTRE_LOV)) |
572 | return -ERANGE; | |
573 | ||
574 | memcpy(buffer + rc, XATTR_LUSTRE_LOV, sizeof(XATTR_LUSTRE_LOV)); | |
575 | ||
576 | return rc + sizeof(XATTR_LUSTRE_LOV); | |
d7e09d03 | 577 | } |
2c563880 JS |
578 | |
579 | static const struct xattr_handler ll_user_xattr_handler = { | |
580 | .prefix = XATTR_USER_PREFIX, | |
581 | .flags = XATTR_USER_T, | |
582 | .get = ll_xattr_get_common, | |
583 | .set = ll_xattr_set_common, | |
584 | }; | |
585 | ||
586 | static const struct xattr_handler ll_trusted_xattr_handler = { | |
587 | .prefix = XATTR_TRUSTED_PREFIX, | |
588 | .flags = XATTR_TRUSTED_T, | |
589 | .get = ll_xattr_get, | |
590 | .set = ll_xattr_set, | |
591 | }; | |
592 | ||
593 | static const struct xattr_handler ll_security_xattr_handler = { | |
594 | .prefix = XATTR_SECURITY_PREFIX, | |
595 | .flags = XATTR_SECURITY_T, | |
596 | .get = ll_xattr_get_common, | |
597 | .set = ll_xattr_set_common, | |
598 | }; | |
599 | ||
600 | static const struct xattr_handler ll_acl_access_xattr_handler = { | |
601 | .prefix = XATTR_NAME_POSIX_ACL_ACCESS, | |
602 | .flags = XATTR_ACL_ACCESS_T, | |
603 | .get = ll_xattr_get_common, | |
604 | .set = ll_xattr_set_common, | |
605 | }; | |
606 | ||
607 | static const struct xattr_handler ll_acl_default_xattr_handler = { | |
608 | .prefix = XATTR_NAME_POSIX_ACL_DEFAULT, | |
609 | .flags = XATTR_ACL_DEFAULT_T, | |
610 | .get = ll_xattr_get_common, | |
611 | .set = ll_xattr_set_common, | |
612 | }; | |
613 | ||
614 | static const struct xattr_handler ll_lustre_xattr_handler = { | |
615 | .prefix = XATTR_LUSTRE_PREFIX, | |
616 | .flags = XATTR_LUSTRE_T, | |
617 | .get = ll_xattr_get, | |
618 | .set = ll_xattr_set, | |
619 | }; | |
620 | ||
621 | const struct xattr_handler *ll_xattr_handlers[] = { | |
622 | &ll_user_xattr_handler, | |
623 | &ll_trusted_xattr_handler, | |
624 | &ll_security_xattr_handler, | |
625 | #ifdef CONFIG_FS_POSIX_ACL | |
626 | &ll_acl_access_xattr_handler, | |
627 | &ll_acl_default_xattr_handler, | |
628 | #endif | |
629 | &ll_lustre_xattr_handler, | |
630 | NULL, | |
631 | }; |