diff options
Diffstat (limited to 'fs/gfs2/ops_file.c')
-rw-r--r-- | fs/gfs2/ops_file.c | 219 |
1 files changed, 215 insertions, 4 deletions
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 6333a14cf77a..ac8e1238cb6f 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include <linux/gfs2_ondisk.h> | 21 | #include <linux/gfs2_ondisk.h> |
22 | #include <linux/ext2_fs.h> | ||
23 | #include <linux/crc32.h> | ||
22 | #include <asm/semaphore.h> | 24 | #include <asm/semaphore.h> |
23 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
24 | 26 | ||
@@ -39,6 +41,7 @@ | |||
39 | #include "rgrp.h" | 41 | #include "rgrp.h" |
40 | #include "trans.h" | 42 | #include "trans.h" |
41 | #include "util.h" | 43 | #include "util.h" |
44 | #include "eaops.h" | ||
42 | 45 | ||
43 | /* "bad" is for NFS support */ | 46 | /* "bad" is for NFS support */ |
44 | struct filldir_bad_entry { | 47 | struct filldir_bad_entry { |
@@ -357,7 +360,8 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, | |||
357 | 360 | ||
358 | static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) | 361 | static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) |
359 | { | 362 | { |
360 | struct gfs2_inode *dip = file->f_mapping->host->u.generic_ip; | 363 | struct inode *dir = file->f_mapping->host; |
364 | struct gfs2_inode *dip = dir->u.generic_ip; | ||
361 | struct filldir_reg fdr; | 365 | struct filldir_reg fdr; |
362 | struct gfs2_holder d_gh; | 366 | struct gfs2_holder d_gh; |
363 | uint64_t offset = file->f_pos; | 367 | uint64_t offset = file->f_pos; |
@@ -375,7 +379,7 @@ static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) | |||
375 | return error; | 379 | return error; |
376 | } | 380 | } |
377 | 381 | ||
378 | error = gfs2_dir_read(dip, &offset, &fdr, filldir_reg_func); | 382 | error = gfs2_dir_read(dir, &offset, &fdr, filldir_reg_func); |
379 | 383 | ||
380 | gfs2_glock_dq_uninit(&d_gh); | 384 | gfs2_glock_dq_uninit(&d_gh); |
381 | 385 | ||
@@ -446,7 +450,8 @@ static int filldir_bad_func(void *opaque, const char *name, unsigned int length, | |||
446 | 450 | ||
447 | static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) | 451 | static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) |
448 | { | 452 | { |
449 | struct gfs2_inode *dip = file->f_mapping->host->u.generic_ip; | 453 | struct inode *dir = file->f_mapping->host; |
454 | struct gfs2_inode *dip = dir->u.generic_ip; | ||
450 | struct gfs2_sbd *sdp = dip->i_sbd; | 455 | struct gfs2_sbd *sdp = dip->i_sbd; |
451 | struct filldir_reg fdr; | 456 | struct filldir_reg fdr; |
452 | unsigned int entries, size; | 457 | unsigned int entries, size; |
@@ -479,7 +484,7 @@ static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) | |||
479 | goto out; | 484 | goto out; |
480 | } | 485 | } |
481 | 486 | ||
482 | error = gfs2_dir_read(dip, &offset, fdb, filldir_bad_func); | 487 | error = gfs2_dir_read(dir, &offset, fdb, filldir_bad_func); |
483 | 488 | ||
484 | gfs2_glock_dq_uninit(&d_gh); | 489 | gfs2_glock_dq_uninit(&d_gh); |
485 | 490 | ||
@@ -531,6 +536,210 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) | |||
531 | return error; | 536 | return error; |
532 | } | 537 | } |
533 | 538 | ||
539 | const struct gfs2_flag_eattr { | ||
540 | u32 flag; | ||
541 | u32 ext2; | ||
542 | } gfs2_flag_eattrs[] = { | ||
543 | { | ||
544 | .flag = GFS2_DIF_IMMUTABLE, | ||
545 | .ext2 = EXT2_IMMUTABLE_FL, | ||
546 | }, { | ||
547 | .flag = GFS2_DIF_APPENDONLY, | ||
548 | .ext2 = EXT2_APPEND_FL, | ||
549 | }, { | ||
550 | .flag = GFS2_DIF_JDATA, | ||
551 | .ext2 = EXT2_JOURNAL_DATA_FL, | ||
552 | }, { | ||
553 | .flag = GFS2_DIF_EXHASH, | ||
554 | .ext2 = EXT2_INDEX_FL, | ||
555 | }, { | ||
556 | .flag = GFS2_DIF_EA_INDIRECT, | ||
557 | }, { | ||
558 | .flag = GFS2_DIF_DIRECTIO, | ||
559 | }, { | ||
560 | .flag = GFS2_DIF_NOATIME, | ||
561 | .ext2 = EXT2_NOATIME_FL, | ||
562 | }, { | ||
563 | .flag = GFS2_DIF_SYNC, | ||
564 | .ext2 = EXT2_SYNC_FL, | ||
565 | }, { | ||
566 | .flag = GFS2_DIF_SYSTEM, | ||
567 | }, { | ||
568 | .flag = GFS2_DIF_TRUNC_IN_PROG, | ||
569 | }, { | ||
570 | .flag = GFS2_DIF_INHERIT_JDATA, | ||
571 | }, { | ||
572 | .flag = GFS2_DIF_INHERIT_DIRECTIO, | ||
573 | }, { | ||
574 | }, | ||
575 | }; | ||
576 | |||
577 | static const struct gfs2_flag_eattr *get_by_ext2(u32 ext2) | ||
578 | { | ||
579 | const struct gfs2_flag_eattr *p = gfs2_flag_eattrs; | ||
580 | for(; p->flag; p++) { | ||
581 | if (ext2 == p->ext2) | ||
582 | return p; | ||
583 | } | ||
584 | return NULL; | ||
585 | } | ||
586 | |||
587 | static const struct gfs2_flag_eattr *get_by_gfs2(u32 gfs2) | ||
588 | { | ||
589 | const struct gfs2_flag_eattr *p = gfs2_flag_eattrs; | ||
590 | for(; p->flag; p++) { | ||
591 | if (gfs2 == p->flag) | ||
592 | return p; | ||
593 | } | ||
594 | return NULL; | ||
595 | } | ||
596 | |||
597 | static u32 gfs2_flags_to_ext2(u32 gfs2) | ||
598 | { | ||
599 | const struct gfs2_flag_eattr *ea; | ||
600 | u32 ext2 = 0; | ||
601 | u32 mask = 1; | ||
602 | |||
603 | for(; mask != 0; mask <<=1) { | ||
604 | if (mask & gfs2) { | ||
605 | ea = get_by_gfs2(mask); | ||
606 | if (ea) | ||
607 | ext2 |= ea->ext2; | ||
608 | } | ||
609 | } | ||
610 | return ext2; | ||
611 | } | ||
612 | |||
613 | static int gfs2_flags_from_ext2(u32 *gfs2, u32 ext2) | ||
614 | { | ||
615 | const struct gfs2_flag_eattr *ea; | ||
616 | u32 mask = 1; | ||
617 | |||
618 | for(; mask != 0; mask <<= 1) { | ||
619 | if (mask & ext2) { | ||
620 | ea = get_by_ext2(mask); | ||
621 | if (ea == NULL) | ||
622 | return -EINVAL; | ||
623 | *gfs2 |= ea->flag; | ||
624 | } | ||
625 | } | ||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | static int get_ext2_flags(struct inode *inode, u32 __user *ptr) | ||
630 | { | ||
631 | struct gfs2_inode *ip = inode->u.generic_ip; | ||
632 | struct gfs2_holder gh; | ||
633 | int error; | ||
634 | u32 ext2; | ||
635 | |||
636 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); | ||
637 | error = gfs2_glock_nq_m_atime(1, &gh); | ||
638 | if (error) | ||
639 | return error; | ||
640 | |||
641 | ext2 = gfs2_flags_to_ext2(ip->i_di.di_flags); | ||
642 | if (put_user(ext2, ptr)) | ||
643 | error = -EFAULT; | ||
644 | |||
645 | gfs2_glock_dq_m(1, &gh); | ||
646 | gfs2_holder_uninit(&gh); | ||
647 | return error; | ||
648 | } | ||
649 | |||
650 | /* Flags that can be set by user space */ | ||
651 | #define GFS2_FLAGS_USER_SET (GFS2_DIF_JDATA| \ | ||
652 | GFS2_DIF_DIRECTIO| \ | ||
653 | GFS2_DIF_IMMUTABLE| \ | ||
654 | GFS2_DIF_APPENDONLY| \ | ||
655 | GFS2_DIF_NOATIME| \ | ||
656 | GFS2_DIF_SYNC| \ | ||
657 | GFS2_DIF_SYSTEM| \ | ||
658 | GFS2_DIF_INHERIT_DIRECTIO| \ | ||
659 | GFS2_DIF_INHERIT_JDATA) | ||
660 | |||
661 | /** | ||
662 | * gfs2_set_flags - set flags on an inode | ||
663 | * @inode: The inode | ||
664 | * @flags: The flags to set | ||
665 | * @mask: Indicates which flags are valid | ||
666 | * | ||
667 | */ | ||
668 | static int gfs2_set_flags(struct inode *inode, u32 flags, u32 mask) | ||
669 | { | ||
670 | struct gfs2_inode *ip = inode->u.generic_ip; | ||
671 | struct buffer_head *bh; | ||
672 | struct gfs2_holder gh; | ||
673 | int error; | ||
674 | u32 new_flags; | ||
675 | |||
676 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); | ||
677 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); | ||
678 | if (error) | ||
679 | return error; | ||
680 | |||
681 | new_flags = (ip->i_di.di_flags & ~mask) | (flags & mask); | ||
682 | if ((new_flags ^ flags) == 0) | ||
683 | goto out; | ||
684 | |||
685 | error = -EINVAL; | ||
686 | if ((new_flags ^ flags) & ~GFS2_FLAGS_USER_SET) | ||
687 | goto out; | ||
688 | |||
689 | if (S_ISDIR(inode->i_mode)) { | ||
690 | if ((new_flags ^ flags) & (GFS2_DIF_JDATA | GFS2_DIF_DIRECTIO)) | ||
691 | goto out; | ||
692 | } else if (S_ISREG(inode->i_mode)) { | ||
693 | if ((new_flags ^ flags) & (GFS2_DIF_INHERIT_DIRECTIO| | ||
694 | GFS2_DIF_INHERIT_JDATA)) | ||
695 | goto out; | ||
696 | } else | ||
697 | goto out; | ||
698 | |||
699 | error = -EPERM; | ||
700 | if (IS_IMMUTABLE(inode) && (new_flags & GFS2_DIF_IMMUTABLE)) | ||
701 | goto out; | ||
702 | if (IS_APPEND(inode) && (new_flags & GFS2_DIF_APPENDONLY)) | ||
703 | goto out; | ||
704 | error = gfs2_repermission(inode, MAY_WRITE, NULL); | ||
705 | if (error) | ||
706 | goto out; | ||
707 | |||
708 | error = gfs2_meta_inode_buffer(ip, &bh); | ||
709 | if (error) | ||
710 | goto out; | ||
711 | gfs2_trans_add_bh(ip->i_gl, bh, 1); | ||
712 | ip->i_di.di_flags = new_flags; | ||
713 | gfs2_dinode_out(&ip->i_di, bh->b_data); | ||
714 | brelse(bh); | ||
715 | out: | ||
716 | gfs2_glock_dq_uninit(&gh); | ||
717 | return error; | ||
718 | } | ||
719 | |||
720 | static int set_ext2_flags(struct inode *inode, u32 __user *ptr) | ||
721 | { | ||
722 | u32 ext2, gfs2; | ||
723 | if (get_user(ext2, ptr)) | ||
724 | return -EFAULT; | ||
725 | if (gfs2_flags_from_ext2(&gfs2, ext2)) | ||
726 | return -EINVAL; | ||
727 | return gfs2_set_flags(inode, gfs2, ~0); | ||
728 | } | ||
729 | |||
730 | int gfs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | ||
731 | unsigned long arg) | ||
732 | { | ||
733 | switch(cmd) { | ||
734 | case EXT2_IOC_GETFLAGS: | ||
735 | return get_ext2_flags(inode, (u32 __user *)arg); | ||
736 | case EXT2_IOC_SETFLAGS: | ||
737 | return set_ext2_flags(inode, (u32 __user *)arg); | ||
738 | } | ||
739 | return -ENOTTY; | ||
740 | } | ||
741 | |||
742 | |||
534 | /** | 743 | /** |
535 | * gfs2_mmap - | 744 | * gfs2_mmap - |
536 | * @file: The file to map | 745 | * @file: The file to map |
@@ -832,6 +1041,7 @@ struct file_operations gfs2_file_fops = { | |||
832 | .write = generic_file_write, | 1041 | .write = generic_file_write, |
833 | .writev = generic_file_writev, | 1042 | .writev = generic_file_writev, |
834 | .aio_write = generic_file_aio_write, | 1043 | .aio_write = generic_file_aio_write, |
1044 | .ioctl = gfs2_ioctl, | ||
835 | .mmap = gfs2_mmap, | 1045 | .mmap = gfs2_mmap, |
836 | .open = gfs2_open, | 1046 | .open = gfs2_open, |
837 | .release = gfs2_close, | 1047 | .release = gfs2_close, |
@@ -843,6 +1053,7 @@ struct file_operations gfs2_file_fops = { | |||
843 | 1053 | ||
844 | struct file_operations gfs2_dir_fops = { | 1054 | struct file_operations gfs2_dir_fops = { |
845 | .readdir = gfs2_readdir, | 1055 | .readdir = gfs2_readdir, |
1056 | .ioctl = gfs2_ioctl, | ||
846 | .open = gfs2_open, | 1057 | .open = gfs2_open, |
847 | .release = gfs2_close, | 1058 | .release = gfs2_close, |
848 | .fsync = gfs2_fsync, | 1059 | .fsync = gfs2_fsync, |