1 /* -*- MODE: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
5 * Lustre Metadata Server (mdd) routines
7 * Copyright (C) 2006 Cluster File Systems, Inc.
8 * Author: fangyong@clusterfs.com
10 * This file is part of the Lustre file system, http://www.lustre.org
11 * Lustre is a trademark of Cluster File Systems, Inc.
13 * You may have signed or agreed to another license before downloading
14 * this software. If so, you are bound by the terms and conditions
15 * of that agreement, and the following does not apply to you. See the
16 * LICENSE file included with this distribution for more information.
18 * If you did not agree to a different license, then this copy of Lustre
19 * is open source software; you can redistribute it and/or modify it
20 * under the terms of version 2 of the GNU General Public License as
21 * published by the Free Software Foundation.
23 * In either case, Lustre is distributed in the hope that it will be
24 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
25 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * license text for more details.
29 # define EXPORT_SYMTAB
31 #define DEBUG_SUBSYSTEM S_MDS
33 #include <linux/module.h>
34 #include <linux/jbd.h>
36 #include <obd_class.h>
37 #include <lustre_ver.h>
38 #include <obd_support.h>
39 #include <lprocfs_status.h>
41 #include <linux/ldiskfs_fs.h>
42 #include <lustre_mds.h>
43 #include <lustre/lustre_idl.h>
45 #include "mdd_internal.h"
47 #ifdef CONFIG_FS_POSIX_ACL
50 * Get default acl EA only.
51 * Hold read_lock for mdd_obj.
53 int mdd_acl_def_get(const struct lu_env *env, struct mdd_object *mdd_obj,
60 if (ma->ma_valid & MA_ACL_DEF)
63 buf = mdd_buf_get(env, ma->ma_acl, ma->ma_acl_size);
64 rc = mdo_xattr_get(env, mdd_obj, buf, XATTR_NAME_ACL_DEFAULT,
68 ma->ma_valid |= MA_ACL_DEF;
70 } else if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) {
77 * Hold write_lock for o.
79 int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode,
80 struct thandle *handle)
83 posix_acl_xattr_header *head;
84 posix_acl_xattr_entry *entry;
90 buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf,
91 sizeof(mdd_env_info(env)->mti_xattr_buf));
93 rc = mdo_xattr_get(env, o, buf, XATTR_NAME_ACL_ACCESS, BYPASS_CAPA);
94 if ((rc == -EOPNOTSUPP) || (rc == -ENODATA))
100 head = (posix_acl_xattr_header *)(buf->lb_buf);
101 entry = head->a_entries;
102 entry_count = (buf->lb_len - sizeof(head->a_version)) /
103 sizeof(posix_acl_xattr_entry);
104 if (entry_count <= 0)
107 rc = lustre_posix_acl_chmod_masq(entry, mode, entry_count);
111 rc = mdo_xattr_set(env, o, buf, XATTR_NAME_ACL_ACCESS,
112 0, handle, BYPASS_CAPA);
117 * Hold write_lock for obj.
119 int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj,
120 struct lu_buf *buf, __u32 *mode, struct thandle *handle)
122 posix_acl_xattr_header *head;
123 posix_acl_xattr_entry *entry;
129 head = (posix_acl_xattr_header *)(buf->lb_buf);
130 entry = head->a_entries;
131 entry_count = (buf->lb_len - sizeof(head->a_version)) /
132 sizeof(posix_acl_xattr_entry);
133 if (entry_count <= 0)
136 if (S_ISDIR(*mode)) {
137 rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_DEFAULT, 0,
138 handle, BYPASS_CAPA);
143 rc = lustre_posix_acl_create_masq(entry, mode, entry_count);
147 rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_ACCESS, 0, handle,
153 * Hold read_lock for pobj.
154 * Hold write_lock for cobj.
156 int mdd_acl_init(const struct lu_env *env, struct mdd_object *pobj,
157 struct mdd_object *cobj, __u32 *mode, struct thandle *handle)
166 buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf,
167 sizeof(mdd_env_info(env)->mti_xattr_buf));
168 rc = mdo_xattr_get(env, pobj, buf, XATTR_NAME_ACL_DEFAULT, BYPASS_CAPA);
169 if ((rc == -EOPNOTSUPP) || (rc == -ENODATA))
175 rc = __mdd_acl_init(env, cobj, buf, mode, handle);
181 * Hold read_lock for obj.
183 static int mdd_check_acl(const struct lu_env *env, struct mdd_object *obj,
184 struct lu_attr *la, int mask)
186 #ifdef CONFIG_FS_POSIX_ACL
187 struct md_ucred *uc = md_ucred(env);
188 posix_acl_xattr_header *head;
189 posix_acl_xattr_entry *entry;
195 buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf,
196 sizeof(mdd_env_info(env)->mti_xattr_buf));
197 rc = mdo_xattr_get(env, obj, buf, XATTR_NAME_ACL_ACCESS,
198 mdd_object_capa(env, obj));
200 RETURN(rc ? : -EACCES);
203 head = (posix_acl_xattr_header *)(buf->lb_buf);
204 entry = head->a_entries;
205 entry_count = (buf->lb_len - sizeof(head->a_version)) /
206 sizeof(posix_acl_xattr_entry);
208 rc = lustre_posix_acl_permission(uc, la, mask, entry, entry_count);
216 int __mdd_permission_internal(const struct lu_env *env, struct mdd_object *obj,
217 struct lu_attr *la, int mask, int needlock)
219 struct md_ucred *uc = md_ucred(env);
227 /* These means unnecessary for permission check */
228 if ((uc == NULL) || (uc->mu_valid == UCRED_INIT))
231 /* Invalid user credit */
232 if (uc->mu_valid == UCRED_INVALID)
236 * Nobody gets write access to an immutable file.
238 if ((mask & MAY_WRITE) && mdd_is_immutable(obj))
242 la = &mdd_env_info(env)->mti_la;
243 rc = mdd_la_get(env, obj, la, BYPASS_CAPA);
249 if (uc->mu_fsuid == la->la_uid) {
252 if (mode & S_IRWXG) {
254 mdd_read_lock(env, obj);
255 rc = mdd_check_acl(env, obj, la, mask);
257 mdd_read_unlock(env, obj);
259 goto check_capabilities;
260 else if ((rc != -EAGAIN) && (rc != -EOPNOTSUPP) &&
264 if (lustre_in_group_p(uc, la->la_gid))
268 if (((mode & mask & S_IRWXO) == mask))
272 if (!(mask & MAY_EXEC) ||
273 (la->la_mode & S_IXUGO) || S_ISDIR(la->la_mode))
274 if (mdd_capable(uc, CAP_DAC_OVERRIDE))
277 if ((mask == MAY_READ) ||
278 (S_ISDIR(la->la_mode) && !(mask & MAY_WRITE)))
279 if (mdd_capable(uc, CAP_DAC_READ_SEARCH))
285 int mdd_permission(const struct lu_env *env,
286 struct md_object *pobj, struct md_object *cobj,
287 struct md_attr *ma, int mask)
289 struct mdd_object *mdd_pobj, *mdd_cobj;
290 struct md_ucred *uc = NULL;
291 struct lu_attr *la = NULL;
292 int check_create, check_link;
294 int check_rename_src, check_rename_tar;
295 int check_vtx_part, check_vtx_full;
301 mdd_cobj = md2mdd_obj(cobj);
303 /* For cross_open case, the "mask" is open flags,
304 * so convert it to permission mask first.
305 * XXX: MDS_OPEN_CROSS must be NOT equal to permission mask MAY_*. */
306 if (unlikely(mask & MDS_OPEN_CROSS)) {
307 la = &mdd_env_info(env)->mti_la;
308 rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA);
312 mask = accmode(env, la, mask & ~MDS_OPEN_CROSS);
315 check_create = mask & MAY_CREATE;
316 check_link = mask & MAY_LINK;
317 check_unlink = mask & MAY_UNLINK;
318 check_rename_src = mask & MAY_RENAME_SRC;
319 check_rename_tar = mask & MAY_RENAME_TAR;
320 check_vtx_part = mask & MAY_VTX_PART;
321 check_vtx_full = mask & MAY_VTX_FULL;
322 check_rgetfacl = mask & MAY_RGETFACL;
324 mask &= ~(MAY_CREATE | MAY_LINK |
326 MAY_RENAME_SRC | MAY_RENAME_TAR |
327 MAY_VTX_PART | MAY_VTX_FULL |
330 rc = mdd_permission_internal_locked(env, mdd_cobj, NULL, mask);
332 if (!rc && (check_create || check_link))
333 rc = mdd_may_create(env, mdd_cobj, NULL, 1, check_link);
335 if (!rc && check_unlink) {
337 rc = mdd_may_unlink(env, mdd_cobj, ma);
340 if (!rc && (check_rename_src || check_rename_tar)) {
343 mdd_pobj = md2mdd_obj(pobj);
344 rc = mdd_may_delete(env, mdd_pobj, mdd_cobj, ma, 1,
348 if (!rc && (check_vtx_part || check_vtx_full)) {
352 la = &mdd_env_info(env)->mti_la;
353 rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA);
358 if (!(la->la_mode & S_ISVTX) || (la->la_uid == uc->mu_fsuid) ||
359 (check_vtx_full && (ma->ma_attr.la_valid & LA_UID) &&
360 (ma->ma_attr.la_uid == uc->mu_fsuid))) {
361 ma->ma_attr_flags |= MDS_VTX_BYPASS;
363 ma->ma_attr_flags &= ~MDS_VTX_BYPASS;
369 if (unlikely(!rc && check_rgetfacl)) {
374 la = &mdd_env_info(env)->mti_la;
375 rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA);
380 if (la->la_uid != uc->mu_fsuid && !mdd_capable(uc, CAP_FOWNER))
387 int mdd_capa_get(const struct lu_env *env, struct md_object *obj,
388 struct lustre_capa *capa, int renewal)
390 struct mdd_object *mdd_obj = md2mdd_obj(obj);
395 oc = mdo_capa_get(env, mdd_obj, renewal ? capa : NULL,