aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/ops_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/gfs2/ops_file.c')
-rw-r--r--fs/gfs2/ops_file.c219
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 */
44struct filldir_bad_entry { 47struct filldir_bad_entry {
@@ -357,7 +360,8 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length,
357 360
358static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) 361static 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
447static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) 451static 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
539const 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
577static 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
587static 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
597static 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
613static 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
629static 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 */
668static 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);
715out:
716 gfs2_glock_dq_uninit(&gh);
717 return error;
718}
719
720static 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
730int 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
844struct file_operations gfs2_dir_fops = { 1054struct 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,