These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / lustre / lustre / obdclass / acl.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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2012, Intel Corporation.
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/obdclass/acl.c
37  *
38  * Lustre Access Control List.
39  *
40  * Author: Fan Yong <fanyong@clusterfs.com>
41  */
42
43 #define DEBUG_SUBSYSTEM S_SEC
44 #include "../include/lu_object.h"
45 #include "../include/lustre_acl.h"
46 #include "../include/lustre_eacl.h"
47 #include "../include/obd_support.h"
48
49 #ifdef CONFIG_FS_POSIX_ACL
50
51 #define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION
52
53 enum {
54         ES_UNK  = 0,    /* unknown stat */
55         ES_UNC  = 1,    /* ACL entry is not changed */
56         ES_MOD  = 2,    /* ACL entry is modified */
57         ES_ADD  = 3,    /* ACL entry is added */
58         ES_DEL  = 4     /* ACL entry is deleted */
59 };
60
61 static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry *d,
62                                             ext_acl_xattr_entry *s)
63 {
64         d->e_tag        = le16_to_cpu(s->e_tag);
65         d->e_perm       = le16_to_cpu(s->e_perm);
66         d->e_id  = le32_to_cpu(s->e_id);
67         d->e_stat       = le32_to_cpu(s->e_stat);
68 }
69
70 static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry *d,
71                                             ext_acl_xattr_entry *s)
72 {
73         d->e_tag        = cpu_to_le16(s->e_tag);
74         d->e_perm       = cpu_to_le16(s->e_perm);
75         d->e_id  = cpu_to_le32(s->e_id);
76         d->e_stat       = cpu_to_le32(s->e_stat);
77 }
78
79 static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d,
80                                               posix_acl_xattr_entry *s)
81 {
82         d->e_tag        = le16_to_cpu(s->e_tag);
83         d->e_perm       = le16_to_cpu(s->e_perm);
84         d->e_id  = le32_to_cpu(s->e_id);
85 }
86
87 static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d,
88                                               posix_acl_xattr_entry *s)
89 {
90         d->e_tag        = cpu_to_le16(s->e_tag);
91         d->e_perm       = cpu_to_le16(s->e_perm);
92         d->e_id  = cpu_to_le32(s->e_id);
93 }
94
95 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
96 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
97                                                int old_count, int new_count)
98 {
99         int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr);
100         int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr);
101         posix_acl_xattr_header *new;
102
103         if (unlikely(old_count <= new_count))
104                 return old_size;
105
106         new = kmemdup(*header, new_size, GFP_NOFS);
107         if (unlikely(new == NULL))
108                 return -ENOMEM;
109
110         kfree(*header);
111         *header = new;
112         return new_size;
113 }
114
115 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
116 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
117                                              int old_count)
118 {
119         int ext_count = le32_to_cpu((*header)->a_count);
120         int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
121         ext_acl_xattr_header *new;
122
123         if (unlikely(old_count <= ext_count))
124                 return 0;
125
126         new = kmemdup(*header, ext_size, GFP_NOFS);
127         if (unlikely(new == NULL))
128                 return -ENOMEM;
129
130         kfree(*header);
131         *header = new;
132         return 0;
133 }
134
135 /*
136  * Generate new extended ACL based on the posix ACL.
137  */
138 ext_acl_xattr_header *
139 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
140 {
141         int count, i, esize;
142         ext_acl_xattr_header *new;
143
144         if (unlikely(size < 0))
145                 return ERR_PTR(-EINVAL);
146         else if (!size)
147                 count = 0;
148         else
149                 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
150         esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
151         new = kzalloc(esize, GFP_NOFS);
152         if (unlikely(new == NULL))
153                 return ERR_PTR(-ENOMEM);
154
155         new->a_count = cpu_to_le32(count);
156         for (i = 0; i < count; i++) {
157                 new->a_entries[i].e_tag  = header->a_entries[i].e_tag;
158                 new->a_entries[i].e_perm = header->a_entries[i].e_perm;
159                 new->a_entries[i].e_id   = header->a_entries[i].e_id;
160                 new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
161         }
162
163         return new;
164 }
165 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
166
167 /*
168  * Filter out the "nobody" entries in the posix ACL.
169  */
170 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, size_t size,
171                                   posix_acl_xattr_header **out)
172 {
173         int count, i, j, rc = 0;
174         __u32 id;
175         posix_acl_xattr_header *new;
176
177         if (!size)
178                 return 0;
179         if (size < sizeof(*new))
180                 return -EINVAL;
181
182         new = kzalloc(size, GFP_NOFS);
183         if (unlikely(new == NULL))
184                 return -ENOMEM;
185
186         new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
187         count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
188         for (i = 0, j = 0; i < count; i++) {
189                 id = le32_to_cpu(header->a_entries[i].e_id);
190                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
191                 case ACL_USER_OBJ:
192                 case ACL_GROUP_OBJ:
193                 case ACL_MASK:
194                 case ACL_OTHER:
195                         if (id != ACL_UNDEFINED_ID) {
196                                 rc = -EIO;
197                                 goto _out;
198                         }
199
200                         memcpy(&new->a_entries[j++], &header->a_entries[i],
201                                sizeof(posix_acl_xattr_entry));
202                         break;
203                 case ACL_USER:
204                         if (id != NOBODY_UID)
205                                 memcpy(&new->a_entries[j++],
206                                        &header->a_entries[i],
207                                        sizeof(posix_acl_xattr_entry));
208                         break;
209                 case ACL_GROUP:
210                         if (id != NOBODY_GID)
211                                 memcpy(&new->a_entries[j++],
212                                        &header->a_entries[i],
213                                        sizeof(posix_acl_xattr_entry));
214                         break;
215                 default:
216                         rc = -EIO;
217                         goto _out;
218                 }
219         }
220
221         /* free unused space. */
222         rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
223         if (rc >= 0) {
224                 size = rc;
225                 *out = new;
226                 rc = 0;
227         }
228
229 _out:
230         if (rc) {
231                 kfree(new);
232                 size = rc;
233         }
234         return size;
235 }
236 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
237
238 /*
239  * Release the posix ACL space.
240  */
241 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
242 {
243         kfree(header);
244 }
245 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
246
247 /*
248  * Release the extended ACL space.
249  */
250 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
251 {
252         kfree(header);
253 }
254 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
255
256 static ext_acl_xattr_entry *
257 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
258                             posix_acl_xattr_entry *entry, int *pos)
259 {
260         int once, start, end, i, j, count = le32_to_cpu(header->a_count);
261
262         once = 0;
263         start = *pos;
264         end = count;
265
266 again:
267         for (i = start; i < end; i++) {
268                 if (header->a_entries[i].e_tag == entry->e_tag &&
269                     header->a_entries[i].e_id == entry->e_id) {
270                         j = i;
271                         if (++i >= count)
272                                 i = 0;
273                         *pos = i;
274                         return &header->a_entries[j];
275                 }
276         }
277
278         if (!once) {
279                 once = 1;
280                 start = 0;
281                 end = *pos;
282                 goto again;
283         }
284
285         return NULL;
286 }
287
288 /*
289  * Merge the posix ACL and the extended ACL into new extended ACL.
290  */
291 ext_acl_xattr_header *
292 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
293                            ext_acl_xattr_header *ext_header)
294 {
295         int ori_ext_count, posix_count, ext_count, ext_size;
296         int i, j, pos = 0, rc = 0;
297         posix_acl_xattr_entry pae;
298         ext_acl_xattr_header *new;
299         ext_acl_xattr_entry *ee, eae;
300
301         if (unlikely(size < 0))
302                 return ERR_PTR(-EINVAL);
303         else if (!size)
304                 posix_count = 0;
305         else
306                 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
307         ori_ext_count = le32_to_cpu(ext_header->a_count);
308         ext_count = posix_count + ori_ext_count;
309         ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
310
311         new = kzalloc(ext_size, GFP_NOFS);
312         if (unlikely(new == NULL))
313                 return ERR_PTR(-ENOMEM);
314
315         for (i = 0, j = 0; i < posix_count; i++) {
316                 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
317                 switch (pae.e_tag) {
318                 case ACL_USER_OBJ:
319                 case ACL_GROUP_OBJ:
320                 case ACL_MASK:
321                 case ACL_OTHER:
322                         if (pae.e_id != ACL_UNDEFINED_ID) {
323                                 rc = -EIO;
324                                 goto out;
325                 }
326                 case ACL_USER:
327                         /* ignore "nobody" entry. */
328                         if (pae.e_id == NOBODY_UID)
329                                 break;
330
331                         new->a_entries[j].e_tag =
332                                         posix_header->a_entries[i].e_tag;
333                         new->a_entries[j].e_perm =
334                                         posix_header->a_entries[i].e_perm;
335                         new->a_entries[j].e_id =
336                                         posix_header->a_entries[i].e_id;
337                         ee = lustre_ext_acl_xattr_search(ext_header,
338                                         &posix_header->a_entries[i], &pos);
339                         if (ee) {
340                                 if (posix_header->a_entries[i].e_perm !=
341                                                                 ee->e_perm)
342                                         /* entry modified. */
343                                         ee->e_stat =
344                                         new->a_entries[j++].e_stat =
345                                                         cpu_to_le32(ES_MOD);
346                                 else
347                                         /* entry unchanged. */
348                                         ee->e_stat =
349                                         new->a_entries[j++].e_stat =
350                                                         cpu_to_le32(ES_UNC);
351                         } else {
352                                 /* new entry. */
353                                 new->a_entries[j++].e_stat =
354                                                         cpu_to_le32(ES_ADD);
355                         }
356                         break;
357                 case ACL_GROUP:
358                         /* ignore "nobody" entry. */
359                         if (pae.e_id == NOBODY_GID)
360                                 break;
361                         new->a_entries[j].e_tag =
362                                         posix_header->a_entries[i].e_tag;
363                         new->a_entries[j].e_perm =
364                                         posix_header->a_entries[i].e_perm;
365                         new->a_entries[j].e_id =
366                                         posix_header->a_entries[i].e_id;
367                         ee = lustre_ext_acl_xattr_search(ext_header,
368                                         &posix_header->a_entries[i], &pos);
369                         if (ee) {
370                                 if (posix_header->a_entries[i].e_perm !=
371                                                                 ee->e_perm)
372                                         /* entry modified. */
373                                         ee->e_stat =
374                                         new->a_entries[j++].e_stat =
375                                                         cpu_to_le32(ES_MOD);
376                                 else
377                                         /* entry unchanged. */
378                                         ee->e_stat =
379                                         new->a_entries[j++].e_stat =
380                                                         cpu_to_le32(ES_UNC);
381                         } else {
382                                 /* new entry. */
383                                 new->a_entries[j++].e_stat =
384                                                         cpu_to_le32(ES_ADD);
385                         }
386                         break;
387                 default:
388                         rc = -EIO;
389                         goto out;
390                 }
391         }
392
393         /* process deleted entries. */
394         for (i = 0; i < ori_ext_count; i++) {
395                 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
396                 if (eae.e_stat == ES_UNK) {
397                         /* ignore "nobody" entry. */
398                         if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
399                             (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
400                                 continue;
401
402                         new->a_entries[j].e_tag =
403                                                 ext_header->a_entries[i].e_tag;
404                         new->a_entries[j].e_perm =
405                                                 ext_header->a_entries[i].e_perm;
406                         new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
407                         new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
408                 }
409         }
410
411         new->a_count = cpu_to_le32(j);
412         /* free unused space. */
413         rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
414
415 out:
416         if (rc) {
417                 kfree(new);
418                 new = ERR_PTR(rc);
419         }
420         return new;
421 }
422 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);
423
424 #endif