Whamcloud - gitweb
LU-11107 mdt: handle nonexistent xattrs correctly
[fs/lustre-release.git] / lustre / mdt / mdt_xattr.c
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
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
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  *
26  * Copyright (c) 2011, 2016, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lustre/mdt/mdt_xattr.c
33  *
34  * Lustre Metadata Target (mdt) extended attributes management.
35  *
36  * Author: Peter Braam <braam@clusterfs.com>
37  * Author: Andreas Dilger <adilger@clusterfs.com>
38  * Author: Phil Schwan <phil@clusterfs.com>
39  * Author: Huang Hua <huanghua@clusterfs.com>
40  */
41
42 #define DEBUG_SUBSYSTEM S_MDS
43
44 #include <linux/xattr.h>
45 #include <obd_class.h>
46 #include <lustre_nodemap.h>
47 #include <lustre_acl.h>
48 #include "mdt_internal.h"
49
50
51 /* return EADATA length to the caller. negative value means error */
52 static int mdt_getxattr_pack_reply(struct mdt_thread_info * info)
53 {
54         struct req_capsule *pill = info->mti_pill;
55         struct ptlrpc_request *req = mdt_info_req(info);
56         const char *xattr_name;
57         u64 valid;
58         static const char user_string[] = "user.";
59         int size;
60         int rc = 0;
61         int rc2;
62         ENTRY;
63
64         valid = info->mti_body->mbo_valid & (OBD_MD_FLXATTR | OBD_MD_FLXATTRLS);
65
66         /* Determine how many bytes we need */
67         if (valid == OBD_MD_FLXATTR) {
68                 xattr_name = req_capsule_client_get(pill, &RMF_NAME);
69                 if (!xattr_name)
70                         RETURN(-EFAULT);
71
72                 if (!(exp_connect_flags(req->rq_export) & OBD_CONNECT_XATTR) &&
73                     !strncmp(xattr_name, user_string, sizeof(user_string) - 1))
74                         RETURN(-EOPNOTSUPP);
75
76                 size = mo_xattr_get(info->mti_env,
77                                     mdt_object_child(info->mti_object),
78                                     &LU_BUF_NULL, xattr_name);
79                 if (size == -ENODATA) {
80                         /* XXX: Some client code will not handle -ENODATA
81                          * for XATTR_NAME_LOV (trusted.lov) properly. */
82                         if (strcmp(xattr_name, XATTR_NAME_LOV) == 0)
83                                 rc = 0;
84                         else
85                                 rc = -ENODATA;
86
87                         size = 0;
88                 }
89         } else if (valid == OBD_MD_FLXATTRLS) {
90                 size = mo_xattr_list(info->mti_env,
91                                      mdt_object_child(info->mti_object),
92                                      &LU_BUF_NULL);
93         } else if (valid == OBD_MD_FLXATTRALL) {
94                 /* N.B. eadatasize = 0 is not valid for FLXATTRALL */
95                 /* We could calculate accurate sizes, but this would
96                  * introduce a lot of overhead, let's do it later... */
97                 size = info->mti_body->mbo_eadatasize;
98                 req_capsule_set_size(pill, &RMF_EAVALS, RCL_SERVER, size);
99                 req_capsule_set_size(pill, &RMF_EAVALS_LENS, RCL_SERVER, size);
100         } else {
101                 CDEBUG(D_INFO, "Valid bits: %#llx\n",
102                        info->mti_body->mbo_valid);
103                 RETURN(-EINVAL);
104         }
105
106         if (size < 0) {
107                 if (size != -EOPNOTSUPP)
108                         CERROR("Error geting EA size: %d\n", size);
109                 RETURN(size);
110         }
111
112         if (req_capsule_has_field(pill, &RMF_ACL, RCL_SERVER))
113                 req_capsule_set_size(pill, &RMF_ACL, RCL_SERVER,
114                                      LUSTRE_POSIX_ACL_MAX_SIZE_OLD);
115
116         req_capsule_set_size(pill, &RMF_EADATA, RCL_SERVER,
117                              info->mti_body->mbo_eadatasize == 0 ? 0 : size);
118
119         rc2 = req_capsule_server_pack(pill);
120         if (rc2 < 0)
121                 RETURN(rc2);
122
123         if (OBD_FAIL_CHECK(OBD_FAIL_MDS_GETXATTR_PACK))
124                 RETURN(-ENOMEM);
125
126         RETURN(rc < 0 ? rc : size);
127 }
128
129 static int mdt_nodemap_map_acl(struct mdt_thread_info *info, void *buf,
130                                size_t size, const char *name,
131                                enum nodemap_tree_type tree_type)
132 {
133         struct lu_nodemap      *nodemap;
134         struct obd_export      *exp = info->mti_exp;
135         int                     rc = size;
136
137         ENTRY;
138
139         if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0 ||
140             strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) {
141                 if (size > info->mti_mdt->mdt_max_ea_size ||
142                      (!exp_connect_large_acl(exp) &&
143                       size > LUSTRE_POSIX_ACL_MAX_SIZE_OLD))
144                         GOTO(out, rc = -ERANGE);
145
146                 nodemap = nodemap_get_from_exp(exp);
147                 if (IS_ERR(nodemap))
148                         GOTO(out, rc = PTR_ERR(nodemap));
149
150                 rc = nodemap_map_acl(nodemap, buf, size, tree_type);
151                 nodemap_putref(nodemap);
152                 if (rc < 0)
153                         GOTO(out, rc);
154         }
155 out:
156         RETURN(rc);
157 }
158
159 static int mdt_getxattr_all(struct mdt_thread_info *info,
160                             struct mdt_body *reqbody, struct mdt_body *repbody,
161                             struct lu_buf *buf, struct md_object *next)
162 {
163         const struct lu_env *env = info->mti_env;
164         char *v, *b, *eadatahead, *eadatatail;
165         __u32 *sizes;
166         int eadatasize, eavallen = 0, eavallens = 0, rc;
167
168         ENTRY;
169
170         /*
171          * The format of the pill is the following:
172          * EADATA:      attr1\0attr2\0...attrn\0
173          * EAVALS:      val1val2...valn
174          * EAVALS_LENS: 4,4,...4
175          */
176
177         eadatahead = buf->lb_buf;
178
179         /* Fill out EADATA first */
180         rc = mo_xattr_list(env, next, buf);
181         if (rc < 0)
182                 GOTO(out_shrink, rc);
183
184         eadatasize = rc;
185         eadatatail = eadatahead + eadatasize;
186
187         v = req_capsule_server_get(info->mti_pill, &RMF_EAVALS);
188         sizes = req_capsule_server_get(info->mti_pill, &RMF_EAVALS_LENS);
189
190         /* Fill out EAVALS and EAVALS_LENS */
191         for (b = eadatahead; b < eadatatail; b += strlen(b) + 1, v += rc) {
192                 buf->lb_buf = v;
193                 buf->lb_len = reqbody->mbo_eadatasize - eavallen;
194                 rc = mo_xattr_get(env, next, buf, b);
195                 if (rc < 0)
196                         GOTO(out_shrink, rc);
197                 rc = mdt_nodemap_map_acl(info, buf->lb_buf, rc, b,
198                                          NODEMAP_FS_TO_CLIENT);
199                 if (rc < 0)
200                         GOTO(out_shrink, rc);
201                 sizes[eavallens] = rc;
202                 eavallens++;
203                 eavallen += rc;
204         }
205
206 out_shrink:
207         if (rc < 0) {
208                 eadatasize = 0;
209                 eavallens = 0;
210                 eavallen = 0;
211         }
212         repbody->mbo_aclsize = eavallen;
213         repbody->mbo_max_mdsize = eavallens;
214
215         req_capsule_shrink(info->mti_pill, &RMF_EAVALS, eavallen, RCL_SERVER);
216         req_capsule_shrink(info->mti_pill, &RMF_EAVALS_LENS,
217                            eavallens * sizeof(__u32), RCL_SERVER);
218         req_capsule_shrink(info->mti_pill, &RMF_EADATA, eadatasize, RCL_SERVER);
219
220         if (rc >= 0)
221                 RETURN(eadatasize);
222         return rc;
223 }
224
225 int mdt_getxattr(struct mdt_thread_info *info)
226 {
227         struct ptlrpc_request  *req = mdt_info_req(info);
228         struct mdt_body        *reqbody;
229         struct mdt_body        *repbody = NULL;
230         struct md_object       *next;
231         struct lu_buf          *buf;
232         int                     easize, rc;
233         u64                     valid;
234         ENTRY;
235
236         LASSERT(info->mti_object != NULL);
237         LASSERT(lu_object_assert_exists(&info->mti_object->mot_obj));
238
239         CDEBUG(D_INODE, "getxattr "DFID"\n", PFID(&info->mti_body->mbo_fid1));
240
241         reqbody = req_capsule_client_get(info->mti_pill, &RMF_MDT_BODY);
242         if (reqbody == NULL)
243                 RETURN(err_serious(-EFAULT));
244
245         rc = mdt_init_ucred(info, reqbody);
246         if (rc)
247                 RETURN(err_serious(rc));
248
249         next = mdt_object_child(info->mti_object);
250         easize = mdt_getxattr_pack_reply(info);
251         if (easize == -ENODATA)
252                 GOTO(out, rc = easize);
253         else if (easize < 0)
254                 GOTO(out, rc = err_serious(easize));
255
256         repbody = req_capsule_server_get(info->mti_pill, &RMF_MDT_BODY);
257         LASSERT(repbody != NULL);
258
259         /* No need further getxattr. */
260         if (easize == 0 || reqbody->mbo_eadatasize == 0)
261                 GOTO(out, rc = easize);
262
263         buf = &info->mti_buf;
264         buf->lb_buf = req_capsule_server_get(info->mti_pill, &RMF_EADATA);
265         buf->lb_len = easize;
266
267         valid = info->mti_body->mbo_valid & (OBD_MD_FLXATTR | OBD_MD_FLXATTRLS);
268
269         if (valid == OBD_MD_FLXATTR) {
270                 const char *xattr_name = req_capsule_client_get(info->mti_pill,
271                                                                 &RMF_NAME);
272                 rc = mo_xattr_get(info->mti_env, next, buf, xattr_name);
273                 rc = mdt_nodemap_map_acl(info, buf->lb_buf, rc, xattr_name,
274                                          NODEMAP_FS_TO_CLIENT);
275         } else if (valid == OBD_MD_FLXATTRLS) {
276                 CDEBUG(D_INODE, "listxattr\n");
277
278                 rc = mo_xattr_list(info->mti_env, next, buf);
279                 if (rc < 0)
280                         CDEBUG(D_INFO, "listxattr failed: %d\n", rc);
281         } else if (valid == OBD_MD_FLXATTRALL) {
282                 rc = mdt_getxattr_all(info, reqbody, repbody,
283                                       buf, next);
284         } else
285                 LBUG();
286
287         EXIT;
288 out:
289         if (rc >= 0) {
290                 mdt_counter_incr(req, LPROC_MDT_GETXATTR);
291                 repbody->mbo_eadatasize = rc;
292                 rc = 0;
293         }
294         mdt_exit_ucred(info);
295         return rc;
296 }
297
298 int mdt_reint_setxattr(struct mdt_thread_info *info,
299                        struct mdt_lock_handle *unused)
300 {
301         struct ptlrpc_request   *req = mdt_info_req(info);
302         struct mdt_lock_handle  *lh;
303         const struct lu_env     *env  = info->mti_env;
304         struct lu_buf           *buf  = &info->mti_buf;
305         struct mdt_reint_record *rr   = &info->mti_rr;
306         struct md_attr          *ma = &info->mti_attr;
307         struct lu_attr          *attr = &info->mti_attr.ma_attr;
308         struct mdt_object       *obj;
309         struct md_object        *child;
310         __u64                    valid = attr->la_valid;
311         const char              *xattr_name = rr->rr_name.ln_name;
312         int                      xattr_len = rr->rr_eadatalen;
313         __u64                    lockpart = MDS_INODELOCK_UPDATE;
314         int                      rc;
315         ENTRY;
316
317         CDEBUG(D_INODE, "setxattr for "DFID": %s %s\n", PFID(rr->rr_fid1),
318                valid & OBD_MD_FLXATTR ? "set" : "remove", xattr_name);
319
320         if (info->mti_dlm_req)
321                 ldlm_request_cancel(req, info->mti_dlm_req, 0, LATF_SKIP);
322
323         if (OBD_FAIL_CHECK(OBD_FAIL_MDS_SETXATTR))
324                 RETURN(err_serious(-ENOMEM));
325
326         rc = mdt_init_ucred_reint(info);
327         if (rc != 0)
328                 RETURN(rc);
329
330         if (strncmp(xattr_name, XATTR_USER_PREFIX,
331                     sizeof(XATTR_USER_PREFIX) - 1) == 0) {
332                 if (!(exp_connect_flags(req->rq_export) & OBD_CONNECT_XATTR))
333                         GOTO(out, rc = -EOPNOTSUPP);
334         } else if (strncmp(xattr_name, XATTR_TRUSTED_PREFIX,
335                     sizeof(XATTR_TRUSTED_PREFIX) - 1) == 0) {
336
337                 if (!md_capable(mdt_ucred(info), CFS_CAP_SYS_ADMIN))
338                         GOTO(out, rc = -EPERM);
339
340                 if (strcmp(xattr_name, XATTR_NAME_LOV) == 0 ||
341                     strcmp(xattr_name, XATTR_NAME_LMA) == 0 ||
342                     strcmp(xattr_name, XATTR_NAME_LMV) == 0 ||
343                     strcmp(xattr_name, XATTR_NAME_LINK) == 0 ||
344                     strcmp(xattr_name, XATTR_NAME_FID) == 0 ||
345                     strcmp(xattr_name, XATTR_NAME_VERSION) == 0 ||
346                     strcmp(xattr_name, XATTR_NAME_SOM) == 0 ||
347                     strcmp(xattr_name, XATTR_NAME_HSM) == 0 ||
348                     strcmp(xattr_name, XATTR_NAME_LFSCK_NAMESPACE) == 0)
349                         GOTO(out, rc = 0);
350         } else if ((valid & OBD_MD_FLXATTR) &&
351                    (strcmp(xattr_name, XATTR_NAME_ACL_ACCESS) == 0 ||
352                     strcmp(xattr_name, XATTR_NAME_ACL_DEFAULT) == 0)) {
353                 rc = mdt_nodemap_map_acl(info, rr->rr_eadata, xattr_len,
354                                          xattr_name, NODEMAP_CLIENT_TO_FS);
355                 if (rc < 0)
356                         GOTO(out, rc);
357                 /* ACLs were mapped out, return an error so the user knows */
358                 if (rc != xattr_len)
359                         GOTO(out, rc = -EPERM);
360         } else if ((strlen(xattr_name) > strlen(XATTR_LUSTRE_LOV) + 1) &&
361                    strncmp(xattr_name, XATTR_LUSTRE_LOV,
362                            strlen(XATTR_LUSTRE_LOV)) == 0) {
363
364                 if (strncmp(xattr_name, XATTR_LUSTRE_LOV".add",
365                             strlen(XATTR_LUSTRE_LOV".add")) &&
366                     strncmp(xattr_name, XATTR_LUSTRE_LOV".set",
367                             strlen(XATTR_LUSTRE_LOV".set")) &&
368                     strncmp(xattr_name, XATTR_LUSTRE_LOV".del",
369                             strlen(XATTR_LUSTRE_LOV".del"))) {
370                         CERROR("%s: invalid xattr name: %s\n",
371                                mdt_obd_name(info->mti_mdt), xattr_name);
372                         GOTO(out, rc = -EINVAL);
373                 }
374
375                 lockpart |= MDS_INODELOCK_LAYOUT;
376         }
377
378         /* Revoke all clients' lookup lock, since the access
379          * permissions for this inode is changed when ACL_ACCESS is
380          * set. This isn't needed for ACL_DEFAULT, since that does
381          * not change the access permissions of this inode, nor any
382          * other existing inodes. It is setting the ACLs inherited
383          * by new directories/files at create time. */
384         /* We need revoke both LOOKUP|PERM lock here, see mdt_attr_set. */
385         if (!strcmp(xattr_name, XATTR_NAME_ACL_ACCESS))
386                 lockpart |= MDS_INODELOCK_PERM | MDS_INODELOCK_LOOKUP;
387         /* We need to take the lock on behalf of old clients so that newer
388          * clients flush their xattr caches */
389         else
390                 lockpart |= MDS_INODELOCK_XATTR;
391
392         lh = &info->mti_lh[MDT_LH_PARENT];
393         /* ACLs were sent to clients under LCK_CR locks, so taking LCK_EX
394          * to cancel them. */
395         mdt_lock_reg_init(lh, LCK_EX);
396         obj = mdt_object_find_lock(info, rr->rr_fid1, lh, lockpart);
397         if (IS_ERR(obj))
398                 GOTO(out, rc = PTR_ERR(obj));
399
400         tgt_vbr_obj_set(env, mdt_obj2dt(obj));
401         rc = mdt_version_get_check_save(info, obj, 0);
402         if (rc)
403                 GOTO(out_unlock, rc);
404
405         if (unlikely(!(valid & OBD_MD_FLCTIME))) {
406                 /* This isn't strictly an error, but all current clients
407                  * should set OBD_MD_FLCTIME when setting attributes. */
408                 CWARN("%s: client miss to set OBD_MD_FLCTIME when "
409                       "setxattr %s: [object "DFID"] [valid %llu]\n",
410                       mdt_obd_name(info->mti_mdt), xattr_name,
411                       PFID(rr->rr_fid1), valid);
412                 attr->la_ctime = cfs_time_current_sec();
413         }
414         attr->la_valid = LA_CTIME;
415         child = mdt_object_child(obj);
416         if (valid & OBD_MD_FLXATTR) {
417                 int     flags = 0;
418
419                 if (attr->la_flags & XATTR_REPLACE)
420                         flags |= LU_XATTR_REPLACE;
421
422                 if (attr->la_flags & XATTR_CREATE)
423                         flags |= LU_XATTR_CREATE;
424
425                 mdt_fail_write(env, info->mti_mdt->mdt_bottom,
426                                OBD_FAIL_MDS_SETXATTR_WRITE);
427
428                 buf->lb_buf = rr->rr_eadata;
429                 buf->lb_len = xattr_len;
430                 rc = mo_xattr_set(env, child, buf, xattr_name, flags);
431                 /* update ctime after xattr changed */
432                 if (rc == 0) {
433                         ma->ma_attr_flags |= MDS_PERM_BYPASS;
434                         mo_attr_set(env, child, ma);
435                 }
436         } else if (valid & OBD_MD_FLXATTRRM) {
437                 rc = mo_xattr_del(env, child, xattr_name);
438                 /* update ctime after xattr changed */
439                 if (rc == 0) {
440                         ma->ma_attr_flags |= MDS_PERM_BYPASS;
441                         mo_attr_set(env, child, ma);
442                 }
443         } else {
444                 CDEBUG(D_INFO, "valid bits: %#llx\n", valid);
445                 rc = -EINVAL;
446         }
447
448         if (rc == 0)
449                 mdt_counter_incr(req, LPROC_MDT_SETXATTR);
450
451         EXIT;
452 out_unlock:
453         mdt_object_unlock_put(info, obj, lh, rc);
454 out:
455         mdt_exit_ucred(info);
456         return rc;
457 }