Add the rt linux 4.1.3-rt3 as base
[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
96 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
97 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
98                                                int old_count, int new_count)
99 {
100         int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr);
101         int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr);
102         posix_acl_xattr_header *new;
103
104         if (unlikely(old_count <= new_count))
105                 return old_size;
106
107         OBD_ALLOC(new, new_size);
108         if (unlikely(new == NULL))
109                 return -ENOMEM;
110
111         memcpy(new, *header, new_size);
112         OBD_FREE(*header, old_size);
113         *header = new;
114         return new_size;
115 }
116
117 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
118 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
119                                              int old_count)
120 {
121         int ext_count = le32_to_cpu((*header)->a_count);
122         int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
123         int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr);
124         ext_acl_xattr_header *new;
125
126         if (unlikely(old_count <= ext_count))
127                 return 0;
128
129         OBD_ALLOC(new, ext_size);
130         if (unlikely(new == NULL))
131                 return -ENOMEM;
132
133         memcpy(new, *header, ext_size);
134         OBD_FREE(*header, old_size);
135         *header = new;
136         return 0;
137 }
138
139 /*
140  * Generate new extended ACL based on the posix ACL.
141  */
142 ext_acl_xattr_header *
143 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
144 {
145         int count, i, esize;
146         ext_acl_xattr_header *new;
147
148         if (unlikely(size < 0))
149                 return ERR_PTR(-EINVAL);
150         else if (!size)
151                 count = 0;
152         else
153                 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
154         esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
155         OBD_ALLOC(new, esize);
156         if (unlikely(new == NULL))
157                 return ERR_PTR(-ENOMEM);
158
159         new->a_count = cpu_to_le32(count);
160         for (i = 0; i < count; i++) {
161                 new->a_entries[i].e_tag  = header->a_entries[i].e_tag;
162                 new->a_entries[i].e_perm = header->a_entries[i].e_perm;
163                 new->a_entries[i].e_id   = header->a_entries[i].e_id;
164                 new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
165         }
166
167         return new;
168 }
169 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
170
171 /*
172  * Filter out the "nobody" entries in the posix ACL.
173  */
174 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, size_t size,
175                                   posix_acl_xattr_header **out)
176 {
177         int count, i, j, rc = 0;
178         __u32 id;
179         posix_acl_xattr_header *new;
180
181         if (!size)
182                 return 0;
183         if (size < sizeof(*new))
184                 return -EINVAL;
185
186         OBD_ALLOC(new, size);
187         if (unlikely(new == NULL))
188                 return -ENOMEM;
189
190         new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
191         count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
192         for (i = 0, j = 0; i < count; i++) {
193                 id = le32_to_cpu(header->a_entries[i].e_id);
194                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
195                 case ACL_USER_OBJ:
196                 case ACL_GROUP_OBJ:
197                 case ACL_MASK:
198                 case ACL_OTHER:
199                         if (id != ACL_UNDEFINED_ID) {
200                                 rc = -EIO;
201                                 goto _out;
202                         }
203
204                         memcpy(&new->a_entries[j++], &header->a_entries[i],
205                                sizeof(posix_acl_xattr_entry));
206                         break;
207                 case ACL_USER:
208                         if (id != NOBODY_UID)
209                                 memcpy(&new->a_entries[j++],
210                                        &header->a_entries[i],
211                                        sizeof(posix_acl_xattr_entry));
212                         break;
213                 case ACL_GROUP:
214                         if (id != NOBODY_GID)
215                                 memcpy(&new->a_entries[j++],
216                                        &header->a_entries[i],
217                                        sizeof(posix_acl_xattr_entry));
218                         break;
219                 default:
220                         rc = -EIO;
221                         goto _out;
222                 }
223         }
224
225         /* free unused space. */
226         rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
227         if (rc >= 0) {
228                 size = rc;
229                 *out = new;
230                 rc = 0;
231         }
232
233 _out:
234         if (rc) {
235                 OBD_FREE(new, size);
236                 size = rc;
237         }
238         return size;
239 }
240 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
241
242 /*
243  * Release the posix ACL space.
244  */
245 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
246 {
247         OBD_FREE(header, size);
248 }
249 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
250
251 /*
252  * Release the extended ACL space.
253  */
254 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
255 {
256         OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
257                                             ext_acl_xattr));
258 }
259 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
260
261 static ext_acl_xattr_entry *
262 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
263                             posix_acl_xattr_entry *entry, int *pos)
264 {
265         int once, start, end, i, j, count = le32_to_cpu(header->a_count);
266
267         once = 0;
268         start = *pos;
269         end = count;
270
271 again:
272         for (i = start; i < end; i++) {
273                 if (header->a_entries[i].e_tag == entry->e_tag &&
274                     header->a_entries[i].e_id == entry->e_id) {
275                         j = i;
276                         if (++i >= count)
277                                 i = 0;
278                         *pos = i;
279                         return &header->a_entries[j];
280                 }
281         }
282
283         if (!once) {
284                 once = 1;
285                 start = 0;
286                 end = *pos;
287                 goto again;
288         }
289
290         return NULL;
291 }
292
293 /*
294  * Merge the posix ACL and the extended ACL into new posix ACL.
295  */
296 int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
297                                  ext_acl_xattr_header *ext_header,
298                                  posix_acl_xattr_header **out)
299 {
300         int posix_count, posix_size, i, j;
301         int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0;
302         posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
303         posix_acl_xattr_header *new;
304         ext_acl_xattr_entry *ee, ae;
305
306         lustre_posix_acl_cpu_to_le(&pe, &pe);
307         ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
308         if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) {
309                 /* there are only base ACL entries at most. */
310                 posix_count = 3;
311                 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
312                 OBD_ALLOC(new, posix_size);
313                 if (unlikely(new == NULL))
314                         return -ENOMEM;
315
316                 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
317                 for (i = 0, j = 0; i < ext_count; i++) {
318                         lustre_ext_acl_le_to_cpu(&ae,
319                                                  &ext_header->a_entries[i]);
320                         switch (ae.e_tag) {
321                         case ACL_USER_OBJ:
322                         case ACL_GROUP_OBJ:
323                         case ACL_OTHER:
324                                 if (ae.e_id != ACL_UNDEFINED_ID) {
325                                         rc = -EIO;
326                                         goto _out;
327                                 }
328
329                                 if (ae.e_stat != ES_DEL) {
330                                         new->a_entries[j].e_tag =
331                                                 ext_header->a_entries[i].e_tag;
332                                         new->a_entries[j].e_perm =
333                                                 ext_header->a_entries[i].e_perm;
334                                         new->a_entries[j++].e_id =
335                                                 ext_header->a_entries[i].e_id;
336                                 }
337                                 break;
338                         case ACL_MASK:
339                         case ACL_USER:
340                         case ACL_GROUP:
341                                 if (ae.e_stat == ES_DEL)
342                                         break;
343                         default:
344                                 rc = -EIO;
345                                 goto _out;
346                         }
347                 }
348         } else {
349                 /* maybe there are valid ACL_USER or ACL_GROUP entries in the
350                  * original server-side ACL, they are regarded as ES_UNC stat.*/
351                 int ori_posix_count;
352
353                 if (unlikely(size < 0))
354                         return -EINVAL;
355                 else if (!size)
356                         ori_posix_count = 0;
357                 else
358                         ori_posix_count =
359                                 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
360                 posix_count = ori_posix_count + ext_count;
361                 posix_size =
362                         CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
363                 OBD_ALLOC(new, posix_size);
364                 if (unlikely(new == NULL))
365                         return -ENOMEM;
366
367                 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
368                 /* 1. process the unchanged ACL entries
369                  *    in the original server-side ACL. */
370                 pos = 0;
371                 for (i = 0, j = 0; i < ori_posix_count; i++) {
372                         ee = lustre_ext_acl_xattr_search(ext_header,
373                                         &posix_header->a_entries[i], &pos);
374                         if (ee == NULL)
375                                 memcpy(&new->a_entries[j++],
376                                        &posix_header->a_entries[i],
377                                        sizeof(posix_acl_xattr_entry));
378                 }
379
380                 /* 2. process the non-deleted entries
381                  *    from client-side extended ACL. */
382                 for (i = 0; i < ext_count; i++) {
383                         if (le16_to_cpu(ext_header->a_entries[i].e_stat) !=
384                             ES_DEL) {
385                                 new->a_entries[j].e_tag =
386                                                 ext_header->a_entries[i].e_tag;
387                                 new->a_entries[j].e_perm =
388                                                 ext_header->a_entries[i].e_perm;
389                                 new->a_entries[j++].e_id =
390                                                 ext_header->a_entries[i].e_id;
391                         }
392                 }
393         }
394
395         /* free unused space. */
396         rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
397         if (rc >= 0) {
398                 posix_size = rc;
399                 *out = new;
400                 rc = 0;
401         }
402
403 _out:
404         if (rc) {
405                 OBD_FREE(new, posix_size);
406                 posix_size = rc;
407         }
408         return posix_size;
409 }
410 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
411
412 /*
413  * Merge the posix ACL and the extended ACL into new extended ACL.
414  */
415 ext_acl_xattr_header *
416 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
417                            ext_acl_xattr_header *ext_header)
418 {
419         int ori_ext_count, posix_count, ext_count, ext_size;
420         int i, j, pos = 0, rc = 0;
421         posix_acl_xattr_entry pae;
422         ext_acl_xattr_header *new;
423         ext_acl_xattr_entry *ee, eae;
424
425         if (unlikely(size < 0))
426                 return ERR_PTR(-EINVAL);
427         else if (!size)
428                 posix_count = 0;
429         else
430                 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
431         ori_ext_count = le32_to_cpu(ext_header->a_count);
432         ext_count = posix_count + ori_ext_count;
433         ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
434
435         OBD_ALLOC(new, ext_size);
436         if (unlikely(new == NULL))
437                 return ERR_PTR(-ENOMEM);
438
439         for (i = 0, j = 0; i < posix_count; i++) {
440                 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
441                 switch (pae.e_tag) {
442                 case ACL_USER_OBJ:
443                 case ACL_GROUP_OBJ:
444                 case ACL_MASK:
445                 case ACL_OTHER:
446                         if (pae.e_id != ACL_UNDEFINED_ID) {
447                                 rc = -EIO;
448                                 goto out;
449                 }
450                 case ACL_USER:
451                         /* ignore "nobody" entry. */
452                         if (pae.e_id == NOBODY_UID)
453                                 break;
454
455                         new->a_entries[j].e_tag =
456                                         posix_header->a_entries[i].e_tag;
457                         new->a_entries[j].e_perm =
458                                         posix_header->a_entries[i].e_perm;
459                         new->a_entries[j].e_id =
460                                         posix_header->a_entries[i].e_id;
461                         ee = lustre_ext_acl_xattr_search(ext_header,
462                                         &posix_header->a_entries[i], &pos);
463                         if (ee) {
464                                 if (posix_header->a_entries[i].e_perm !=
465                                                                 ee->e_perm)
466                                         /* entry modified. */
467                                         ee->e_stat =
468                                         new->a_entries[j++].e_stat =
469                                                         cpu_to_le32(ES_MOD);
470                                 else
471                                         /* entry unchanged. */
472                                         ee->e_stat =
473                                         new->a_entries[j++].e_stat =
474                                                         cpu_to_le32(ES_UNC);
475                         } else {
476                                 /* new entry. */
477                                 new->a_entries[j++].e_stat =
478                                                         cpu_to_le32(ES_ADD);
479                         }
480                         break;
481                 case ACL_GROUP:
482                         /* ignore "nobody" entry. */
483                         if (pae.e_id == NOBODY_GID)
484                                 break;
485                         new->a_entries[j].e_tag =
486                                         posix_header->a_entries[i].e_tag;
487                         new->a_entries[j].e_perm =
488                                         posix_header->a_entries[i].e_perm;
489                         new->a_entries[j].e_id =
490                                         posix_header->a_entries[i].e_id;
491                         ee = lustre_ext_acl_xattr_search(ext_header,
492                                         &posix_header->a_entries[i], &pos);
493                         if (ee) {
494                                 if (posix_header->a_entries[i].e_perm !=
495                                                                 ee->e_perm)
496                                         /* entry modified. */
497                                         ee->e_stat =
498                                         new->a_entries[j++].e_stat =
499                                                         cpu_to_le32(ES_MOD);
500                                 else
501                                         /* entry unchanged. */
502                                         ee->e_stat =
503                                         new->a_entries[j++].e_stat =
504                                                         cpu_to_le32(ES_UNC);
505                         } else {
506                                 /* new entry. */
507                                 new->a_entries[j++].e_stat =
508                                                         cpu_to_le32(ES_ADD);
509                         }
510                         break;
511                 default:
512                         rc = -EIO;
513                         goto out;
514                 }
515         }
516
517         /* process deleted entries. */
518         for (i = 0; i < ori_ext_count; i++) {
519                 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
520                 if (eae.e_stat == ES_UNK) {
521                         /* ignore "nobody" entry. */
522                         if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
523                             (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
524                                 continue;
525
526                         new->a_entries[j].e_tag =
527                                                 ext_header->a_entries[i].e_tag;
528                         new->a_entries[j].e_perm =
529                                                 ext_header->a_entries[i].e_perm;
530                         new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
531                         new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
532                 }
533         }
534
535         new->a_count = cpu_to_le32(j);
536         /* free unused space. */
537         rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
538
539 out:
540         if (rc) {
541                 OBD_FREE(new, ext_size);
542                 new = ERR_PTR(rc);
543         }
544         return new;
545 }
546 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);
547
548 #endif