diff options
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 58 |
1 files changed, 56 insertions, 2 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 5ddd6ea8f839..206632887bb4 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -868,7 +868,7 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat, | |||
868 | } | 868 | } |
869 | 869 | ||
870 | int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, | 870 | int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, |
871 | struct qstr *name) | 871 | u64 child_nodeid, struct qstr *name) |
872 | { | 872 | { |
873 | int err = -ENOTDIR; | 873 | int err = -ENOTDIR; |
874 | struct inode *parent; | 874 | struct inode *parent; |
@@ -895,8 +895,36 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, | |||
895 | 895 | ||
896 | fuse_invalidate_attr(parent); | 896 | fuse_invalidate_attr(parent); |
897 | fuse_invalidate_entry(entry); | 897 | fuse_invalidate_entry(entry); |
898 | |||
899 | if (child_nodeid != 0 && entry->d_inode) { | ||
900 | mutex_lock(&entry->d_inode->i_mutex); | ||
901 | if (get_node_id(entry->d_inode) != child_nodeid) { | ||
902 | err = -ENOENT; | ||
903 | goto badentry; | ||
904 | } | ||
905 | if (d_mountpoint(entry)) { | ||
906 | err = -EBUSY; | ||
907 | goto badentry; | ||
908 | } | ||
909 | if (S_ISDIR(entry->d_inode->i_mode)) { | ||
910 | shrink_dcache_parent(entry); | ||
911 | if (!simple_empty(entry)) { | ||
912 | err = -ENOTEMPTY; | ||
913 | goto badentry; | ||
914 | } | ||
915 | entry->d_inode->i_flags |= S_DEAD; | ||
916 | } | ||
917 | dont_mount(entry); | ||
918 | clear_nlink(entry->d_inode); | ||
919 | err = 0; | ||
920 | badentry: | ||
921 | mutex_unlock(&entry->d_inode->i_mutex); | ||
922 | if (!err) | ||
923 | d_delete(entry); | ||
924 | } else { | ||
925 | err = 0; | ||
926 | } | ||
898 | dput(entry); | 927 | dput(entry); |
899 | err = 0; | ||
900 | 928 | ||
901 | unlock: | 929 | unlock: |
902 | mutex_unlock(&parent->i_mutex); | 930 | mutex_unlock(&parent->i_mutex); |
@@ -1182,6 +1210,30 @@ static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end, | |||
1182 | return fuse_fsync_common(file, start, end, datasync, 1); | 1210 | return fuse_fsync_common(file, start, end, datasync, 1); |
1183 | } | 1211 | } |
1184 | 1212 | ||
1213 | static long fuse_dir_ioctl(struct file *file, unsigned int cmd, | ||
1214 | unsigned long arg) | ||
1215 | { | ||
1216 | struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host); | ||
1217 | |||
1218 | /* FUSE_IOCTL_DIR only supported for API version >= 7.18 */ | ||
1219 | if (fc->minor < 18) | ||
1220 | return -ENOTTY; | ||
1221 | |||
1222 | return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_DIR); | ||
1223 | } | ||
1224 | |||
1225 | static long fuse_dir_compat_ioctl(struct file *file, unsigned int cmd, | ||
1226 | unsigned long arg) | ||
1227 | { | ||
1228 | struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host); | ||
1229 | |||
1230 | if (fc->minor < 18) | ||
1231 | return -ENOTTY; | ||
1232 | |||
1233 | return fuse_ioctl_common(file, cmd, arg, | ||
1234 | FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR); | ||
1235 | } | ||
1236 | |||
1185 | static bool update_mtime(unsigned ivalid) | 1237 | static bool update_mtime(unsigned ivalid) |
1186 | { | 1238 | { |
1187 | /* Always update if mtime is explicitly set */ | 1239 | /* Always update if mtime is explicitly set */ |
@@ -1596,6 +1648,8 @@ static const struct file_operations fuse_dir_operations = { | |||
1596 | .open = fuse_dir_open, | 1648 | .open = fuse_dir_open, |
1597 | .release = fuse_dir_release, | 1649 | .release = fuse_dir_release, |
1598 | .fsync = fuse_dir_fsync, | 1650 | .fsync = fuse_dir_fsync, |
1651 | .unlocked_ioctl = fuse_dir_ioctl, | ||
1652 | .compat_ioctl = fuse_dir_compat_ioctl, | ||
1599 | }; | 1653 | }; |
1600 | 1654 | ||
1601 | static const struct inode_operations fuse_common_inode_operations = { | 1655 | static const struct inode_operations fuse_common_inode_operations = { |