forked from Minki/linux
A cap handling fix from Zhi that ensures that metadata writeback isn't
delayed and three error path memory leak fixups from Chengguang. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAABCAAGBQJamV3qAAoJEEp/3jgCEfOLv6kIAI0RXShR20dz9M3GnL2bDws7 KFkC/aNwbviXMAih3q7Q7ZiwXv6BI/uUK0YIYG/tWZoNHucYGS8ZOFDikdiIMcJR 2VP8Yas1/NvnLlh0ut45s2imvbXinkHcjWOLqgJJmJ2cEP9Ar/mbwz//TgfVMdNm TSHEm2LPRge9jK3Ab/ZiatExGH6dx5hRJvssSauF+f2iN+q4nKj2aBqle+FKaNWT Iv0ONi2f7aXnaXRvum4Y1gnKWXzKSFd8Y2Cr5R3tfTrKBv8nmQz54eRsMnnuxK/7 uV6Ujch4LUXBI1etXLqTwRdZQIcw3Li5PYxGrO8fl8mQfJau9yv5REw/rbgB5FU= =f8gA -----END PGP SIGNATURE----- Merge tag 'ceph-for-4.16-rc4' of git://github.com/ceph/ceph-client Pull ceph fixes from Ilya Dryomov: "A cap handling fix from Zhi that ensures that metadata writeback isn't delayed and three error path memory leak fixups from Chengguang" * tag 'ceph-for-4.16-rc4' of git://github.com/ceph/ceph-client: ceph: fix potential memory leak in init_caches() ceph: fix dentry leak when failing to init debugfs libceph, ceph: avoid memory leak when specifying same option several times ceph: flush dirty caps of unlinked inode ASAP
This commit is contained in:
commit
2833419a62
@ -3964,6 +3964,32 @@ void ceph_put_fmode(struct ceph_inode_info *ci, int fmode)
|
||||
ceph_check_caps(ci, 0, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* For a soon-to-be unlinked file, drop the AUTH_RDCACHE caps. If it
|
||||
* looks like the link count will hit 0, drop any other caps (other
|
||||
* than PIN) we don't specifically want (due to the file still being
|
||||
* open).
|
||||
*/
|
||||
int ceph_drop_caps_for_unlink(struct inode *inode)
|
||||
{
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
int drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL;
|
||||
|
||||
spin_lock(&ci->i_ceph_lock);
|
||||
if (inode->i_nlink == 1) {
|
||||
drop |= ~(__ceph_caps_wanted(ci) | CEPH_CAP_PIN);
|
||||
|
||||
ci->i_ceph_flags |= CEPH_I_NODELAY;
|
||||
if (__ceph_caps_dirty(ci)) {
|
||||
struct ceph_mds_client *mdsc =
|
||||
ceph_inode_to_client(inode)->mdsc;
|
||||
__cap_delay_requeue_front(mdsc, ci);
|
||||
}
|
||||
}
|
||||
spin_unlock(&ci->i_ceph_lock);
|
||||
return drop;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helpers for embedding cap and dentry lease releases into mds
|
||||
* requests.
|
||||
|
@ -1002,26 +1002,6 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a soon-to-be unlinked file, drop the AUTH_RDCACHE caps. If it
|
||||
* looks like the link count will hit 0, drop any other caps (other
|
||||
* than PIN) we don't specifically want (due to the file still being
|
||||
* open).
|
||||
*/
|
||||
static int drop_caps_for_unlink(struct inode *inode)
|
||||
{
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
int drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL;
|
||||
|
||||
spin_lock(&ci->i_ceph_lock);
|
||||
if (inode->i_nlink == 1) {
|
||||
drop |= ~(__ceph_caps_wanted(ci) | CEPH_CAP_PIN);
|
||||
ci->i_ceph_flags |= CEPH_I_NODELAY;
|
||||
}
|
||||
spin_unlock(&ci->i_ceph_lock);
|
||||
return drop;
|
||||
}
|
||||
|
||||
/*
|
||||
* rmdir and unlink are differ only by the metadata op code
|
||||
*/
|
||||
@ -1056,7 +1036,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
|
||||
set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
|
||||
req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
|
||||
req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
|
||||
req->r_inode_drop = drop_caps_for_unlink(inode);
|
||||
req->r_inode_drop = ceph_drop_caps_for_unlink(inode);
|
||||
err = ceph_mdsc_do_request(mdsc, dir, req);
|
||||
if (!err && !req->r_reply_info.head->is_dentry)
|
||||
d_delete(dentry);
|
||||
@ -1104,8 +1084,10 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
|
||||
/* release LINK_RDCACHE on source inode (mds will lock it) */
|
||||
req->r_old_inode_drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL;
|
||||
if (d_really_is_positive(new_dentry))
|
||||
req->r_inode_drop = drop_caps_for_unlink(d_inode(new_dentry));
|
||||
if (d_really_is_positive(new_dentry)) {
|
||||
req->r_inode_drop =
|
||||
ceph_drop_caps_for_unlink(d_inode(new_dentry));
|
||||
}
|
||||
err = ceph_mdsc_do_request(mdsc, old_dir, req);
|
||||
if (!err && !req->r_reply_info.head->is_dentry) {
|
||||
/*
|
||||
|
@ -225,6 +225,7 @@ static int parse_fsopt_token(char *c, void *private)
|
||||
return -ENOMEM;
|
||||
break;
|
||||
case Opt_mds_namespace:
|
||||
kfree(fsopt->mds_namespace);
|
||||
fsopt->mds_namespace = kstrndup(argstr[0].from,
|
||||
argstr[0].to-argstr[0].from,
|
||||
GFP_KERNEL);
|
||||
@ -232,6 +233,7 @@ static int parse_fsopt_token(char *c, void *private)
|
||||
return -ENOMEM;
|
||||
break;
|
||||
case Opt_fscache_uniq:
|
||||
kfree(fsopt->fscache_uniq);
|
||||
fsopt->fscache_uniq = kstrndup(argstr[0].from,
|
||||
argstr[0].to-argstr[0].from,
|
||||
GFP_KERNEL);
|
||||
@ -711,14 +713,17 @@ static int __init init_caches(void)
|
||||
goto bad_dentry;
|
||||
|
||||
ceph_file_cachep = KMEM_CACHE(ceph_file_info, SLAB_MEM_SPREAD);
|
||||
|
||||
if (!ceph_file_cachep)
|
||||
goto bad_file;
|
||||
|
||||
if ((error = ceph_fscache_register()))
|
||||
goto bad_file;
|
||||
error = ceph_fscache_register();
|
||||
if (error)
|
||||
goto bad_fscache;
|
||||
|
||||
return 0;
|
||||
|
||||
bad_fscache:
|
||||
kmem_cache_destroy(ceph_file_cachep);
|
||||
bad_file:
|
||||
kmem_cache_destroy(ceph_dentry_cachep);
|
||||
bad_dentry:
|
||||
@ -836,7 +841,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
|
||||
int err;
|
||||
unsigned long started = jiffies; /* note the start time */
|
||||
struct dentry *root;
|
||||
int first = 0; /* first vfsmount for this super_block */
|
||||
|
||||
dout("mount start %p\n", fsc);
|
||||
mutex_lock(&fsc->client->mount_mutex);
|
||||
@ -861,17 +865,17 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
|
||||
path = fsc->mount_options->server_path + 1;
|
||||
dout("mount opening path %s\n", path);
|
||||
}
|
||||
|
||||
err = ceph_fs_debugfs_init(fsc);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
root = open_root_dentry(fsc, path, started);
|
||||
if (IS_ERR(root)) {
|
||||
err = PTR_ERR(root);
|
||||
goto out;
|
||||
}
|
||||
fsc->sb->s_root = dget(root);
|
||||
first = 1;
|
||||
|
||||
err = ceph_fs_debugfs_init(fsc);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
} else {
|
||||
root = dget(fsc->sb->s_root);
|
||||
}
|
||||
@ -881,11 +885,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
|
||||
mutex_unlock(&fsc->client->mount_mutex);
|
||||
return root;
|
||||
|
||||
fail:
|
||||
if (first) {
|
||||
dput(fsc->sb->s_root);
|
||||
fsc->sb->s_root = NULL;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&fsc->client->mount_mutex);
|
||||
return ERR_PTR(err);
|
||||
|
@ -987,7 +987,7 @@ extern void ceph_check_caps(struct ceph_inode_info *ci, int flags,
|
||||
struct ceph_mds_session *session);
|
||||
extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc);
|
||||
extern void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc);
|
||||
|
||||
extern int ceph_drop_caps_for_unlink(struct inode *inode);
|
||||
extern int ceph_encode_inode_release(void **p, struct inode *inode,
|
||||
int mds, int drop, int unless, int force);
|
||||
extern int ceph_encode_dentry_release(void **p, struct dentry *dn,
|
||||
|
@ -418,6 +418,7 @@ ceph_parse_options(char *options, const char *dev_name,
|
||||
opt->flags |= CEPH_OPT_FSID;
|
||||
break;
|
||||
case Opt_name:
|
||||
kfree(opt->name);
|
||||
opt->name = kstrndup(argstr[0].from,
|
||||
argstr[0].to-argstr[0].from,
|
||||
GFP_KERNEL);
|
||||
@ -427,6 +428,9 @@ ceph_parse_options(char *options, const char *dev_name,
|
||||
}
|
||||
break;
|
||||
case Opt_secret:
|
||||
ceph_crypto_key_destroy(opt->key);
|
||||
kfree(opt->key);
|
||||
|
||||
opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
|
||||
if (!opt->key) {
|
||||
err = -ENOMEM;
|
||||
@ -437,6 +441,9 @@ ceph_parse_options(char *options, const char *dev_name,
|
||||
goto out;
|
||||
break;
|
||||
case Opt_key:
|
||||
ceph_crypto_key_destroy(opt->key);
|
||||
kfree(opt->key);
|
||||
|
||||
opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
|
||||
if (!opt->key) {
|
||||
err = -ENOMEM;
|
||||
|
Loading…
Reference in New Issue
Block a user