2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
3 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
5 * This copyrighted material is made available to anyone wishing to use,
6 * modify, copy, or redistribute it subject to the terms and conditions
7 * of the GNU General Public License version 2.
10 #include <linux/sched.h>
11 #include <linux/slab.h>
12 #include <linux/spinlock.h>
13 #include <linux/completion.h>
14 #include <linux/buffer_head.h>
15 #include <linux/posix_acl.h>
16 #include <linux/posix_acl_xattr.h>
17 #include <linux/gfs2_ondisk.h>
18 #include <linux/lm_interface.h>
34 int gfs2_acl_validate_set(struct gfs2_inode
*ip
, int access
,
35 struct gfs2_ea_request
*er
,
36 int *remove
, mode_t
*mode
)
38 struct posix_acl
*acl
;
41 error
= gfs2_acl_validate_remove(ip
, access
);
48 acl
= posix_acl_from_xattr(er
->er_data
, er
->er_data_len
);
56 error
= posix_acl_valid(acl
);
61 error
= posix_acl_equiv_mode(acl
, mode
);
69 posix_acl_release(acl
);
73 int gfs2_acl_validate_remove(struct gfs2_inode
*ip
, int access
)
75 if (!GFS2_SB(&ip
->i_inode
)->sd_args
.ar_posix_acl
)
77 if (current
->fsuid
!= ip
->i_di
.di_uid
&& !capable(CAP_FOWNER
))
79 if (S_ISLNK(ip
->i_di
.di_mode
))
81 if (!access
&& !S_ISDIR(ip
->i_di
.di_mode
))
87 static int acl_get(struct gfs2_inode
*ip
, int access
, struct posix_acl
**acl
,
88 struct gfs2_ea_location
*el
, char **data
, unsigned int *len
)
90 struct gfs2_ea_request er
;
91 struct gfs2_ea_location el_this
;
94 if (!ip
->i_di
.di_eattr
)
97 memset(&er
, 0, sizeof(struct gfs2_ea_request
));
99 er
.er_name
= GFS2_POSIX_ACL_ACCESS
;
100 er
.er_name_len
= GFS2_POSIX_ACL_ACCESS_LEN
;
102 er
.er_name
= GFS2_POSIX_ACL_DEFAULT
;
103 er
.er_name_len
= GFS2_POSIX_ACL_DEFAULT_LEN
;
105 er
.er_type
= GFS2_EATYPE_SYS
;
110 error
= gfs2_ea_find(ip
, &er
, el
);
115 if (!GFS2_EA_DATA_LEN(el
->el_ea
))
118 er
.er_data_len
= GFS2_EA_DATA_LEN(el
->el_ea
);
119 er
.er_data
= kmalloc(er
.er_data_len
, GFP_KERNEL
);
124 error
= gfs2_ea_get_copy(ip
, el
, er
.er_data
);
129 *acl
= posix_acl_from_xattr(er
.er_data
, er
.er_data_len
);
131 error
= PTR_ERR(*acl
);
139 *len
= er
.er_data_len
;
142 if (error
|| el
== &el_this
)
148 * gfs2_check_acl_locked - Check an ACL to see if we're allowed to do something
149 * @inode: the file we want to do something to
150 * @mask: what we want to do
155 int gfs2_check_acl_locked(struct inode
*inode
, int mask
)
157 struct posix_acl
*acl
= NULL
;
160 error
= acl_get(GFS2_I(inode
), ACL_ACCESS
, &acl
, NULL
, NULL
, NULL
);
165 error
= posix_acl_permission(inode
, acl
, mask
);
166 posix_acl_release(acl
);
173 int gfs2_check_acl(struct inode
*inode
, int mask
)
175 struct gfs2_inode
*ip
= GFS2_I(inode
);
176 struct gfs2_holder i_gh
;
179 error
= gfs2_glock_nq_init(ip
->i_gl
, LM_ST_SHARED
, LM_FLAG_ANY
, &i_gh
);
181 error
= gfs2_check_acl_locked(inode
, mask
);
182 gfs2_glock_dq_uninit(&i_gh
);
188 static int munge_mode(struct gfs2_inode
*ip
, mode_t mode
)
190 struct gfs2_sbd
*sdp
= GFS2_SB(&ip
->i_inode
);
191 struct buffer_head
*dibh
;
194 error
= gfs2_trans_begin(sdp
, RES_DINODE
, 0);
198 error
= gfs2_meta_inode_buffer(ip
, &dibh
);
200 gfs2_assert_withdraw(sdp
,
201 (ip
->i_di
.di_mode
& S_IFMT
) == (mode
& S_IFMT
));
202 ip
->i_di
.di_mode
= mode
;
203 gfs2_trans_add_bh(ip
->i_gl
, dibh
, 1);
204 gfs2_dinode_out(&ip
->i_di
, dibh
->b_data
);
213 int gfs2_acl_create(struct gfs2_inode
*dip
, struct gfs2_inode
*ip
)
215 struct gfs2_sbd
*sdp
= GFS2_SB(&dip
->i_inode
);
216 struct posix_acl
*acl
= NULL
, *clone
;
217 struct gfs2_ea_request er
;
218 mode_t mode
= ip
->i_di
.di_mode
;
221 if (!sdp
->sd_args
.ar_posix_acl
)
223 if (S_ISLNK(ip
->i_di
.di_mode
))
226 memset(&er
, 0, sizeof(struct gfs2_ea_request
));
227 er
.er_type
= GFS2_EATYPE_SYS
;
229 error
= acl_get(dip
, ACL_DEFAULT
, &acl
, NULL
,
230 &er
.er_data
, &er
.er_data_len
);
234 mode
&= ~current
->fs
->umask
;
235 if (mode
!= ip
->i_di
.di_mode
)
236 error
= munge_mode(ip
, mode
);
240 clone
= posix_acl_clone(acl
, GFP_KERNEL
);
244 posix_acl_release(acl
);
247 if (S_ISDIR(ip
->i_di
.di_mode
)) {
248 er
.er_name
= GFS2_POSIX_ACL_DEFAULT
;
249 er
.er_name_len
= GFS2_POSIX_ACL_DEFAULT_LEN
;
250 error
= gfs2_system_eaops
.eo_set(ip
, &er
);
255 error
= posix_acl_create_masq(acl
, &mode
);
259 er
.er_name
= GFS2_POSIX_ACL_ACCESS
;
260 er
.er_name_len
= GFS2_POSIX_ACL_ACCESS_LEN
;
261 posix_acl_to_xattr(acl
, er
.er_data
, er
.er_data_len
);
263 er
.er_flags
= GFS2_ERF_MODE
;
264 error
= gfs2_system_eaops
.eo_set(ip
, &er
);
268 munge_mode(ip
, mode
);
271 posix_acl_release(acl
);
276 int gfs2_acl_chmod(struct gfs2_inode
*ip
, struct iattr
*attr
)
278 struct posix_acl
*acl
= NULL
, *clone
;
279 struct gfs2_ea_location el
;
284 error
= acl_get(ip
, ACL_ACCESS
, &acl
, &el
, &data
, &len
);
288 return gfs2_setattr_simple(ip
, attr
);
290 clone
= posix_acl_clone(acl
, GFP_KERNEL
);
294 posix_acl_release(acl
);
297 error
= posix_acl_chmod_masq(acl
, attr
->ia_mode
);
299 posix_acl_to_xattr(acl
, data
, len
);
300 error
= gfs2_ea_acl_chmod(ip
, &el
, attr
, data
);
304 posix_acl_release(acl
);