Commit | Line | Data |
---|---|---|
d7e09d03 PT |
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, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License version 2 for more details (a copy is included | |
14 | * in the LICENSE file that accompanied this code). | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * version 2 along with this program; If not, see | |
6a5b99a4 | 18 | * http://www.gnu.org/licenses/gpl-2.0.html |
d7e09d03 | 19 | * |
d7e09d03 PT |
20 | * GPL HEADER END |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. | |
24 | * Use is subject to license terms. | |
25 | * | |
1dc563a6 | 26 | * Copyright (c) 2011, 2015, Intel Corporation. |
d7e09d03 PT |
27 | */ |
28 | /* | |
29 | * This file is part of Lustre, http://www.lustre.org/ | |
30 | * Lustre is a trademark of Sun Microsystems, Inc. | |
31 | */ | |
32 | ||
33 | #include <linux/fs.h> | |
34 | #include <linux/sched.h> | |
35 | #include <linux/mm.h> | |
36 | #include <linux/selinux.h> | |
37 | ||
38 | #define DEBUG_SUBSYSTEM S_LLITE | |
39 | ||
67a235f5 GKH |
40 | #include "../include/obd_support.h" |
41 | #include "../include/lustre_lite.h" | |
42 | #include "../include/lustre_dlm.h" | |
43 | #include "../include/lustre_ver.h" | |
44 | #include "../include/lustre_eacl.h" | |
d7e09d03 PT |
45 | |
46 | #include "llite_internal.h" | |
47 | ||
48 | #define XATTR_USER_T (1) | |
49 | #define XATTR_TRUSTED_T (2) | |
50 | #define XATTR_SECURITY_T (3) | |
51 | #define XATTR_ACL_ACCESS_T (4) | |
52 | #define XATTR_ACL_DEFAULT_T (5) | |
53 | #define XATTR_LUSTRE_T (6) | |
54 | #define XATTR_OTHER_T (7) | |
55 | ||
56 | static | |
57 | int get_xattr_type(const char *name) | |
58 | { | |
97d79299 | 59 | if (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS)) |
d7e09d03 PT |
60 | return XATTR_ACL_ACCESS_T; |
61 | ||
97d79299 | 62 | if (!strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT)) |
d7e09d03 PT |
63 | return XATTR_ACL_DEFAULT_T; |
64 | ||
65 | if (!strncmp(name, XATTR_USER_PREFIX, | |
66 | sizeof(XATTR_USER_PREFIX) - 1)) | |
67 | return XATTR_USER_T; | |
68 | ||
69 | if (!strncmp(name, XATTR_TRUSTED_PREFIX, | |
70 | sizeof(XATTR_TRUSTED_PREFIX) - 1)) | |
71 | return XATTR_TRUSTED_T; | |
72 | ||
73 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | |
74 | sizeof(XATTR_SECURITY_PREFIX) - 1)) | |
75 | return XATTR_SECURITY_T; | |
76 | ||
77 | if (!strncmp(name, XATTR_LUSTRE_PREFIX, | |
78 | sizeof(XATTR_LUSTRE_PREFIX) - 1)) | |
79 | return XATTR_LUSTRE_T; | |
80 | ||
81 | return XATTR_OTHER_T; | |
82 | } | |
83 | ||
84 | static | |
85 | int xattr_type_filter(struct ll_sb_info *sbi, int xattr_type) | |
86 | { | |
87 | if ((xattr_type == XATTR_ACL_ACCESS_T || | |
88 | xattr_type == XATTR_ACL_DEFAULT_T) && | |
89 | !(sbi->ll_flags & LL_SBI_ACL)) | |
90 | return -EOPNOTSUPP; | |
91 | ||
92 | if (xattr_type == XATTR_USER_T && !(sbi->ll_flags & LL_SBI_USER_XATTR)) | |
93 | return -EOPNOTSUPP; | |
2eb90a75 | 94 | if (xattr_type == XATTR_TRUSTED_T && !capable(CFS_CAP_SYS_ADMIN)) |
d7e09d03 PT |
95 | return -EPERM; |
96 | if (xattr_type == XATTR_OTHER_T) | |
97 | return -EOPNOTSUPP; | |
98 | ||
99 | return 0; | |
100 | } | |
101 | ||
2c563880 JS |
102 | static int |
103 | ll_xattr_set_common(const struct xattr_handler *handler, | |
104 | struct dentry *dentry, struct inode *inode, | |
105 | const char *name, const void *value, size_t size, | |
106 | int flags) | |
d7e09d03 | 107 | { |
2c563880 | 108 | char fullname[strlen(handler->prefix) + strlen(name) + 1]; |
d7e09d03 | 109 | struct ll_sb_info *sbi = ll_i2sbi(inode); |
7fc1f831 | 110 | struct ptlrpc_request *req = NULL; |
d7e09d03 | 111 | const char *pv = value; |
2c563880 JS |
112 | __u64 valid; |
113 | int rc; | |
d7e09d03 | 114 | |
2c563880 JS |
115 | if (flags == XATTR_REPLACE) { |
116 | ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_REMOVEXATTR, 1); | |
117 | valid = OBD_MD_FLXATTRRM; | |
118 | } else { | |
119 | ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_SETXATTR, 1); | |
120 | valid = OBD_MD_FLXATTR; | |
121 | } | |
122 | ||
123 | rc = xattr_type_filter(sbi, handler->flags); | |
d7e09d03 | 124 | if (rc) |
0a3bdb00 | 125 | return rc; |
d7e09d03 | 126 | |
2c563880 JS |
127 | if ((handler->flags == XATTR_ACL_ACCESS_T || |
128 | handler->flags == XATTR_ACL_DEFAULT_T) && | |
0667dfff LX |
129 | !inode_owner_or_capable(inode)) |
130 | return -EPERM; | |
131 | ||
d7e09d03 | 132 | /* b10667: ignore lustre special xattr for now */ |
2c563880 JS |
133 | if ((handler->flags == XATTR_TRUSTED_T && !strcmp(name, "lov")) || |
134 | (handler->flags == XATTR_LUSTRE_T && !strcmp(name, "lov"))) | |
0a3bdb00 | 135 | return 0; |
d7e09d03 PT |
136 | |
137 | /* b15587: ignore security.capability xattr for now */ | |
2c563880 JS |
138 | if ((handler->flags == XATTR_SECURITY_T && |
139 | !strcmp(name, "capability"))) | |
0a3bdb00 | 140 | return 0; |
d7e09d03 PT |
141 | |
142 | /* LU-549: Disable security.selinux when selinux is disabled */ | |
2c563880 JS |
143 | if (handler->flags == XATTR_SECURITY_T && !selinux_is_enabled() && |
144 | strcmp(name, "selinux") == 0) | |
0a3bdb00 | 145 | return -EOPNOTSUPP; |
d7e09d03 | 146 | |
2c563880 | 147 | sprintf(fullname, "%s%s\n", handler->prefix, name); |
ef2e0f55 | 148 | rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), |
2c563880 | 149 | valid, fullname, pv, size, 0, flags, |
a612b007 | 150 | ll_i2suppgid(inode), &req); |
d7e09d03 | 151 | if (rc) { |
2c563880 | 152 | if (rc == -EOPNOTSUPP && handler->flags == XATTR_USER_T) { |
2d00bd17 | 153 | LCONSOLE_INFO("Disabling user_xattr feature because it is not supported on the server\n"); |
d7e09d03 PT |
154 | sbi->ll_flags &= ~LL_SBI_USER_XATTR; |
155 | } | |
0a3bdb00 | 156 | return rc; |
d7e09d03 PT |
157 | } |
158 | ||
159 | ptlrpc_req_finished(req); | |
0a3bdb00 | 160 | return 0; |
d7e09d03 PT |
161 | } |
162 | ||
2c563880 JS |
163 | static int ll_xattr_set(const struct xattr_handler *handler, |
164 | struct dentry *dentry, struct inode *inode, | |
165 | const char *name, const void *value, size_t size, | |
166 | int flags) | |
d7e09d03 | 167 | { |
d7e09d03 PT |
168 | LASSERT(inode); |
169 | LASSERT(name); | |
170 | ||
97a075cd JN |
171 | CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), xattr %s\n", |
172 | PFID(ll_inode2fid(inode)), inode, name); | |
d7e09d03 | 173 | |
2c563880 | 174 | if (!strcmp(name, "lov")) { |
d7e09d03 | 175 | struct lov_user_md *lump = (struct lov_user_md *)value; |
2c563880 JS |
176 | int op_type = flags == XATTR_REPLACE ? LPROC_LL_REMOVEXATTR : |
177 | LPROC_LL_SETXATTR; | |
d7e09d03 PT |
178 | int rc = 0; |
179 | ||
2c563880 JS |
180 | ll_stats_ops_tally(ll_i2sbi(inode), op_type, 1); |
181 | ||
87ebccf9 DC |
182 | if (size != 0 && size < sizeof(struct lov_user_md)) |
183 | return -EINVAL; | |
184 | ||
2c563880 JS |
185 | /* |
186 | * It is possible to set an xattr to a "" value of zero size. | |
187 | * For this case we are going to treat it as a removal. | |
188 | */ | |
189 | if (!size && lump) | |
190 | lump = NULL; | |
191 | ||
d7e09d03 PT |
192 | /* Attributes that are saved via getxattr will always have |
193 | * the stripe_offset as 0. Instead, the MDS should be | |
c0894c6c OD |
194 | * allowed to pick the starting OST index. b=17846 |
195 | */ | |
6e16818b | 196 | if (lump && lump->lmm_stripe_offset == 0) |
d7e09d03 PT |
197 | lump->lmm_stripe_offset = -1; |
198 | ||
6e16818b | 199 | if (lump && S_ISREG(inode->i_mode)) { |
d467220e | 200 | __u64 it_flags = FMODE_WRITE; |
d7e09d03 PT |
201 | int lum_size = (lump->lmm_magic == LOV_USER_MAGIC_V1) ? |
202 | sizeof(*lump) : sizeof(struct lov_user_md_v3); | |
203 | ||
d467220e NY |
204 | rc = ll_lov_setstripe_ea_info(inode, dentry, it_flags, |
205 | lump, lum_size); | |
d7e09d03 PT |
206 | /* b10667: rc always be 0 here for now */ |
207 | rc = 0; | |
208 | } else if (S_ISDIR(inode->i_mode)) { | |
209 | rc = ll_dir_setstripe(inode, lump, 0); | |
210 | } | |
211 | ||
212 | return rc; | |
213 | ||
2c563880 JS |
214 | } else if (!strcmp(name, "lma") || !strcmp(name, "link")) { |
215 | ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_SETXATTR, 1); | |
d7e09d03 | 216 | return 0; |
2c563880 | 217 | } |
d7e09d03 | 218 | |
2c563880 JS |
219 | return ll_xattr_set_common(handler, dentry, inode, name, value, size, |
220 | flags); | |
d7e09d03 PT |
221 | } |
222 | ||
1e1f9ff4 JS |
223 | static int |
224 | ll_xattr_list(struct inode *inode, const char *name, int type, void *buffer, | |
225 | size_t size, __u64 valid) | |
d7e09d03 | 226 | { |
1e1f9ff4 | 227 | struct ll_inode_info *lli = ll_i2info(inode); |
d7e09d03 PT |
228 | struct ll_sb_info *sbi = ll_i2sbi(inode); |
229 | struct ptlrpc_request *req = NULL; | |
230 | struct mdt_body *body; | |
d7e09d03 | 231 | void *xdata; |
1e1f9ff4 | 232 | int rc; |
d7e09d03 | 233 | |
1e1f9ff4 | 234 | if (sbi->ll_xattr_cache_enabled && type != XATTR_ACL_ACCESS_T) { |
7fc1f831 | 235 | rc = ll_xattr_cache_get(inode, name, buffer, size, valid); |
e93a3082 AP |
236 | if (rc == -EAGAIN) |
237 | goto getxattr_nocache; | |
7fc1f831 | 238 | if (rc < 0) |
34e1f2bb | 239 | goto out_xattr; |
e93a3082 AP |
240 | |
241 | /* Add "system.posix_acl_access" to the list */ | |
6e16818b | 242 | if (lli->lli_posix_acl && valid & OBD_MD_FLXATTRLS) { |
e93a3082 AP |
243 | if (size == 0) { |
244 | rc += sizeof(XATTR_NAME_ACL_ACCESS); | |
245 | } else if (size - rc >= sizeof(XATTR_NAME_ACL_ACCESS)) { | |
246 | memcpy(buffer + rc, XATTR_NAME_ACL_ACCESS, | |
247 | sizeof(XATTR_NAME_ACL_ACCESS)); | |
248 | rc += sizeof(XATTR_NAME_ACL_ACCESS); | |
249 | } else { | |
34e1f2bb JL |
250 | rc = -ERANGE; |
251 | goto out_xattr; | |
e93a3082 AP |
252 | } |
253 | } | |
7fc1f831 | 254 | } else { |
e93a3082 | 255 | getxattr_nocache: |
ef2e0f55 | 256 | rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), |
341f1f0a | 257 | valid, name, NULL, 0, size, 0, &req); |
7fc1f831 | 258 | if (rc < 0) |
34e1f2bb | 259 | goto out_xattr; |
7fc1f831 AP |
260 | |
261 | body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); | |
262 | LASSERT(body); | |
263 | ||
264 | /* only detect the xattr size */ | |
34e1f2bb | 265 | if (size == 0) { |
2e1b5b8b | 266 | rc = body->mbo_eadatasize; |
34e1f2bb JL |
267 | goto out; |
268 | } | |
7fc1f831 | 269 | |
2e1b5b8b | 270 | if (size < body->mbo_eadatasize) { |
7fc1f831 | 271 | CERROR("server bug: replied size %u > %u\n", |
2e1b5b8b | 272 | body->mbo_eadatasize, (int)size); |
34e1f2bb JL |
273 | rc = -ERANGE; |
274 | goto out; | |
d7e09d03 | 275 | } |
d7e09d03 | 276 | |
2e1b5b8b | 277 | if (body->mbo_eadatasize == 0) { |
34e1f2bb JL |
278 | rc = -ENODATA; |
279 | goto out; | |
280 | } | |
d7e09d03 | 281 | |
7fc1f831 AP |
282 | /* do not need swab xattr data */ |
283 | xdata = req_capsule_server_sized_get(&req->rq_pill, &RMF_EADATA, | |
2e1b5b8b | 284 | body->mbo_eadatasize); |
34e1f2bb JL |
285 | if (!xdata) { |
286 | rc = -EFAULT; | |
287 | goto out; | |
288 | } | |
d7e09d03 | 289 | |
2e1b5b8b JH |
290 | memcpy(buffer, xdata, body->mbo_eadatasize); |
291 | rc = body->mbo_eadatasize; | |
d7e09d03 PT |
292 | } |
293 | ||
7fc1f831 | 294 | out_xattr: |
1e1f9ff4 | 295 | if (rc == -EOPNOTSUPP && type == XATTR_USER_T) { |
7fc1f831 AP |
296 | LCONSOLE_INFO( |
297 | "%s: disabling user_xattr feature because it is not supported on the server: rc = %d\n", | |
298 | ll_get_fsname(inode->i_sb, NULL, 0), rc); | |
299 | sbi->ll_flags &= ~LL_SBI_USER_XATTR; | |
d7e09d03 | 300 | } |
d7e09d03 PT |
301 | out: |
302 | ptlrpc_req_finished(req); | |
303 | return rc; | |
304 | } | |
305 | ||
2c563880 JS |
306 | static int ll_xattr_get_common(const struct xattr_handler *handler, |
307 | struct dentry *dentry, struct inode *inode, | |
308 | const char *name, void *buffer, size_t size) | |
1e1f9ff4 | 309 | { |
2c563880 | 310 | char fullname[strlen(handler->prefix) + strlen(name) + 1]; |
1e1f9ff4 | 311 | struct ll_sb_info *sbi = ll_i2sbi(inode); |
d6a80699 | 312 | #ifdef CONFIG_FS_POSIX_ACL |
1e1f9ff4 | 313 | struct ll_inode_info *lli = ll_i2info(inode); |
d6a80699 | 314 | #endif |
2c563880 | 315 | int rc; |
1e1f9ff4 JS |
316 | |
317 | CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n", | |
318 | PFID(ll_inode2fid(inode)), inode); | |
319 | ||
2c563880 JS |
320 | ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_GETXATTR, 1); |
321 | ||
322 | rc = xattr_type_filter(sbi, handler->flags); | |
1e1f9ff4 JS |
323 | if (rc) |
324 | return rc; | |
325 | ||
326 | /* b15587: ignore security.capability xattr for now */ | |
2c563880 | 327 | if ((handler->flags == XATTR_SECURITY_T && !strcmp(name, "capability"))) |
1e1f9ff4 JS |
328 | return -ENODATA; |
329 | ||
330 | /* LU-549: Disable security.selinux when selinux is disabled */ | |
2c563880 JS |
331 | if (handler->flags == XATTR_SECURITY_T && !selinux_is_enabled() && |
332 | !strcmp(name, "selinux")) | |
1e1f9ff4 JS |
333 | return -EOPNOTSUPP; |
334 | ||
335 | #ifdef CONFIG_FS_POSIX_ACL | |
336 | /* posix acl is under protection of LOOKUP lock. when calling to this, | |
337 | * we just have path resolution to the target inode, so we have great | |
338 | * chance that cached ACL is uptodate. | |
339 | */ | |
2c563880 | 340 | if (handler->flags == XATTR_ACL_ACCESS_T) { |
1e1f9ff4 JS |
341 | struct posix_acl *acl; |
342 | ||
343 | spin_lock(&lli->lli_lock); | |
344 | acl = posix_acl_dup(lli->lli_posix_acl); | |
345 | spin_unlock(&lli->lli_lock); | |
346 | ||
347 | if (!acl) | |
348 | return -ENODATA; | |
349 | ||
350 | rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); | |
351 | posix_acl_release(acl); | |
352 | return rc; | |
353 | } | |
2c563880 | 354 | if (handler->flags == XATTR_ACL_DEFAULT_T && !S_ISDIR(inode->i_mode)) |
1e1f9ff4 JS |
355 | return -ENODATA; |
356 | #endif | |
2c563880 JS |
357 | sprintf(fullname, "%s%s\n", handler->prefix, name); |
358 | return ll_xattr_list(inode, fullname, handler->flags, buffer, size, | |
1e1f9ff4 JS |
359 | OBD_MD_FLXATTR); |
360 | } | |
361 | ||
2c563880 JS |
362 | static int ll_xattr_get(const struct xattr_handler *handler, |
363 | struct dentry *dentry, struct inode *inode, | |
364 | const char *name, void *buffer, size_t size) | |
d7e09d03 | 365 | { |
d7e09d03 PT |
366 | LASSERT(inode); |
367 | LASSERT(name); | |
368 | ||
97a075cd JN |
369 | CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), xattr %s\n", |
370 | PFID(ll_inode2fid(inode)), inode, name); | |
d7e09d03 | 371 | |
2c563880 | 372 | if (!strcmp(name, "lov")) { |
d7e09d03 PT |
373 | struct lov_stripe_md *lsm; |
374 | struct lov_user_md *lump; | |
375 | struct lov_mds_md *lmm = NULL; | |
376 | struct ptlrpc_request *request = NULL; | |
377 | int rc = 0, lmmsize = 0; | |
378 | ||
2c563880 JS |
379 | ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_GETXATTR, 1); |
380 | ||
d7e09d03 PT |
381 | if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) |
382 | return -ENODATA; | |
383 | ||
d7e09d03 | 384 | lsm = ccc_inode_lsm_get(inode); |
6e16818b | 385 | if (!lsm) { |
d7e09d03 | 386 | if (S_ISDIR(inode->i_mode)) { |
6e23ea98 | 387 | rc = ll_dir_getstripe(inode, (void **)&lmm, |
388 | &lmmsize, &request, 0); | |
d7e09d03 PT |
389 | } else { |
390 | rc = -ENODATA; | |
391 | } | |
392 | } else { | |
393 | /* LSM is present already after lookup/getattr call. | |
c0894c6c OD |
394 | * we need to grab layout lock once it is implemented |
395 | */ | |
d7e09d03 PT |
396 | rc = obd_packmd(ll_i2dtexp(inode), &lmm, lsm); |
397 | lmmsize = rc; | |
398 | } | |
399 | ccc_inode_lsm_put(inode, lsm); | |
400 | ||
401 | if (rc < 0) | |
34e1f2bb | 402 | goto out; |
d7e09d03 PT |
403 | |
404 | if (size == 0) { | |
405 | /* used to call ll_get_max_mdsize() forward to get | |
406 | * the maximum buffer size, while some apps (such as | |
407 | * rsync 3.0.x) care much about the exact xattr value | |
c0894c6c OD |
408 | * size |
409 | */ | |
d7e09d03 | 410 | rc = lmmsize; |
34e1f2bb | 411 | goto out; |
d7e09d03 PT |
412 | } |
413 | ||
414 | if (size < lmmsize) { | |
09561a53 AV |
415 | CERROR("server bug: replied size %d > %d for %pd (%s)\n", |
416 | lmmsize, (int)size, dentry, name); | |
34e1f2bb JL |
417 | rc = -ERANGE; |
418 | goto out; | |
d7e09d03 PT |
419 | } |
420 | ||
634ffdd9 | 421 | lump = buffer; |
d7e09d03 PT |
422 | memcpy(lump, lmm, lmmsize); |
423 | /* do not return layout gen for getxattr otherwise it would | |
424 | * confuse tar --xattr by recognizing layout gen as stripe | |
c0894c6c OD |
425 | * offset when the file is restored. See LU-2809. |
426 | */ | |
d7e09d03 PT |
427 | lump->lmm_layout_gen = 0; |
428 | ||
429 | rc = lmmsize; | |
430 | out: | |
431 | if (request) | |
432 | ptlrpc_req_finished(request); | |
433 | else if (lmm) | |
434 | obd_free_diskmd(ll_i2dtexp(inode), &lmm); | |
fbe7c6c7 | 435 | return rc; |
d7e09d03 PT |
436 | } |
437 | ||
2c563880 | 438 | return ll_xattr_get_common(handler, dentry, inode, name, buffer, size); |
d7e09d03 PT |
439 | } |
440 | ||
441 | ssize_t ll_listxattr(struct dentry *dentry, char *buffer, size_t size) | |
442 | { | |
2b0143b5 | 443 | struct inode *inode = d_inode(dentry); |
d7e09d03 PT |
444 | int rc = 0, rc2 = 0; |
445 | struct lov_mds_md *lmm = NULL; | |
446 | struct ptlrpc_request *request = NULL; | |
447 | int lmmsize; | |
448 | ||
449 | LASSERT(inode); | |
450 | ||
97a075cd JN |
451 | CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n", |
452 | PFID(ll_inode2fid(inode)), inode); | |
d7e09d03 PT |
453 | |
454 | ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_LISTXATTR, 1); | |
455 | ||
1e1f9ff4 JS |
456 | rc = ll_xattr_list(inode, NULL, XATTR_OTHER_T, buffer, size, |
457 | OBD_MD_FLXATTRLS); | |
d7e09d03 | 458 | if (rc < 0) |
34e1f2bb | 459 | goto out; |
d7e09d03 | 460 | |
6e16818b | 461 | if (buffer) { |
d7e09d03 PT |
462 | struct ll_sb_info *sbi = ll_i2sbi(inode); |
463 | char *xattr_name = buffer; | |
464 | int xlen, rem = rc; | |
465 | ||
466 | while (rem > 0) { | |
467 | xlen = strnlen(xattr_name, rem - 1) + 1; | |
468 | rem -= xlen; | |
469 | if (xattr_type_filter(sbi, | |
470 | get_xattr_type(xattr_name)) == 0) { | |
471 | /* skip OK xattr type | |
472 | * leave it in buffer | |
473 | */ | |
474 | xattr_name += xlen; | |
475 | continue; | |
476 | } | |
477 | /* move up remaining xattrs in buffer | |
478 | * removing the xattr that is not OK | |
479 | */ | |
480 | memmove(xattr_name, xattr_name + xlen, rem); | |
481 | rc -= xlen; | |
482 | } | |
483 | } | |
484 | if (S_ISREG(inode->i_mode)) { | |
485 | if (!ll_i2info(inode)->lli_has_smd) | |
486 | rc2 = -1; | |
487 | } else if (S_ISDIR(inode->i_mode)) { | |
6e23ea98 | 488 | rc2 = ll_dir_getstripe(inode, (void **)&lmm, &lmmsize, |
489 | &request, 0); | |
d7e09d03 PT |
490 | } |
491 | ||
492 | if (rc2 < 0) { | |
34e1f2bb JL |
493 | rc2 = 0; |
494 | goto out; | |
d7e09d03 PT |
495 | } else if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) { |
496 | const int prefix_len = sizeof(XATTR_LUSTRE_PREFIX) - 1; | |
497 | const size_t name_len = sizeof("lov") - 1; | |
498 | const size_t total_len = prefix_len + name_len + 1; | |
499 | ||
6e16818b | 500 | if (((rc + total_len) > size) && buffer) { |
cb6a2db6 KM |
501 | ptlrpc_req_finished(request); |
502 | return -ERANGE; | |
503 | } | |
504 | ||
6e16818b | 505 | if (buffer) { |
d7e09d03 PT |
506 | buffer += rc; |
507 | memcpy(buffer, XATTR_LUSTRE_PREFIX, prefix_len); | |
508 | memcpy(buffer + prefix_len, "lov", name_len); | |
509 | buffer[prefix_len + name_len] = '\0'; | |
510 | } | |
511 | rc2 = total_len; | |
512 | } | |
513 | out: | |
514 | ptlrpc_req_finished(request); | |
515 | rc = rc + rc2; | |
516 | ||
517 | return rc; | |
518 | } | |
2c563880 JS |
519 | |
520 | static const struct xattr_handler ll_user_xattr_handler = { | |
521 | .prefix = XATTR_USER_PREFIX, | |
522 | .flags = XATTR_USER_T, | |
523 | .get = ll_xattr_get_common, | |
524 | .set = ll_xattr_set_common, | |
525 | }; | |
526 | ||
527 | static const struct xattr_handler ll_trusted_xattr_handler = { | |
528 | .prefix = XATTR_TRUSTED_PREFIX, | |
529 | .flags = XATTR_TRUSTED_T, | |
530 | .get = ll_xattr_get, | |
531 | .set = ll_xattr_set, | |
532 | }; | |
533 | ||
534 | static const struct xattr_handler ll_security_xattr_handler = { | |
535 | .prefix = XATTR_SECURITY_PREFIX, | |
536 | .flags = XATTR_SECURITY_T, | |
537 | .get = ll_xattr_get_common, | |
538 | .set = ll_xattr_set_common, | |
539 | }; | |
540 | ||
541 | static const struct xattr_handler ll_acl_access_xattr_handler = { | |
542 | .prefix = XATTR_NAME_POSIX_ACL_ACCESS, | |
543 | .flags = XATTR_ACL_ACCESS_T, | |
544 | .get = ll_xattr_get_common, | |
545 | .set = ll_xattr_set_common, | |
546 | }; | |
547 | ||
548 | static const struct xattr_handler ll_acl_default_xattr_handler = { | |
549 | .prefix = XATTR_NAME_POSIX_ACL_DEFAULT, | |
550 | .flags = XATTR_ACL_DEFAULT_T, | |
551 | .get = ll_xattr_get_common, | |
552 | .set = ll_xattr_set_common, | |
553 | }; | |
554 | ||
555 | static const struct xattr_handler ll_lustre_xattr_handler = { | |
556 | .prefix = XATTR_LUSTRE_PREFIX, | |
557 | .flags = XATTR_LUSTRE_T, | |
558 | .get = ll_xattr_get, | |
559 | .set = ll_xattr_set, | |
560 | }; | |
561 | ||
562 | const struct xattr_handler *ll_xattr_handlers[] = { | |
563 | &ll_user_xattr_handler, | |
564 | &ll_trusted_xattr_handler, | |
565 | &ll_security_xattr_handler, | |
566 | #ifdef CONFIG_FS_POSIX_ACL | |
567 | &ll_acl_access_xattr_handler, | |
568 | &ll_acl_default_xattr_handler, | |
569 | #endif | |
570 | &ll_lustre_xattr_handler, | |
571 | NULL, | |
572 | }; |