]> git.karo-electronics.de Git - mv-sheeva.git/blob - fs/ocfs2/ioctl.c
ocfs2: Remove EXIT from masklog.
[mv-sheeva.git] / fs / ocfs2 / ioctl.c
1 /*
2  * linux/fs/ocfs2/ioctl.c
3  *
4  * Copyright (C) 2006 Herbert Poetzl
5  * adapted from Remy Card's ext2/ioctl.c
6  */
7
8 #include <linux/fs.h>
9 #include <linux/mount.h>
10 #include <linux/compat.h>
11
12 #define MLOG_MASK_PREFIX ML_INODE
13 #include <cluster/masklog.h>
14
15 #include "ocfs2.h"
16 #include "alloc.h"
17 #include "dlmglue.h"
18 #include "file.h"
19 #include "inode.h"
20 #include "journal.h"
21
22 #include "ocfs2_fs.h"
23 #include "ioctl.h"
24 #include "resize.h"
25 #include "refcounttree.h"
26
27 #include <linux/ext2_fs.h>
28
29 #define o2info_from_user(a, b)  \
30                 copy_from_user(&(a), (b), sizeof(a))
31 #define o2info_to_user(a, b)    \
32                 copy_to_user((typeof(a) __user *)b, &(a), sizeof(a))
33
34 /*
35  * This call is void because we are already reporting an error that may
36  * be -EFAULT.  The error will be returned from the ioctl(2) call.  It's
37  * just a best-effort to tell userspace that this request caused the error.
38  */
39 static inline void __o2info_set_request_error(struct ocfs2_info_request *kreq,
40                                         struct ocfs2_info_request __user *req)
41 {
42         kreq->ir_flags |= OCFS2_INFO_FL_ERROR;
43         (void)put_user(kreq->ir_flags, (__u32 __user *)&(req->ir_flags));
44 }
45
46 #define o2info_set_request_error(a, b) \
47                 __o2info_set_request_error((struct ocfs2_info_request *)&(a), b)
48
49 static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags)
50 {
51         int status;
52
53         status = ocfs2_inode_lock(inode, NULL, 0);
54         if (status < 0) {
55                 mlog_errno(status);
56                 return status;
57         }
58         ocfs2_get_inode_flags(OCFS2_I(inode));
59         *flags = OCFS2_I(inode)->ip_attr;
60         ocfs2_inode_unlock(inode, 0);
61
62         return status;
63 }
64
65 static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
66                                 unsigned mask)
67 {
68         struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode);
69         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
70         handle_t *handle = NULL;
71         struct buffer_head *bh = NULL;
72         unsigned oldflags;
73         int status;
74
75         mutex_lock(&inode->i_mutex);
76
77         status = ocfs2_inode_lock(inode, &bh, 1);
78         if (status < 0) {
79                 mlog_errno(status);
80                 goto bail;
81         }
82
83         status = -EACCES;
84         if (!is_owner_or_cap(inode))
85                 goto bail_unlock;
86
87         if (!S_ISDIR(inode->i_mode))
88                 flags &= ~OCFS2_DIRSYNC_FL;
89
90         handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
91         if (IS_ERR(handle)) {
92                 status = PTR_ERR(handle);
93                 mlog_errno(status);
94                 goto bail_unlock;
95         }
96
97         oldflags = ocfs2_inode->ip_attr;
98         flags = flags & mask;
99         flags |= oldflags & ~mask;
100
101         /*
102          * The IMMUTABLE and APPEND_ONLY flags can only be changed by
103          * the relevant capability.
104          */
105         status = -EPERM;
106         if ((oldflags & OCFS2_IMMUTABLE_FL) || ((flags ^ oldflags) &
107                 (OCFS2_APPEND_FL | OCFS2_IMMUTABLE_FL))) {
108                 if (!capable(CAP_LINUX_IMMUTABLE))
109                         goto bail_unlock;
110         }
111
112         ocfs2_inode->ip_attr = flags;
113         ocfs2_set_inode_flags(inode);
114
115         status = ocfs2_mark_inode_dirty(handle, inode, bh);
116         if (status < 0)
117                 mlog_errno(status);
118
119         ocfs2_commit_trans(osb, handle);
120 bail_unlock:
121         ocfs2_inode_unlock(inode, 1);
122 bail:
123         mutex_unlock(&inode->i_mutex);
124
125         brelse(bh);
126
127         return status;
128 }
129
130 int ocfs2_info_handle_blocksize(struct inode *inode,
131                                 struct ocfs2_info_request __user *req)
132 {
133         int status = -EFAULT;
134         struct ocfs2_info_blocksize oib;
135
136         if (o2info_from_user(oib, req))
137                 goto bail;
138
139         oib.ib_blocksize = inode->i_sb->s_blocksize;
140         oib.ib_req.ir_flags |= OCFS2_INFO_FL_FILLED;
141
142         if (o2info_to_user(oib, req))
143                 goto bail;
144
145         status = 0;
146 bail:
147         if (status)
148                 o2info_set_request_error(oib, req);
149
150         return status;
151 }
152
153 int ocfs2_info_handle_clustersize(struct inode *inode,
154                                   struct ocfs2_info_request __user *req)
155 {
156         int status = -EFAULT;
157         struct ocfs2_info_clustersize oic;
158         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
159
160         if (o2info_from_user(oic, req))
161                 goto bail;
162
163         oic.ic_clustersize = osb->s_clustersize;
164         oic.ic_req.ir_flags |= OCFS2_INFO_FL_FILLED;
165
166         if (o2info_to_user(oic, req))
167                 goto bail;
168
169         status = 0;
170 bail:
171         if (status)
172                 o2info_set_request_error(oic, req);
173
174         return status;
175 }
176
177 int ocfs2_info_handle_maxslots(struct inode *inode,
178                                struct ocfs2_info_request __user *req)
179 {
180         int status = -EFAULT;
181         struct ocfs2_info_maxslots oim;
182         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
183
184         if (o2info_from_user(oim, req))
185                 goto bail;
186
187         oim.im_max_slots = osb->max_slots;
188         oim.im_req.ir_flags |= OCFS2_INFO_FL_FILLED;
189
190         if (o2info_to_user(oim, req))
191                 goto bail;
192
193         status = 0;
194 bail:
195         if (status)
196                 o2info_set_request_error(oim, req);
197
198         return status;
199 }
200
201 int ocfs2_info_handle_label(struct inode *inode,
202                             struct ocfs2_info_request __user *req)
203 {
204         int status = -EFAULT;
205         struct ocfs2_info_label oil;
206         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
207
208         if (o2info_from_user(oil, req))
209                 goto bail;
210
211         memcpy(oil.il_label, osb->vol_label, OCFS2_MAX_VOL_LABEL_LEN);
212         oil.il_req.ir_flags |= OCFS2_INFO_FL_FILLED;
213
214         if (o2info_to_user(oil, req))
215                 goto bail;
216
217         status = 0;
218 bail:
219         if (status)
220                 o2info_set_request_error(oil, req);
221
222         return status;
223 }
224
225 int ocfs2_info_handle_uuid(struct inode *inode,
226                            struct ocfs2_info_request __user *req)
227 {
228         int status = -EFAULT;
229         struct ocfs2_info_uuid oiu;
230         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
231
232         if (o2info_from_user(oiu, req))
233                 goto bail;
234
235         memcpy(oiu.iu_uuid_str, osb->uuid_str, OCFS2_TEXT_UUID_LEN + 1);
236         oiu.iu_req.ir_flags |= OCFS2_INFO_FL_FILLED;
237
238         if (o2info_to_user(oiu, req))
239                 goto bail;
240
241         status = 0;
242 bail:
243         if (status)
244                 o2info_set_request_error(oiu, req);
245
246         return status;
247 }
248
249 int ocfs2_info_handle_fs_features(struct inode *inode,
250                                   struct ocfs2_info_request __user *req)
251 {
252         int status = -EFAULT;
253         struct ocfs2_info_fs_features oif;
254         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
255
256         if (o2info_from_user(oif, req))
257                 goto bail;
258
259         oif.if_compat_features = osb->s_feature_compat;
260         oif.if_incompat_features = osb->s_feature_incompat;
261         oif.if_ro_compat_features = osb->s_feature_ro_compat;
262         oif.if_req.ir_flags |= OCFS2_INFO_FL_FILLED;
263
264         if (o2info_to_user(oif, req))
265                 goto bail;
266
267         status = 0;
268 bail:
269         if (status)
270                 o2info_set_request_error(oif, req);
271
272         return status;
273 }
274
275 int ocfs2_info_handle_journal_size(struct inode *inode,
276                                    struct ocfs2_info_request __user *req)
277 {
278         int status = -EFAULT;
279         struct ocfs2_info_journal_size oij;
280         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
281
282         if (o2info_from_user(oij, req))
283                 goto bail;
284
285         oij.ij_journal_size = osb->journal->j_inode->i_size;
286
287         oij.ij_req.ir_flags |= OCFS2_INFO_FL_FILLED;
288
289         if (o2info_to_user(oij, req))
290                 goto bail;
291
292         status = 0;
293 bail:
294         if (status)
295                 o2info_set_request_error(oij, req);
296
297         return status;
298 }
299
300 int ocfs2_info_handle_unknown(struct inode *inode,
301                               struct ocfs2_info_request __user *req)
302 {
303         int status = -EFAULT;
304         struct ocfs2_info_request oir;
305
306         if (o2info_from_user(oir, req))
307                 goto bail;
308
309         oir.ir_flags &= ~OCFS2_INFO_FL_FILLED;
310
311         if (o2info_to_user(oir, req))
312                 goto bail;
313
314         status = 0;
315 bail:
316         if (status)
317                 o2info_set_request_error(oir, req);
318
319         return status;
320 }
321
322 /*
323  * Validate and distinguish OCFS2_IOC_INFO requests.
324  *
325  * - validate the magic number.
326  * - distinguish different requests.
327  * - validate size of different requests.
328  */
329 int ocfs2_info_handle_request(struct inode *inode,
330                               struct ocfs2_info_request __user *req)
331 {
332         int status = -EFAULT;
333         struct ocfs2_info_request oir;
334
335         if (o2info_from_user(oir, req))
336                 goto bail;
337
338         status = -EINVAL;
339         if (oir.ir_magic != OCFS2_INFO_MAGIC)
340                 goto bail;
341
342         switch (oir.ir_code) {
343         case OCFS2_INFO_BLOCKSIZE:
344                 if (oir.ir_size == sizeof(struct ocfs2_info_blocksize))
345                         status = ocfs2_info_handle_blocksize(inode, req);
346                 break;
347         case OCFS2_INFO_CLUSTERSIZE:
348                 if (oir.ir_size == sizeof(struct ocfs2_info_clustersize))
349                         status = ocfs2_info_handle_clustersize(inode, req);
350                 break;
351         case OCFS2_INFO_MAXSLOTS:
352                 if (oir.ir_size == sizeof(struct ocfs2_info_maxslots))
353                         status = ocfs2_info_handle_maxslots(inode, req);
354                 break;
355         case OCFS2_INFO_LABEL:
356                 if (oir.ir_size == sizeof(struct ocfs2_info_label))
357                         status = ocfs2_info_handle_label(inode, req);
358                 break;
359         case OCFS2_INFO_UUID:
360                 if (oir.ir_size == sizeof(struct ocfs2_info_uuid))
361                         status = ocfs2_info_handle_uuid(inode, req);
362                 break;
363         case OCFS2_INFO_FS_FEATURES:
364                 if (oir.ir_size == sizeof(struct ocfs2_info_fs_features))
365                         status = ocfs2_info_handle_fs_features(inode, req);
366                 break;
367         case OCFS2_INFO_JOURNAL_SIZE:
368                 if (oir.ir_size == sizeof(struct ocfs2_info_journal_size))
369                         status = ocfs2_info_handle_journal_size(inode, req);
370                 break;
371         default:
372                 status = ocfs2_info_handle_unknown(inode, req);
373                 break;
374         }
375
376 bail:
377         return status;
378 }
379
380 int ocfs2_get_request_ptr(struct ocfs2_info *info, int idx,
381                           u64 *req_addr, int compat_flag)
382 {
383         int status = -EFAULT;
384         u64 __user *bp = NULL;
385
386         if (compat_flag) {
387 #ifdef CONFIG_COMPAT
388                 /*
389                  * pointer bp stores the base address of a pointers array,
390                  * which collects all addresses of separate request.
391                  */
392                 bp = (u64 __user *)(unsigned long)compat_ptr(info->oi_requests);
393 #else
394                 BUG();
395 #endif
396         } else
397                 bp = (u64 __user *)(unsigned long)(info->oi_requests);
398
399         if (o2info_from_user(*req_addr, bp + idx))
400                 goto bail;
401
402         status = 0;
403 bail:
404         return status;
405 }
406
407 /*
408  * OCFS2_IOC_INFO handles an array of requests passed from userspace.
409  *
410  * ocfs2_info_handle() recevies a large info aggregation, grab and
411  * validate the request count from header, then break it into small
412  * pieces, later specific handlers can handle them one by one.
413  *
414  * Idea here is to make each separate request small enough to ensure
415  * a better backward&forward compatibility, since a small piece of
416  * request will be less likely to be broken if disk layout get changed.
417  */
418 int ocfs2_info_handle(struct inode *inode, struct ocfs2_info *info,
419                       int compat_flag)
420 {
421         int i, status = 0;
422         u64 req_addr;
423         struct ocfs2_info_request __user *reqp;
424
425         if ((info->oi_count > OCFS2_INFO_MAX_REQUEST) ||
426             (!info->oi_requests)) {
427                 status = -EINVAL;
428                 goto bail;
429         }
430
431         for (i = 0; i < info->oi_count; i++) {
432
433                 status = ocfs2_get_request_ptr(info, i, &req_addr, compat_flag);
434                 if (status)
435                         break;
436
437                 reqp = (struct ocfs2_info_request *)(unsigned long)req_addr;
438                 if (!reqp) {
439                         status = -EINVAL;
440                         goto bail;
441                 }
442
443                 status = ocfs2_info_handle_request(inode, reqp);
444                 if (status)
445                         break;
446         }
447
448 bail:
449         return status;
450 }
451
452 long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
453 {
454         struct inode *inode = filp->f_path.dentry->d_inode;
455         unsigned int flags;
456         int new_clusters;
457         int status;
458         struct ocfs2_space_resv sr;
459         struct ocfs2_new_group_input input;
460         struct reflink_arguments args;
461         const char *old_path, *new_path;
462         bool preserve;
463         struct ocfs2_info info;
464
465         switch (cmd) {
466         case OCFS2_IOC_GETFLAGS:
467                 status = ocfs2_get_inode_attr(inode, &flags);
468                 if (status < 0)
469                         return status;
470
471                 flags &= OCFS2_FL_VISIBLE;
472                 return put_user(flags, (int __user *) arg);
473         case OCFS2_IOC_SETFLAGS:
474                 if (get_user(flags, (int __user *) arg))
475                         return -EFAULT;
476
477                 status = mnt_want_write(filp->f_path.mnt);
478                 if (status)
479                         return status;
480                 status = ocfs2_set_inode_attr(inode, flags,
481                         OCFS2_FL_MODIFIABLE);
482                 mnt_drop_write(filp->f_path.mnt);
483                 return status;
484         case OCFS2_IOC_RESVSP:
485         case OCFS2_IOC_RESVSP64:
486         case OCFS2_IOC_UNRESVSP:
487         case OCFS2_IOC_UNRESVSP64:
488                 if (copy_from_user(&sr, (int __user *) arg, sizeof(sr)))
489                         return -EFAULT;
490
491                 return ocfs2_change_file_space(filp, cmd, &sr);
492         case OCFS2_IOC_GROUP_EXTEND:
493                 if (!capable(CAP_SYS_RESOURCE))
494                         return -EPERM;
495
496                 if (get_user(new_clusters, (int __user *)arg))
497                         return -EFAULT;
498
499                 return ocfs2_group_extend(inode, new_clusters);
500         case OCFS2_IOC_GROUP_ADD:
501         case OCFS2_IOC_GROUP_ADD64:
502                 if (!capable(CAP_SYS_RESOURCE))
503                         return -EPERM;
504
505                 if (copy_from_user(&input, (int __user *) arg, sizeof(input)))
506                         return -EFAULT;
507
508                 return ocfs2_group_add(inode, &input);
509         case OCFS2_IOC_REFLINK:
510                 if (copy_from_user(&args, (struct reflink_arguments *)arg,
511                                    sizeof(args)))
512                         return -EFAULT;
513                 old_path = (const char *)(unsigned long)args.old_path;
514                 new_path = (const char *)(unsigned long)args.new_path;
515                 preserve = (args.preserve != 0);
516
517                 return ocfs2_reflink_ioctl(inode, old_path, new_path, preserve);
518         case OCFS2_IOC_INFO:
519                 if (copy_from_user(&info, (struct ocfs2_info __user *)arg,
520                                    sizeof(struct ocfs2_info)))
521                         return -EFAULT;
522
523                 return ocfs2_info_handle(inode, &info, 0);
524         default:
525                 return -ENOTTY;
526         }
527 }
528
529 #ifdef CONFIG_COMPAT
530 long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
531 {
532         bool preserve;
533         struct reflink_arguments args;
534         struct inode *inode = file->f_path.dentry->d_inode;
535         struct ocfs2_info info;
536
537         switch (cmd) {
538         case OCFS2_IOC32_GETFLAGS:
539                 cmd = OCFS2_IOC_GETFLAGS;
540                 break;
541         case OCFS2_IOC32_SETFLAGS:
542                 cmd = OCFS2_IOC_SETFLAGS;
543                 break;
544         case OCFS2_IOC_RESVSP:
545         case OCFS2_IOC_RESVSP64:
546         case OCFS2_IOC_UNRESVSP:
547         case OCFS2_IOC_UNRESVSP64:
548         case OCFS2_IOC_GROUP_EXTEND:
549         case OCFS2_IOC_GROUP_ADD:
550         case OCFS2_IOC_GROUP_ADD64:
551                 break;
552         case OCFS2_IOC_REFLINK:
553                 if (copy_from_user(&args, (struct reflink_arguments *)arg,
554                                    sizeof(args)))
555                         return -EFAULT;
556                 preserve = (args.preserve != 0);
557
558                 return ocfs2_reflink_ioctl(inode, compat_ptr(args.old_path),
559                                            compat_ptr(args.new_path), preserve);
560         case OCFS2_IOC_INFO:
561                 if (copy_from_user(&info, (struct ocfs2_info __user *)arg,
562                                    sizeof(struct ocfs2_info)))
563                         return -EFAULT;
564
565                 return ocfs2_info_handle(inode, &info, 1);
566         default:
567                 return -ENOIOCTLCMD;
568         }
569
570         return ocfs2_ioctl(file, cmd, arg);
571 }
572 #endif