Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / mdt / mdt_xattr.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/mdt/mdt_xattr.c
37  *
38  * Lustre Metadata Target (mdt) extended attributes management.
39  *
40  * Author: Peter Braam <braam@clusterfs.com>
41  * Author: Andreas Dilger <adilger@clusterfs.com>
42  * Author: Phil Schwan <phil@clusterfs.com>
43  * Author: Huang Hua <huanghua@clusterfs.com>
44  */
45
46 #ifndef EXPORT_SYMTAB
47 # define EXPORT_SYMTAB
48 #endif
49 #define DEBUG_SUBSYSTEM S_MDS
50
51 /* prerequisite for linux/xattr.h */
52 #include <linux/types.h>
53 /* prerequisite for linux/xattr.h */
54 #include <linux/fs.h>
55 /* XATTR_{REPLACE,CREATE} */
56 #include <linux/xattr.h>
57
58 #include "mdt_internal.h"
59
60
61 /* return EADATA length to the caller. negative value means error */
62 static int mdt_getxattr_pack_reply(struct mdt_thread_info * info)
63 {
64         struct req_capsule     *pill = info->mti_pill ;
65         struct ptlrpc_request  *req = mdt_info_req(info);
66         char                   *xattr_name;
67         __u64                   valid = info->mti_body->valid;
68         static const char       user_string[] = "user.";
69         int                     size, rc;
70         ENTRY;
71         
72         if (OBD_FAIL_CHECK(OBD_FAIL_MDS_GETXATTR_PACK))
73                 RETURN(-ENOMEM);
74
75         /* Determine how many bytes we need */
76         if (valid & OBD_MD_FLXATTR) {
77                 xattr_name = req_capsule_client_get(pill, &RMF_NAME);
78                 if (!xattr_name)
79                         RETURN(-EFAULT);
80
81                 if (!(req->rq_export->exp_connect_flags & OBD_CONNECT_XATTR) &&
82                     !strncmp(xattr_name, user_string, sizeof(user_string) - 1))
83                         RETURN(-EOPNOTSUPP);
84                 
85                 size = mo_xattr_get(info->mti_env,
86                                     mdt_object_child(info->mti_object),
87                                     &LU_BUF_NULL, xattr_name);
88         } else if (valid & OBD_MD_FLXATTRLS) {
89                 size = mo_xattr_list(info->mti_env,
90                                      mdt_object_child(info->mti_object),
91                                      &LU_BUF_NULL);
92         } else {
93                 CDEBUG(D_INFO, "Valid bits: "LPX64"\n", info->mti_body->valid);
94                 RETURN(-EINVAL);
95         }
96
97         if (size < 0) {
98                 if (size == -ENODATA)
99                         size = 0;
100                 else if (size != -EOPNOTSUPP) {
101                         CDEBUG(D_INFO, "Error geting EA size: %d\n", size);
102                         RETURN(size);
103                 }
104         }
105
106         if (info->mti_body->eadatasize != 0 &&
107             info->mti_body->eadatasize < size)
108                 RETURN(-ERANGE);
109
110         req_capsule_set_size(pill, &RMF_EADATA, RCL_SERVER,
111                              min_t(int, size, info->mti_body->eadatasize));
112
113         rc = req_capsule_server_pack(pill);
114         if (rc) {
115                 LASSERT(rc < 0);
116                 RETURN(rc);
117         }
118
119         RETURN(size);
120 }
121
122 int mdt_getxattr(struct mdt_thread_info *info)
123 {
124         struct ptlrpc_request  *req = mdt_info_req(info);
125         struct mdt_export_data *med = mdt_req2med(req);
126         struct md_ucred        *uc  = mdt_ucred(info);
127         struct mdt_body        *reqbody;
128         struct mdt_body        *repbody = NULL;
129         struct md_object       *next;
130         struct lu_buf          *buf;
131         __u32                   remote = exp_connect_rmtclient(info->mti_exp);
132         __u32                   perm;
133         int                     easize, rc;
134         ENTRY;
135
136         LASSERT(info->mti_object != NULL);
137         LASSERT(lu_object_assert_exists(&info->mti_object->mot_obj.mo_lu));
138
139         CDEBUG(D_INODE, "getxattr "DFID"\n", PFID(&info->mti_body->fid1));
140
141         reqbody = req_capsule_client_get(info->mti_pill, &RMF_MDT_BODY);
142         if (reqbody == NULL)
143                 RETURN(err_serious(-EFAULT));
144
145         rc = mdt_init_ucred(info, reqbody);
146         if (rc)
147                 RETURN(err_serious(rc));
148
149         next = mdt_object_child(info->mti_object);
150
151         if (info->mti_body->valid & OBD_MD_FLRMTRGETFACL) {
152                 if (unlikely(!remote))
153                         GOTO(out, rc = err_serious(-EINVAL));
154
155                 perm = mdt_identity_get_perm(uc->mu_identity, remote,
156                                              req->rq_peer.nid);
157                 if (!(perm & CFS_RMTACL_PERM))
158                         GOTO(out, rc = err_serious(-EPERM));
159
160                 rc = mo_permission(info->mti_env, NULL, next, NULL,
161                                    MAY_RGETFACL);
162                 if (rc)
163                         GOTO(out, rc = err_serious(rc));
164         }
165
166         easize = mdt_getxattr_pack_reply(info);
167         if (easize < 0)
168                 GOTO(out, rc = err_serious(easize));
169
170         repbody = req_capsule_server_get(info->mti_pill, &RMF_MDT_BODY);
171         LASSERT(repbody != NULL);
172
173         /* No need further getxattr. */
174         if (easize == 0 || reqbody->eadatasize == 0)
175                 GOTO(out, rc = easize);
176
177         buf = &info->mti_buf;
178         buf->lb_buf = req_capsule_server_get(info->mti_pill, &RMF_EADATA);
179         buf->lb_len = easize;
180
181         if (info->mti_body->valid & OBD_MD_FLXATTR) {
182                 int flags = CFS_IC_NOTHING;
183                 char *xattr_name = req_capsule_client_get(info->mti_pill,
184                                                           &RMF_NAME);
185                 CDEBUG(D_INODE, "getxattr %s\n", xattr_name);
186
187                 rc = mo_xattr_get(info->mti_env, next, buf, xattr_name);
188                 if (rc < 0) {
189                         CERROR("getxattr failed: %d\n", rc);
190                         GOTO(out, rc);
191                 }
192
193                 if (info->mti_body->valid &
194                     (OBD_MD_FLRMTLSETFACL | OBD_MD_FLRMTLGETFACL))
195                         flags = CFS_IC_ALL;
196                 else if (info->mti_body->valid & OBD_MD_FLRMTRGETFACL)
197                         flags = CFS_IC_MAPPED;
198
199                 if (rc > 0 && flags != CFS_IC_NOTHING) {
200                         int rc1;
201
202                         if (unlikely(!remote))
203                                 GOTO(out, rc = -EINVAL);
204
205                         rc1 = lustre_posix_acl_xattr_id2client(uc,
206                                         med->med_idmap,
207                                         (posix_acl_xattr_header *)(buf->lb_buf),
208                                         rc, flags);
209                         if (unlikely(rc1 < 0))
210                                 rc = rc1;
211                 }
212         } else if (info->mti_body->valid & OBD_MD_FLXATTRLS) {
213                 CDEBUG(D_INODE, "listxattr\n");
214
215                 rc = mo_xattr_list(info->mti_env, next, buf);
216                 if (rc < 0)
217                         CDEBUG(D_INFO, "listxattr failed: %d\n", rc);
218         } else
219                 LBUG();
220
221         EXIT;
222 out:
223         if (rc >= 0) {
224                 repbody->eadatasize = rc;
225                 rc = 0;
226         }
227         mdt_exit_ucred(info);
228         return rc;
229 }
230
231 static int mdt_rmtlsetfacl(struct mdt_thread_info *info,
232                            struct md_object *next,
233                            const char *xattr_name,
234                            ext_acl_xattr_header *header,
235                            posix_acl_xattr_header **out)
236 {
237         struct ptlrpc_request  *req = mdt_info_req(info);
238         struct mdt_export_data *med = mdt_req2med(req);
239         struct md_ucred        *uc = mdt_ucred(info);
240         struct lu_buf          *buf = &info->mti_buf;
241         int                     rc;
242         ENTRY;
243
244         rc = lustre_ext_acl_xattr_id2server(uc, med->med_idmap, header);
245         if (rc)
246                 RETURN(rc);
247  
248         rc = mo_xattr_get(info->mti_env, next, &LU_BUF_NULL, xattr_name);
249         if (rc == -ENODATA)
250                 rc = 0;
251         else if (rc < 0)
252                 RETURN(rc);
253
254         buf->lb_len = rc;
255         if (buf->lb_len > 0) {
256                 OBD_ALLOC(buf->lb_buf, buf->lb_len);
257                 if (unlikely(buf->lb_buf == NULL))
258                         RETURN(-ENOMEM);
259
260                 rc = mo_xattr_get(info->mti_env, next, buf, xattr_name);
261                 if (rc < 0) {
262                         CERROR("getxattr failed: %d\n", rc);
263                         GOTO(_out, rc);
264                 }
265         } else
266                 buf->lb_buf = NULL;
267
268         rc = lustre_acl_xattr_merge2posix((posix_acl_xattr_header *)(buf->lb_buf),
269                                           buf->lb_len, header, out);
270         EXIT;
271
272 _out:
273         if (rc <= 0 && buf->lb_buf != NULL)
274                 OBD_FREE(buf->lb_buf, buf->lb_len);
275         return rc;
276 }
277
278 int mdt_reint_setxattr(struct mdt_thread_info *info,
279                        struct mdt_lock_handle *unused)
280 {
281         struct ptlrpc_request   *req = mdt_info_req(info);
282         struct md_ucred         *uc  = mdt_ucred(info);
283         struct mdt_lock_handle  *lh;
284         struct req_capsule      *pill = info->mti_pill;
285         const struct lu_env     *env  = info->mti_env;
286         struct lu_buf           *buf  = &info->mti_buf;
287         struct mdt_reint_record *rr   = &info->mti_rr;
288         struct md_attr          *ma = &info->mti_attr;
289         struct lu_attr          *attr = &info->mti_attr.ma_attr;
290         struct mdt_object       *obj; 
291         struct md_object        *child;
292         __u64                    valid = attr->la_valid;
293         const char              *xattr_name;
294         int                      xattr_len = 0;
295         __u64                    lockpart;
296         int                      rc;
297         posix_acl_xattr_header  *new_xattr = NULL;
298         __u32                    remote = exp_connect_rmtclient(info->mti_exp);
299         __u32                    perm;
300         ENTRY;
301
302         CDEBUG(D_INODE, "setxattr for "DFID"\n", PFID(rr->rr_fid1));
303
304         if (OBD_FAIL_CHECK(OBD_FAIL_MDS_SETXATTR))
305                 RETURN(err_serious(-ENOMEM));
306
307         xattr_name = rr->rr_name;
308
309         CDEBUG(D_INODE, "%s xattr %s\n",
310                valid & OBD_MD_FLXATTR ? "set" : "remove", xattr_name);
311
312         rc = mdt_init_ucred_reint(info);
313         if (rc != 0)
314                 RETURN(rc);
315
316         if (valid & OBD_MD_FLRMTRSETFACL) {
317                 if (unlikely(!remote))
318                         GOTO(out, rc = err_serious(-EINVAL));
319
320                 perm = mdt_identity_get_perm(uc->mu_identity, remote,
321                                              req->rq_peer.nid);
322                 if (!(perm & CFS_RMTACL_PERM))
323                         GOTO(out, rc = err_serious(-EPERM));
324         }
325
326         /* various sanity check for xattr name */
327         xattr_name = req_capsule_client_get(pill, &RMF_NAME);
328         if (!xattr_name)
329                 GOTO(out, rc = err_serious(-EFAULT));
330
331         if (strncmp(xattr_name, XATTR_USER_PREFIX,
332                     sizeof(XATTR_USER_PREFIX) - 1) == 0) {
333                 if (strcmp(xattr_name, XATTR_NAME_LOV) == 0)
334                         GOTO(out, rc = -EACCES);
335                 if (strcmp(xattr_name, XATTR_NAME_LMA) == 0)
336                         GOTO(out, rc = 0);
337                 if (strcmp(xattr_name, XATTR_NAME_LINK) == 0)
338                         GOTO(out, rc = 0);
339         }
340
341         if (!(req->rq_export->exp_connect_flags & OBD_CONNECT_XATTR) &&
342             (strncmp(xattr_name, XATTR_USER_PREFIX,
343                      sizeof(XATTR_USER_PREFIX) - 1) == 0)) {
344                 GOTO(out, rc = -EOPNOTSUPP);
345         }
346
347         lockpart = MDS_INODELOCK_UPDATE;
348         if (!strcmp(xattr_name, XATTR_NAME_ACL_ACCESS))
349                 lockpart |= MDS_INODELOCK_LOOKUP;
350
351         lh = &info->mti_lh[MDT_LH_PARENT];
352         mdt_lock_reg_init(lh, LCK_PW);
353         obj = mdt_object_find_lock(info, rr->rr_fid1, lh, lockpart);
354         if (IS_ERR(obj))
355                 GOTO(out, rc =  PTR_ERR(obj));
356
357         if (unlikely(!(valid & OBD_MD_FLCTIME))) {
358                 CWARN("client miss to set OBD_MD_FLCTIME when "
359                       "setxattr: [object "DFID"] [valid %llu]\n",
360                       PFID(rr->rr_fid1), valid);
361                 attr->la_ctime = cfs_time_current_sec();
362         }
363         attr->la_valid = LA_CTIME;
364         child = mdt_object_child(obj);
365         if (valid & OBD_MD_FLXATTR) {
366                 char * xattr;
367
368                 if (!req_capsule_field_present(pill, &RMF_EADATA, RCL_CLIENT)) {
369                         CDEBUG(D_INFO, "no xattr data supplied\n");
370                         GOTO(out_unlock, rc = -EFAULT);
371                 }
372
373                 xattr_len = req_capsule_get_size(pill, &RMF_EADATA, RCL_CLIENT);
374                 if (xattr_len) {
375                         int flags = 0;
376
377                         xattr = req_capsule_client_get(pill, &RMF_EADATA);
378
379                         if (valid & OBD_MD_FLRMTLSETFACL) {
380                                 if (unlikely(!remote))
381                                         GOTO(out_unlock, rc = -EINVAL);
382
383                                 xattr_len = mdt_rmtlsetfacl(info, child,
384                                                 xattr_name,
385                                                 (ext_acl_xattr_header *)xattr,
386                                                 &new_xattr);
387                                 if (xattr_len < 0)
388                                         GOTO(out_unlock, rc = xattr_len);
389
390                                 xattr = (char *)new_xattr;
391                         }
392
393                         if (attr->la_flags & XATTR_REPLACE)
394                                 flags |= LU_XATTR_REPLACE;
395
396                         if (attr->la_flags & XATTR_CREATE)
397                                 flags |= LU_XATTR_CREATE;
398
399                         mdt_fail_write(env, info->mti_mdt->mdt_bottom,
400                                        OBD_FAIL_MDS_SETXATTR_WRITE);
401
402                         buf->lb_buf = xattr;
403                         buf->lb_len = xattr_len;
404                         rc = mo_xattr_set(env, child, buf, xattr_name, flags);
405                         /* update ctime after xattr changed */
406                         if (rc == 0) {
407                                 ma->ma_attr_flags |= MDS_PERM_BYPASS;
408                                 mo_attr_set(env, child, ma);
409                         }
410                 }
411         } else if (valid & OBD_MD_FLXATTRRM) {
412                 rc = mo_xattr_del(env, child, xattr_name);
413                 /* update ctime after xattr changed */
414                 if (rc == 0) {
415                         ma->ma_attr_flags |= MDS_PERM_BYPASS;
416                         mo_attr_set(env, child, ma);
417                 }
418         } else {
419                 CDEBUG(D_INFO, "valid bits: "LPX64"\n", valid);
420                 rc = -EINVAL;
421         }
422         EXIT;
423 out_unlock:
424         mdt_object_unlock_put(info, obj, lh, rc);
425         if (unlikely(new_xattr != NULL))
426                 lustre_posix_acl_xattr_free(new_xattr, xattr_len);
427 out:
428         mdt_exit_ucred(info);
429         return rc;
430 }