diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-12 15:39:21 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-12 15:39:21 -0500 |
commit | 6733e54b669c600eb8e451939ad55130db664fed (patch) | |
tree | 2a8c24c856fa3f5d7d58a3eb39da943ca1c57e65 /fs/fuse | |
parent | bcf8a3dfcb274cf6654a19e12e244f3af8c0d355 (diff) | |
parent | 451d0f599934fd97faf54a5d7954b518e66192cb (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
FUSE: Notifying the kernel of deletion.
fuse: support ioctl on directories
fuse: Use kcalloc instead of kzalloc to allocate array
fuse: llseek optimize SEEK_CUR and SEEK_SET
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/dev.c | 57 | ||||
-rw-r--r-- | fs/fuse/dir.c | 58 | ||||
-rw-r--r-- | fs/fuse/file.c | 58 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 10 |
4 files changed, 134 insertions, 49 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 2aaf3eaaf13d..5f3368ab0fa9 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -1378,7 +1378,59 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, | |||
1378 | down_read(&fc->killsb); | 1378 | down_read(&fc->killsb); |
1379 | err = -ENOENT; | 1379 | err = -ENOENT; |
1380 | if (fc->sb) | 1380 | if (fc->sb) |
1381 | err = fuse_reverse_inval_entry(fc->sb, outarg.parent, &name); | 1381 | err = fuse_reverse_inval_entry(fc->sb, outarg.parent, 0, &name); |
1382 | up_read(&fc->killsb); | ||
1383 | kfree(buf); | ||
1384 | return err; | ||
1385 | |||
1386 | err: | ||
1387 | kfree(buf); | ||
1388 | fuse_copy_finish(cs); | ||
1389 | return err; | ||
1390 | } | ||
1391 | |||
1392 | static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size, | ||
1393 | struct fuse_copy_state *cs) | ||
1394 | { | ||
1395 | struct fuse_notify_delete_out outarg; | ||
1396 | int err = -ENOMEM; | ||
1397 | char *buf; | ||
1398 | struct qstr name; | ||
1399 | |||
1400 | buf = kzalloc(FUSE_NAME_MAX + 1, GFP_KERNEL); | ||
1401 | if (!buf) | ||
1402 | goto err; | ||
1403 | |||
1404 | err = -EINVAL; | ||
1405 | if (size < sizeof(outarg)) | ||
1406 | goto err; | ||
1407 | |||
1408 | err = fuse_copy_one(cs, &outarg, sizeof(outarg)); | ||
1409 | if (err) | ||
1410 | goto err; | ||
1411 | |||
1412 | err = -ENAMETOOLONG; | ||
1413 | if (outarg.namelen > FUSE_NAME_MAX) | ||
1414 | goto err; | ||
1415 | |||
1416 | err = -EINVAL; | ||
1417 | if (size != sizeof(outarg) + outarg.namelen + 1) | ||
1418 | goto err; | ||
1419 | |||
1420 | name.name = buf; | ||
1421 | name.len = outarg.namelen; | ||
1422 | err = fuse_copy_one(cs, buf, outarg.namelen + 1); | ||
1423 | if (err) | ||
1424 | goto err; | ||
1425 | fuse_copy_finish(cs); | ||
1426 | buf[outarg.namelen] = 0; | ||
1427 | name.hash = full_name_hash(name.name, name.len); | ||
1428 | |||
1429 | down_read(&fc->killsb); | ||
1430 | err = -ENOENT; | ||
1431 | if (fc->sb) | ||
1432 | err = fuse_reverse_inval_entry(fc->sb, outarg.parent, | ||
1433 | outarg.child, &name); | ||
1382 | up_read(&fc->killsb); | 1434 | up_read(&fc->killsb); |
1383 | kfree(buf); | 1435 | kfree(buf); |
1384 | return err; | 1436 | return err; |
@@ -1597,6 +1649,9 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, | |||
1597 | case FUSE_NOTIFY_RETRIEVE: | 1649 | case FUSE_NOTIFY_RETRIEVE: |
1598 | return fuse_notify_retrieve(fc, size, cs); | 1650 | return fuse_notify_retrieve(fc, size, cs); |
1599 | 1651 | ||
1652 | case FUSE_NOTIFY_DELETE: | ||
1653 | return fuse_notify_delete(fc, size, cs); | ||
1654 | |||
1600 | default: | 1655 | default: |
1601 | fuse_copy_finish(cs); | 1656 | fuse_copy_finish(cs); |
1602 | return -EINVAL; | 1657 | return -EINVAL; |
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 = { |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 0c84100acd44..4a199fd93fbd 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -1555,48 +1555,16 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin) | |||
1555 | loff_t retval; | 1555 | loff_t retval; |
1556 | struct inode *inode = file->f_path.dentry->d_inode; | 1556 | struct inode *inode = file->f_path.dentry->d_inode; |
1557 | 1557 | ||
1558 | mutex_lock(&inode->i_mutex); | 1558 | /* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */ |
1559 | if (origin != SEEK_CUR && origin != SEEK_SET) { | 1559 | if (origin == SEEK_CUR || origin == SEEK_SET) |
1560 | retval = fuse_update_attributes(inode, NULL, file, NULL); | 1560 | return generic_file_llseek(file, offset, origin); |
1561 | if (retval) | ||
1562 | goto exit; | ||
1563 | } | ||
1564 | 1561 | ||
1565 | switch (origin) { | 1562 | mutex_lock(&inode->i_mutex); |
1566 | case SEEK_END: | 1563 | retval = fuse_update_attributes(inode, NULL, file, NULL); |
1567 | offset += i_size_read(inode); | 1564 | if (!retval) |
1568 | break; | 1565 | retval = generic_file_llseek(file, offset, origin); |
1569 | case SEEK_CUR: | ||
1570 | if (offset == 0) { | ||
1571 | retval = file->f_pos; | ||
1572 | goto exit; | ||
1573 | } | ||
1574 | offset += file->f_pos; | ||
1575 | break; | ||
1576 | case SEEK_DATA: | ||
1577 | if (offset >= i_size_read(inode)) { | ||
1578 | retval = -ENXIO; | ||
1579 | goto exit; | ||
1580 | } | ||
1581 | break; | ||
1582 | case SEEK_HOLE: | ||
1583 | if (offset >= i_size_read(inode)) { | ||
1584 | retval = -ENXIO; | ||
1585 | goto exit; | ||
1586 | } | ||
1587 | offset = i_size_read(inode); | ||
1588 | break; | ||
1589 | } | ||
1590 | retval = -EINVAL; | ||
1591 | if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) { | ||
1592 | if (offset != file->f_pos) { | ||
1593 | file->f_pos = offset; | ||
1594 | file->f_version = 0; | ||
1595 | } | ||
1596 | retval = offset; | ||
1597 | } | ||
1598 | exit: | ||
1599 | mutex_unlock(&inode->i_mutex); | 1566 | mutex_unlock(&inode->i_mutex); |
1567 | |||
1600 | return retval; | 1568 | return retval; |
1601 | } | 1569 | } |
1602 | 1570 | ||
@@ -1808,7 +1776,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | |||
1808 | BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE); | 1776 | BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE); |
1809 | 1777 | ||
1810 | err = -ENOMEM; | 1778 | err = -ENOMEM; |
1811 | pages = kzalloc(sizeof(pages[0]) * FUSE_MAX_PAGES_PER_REQ, GFP_KERNEL); | 1779 | pages = kcalloc(FUSE_MAX_PAGES_PER_REQ, sizeof(pages[0]), GFP_KERNEL); |
1812 | iov_page = (struct iovec *) __get_free_page(GFP_KERNEL); | 1780 | iov_page = (struct iovec *) __get_free_page(GFP_KERNEL); |
1813 | if (!pages || !iov_page) | 1781 | if (!pages || !iov_page) |
1814 | goto out; | 1782 | goto out; |
@@ -1958,8 +1926,8 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | |||
1958 | } | 1926 | } |
1959 | EXPORT_SYMBOL_GPL(fuse_do_ioctl); | 1927 | EXPORT_SYMBOL_GPL(fuse_do_ioctl); |
1960 | 1928 | ||
1961 | static long fuse_file_ioctl_common(struct file *file, unsigned int cmd, | 1929 | long fuse_ioctl_common(struct file *file, unsigned int cmd, |
1962 | unsigned long arg, unsigned int flags) | 1930 | unsigned long arg, unsigned int flags) |
1963 | { | 1931 | { |
1964 | struct inode *inode = file->f_dentry->d_inode; | 1932 | struct inode *inode = file->f_dentry->d_inode; |
1965 | struct fuse_conn *fc = get_fuse_conn(inode); | 1933 | struct fuse_conn *fc = get_fuse_conn(inode); |
@@ -1976,13 +1944,13 @@ static long fuse_file_ioctl_common(struct file *file, unsigned int cmd, | |||
1976 | static long fuse_file_ioctl(struct file *file, unsigned int cmd, | 1944 | static long fuse_file_ioctl(struct file *file, unsigned int cmd, |
1977 | unsigned long arg) | 1945 | unsigned long arg) |
1978 | { | 1946 | { |
1979 | return fuse_file_ioctl_common(file, cmd, arg, 0); | 1947 | return fuse_ioctl_common(file, cmd, arg, 0); |
1980 | } | 1948 | } |
1981 | 1949 | ||
1982 | static long fuse_file_compat_ioctl(struct file *file, unsigned int cmd, | 1950 | static long fuse_file_compat_ioctl(struct file *file, unsigned int cmd, |
1983 | unsigned long arg) | 1951 | unsigned long arg) |
1984 | { | 1952 | { |
1985 | return fuse_file_ioctl_common(file, cmd, arg, FUSE_IOCTL_COMPAT); | 1953 | return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_COMPAT); |
1986 | } | 1954 | } |
1987 | 1955 | ||
1988 | /* | 1956 | /* |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 1964da0257d9..572cefc78012 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -755,9 +755,15 @@ int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid, | |||
755 | /** | 755 | /** |
756 | * File-system tells the kernel to invalidate parent attributes and | 756 | * File-system tells the kernel to invalidate parent attributes and |
757 | * the dentry matching parent/name. | 757 | * the dentry matching parent/name. |
758 | * | ||
759 | * If the child_nodeid is non-zero and: | ||
760 | * - matches the inode number for the dentry matching parent/name, | ||
761 | * - is not a mount point | ||
762 | * - is a file or oan empty directory | ||
763 | * then the dentry is unhashed (d_delete()). | ||
758 | */ | 764 | */ |
759 | int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, | 765 | int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, |
760 | struct qstr *name); | 766 | u64 child_nodeid, struct qstr *name); |
761 | 767 | ||
762 | int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, | 768 | int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, |
763 | bool isdir); | 769 | bool isdir); |
@@ -765,6 +771,8 @@ ssize_t fuse_direct_io(struct file *file, const char __user *buf, | |||
765 | size_t count, loff_t *ppos, int write); | 771 | size_t count, loff_t *ppos, int write); |
766 | long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | 772 | long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, |
767 | unsigned int flags); | 773 | unsigned int flags); |
774 | long fuse_ioctl_common(struct file *file, unsigned int cmd, | ||
775 | unsigned long arg, unsigned int flags); | ||
768 | unsigned fuse_file_poll(struct file *file, poll_table *wait); | 776 | unsigned fuse_file_poll(struct file *file, poll_table *wait); |
769 | int fuse_dev_release(struct inode *inode, struct file *file); | 777 | int fuse_dev_release(struct inode *inode, struct file *file); |
770 | 778 | ||