diff options
-rw-r--r-- | fs/nilfs2/ioctl.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 496738963fdb..3aad6413aba4 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
@@ -97,6 +97,70 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, | |||
97 | return ret; | 97 | return ret; |
98 | } | 98 | } |
99 | 99 | ||
100 | static int nilfs_ioctl_getflags(struct inode *inode, void __user *argp) | ||
101 | { | ||
102 | unsigned int flags = NILFS_I(inode)->i_flags & FS_FL_USER_VISIBLE; | ||
103 | |||
104 | return put_user(flags, (int __user *)argp); | ||
105 | } | ||
106 | |||
107 | static int nilfs_ioctl_setflags(struct inode *inode, struct file *filp, | ||
108 | void __user *argp) | ||
109 | { | ||
110 | struct nilfs_transaction_info ti; | ||
111 | unsigned int flags, oldflags; | ||
112 | int ret; | ||
113 | |||
114 | if (!is_owner_or_cap(inode)) | ||
115 | return -EACCES; | ||
116 | |||
117 | if (get_user(flags, (int __user *)argp)) | ||
118 | return -EFAULT; | ||
119 | |||
120 | ret = mnt_want_write(filp->f_path.mnt); | ||
121 | if (ret) | ||
122 | return ret; | ||
123 | |||
124 | flags = nilfs_mask_flags(inode->i_mode, flags); | ||
125 | |||
126 | mutex_lock(&inode->i_mutex); | ||
127 | |||
128 | oldflags = NILFS_I(inode)->i_flags; | ||
129 | |||
130 | /* | ||
131 | * The IMMUTABLE and APPEND_ONLY flags can only be changed by the | ||
132 | * relevant capability. | ||
133 | */ | ||
134 | ret = -EPERM; | ||
135 | if (((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) && | ||
136 | !capable(CAP_LINUX_IMMUTABLE)) | ||
137 | goto out; | ||
138 | |||
139 | ret = nilfs_transaction_begin(inode->i_sb, &ti, 0); | ||
140 | if (ret) | ||
141 | goto out; | ||
142 | |||
143 | NILFS_I(inode)->i_flags = (oldflags & ~FS_FL_USER_MODIFIABLE) | | ||
144 | (flags & FS_FL_USER_MODIFIABLE); | ||
145 | |||
146 | nilfs_set_inode_flags(inode); | ||
147 | inode->i_ctime = CURRENT_TIME; | ||
148 | if (IS_SYNC(inode)) | ||
149 | nilfs_set_transaction_flag(NILFS_TI_SYNC); | ||
150 | |||
151 | nilfs_mark_inode_dirty(inode); | ||
152 | ret = nilfs_transaction_commit(inode->i_sb); | ||
153 | out: | ||
154 | mutex_unlock(&inode->i_mutex); | ||
155 | mnt_drop_write(filp->f_path.mnt); | ||
156 | return ret; | ||
157 | } | ||
158 | |||
159 | static int nilfs_ioctl_getversion(struct inode *inode, void __user *argp) | ||
160 | { | ||
161 | return put_user(inode->i_generation, (int __user *)argp); | ||
162 | } | ||
163 | |||
100 | static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, | 164 | static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, |
101 | unsigned int cmd, void __user *argp) | 165 | unsigned int cmd, void __user *argp) |
102 | { | 166 | { |
@@ -666,6 +730,12 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
666 | void __user *argp = (void __user *)arg; | 730 | void __user *argp = (void __user *)arg; |
667 | 731 | ||
668 | switch (cmd) { | 732 | switch (cmd) { |
733 | case FS_IOC_GETFLAGS: | ||
734 | return nilfs_ioctl_getflags(inode, argp); | ||
735 | case FS_IOC_SETFLAGS: | ||
736 | return nilfs_ioctl_setflags(inode, filp, argp); | ||
737 | case FS_IOC_GETVERSION: | ||
738 | return nilfs_ioctl_getversion(inode, argp); | ||
669 | case NILFS_IOCTL_CHANGE_CPMODE: | 739 | case NILFS_IOCTL_CHANGE_CPMODE: |
670 | return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp); | 740 | return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp); |
671 | case NILFS_IOCTL_DELETE_CHECKPOINT: | 741 | case NILFS_IOCTL_DELETE_CHECKPOINT: |