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>
This commit is contained in:
parent
b7a2921765
commit
cafe21a4fb
|
@ -1080,6 +1080,11 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
else
|
else
|
||||||
return -EROFS;
|
return -EROFS;
|
||||||
}
|
}
|
||||||
|
/* don't allow cross-quota renames */
|
||||||
|
if ((old_dir != new_dir) &&
|
||||||
|
(!ceph_quota_is_same_realm(old_dir, new_dir)))
|
||||||
|
return -EXDEV;
|
||||||
|
|
||||||
dout("rename dir %p dentry %p to dir %p dentry %p\n",
|
dout("rename dir %p dentry %p to dir %p dentry %p\n",
|
||||||
old_dir, old_dentry, new_dir, new_dentry);
|
old_dir, old_dentry, new_dir, new_dentry);
|
||||||
req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
|
req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
|
||||||
|
|
|
@ -21,6 +21,11 @@
|
||||||
#include "super.h"
|
#include "super.h"
|
||||||
#include "mds_client.h"
|
#include "mds_client.h"
|
||||||
|
|
||||||
|
static inline bool ceph_has_quota(struct ceph_inode_info *ci)
|
||||||
|
{
|
||||||
|
return (ci && (ci->i_max_files || ci->i_max_bytes));
|
||||||
|
}
|
||||||
|
|
||||||
void ceph_handle_quota(struct ceph_mds_client *mdsc,
|
void ceph_handle_quota(struct ceph_mds_client *mdsc,
|
||||||
struct ceph_mds_session *session,
|
struct ceph_mds_session *session,
|
||||||
struct ceph_msg *msg)
|
struct ceph_msg *msg)
|
||||||
|
@ -64,6 +69,70 @@ void ceph_handle_quota(struct ceph_mds_client *mdsc,
|
||||||
iput(inode);
|
iput(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function walks through the snaprealm for an inode and returns the
|
||||||
|
* ceph_snap_realm for the first snaprealm that has quotas set (either max_files
|
||||||
|
* or max_bytes). If the root is reached, return the root ceph_snap_realm
|
||||||
|
* instead.
|
||||||
|
*
|
||||||
|
* Note that the caller is responsible for calling ceph_put_snap_realm() on the
|
||||||
|
* returned realm.
|
||||||
|
*/
|
||||||
|
static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
|
||||||
|
struct inode *inode)
|
||||||
|
{
|
||||||
|
struct ceph_inode_info *ci = NULL;
|
||||||
|
struct ceph_snap_realm *realm, *next;
|
||||||
|
struct ceph_vino vino;
|
||||||
|
struct inode *in;
|
||||||
|
|
||||||
|
realm = ceph_inode(inode)->i_snap_realm;
|
||||||
|
ceph_get_snap_realm(mdsc, realm);
|
||||||
|
while (realm) {
|
||||||
|
vino.ino = realm->ino;
|
||||||
|
vino.snap = CEPH_NOSNAP;
|
||||||
|
in = ceph_find_inode(inode->i_sb, vino);
|
||||||
|
if (!in) {
|
||||||
|
pr_warn("Failed to find inode for %llu\n", vino.ino);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ci = ceph_inode(in);
|
||||||
|
if (ceph_has_quota(ci) || (ci->i_vino.ino == CEPH_INO_ROOT)) {
|
||||||
|
iput(in);
|
||||||
|
return realm;
|
||||||
|
}
|
||||||
|
iput(in);
|
||||||
|
next = realm->parent;
|
||||||
|
ceph_get_snap_realm(mdsc, next);
|
||||||
|
ceph_put_snap_realm(mdsc, realm);
|
||||||
|
realm = next;
|
||||||
|
}
|
||||||
|
if (realm)
|
||||||
|
ceph_put_snap_realm(mdsc, realm);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
|
||||||
|
{
|
||||||
|
struct ceph_mds_client *mdsc = ceph_inode_to_client(old)->mdsc;
|
||||||
|
struct ceph_snap_realm *old_realm, *new_realm;
|
||||||
|
bool is_same;
|
||||||
|
|
||||||
|
down_read(&mdsc->snap_rwsem);
|
||||||
|
old_realm = get_quota_realm(mdsc, old);
|
||||||
|
new_realm = get_quota_realm(mdsc, new);
|
||||||
|
is_same = (old_realm == new_realm);
|
||||||
|
up_read(&mdsc->snap_rwsem);
|
||||||
|
|
||||||
|
if (old_realm)
|
||||||
|
ceph_put_snap_realm(mdsc, old_realm);
|
||||||
|
if (new_realm)
|
||||||
|
ceph_put_snap_realm(mdsc, new_realm);
|
||||||
|
|
||||||
|
return is_same;
|
||||||
|
}
|
||||||
|
|
||||||
enum quota_check_op {
|
enum quota_check_op {
|
||||||
QUOTA_CHECK_MAX_FILES_OP /* check quota max_files limit */
|
QUOTA_CHECK_MAX_FILES_OP /* check quota max_files limit */
|
||||||
};
|
};
|
||||||
|
|
|
@ -1078,5 +1078,6 @@ extern void ceph_handle_quota(struct ceph_mds_client *mdsc,
|
||||||
struct ceph_mds_session *session,
|
struct ceph_mds_session *session,
|
||||||
struct ceph_msg *msg);
|
struct ceph_msg *msg);
|
||||||
extern bool ceph_quota_is_max_files_exceeded(struct inode *inode);
|
extern bool ceph_quota_is_max_files_exceeded(struct inode *inode);
|
||||||
|
extern bool ceph_quota_is_same_realm(struct inode *old, struct inode *new);
|
||||||
|
|
||||||
#endif /* _FS_CEPH_SUPER_H */
|
#endif /* _FS_CEPH_SUPER_H */
|
||||||
|
|
Loading…
Reference in New Issue