summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLuis Henriques <lhenriques@suse.com>2018-01-05 05:47:20 -0500
committerIlya Dryomov <idryomov@gmail.com>2018-04-02 05:17:52 -0400
commitcafe21a4fb3075fb2980caba8fdb533a1bdb52b0 (patch)
treeccdcecba6b1fb66f93c95032fb2be668e10aa7fe /fs
parentb7a2921765cf796280baf653a52b22b52e0ba266 (diff)
ceph: quota: don't allow cross-quota renames
This patch changes ceph_rename so that -EXDEV is returned if an attempt is made to mv a file between two different dir trees with different quotas setup. Signed-off-by: Luis Henriques <lhenriques@suse.com> Reviewed-by: "Yan, Zheng" <zyan@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ceph/dir.c5
-rw-r--r--fs/ceph/quota.c69
-rw-r--r--fs/ceph/super.h1
3 files changed, 75 insertions, 0 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 7d9851cd51bb..1f60498c4631 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1080,6 +1080,11 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
1080 else 1080 else
1081 return -EROFS; 1081 return -EROFS;
1082 } 1082 }
1083 /* don't allow cross-quota renames */
1084 if ((old_dir != new_dir) &&
1085 (!ceph_quota_is_same_realm(old_dir, new_dir)))
1086 return -EXDEV;
1087
1083 dout("rename dir %p dentry %p to dir %p dentry %p\n", 1088 dout("rename dir %p dentry %p to dir %p dentry %p\n",
1084 old_dir, old_dentry, new_dir, new_dentry); 1089 old_dir, old_dentry, new_dir, new_dentry);
1085 req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS); 1090 req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
index cf1c78c4a4d2..5d7dada91a57 100644
--- a/fs/ceph/quota.c
+++ b/fs/ceph/quota.c
@@ -21,6 +21,11 @@
21#include "super.h" 21#include "super.h"
22#include "mds_client.h" 22#include "mds_client.h"
23 23
24static inline bool ceph_has_quota(struct ceph_inode_info *ci)
25{
26 return (ci && (ci->i_max_files || ci->i_max_bytes));
27}
28
24void ceph_handle_quota(struct ceph_mds_client *mdsc, 29void ceph_handle_quota(struct ceph_mds_client *mdsc,
25 struct ceph_mds_session *session, 30 struct ceph_mds_session *session,
26 struct ceph_msg *msg) 31 struct ceph_msg *msg)
@@ -64,6 +69,70 @@ void ceph_handle_quota(struct ceph_mds_client *mdsc,
64 iput(inode); 69 iput(inode);
65} 70}
66 71
72/*
73 * This function walks through the snaprealm for an inode and returns the
74 * ceph_snap_realm for the first snaprealm that has quotas set (either max_files
75 * or max_bytes). If the root is reached, return the root ceph_snap_realm
76 * instead.
77 *
78 * Note that the caller is responsible for calling ceph_put_snap_realm() on the
79 * returned realm.
80 */
81static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
82 struct inode *inode)
83{
84 struct ceph_inode_info *ci = NULL;
85 struct ceph_snap_realm *realm, *next;
86 struct ceph_vino vino;
87 struct inode *in;
88
89 realm = ceph_inode(inode)->i_snap_realm;
90 ceph_get_snap_realm(mdsc, realm);
91 while (realm) {
92 vino.ino = realm->ino;
93 vino.snap = CEPH_NOSNAP;
94 in = ceph_find_inode(inode->i_sb, vino);
95 if (!in) {
96 pr_warn("Failed to find inode for %llu\n", vino.ino);
97 break;
98 }
99 ci = ceph_inode(in);
100 if (ceph_has_quota(ci) || (ci->i_vino.ino == CEPH_INO_ROOT)) {
101 iput(in);
102 return realm;
103 }
104 iput(in);
105 next = realm->parent;
106 ceph_get_snap_realm(mdsc, next);
107 ceph_put_snap_realm(mdsc, realm);
108 realm = next;
109 }
110 if (realm)
111 ceph_put_snap_realm(mdsc, realm);
112
113 return NULL;
114}
115
116bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
117{
118 struct ceph_mds_client *mdsc = ceph_inode_to_client(old)->mdsc;
119 struct ceph_snap_realm *old_realm, *new_realm;
120 bool is_same;
121
122 down_read(&mdsc->snap_rwsem);
123 old_realm = get_quota_realm(mdsc, old);
124 new_realm = get_quota_realm(mdsc, new);
125 is_same = (old_realm == new_realm);
126 up_read(&mdsc->snap_rwsem);
127
128 if (old_realm)
129 ceph_put_snap_realm(mdsc, old_realm);
130 if (new_realm)
131 ceph_put_snap_realm(mdsc, new_realm);
132
133 return is_same;
134}
135
67enum quota_check_op { 136enum quota_check_op {
68 QUOTA_CHECK_MAX_FILES_OP /* check quota max_files limit */ 137 QUOTA_CHECK_MAX_FILES_OP /* check quota max_files limit */
69}; 138};
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 4afc6cca8786..eea6f70f3bf9 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -1078,5 +1078,6 @@ extern void ceph_handle_quota(struct ceph_mds_client *mdsc,
1078 struct ceph_mds_session *session, 1078 struct ceph_mds_session *session,
1079 struct ceph_msg *msg); 1079 struct ceph_msg *msg);
1080extern bool ceph_quota_is_max_files_exceeded(struct inode *inode); 1080extern bool ceph_quota_is_max_files_exceeded(struct inode *inode);
1081extern bool ceph_quota_is_same_realm(struct inode *old, struct inode *new);
1081 1082
1082#endif /* _FS_CEPH_SUPER_H */ 1083#endif /* _FS_CEPH_SUPER_H */