Commit 6b049081 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client

Pull Ceph updates from Sage Weil:
 "There is the long-awaited discard support for RBD (Guangliang Zhao,
  Josh Durgin), a pile of RBD bug fixes that didn't belong in late -rc's
  (Ilya Dryomov, Li RongQing), a pile of fs/ceph bug fixes and
  performance and debugging improvements (Yan, Zheng, John Spray), and a
  smattering of cleanups (Chao Yu, Fabian Frederick, Joe Perches)"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client: (40 commits)
  ceph: fix divide-by-zero in __validate_layout()
  rbd: rbd workqueues need a resque worker
  libceph: ceph-msgr workqueue needs a resque worker
  ceph: fix bool assignments
  libceph: separate multiple ops with commas in debugfs output
  libceph: sync osd op definitions in rados.h
  libceph: remove redundant declaration
  ceph: additional debugfs output
  ceph: export ceph_session_state_name function
  ceph: include the initial ACL in create/mkdir/mknod MDS requests
  ceph: use pagelist to present MDS request data
  libceph: reference counting pagelist
  ceph: fix llistxattr on symlink
  ceph: send client metadata to MDS
  ceph: remove redundant code for max file size verification
  ceph: remove redundant io_iter_advance()
  ceph: move ceph_find_inode() outside the s_mutex
  ceph: request xattrs if xattr_version is zero
  rbd: set the remaining discard properties to enable support
  rbd: use helpers to handle discard for layered images correctly
  ...
parents ce9d7f7b 0bc62284
This diff is collapsed.
...@@ -169,36 +169,109 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type) ...@@ -169,36 +169,109 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
return ret; return ret;
} }
int ceph_init_acl(struct dentry *dentry, struct inode *inode, struct inode *dir) int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
struct ceph_acls_info *info)
{ {
struct posix_acl *default_acl, *acl; struct posix_acl *acl, *default_acl;
umode_t new_mode = inode->i_mode; size_t val_size1 = 0, val_size2 = 0;
int error; struct ceph_pagelist *pagelist = NULL;
void *tmp_buf = NULL;
error = posix_acl_create(dir, &new_mode, &default_acl, &acl); int err;
if (error)
return error; err = posix_acl_create(dir, mode, &default_acl, &acl);
if (err)
if (!default_acl && !acl) { return err;
cache_no_acl(inode);
if (new_mode != inode->i_mode) { if (acl) {
struct iattr newattrs = { int ret = posix_acl_equiv_mode(acl, mode);
.ia_mode = new_mode, if (ret < 0)
.ia_valid = ATTR_MODE, goto out_err;
}; if (ret == 0) {
error = ceph_setattr(dentry, &newattrs); posix_acl_release(acl);
acl = NULL;
} }
return error;
} }
if (default_acl) { if (!default_acl && !acl)
error = ceph_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); return 0;
posix_acl_release(default_acl);
} if (acl)
val_size1 = posix_acl_xattr_size(acl->a_count);
if (default_acl)
val_size2 = posix_acl_xattr_size(default_acl->a_count);
err = -ENOMEM;
tmp_buf = kmalloc(max(val_size1, val_size2), GFP_NOFS);
if (!tmp_buf)
goto out_err;
pagelist = kmalloc(sizeof(struct ceph_pagelist), GFP_NOFS);
if (!pagelist)
goto out_err;
ceph_pagelist_init(pagelist);
err = ceph_pagelist_reserve(pagelist, PAGE_SIZE);
if (err)
goto out_err;
ceph_pagelist_encode_32(pagelist, acl && default_acl ? 2 : 1);
if (acl) { if (acl) {
if (!error) size_t len = strlen(POSIX_ACL_XATTR_ACCESS);
error = ceph_set_acl(inode, acl, ACL_TYPE_ACCESS); err = ceph_pagelist_reserve(pagelist, len + val_size1 + 8);
posix_acl_release(acl); if (err)
goto out_err;
ceph_pagelist_encode_string(pagelist, POSIX_ACL_XATTR_ACCESS,
len);
err = posix_acl_to_xattr(&init_user_ns, acl,
tmp_buf, val_size1);
if (err < 0)
goto out_err;
ceph_pagelist_encode_32(pagelist, val_size1);
ceph_pagelist_append(pagelist, tmp_buf, val_size1);
} }
return error; if (default_acl) {
size_t len = strlen(POSIX_ACL_XATTR_DEFAULT);
err = ceph_pagelist_reserve(pagelist, len + val_size2 + 8);
if (err)
goto out_err;
err = ceph_pagelist_encode_string(pagelist,
POSIX_ACL_XATTR_DEFAULT, len);
err = posix_acl_to_xattr(&init_user_ns, default_acl,
tmp_buf, val_size2);
if (err < 0)
goto out_err;
ceph_pagelist_encode_32(pagelist, val_size2);
ceph_pagelist_append(pagelist, tmp_buf, val_size2);
}
kfree(tmp_buf);
info->acl = acl;
info->default_acl = default_acl;
info->pagelist = pagelist;
return 0;
out_err:
posix_acl_release(acl);
posix_acl_release(default_acl);
kfree(tmp_buf);
if (pagelist)
ceph_pagelist_release(pagelist);
return err;
}
void ceph_init_inode_acls(struct inode* inode, struct ceph_acls_info *info)
{
if (!inode)
return;
ceph_set_cached_acl(inode, ACL_TYPE_ACCESS, info->acl);
ceph_set_cached_acl(inode, ACL_TYPE_DEFAULT, info->default_acl);
}
void ceph_release_acls_info(struct ceph_acls_info *info)
{
posix_acl_release(info->acl);
posix_acl_release(info->default_acl);
if (info->pagelist)
ceph_pagelist_release(info->pagelist);
} }
...@@ -1076,12 +1076,6 @@ static int ceph_update_writeable_page(struct file *file, ...@@ -1076,12 +1076,6 @@ static int ceph_update_writeable_page(struct file *file,
/* past end of file? */ /* past end of file? */
i_size = inode->i_size; /* caller holds i_mutex */ i_size = inode->i_size; /* caller holds i_mutex */
if (i_size + len > inode->i_sb->s_maxbytes) {
/* file is too big */
r = -EINVAL;
goto fail;
}
if (page_off >= i_size || if (page_off >= i_size ||
(pos_in_page == 0 && (pos+len) >= i_size && (pos_in_page == 0 && (pos+len) >= i_size &&
end_in_page - pos_in_page != PAGE_CACHE_SIZE)) { end_in_page - pos_in_page != PAGE_CACHE_SIZE)) {
...@@ -1099,9 +1093,6 @@ static int ceph_update_writeable_page(struct file *file, ...@@ -1099,9 +1093,6 @@ static int ceph_update_writeable_page(struct file *file,
if (r < 0) if (r < 0)
goto fail_nosnap; goto fail_nosnap;
goto retry_locked; goto retry_locked;
fail:
up_read(&mdsc->snap_rwsem);
fail_nosnap: fail_nosnap:
unlock_page(page); unlock_page(page);
return r; return r;
......
...@@ -2397,12 +2397,12 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc, ...@@ -2397,12 +2397,12 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
u64 max_size = le64_to_cpu(grant->max_size); u64 max_size = le64_to_cpu(grant->max_size);
struct timespec mtime, atime, ctime; struct timespec mtime, atime, ctime;
int check_caps = 0; int check_caps = 0;
bool wake = 0; bool wake = false;
bool writeback = 0; bool writeback = false;
bool queue_trunc = 0; bool queue_trunc = false;
bool queue_invalidate = 0; bool queue_invalidate = false;
bool queue_revalidate = 0; bool queue_revalidate = false;
bool deleted_inode = 0; bool deleted_inode = false;
dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n", dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n",
inode, cap, mds, seq, ceph_cap_string(newcaps)); inode, cap, mds, seq, ceph_cap_string(newcaps));
...@@ -2437,7 +2437,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc, ...@@ -2437,7 +2437,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
/* there were locked pages.. invalidate later /* there were locked pages.. invalidate later
in a separate thread. */ in a separate thread. */
if (ci->i_rdcache_revoking != ci->i_rdcache_gen) { if (ci->i_rdcache_revoking != ci->i_rdcache_gen) {
queue_invalidate = 1; queue_invalidate = true;
ci->i_rdcache_revoking = ci->i_rdcache_gen; ci->i_rdcache_revoking = ci->i_rdcache_gen;
} }
} }
...@@ -2466,7 +2466,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc, ...@@ -2466,7 +2466,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
set_nlink(inode, le32_to_cpu(grant->nlink)); set_nlink(inode, le32_to_cpu(grant->nlink));
if (inode->i_nlink == 0 && if (inode->i_nlink == 0 &&
(newcaps & (CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL))) (newcaps & (CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL)))
deleted_inode = 1; deleted_inode = true;
} }
if ((issued & CEPH_CAP_XATTR_EXCL) == 0 && grant->xattr_len) { if ((issued & CEPH_CAP_XATTR_EXCL) == 0 && grant->xattr_len) {
...@@ -2487,7 +2487,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc, ...@@ -2487,7 +2487,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
/* Do we need to revalidate our fscache cookie. Don't bother on the /* Do we need to revalidate our fscache cookie. Don't bother on the
* first cache cap as we already validate at cookie creation time. */ * first cache cap as we already validate at cookie creation time. */
if ((issued & CEPH_CAP_FILE_CACHE) && ci->i_rdcache_gen > 1) if ((issued & CEPH_CAP_FILE_CACHE) && ci->i_rdcache_gen > 1)
queue_revalidate = 1; queue_revalidate = true;
if (newcaps & CEPH_CAP_ANY_RD) { if (newcaps & CEPH_CAP_ANY_RD) {
/* ctime/mtime/atime? */ /* ctime/mtime/atime? */
...@@ -2516,7 +2516,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc, ...@@ -2516,7 +2516,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
ci->i_wanted_max_size = 0; /* reset */ ci->i_wanted_max_size = 0; /* reset */
ci->i_requested_max_size = 0; ci->i_requested_max_size = 0;
} }
wake = 1; wake = true;
} }
} }
...@@ -2546,7 +2546,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc, ...@@ -2546,7 +2546,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
ceph_cap_string(newcaps), ceph_cap_string(newcaps),
ceph_cap_string(revoking)); ceph_cap_string(revoking));
if (revoking & used & CEPH_CAP_FILE_BUFFER) if (revoking & used & CEPH_CAP_FILE_BUFFER)
writeback = 1; /* initiate writeback; will delay ack */ writeback = true; /* initiate writeback; will delay ack */
else if (revoking == CEPH_CAP_FILE_CACHE && else if (revoking == CEPH_CAP_FILE_CACHE &&
(newcaps & CEPH_CAP_FILE_LAZYIO) == 0 && (newcaps & CEPH_CAP_FILE_LAZYIO) == 0 &&
queue_invalidate) queue_invalidate)
...@@ -2572,7 +2572,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc, ...@@ -2572,7 +2572,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
cap->implemented |= newcaps; /* add bits only, to cap->implemented |= newcaps; /* add bits only, to
* avoid stepping on a * avoid stepping on a
* pending revocation */ * pending revocation */
wake = 1; wake = true;
} }
BUG_ON(cap->issued & ~cap->implemented); BUG_ON(cap->issued & ~cap->implemented);
...@@ -2586,7 +2586,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc, ...@@ -2586,7 +2586,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
kick_flushing_inode_caps(mdsc, session, inode); kick_flushing_inode_caps(mdsc, session, inode);
up_read(&mdsc->snap_rwsem); up_read(&mdsc->snap_rwsem);
if (newcaps & ~issued) if (newcaps & ~issued)
wake = 1; wake = true;
} }
if (queue_trunc) { if (queue_trunc) {
...@@ -3045,6 +3045,12 @@ void ceph_handle_caps(struct ceph_mds_session *session, ...@@ -3045,6 +3045,12 @@ void ceph_handle_caps(struct ceph_mds_session *session,
} }
} }
/* lookup ino */
inode = ceph_find_inode(sb, vino);
ci = ceph_inode(inode);
dout(" op %s ino %llx.%llx inode %p\n", ceph_cap_op_name(op), vino.ino,
vino.snap, inode);
mutex_lock(&session->s_mutex); mutex_lock(&session->s_mutex);
session->s_seq++; session->s_seq++;
dout(" mds%d seq %lld cap seq %u\n", session->s_mds, session->s_seq, dout(" mds%d seq %lld cap seq %u\n", session->s_mds, session->s_seq,
...@@ -3053,11 +3059,6 @@ void ceph_handle_caps(struct ceph_mds_session *session, ...@@ -3053,11 +3059,6 @@ void ceph_handle_caps(struct ceph_mds_session *session,
if (op == CEPH_CAP_OP_IMPORT) if (op == CEPH_CAP_OP_IMPORT)
ceph_add_cap_releases(mdsc, session); ceph_add_cap_releases(mdsc, session);
/* lookup ino */
inode = ceph_find_inode(sb, vino);
ci = ceph_inode(inode);
dout(" op %s ino %llx.%llx inode %p\n", ceph_cap_op_name(op), vino.ino,
vino.snap, inode);
if (!inode) { if (!inode) {
dout(" i don't have ino %llx\n", vino.ino); dout(" i don't have ino %llx\n", vino.ino);
......
...@@ -158,10 +158,47 @@ static int dentry_lru_show(struct seq_file *s, void *ptr) ...@@ -158,10 +158,47 @@ static int dentry_lru_show(struct seq_file *s, void *ptr)
return 0; return 0;
} }
static int mds_sessions_show(struct seq_file *s, void *ptr)
{
struct ceph_fs_client *fsc = s->private;
struct ceph_mds_client *mdsc = fsc->mdsc;
struct ceph_auth_client *ac = fsc->client->monc.auth;
struct ceph_options *opt = fsc->client->options;
int mds = -1;
mutex_lock(&mdsc->mutex);
/* The 'num' portion of an 'entity name' */
seq_printf(s, "global_id %llu\n", ac->global_id);
/* The -o name mount argument */
seq_printf(s, "name \"%s\"\n", opt->name ? opt->name : "");
/* The list of MDS session rank+state */
for (mds = 0; mds < mdsc->max_sessions; mds++) {
struct ceph_mds_session *session =
__ceph_lookup_mds_session(mdsc, mds);
if (!session) {
continue;
}
mutex_unlock(&mdsc->mutex);
seq_printf(s, "mds.%d %s\n",
session->s_mds,
ceph_session_state_name(session->s_state));
ceph_put_mds_session(session);
mutex_lock(&mdsc->mutex);
}
mutex_unlock(&mdsc->mutex);
return 0;
}
CEPH_DEFINE_SHOW_FUNC(mdsmap_show) CEPH_DEFINE_SHOW_FUNC(mdsmap_show)
CEPH_DEFINE_SHOW_FUNC(mdsc_show) CEPH_DEFINE_SHOW_FUNC(mdsc_show)
CEPH_DEFINE_SHOW_FUNC(caps_show) CEPH_DEFINE_SHOW_FUNC(caps_show)
CEPH_DEFINE_SHOW_FUNC(dentry_lru_show) CEPH_DEFINE_SHOW_FUNC(dentry_lru_show)
CEPH_DEFINE_SHOW_FUNC(mds_sessions_show)
/* /*
...@@ -193,6 +230,7 @@ void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc) ...@@ -193,6 +230,7 @@ void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc)
debugfs_remove(fsc->debugfs_bdi); debugfs_remove(fsc->debugfs_bdi);
debugfs_remove(fsc->debugfs_congestion_kb); debugfs_remove(fsc->debugfs_congestion_kb);
debugfs_remove(fsc->debugfs_mdsmap); debugfs_remove(fsc->debugfs_mdsmap);
debugfs_remove(fsc->debugfs_mds_sessions);
debugfs_remove(fsc->debugfs_caps); debugfs_remove(fsc->debugfs_caps);
debugfs_remove(fsc->debugfs_mdsc); debugfs_remove(fsc->debugfs_mdsc);
debugfs_remove(fsc->debugfs_dentry_lru); debugfs_remove(fsc->debugfs_dentry_lru);
...@@ -231,6 +269,14 @@ int ceph_fs_debugfs_init(struct ceph_fs_client *fsc) ...@@ -231,6 +269,14 @@ int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
if (!fsc->debugfs_mdsmap) if (!fsc->debugfs_mdsmap)
goto out; goto out;
fsc->debugfs_mds_sessions = debugfs_create_file("mds_sessions",
0600,
fsc->client->debugfs_dir,
fsc,
&mds_sessions_show_fops);
if (!fsc->debugfs_mds_sessions)
goto out;
fsc->debugfs_mdsc = debugfs_create_file("mdsc", fsc->debugfs_mdsc = debugfs_create_file("mdsc",
0600, 0600,
fsc->client->debugfs_dir, fsc->client->debugfs_dir,
......
...@@ -682,17 +682,22 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry, ...@@ -682,17 +682,22 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
struct ceph_mds_client *mdsc = fsc->mdsc; struct ceph_mds_client *mdsc = fsc->mdsc;
struct ceph_mds_request *req; struct ceph_mds_request *req;
struct ceph_acls_info acls = {};
int err; int err;
if (ceph_snap(dir) != CEPH_NOSNAP) if (ceph_snap(dir) != CEPH_NOSNAP)
return -EROFS; return -EROFS;
err = ceph_pre_init_acls(dir, &mode, &acls);
if (err < 0)
return err;
dout("mknod in dir %p dentry %p mode 0%ho rdev %d\n", dout("mknod in dir %p dentry %p mode 0%ho rdev %d\n",
dir, dentry, mode, rdev); dir, dentry, mode, rdev);
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_MKNOD, USE_AUTH_MDS); req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_MKNOD, USE_AUTH_MDS);
if (IS_ERR(req)) { if (IS_ERR(req)) {
d_drop(dentry); err = PTR_ERR(req);
return PTR_ERR(req); goto out;
} }
req->r_dentry = dget(dentry); req->r_dentry = dget(dentry);
req->r_num_caps = 2; req->r_num_caps = 2;
...@@ -701,15 +706,20 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry, ...@@ -701,15 +706,20 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
req->r_args.mknod.rdev = cpu_to_le32(rdev); req->r_args.mknod.rdev = cpu_to_le32(rdev);
req->r_dentry_drop = CEPH_CAP_FILE_SHARED; req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
req->r_dentry_unless = CEPH_CAP_FILE_EXCL; req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
if (acls.pagelist) {
req->r_pagelist = acls.pagelist;
acls.pagelist = NULL;
}
err = ceph_mdsc_do_request(mdsc, dir, req); err = ceph_mdsc_do_request(mdsc, dir, req);
if (!err && !req->r_reply_info.head->is_dentry) if (!err && !req->r_reply_info.head->is_dentry)
err = ceph_handle_notrace_create(dir, dentry); err = ceph_handle_notrace_create(dir, dentry);
ceph_mdsc_put_request(req); ceph_mdsc_put_request(req);
out:
if (!err) if (!err)
ceph_init_acl(dentry, dentry->d_inode, dir); ceph_init_inode_acls(dentry->d_inode, &acls);
else else
d_drop(dentry); d_drop(dentry);
ceph_release_acls_info(&acls);
return err; return err;
} }
...@@ -733,8 +743,8 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry, ...@@ -733,8 +743,8 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry,
dout("symlink in dir %p dentry %p to '%s'\n", dir, dentry, dest); dout("symlink in dir %p dentry %p to '%s'\n", dir, dentry, dest);
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SYMLINK, USE_AUTH_MDS); req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SYMLINK, USE_AUTH_MDS);
if (IS_ERR(req)) { if (IS_ERR(req)) {
d_drop(dentry); err = PTR_ERR(req);
return PTR_ERR(req); goto out;
} }
req->r_dentry = dget(dentry); req->r_dentry = dget(dentry);
req->r_num_caps = 2; req->r_num_caps = 2;
...@@ -746,9 +756,8 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry, ...@@ -746,9 +756,8 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry,
if (!err && !req->r_reply_info.head->is_dentry) if (!err && !req->r_reply_info.head->is_dentry)
err = ceph_handle_notrace_create(dir, dentry); err = ceph_handle_notrace_create(dir, dentry);
ceph_mdsc_put_request(req); ceph_mdsc_put_request(req);
if (!err) out:
ceph_init_acl(dentry, dentry->d_inode, dir); if (err)
else
d_drop(dentry); d_drop(dentry);
return err; return err;
} }
...@@ -758,6 +767,7 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -758,6 +767,7 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
struct ceph_mds_client *mdsc = fsc->mdsc; struct ceph_mds_client *mdsc = fsc->mdsc;
struct ceph_mds_request *req; struct ceph_mds_request *req;
struct ceph_acls_info acls = {};
int err = -EROFS; int err = -EROFS;
int op; int op;
...@@ -772,6 +782,12 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -772,6 +782,12 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
} else { } else {
goto out; goto out;
} }
mode |= S_IFDIR;
err = ceph_pre_init_acls(dir, &mode, &acls);
if (err < 0)
goto out;
req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS); req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
if (IS_ERR(req)) { if (IS_ERR(req)) {
err = PTR_ERR(req); err = PTR_ERR(req);
...@@ -784,15 +800,20 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -784,15 +800,20 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
req->r_args.mkdir.mode = cpu_to_le32(mode); req->r_args.mkdir.mode = cpu_to_le32(mode);
req->r_dentry_drop = CEPH_CAP_FILE_SHARED; req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
req->r_dentry_unless = CEPH_CAP_FILE_EXCL; req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
if (acls.pagelist) {
req->r_pagelist = acls.pagelist;
acls.pagelist = NULL;
}
err = ceph_mdsc_do_request(mdsc, dir, req); err = ceph_mdsc_do_request(mdsc, dir, req);
if (!err && !req->r_reply_info.head->is_dentry) if (!err && !req->r_reply_info.head->is_dentry)
err = ceph_handle_notrace_create(dir, dentry); err = ceph_handle_notrace_create(dir, dentry);
ceph_mdsc_put_request(req); ceph_mdsc_put_request(req);
out: out:
if (!err) if (!err)
ceph_init_acl(dentry, dentry->d_inode, dir); ceph_init_inode_acls(dentry->d_inode, &acls);
else else
d_drop(dentry); d_drop(dentry);
ceph_release_acls_info(&acls);
return err; return err;
} }
......
...@@ -235,6 +235,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -235,6 +235,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
struct ceph_mds_client *mdsc = fsc->mdsc; struct ceph_mds_client *mdsc = fsc->mdsc;
struct ceph_mds_request *req; struct ceph_mds_request *req;
struct dentry *dn; struct dentry *dn;
struct ceph_acls_info acls = {};
int err; int err;
dout("atomic_open %p dentry %p '%.*s' %s flags %d mode 0%o\n", dout("atomic_open %p dentry %p '%.*s' %s flags %d mode 0%o\n",
...@@ -248,22 +249,34 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -248,22 +249,34 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
if (err < 0) if (err < 0)
return err; return err;
if (flags & O_CREAT) {
err = ceph_pre_init_acls(dir, &mode, &acls);
if (err < 0)
return err;
}
/* do the open */ /* do the open */
req = prepare_open_request(dir->i_sb, flags, mode); req = prepare_open_request(dir->i_sb, flags, mode);
if (IS_ERR(req)) if (IS_ERR(req)) {
return PTR_ERR(req); err = PTR_ERR(req);
goto out_acl;
}
req->r_dentry = dget(dentry); req->r_dentry = dget(dentry);
req->r_num_caps = 2; req->r_num_caps = 2;
if (flags & O_CREAT) { if (flags & O_CREAT) {
req->r_dentry_drop = CEPH_CAP_FILE_SHARED; req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
req->r_dentry_unless = CEPH_CAP_FILE_EXCL; req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
if (acls.pagelist) {
req->r_pagelist = acls.pagelist;
acls.pagelist = NULL;
}
} }
req->r_locked_dir = dir; /* caller holds dir->i_mutex */ req->r_locked_dir = dir; /* caller holds dir->i_mutex */
err = ceph_mdsc_do_request(mdsc, err = ceph_mdsc_do_request(mdsc,
(flags & (O_CREAT|O_TRUNC)) ? dir : NULL, (flags & (O_CREAT|O_TRUNC)) ? dir : NULL,
req); req);
if (err) if (err)
goto out_err; goto out_req;
err = ceph_handle_snapdir(req, dentry, err); err = ceph_handle_snapdir(req, dentry, err);
if (err == 0 && (flags & O_CREAT) && !req->r_reply_info.head->is_dentry) if (err == 0 && (flags & O_CREAT) && !req->r_reply_info.head->is_dentry)
...@@ -278,7 +291,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -278,7 +291,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
dn = NULL; dn = NULL;
} }
if (err) if (err)
goto out_err; goto out_req;
if (dn || dentry->d_inode == NULL || S_ISLNK(dentry->d_inode->i_mode)) { if (dn || dentry->d_inode == NULL || S_ISLNK(dentry->d_inode->i_mode)) {
/* make vfs retry on splice, ENOENT, or symlink */ /* make vfs retry on splice, ENOENT, or symlink */
dout("atomic_open finish_no_open on dn %p\n", dn); dout("atomic_open finish_no_open on dn %p\n", dn);
...@@ -286,15 +299,17 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -286,15 +299,17 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
} else { } else {
dout("atomic_open finish_open on dn %p\n", dn); dout("atomic_open finish_open on dn %p\n", dn);
if (req->r_op == CEPH_MDS_OP_CREATE && req->r_reply_info.has_create_ino) { if (req->r_op == CEPH_MDS_OP_CREATE && req->r_reply_info.has_create_ino) {
ceph_init_acl(dentry, dentry->d_inode, dir); ceph_init_inode_acls(dentry->d_inode, &acls);
*opened |= FILE_CREATED; *opened |= FILE_CREATED;
} }
err = finish_open(file, dentry, ceph_open, opened); err = finish_open(file, dentry, ceph_open, opened);
} }
out_err: out_req:
if (!req->r_err && req->r_target_inode) if (!req->r_err && req->r_target_inode)
ceph_put_fmode(ceph_inode(req->r_target_inode), req->r_fmode); ceph_put_fmode(ceph_inode(req->r_target_inode), req->r_fmode);
ceph_mdsc_put_request(req); ceph_mdsc_put_request(req);
out_acl:
ceph_release_acls_info(&acls);
dout("atomic_open result=%d\n", err); dout("atomic_open result=%d\n", err);
return err; return err;
} }
...@@ -826,8 +841,7 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to) ...@@ -826,8 +841,7 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to)
ceph_put_cap_refs(ci, got); ceph_put_cap_refs(ci, got);
if (checkeof && ret >= 0) { if (checkeof && ret >= 0) {
int statret = ceph_do_getattr(inode, int statret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE, false);
CEPH_STAT_CAP_SIZE);
/* hit EOF or hole? */ /* hit EOF or hole? */
if (statret == 0 && iocb->ki_pos < inode->i_size && if (statret == 0 && iocb->ki_pos < inode->i_size &&
...@@ -836,7 +850,6 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to) ...@@ -836,7 +850,6 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to)
", reading more\n", iocb->ki_pos, ", reading more\n", iocb->ki_pos,
inode->i_size); inode->i_size);
iov_iter_advance(to, ret);
read += ret; read += ret;
len -= ret; len -= ret;
checkeof = 0; checkeof = 0;
...@@ -995,7 +1008,7 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int whence) ...@@ -995,7 +1008,7 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int whence)
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
if (whence == SEEK_END || whence == SEEK_DATA || whence == SEEK_HOLE) { if (whence == SEEK_END || whence == SEEK_DATA || whence == SEEK_HOLE) {
ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE); ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE, false);
if (ret < 0) { if (ret < 0) {
offset = ret; offset = ret;
goto out; goto out;
......
...@@ -766,7 +766,7 @@ static int fill_inode(struct inode *inode, ...@@ -766,7 +766,7 @@ static int fill_inode(struct inode *inode,
/* xattrs */ /* xattrs */
/* note that if i_xattrs.len <= 4, i_xattrs.data will still be NULL. */ /* note that if i_xattrs.len <= 4, i_xattrs.data will still be NULL. */
if ((issued & CEPH_CAP_XATTR_EXCL) == 0 && if ((ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL)) &&
le64_to_cpu(info->xattr_version) > ci->i_xattrs.version) { le64_to_cpu(info->xattr_version) > ci->i_xattrs.version) {
if (ci->i_xattrs.blob) if (ci->i_xattrs.blob)
ceph_buffer_put(ci->i_xattrs.blob); ceph_buffer_put(ci->i_xattrs.blob);
...@@ -1813,10 +1813,6 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -1813,10 +1813,6 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
if (ia_valid & ATTR_SIZE) { if (ia_valid & ATTR_SIZE) {
dout("setattr %p size %lld -> %lld\n", inode, dout("setattr %p size %lld -> %lld\n", inode,
inode->i_size, attr->ia_size); inode->i_size, attr->ia_size);
if (attr->ia_size > inode->i_sb->s_maxbytes) {
err = -EINVAL;
goto out;
}
if ((issued & CEPH_CAP_FILE_EXCL) && if ((issued & CEPH_CAP_FILE_EXCL) &&
attr->ia_size > inode->i_size) { attr->ia_size > inode->i_size) {
inode->i_size = attr->ia_size; inode->i_size = attr->ia_size;
...@@ -1896,8 +1892,6 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -1896,8 +1892,6 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
if (mask & CEPH_SETATTR_SIZE) if (mask & CEPH_SETATTR_SIZE)
__ceph_do_pending_vmtruncate(inode); __ceph_do_pending_vmtruncate(inode);
return err; return err;
out:
spin_unlock(&ci->i_ceph_lock);
out_put: out_put:
ceph_mdsc_put_request(req); ceph_mdsc_put_request(req);
return err; return err;
...@@ -1907,7 +1901,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -1907,7 +1901,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
* Verify that we have a lease on the given mask. If not, * Verify that we have a lease on the given mask. If not,
* do a getattr against an mds. * do a getattr against an mds.
*/ */
int ceph_do_getattr(struct inode *inode, int mask) int ceph_do_getattr(struct inode *inode, int mask, bool force)
{ {
struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb); struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb);
struct ceph_mds_client *mdsc = fsc->mdsc; struct ceph_mds_client *mdsc = fsc->mdsc;
...@@ -1920,7 +1914,7 @@ int ceph_do_getattr(struct inode *inode, int mask) ...@@ -1920,7 +1914,7 @@ int ceph_do_getattr(struct inode *inode, int mask)
} }
dout("do_getattr inode %p mask %s mode 0%o\n", inode, ceph_cap_string(mask), inode->i_mode); dout("do_getattr inode %p mask %s mode 0%o\n", inode, ceph_cap_string(mask), inode->i_mode);
if (ceph_caps_issued_mask(ceph_inode(inode), mask, 1)) if (!force && ceph_caps_issued_mask(ceph_inode(inode), mask, 1))
return 0; return 0;
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS); req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS);
...@@ -1948,7 +1942,7 @@ int ceph_permission(struct inode *inode, int mask) ...@@ -1948,7 +1942,7 @@ int ceph_permission(struct inode *inode, int mask)
if (mask & MAY_NOT_BLOCK) if (mask & MAY_NOT_BLOCK)
return -ECHILD; return -ECHILD;
err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED); err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED, false);
if (!err) if (!err)
err = generic_permission(inode, mask); err = generic_permission(inode, mask);
...@@ -1966,7 +1960,7 @@ int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry, ...@@ -1966,7 +1960,7 @@ int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
int err; int err;
err = ceph_do_getattr(inode, CEPH_STAT_CAP_INODE_ALL); err = ceph_do_getattr(inode, CEPH_STAT_CAP_INODE_ALL, false);
if (!err) { if (!err) {
generic_fillattr(inode, stat); generic_fillattr(inode, stat);
stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino); stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino);
......
...@@ -19,7 +19,7 @@ static long ceph_ioctl_get_layout(struct file *file, void __user *arg) ...@@ -19,7 +19,7 @@ static long ceph_ioctl_get_layout(struct file *file, void __user *arg)
struct ceph_ioctl_layout l; struct ceph_ioctl_layout l;
int err; int err;
err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT); err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT, false);
if (!err) { if (!err) {
l.stripe_unit = ceph_file_layout_su(ci->i_layout); l.stripe_unit = ceph_file_layout_su(ci->i_layout);
l.stripe_count = ceph_file_layout_stripe_count(ci->i_layout); l.stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
...@@ -41,7 +41,7 @@ static long __validate_layout(struct ceph_mds_client *mdsc, ...@@ -41,7 +41,7 @@ static long __validate_layout(struct ceph_mds_client *mdsc,
/* validate striping parameters */ /* validate striping parameters */
if ((l->object_size & ~PAGE_MASK) || if ((l->object_size & ~PAGE_MASK) ||
(l->stripe_unit & ~PAGE_MASK) || (l->stripe_unit & ~PAGE_MASK) ||
(l->stripe_unit != 0 && ((unsigned)l->stripe_unit != 0 &&
((unsigned)l->object_size % (unsigned)l->stripe_unit))) ((unsigned)l->object_size % (unsigned)l->stripe_unit)))
return -EINVAL; return -EINVAL;
...@@ -74,7 +74,7 @@ static long ceph_ioctl_set_layout(struct file *file, void __user *arg) ...@@ -74,7 +74,7 @@ static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
return -EFAULT; return -EFAULT;
/* validate changed params against current layout */ /* validate changed params against current layout */
err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT); err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT, false);
if (err) if (err)
return err; return err;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/utsname.h>
#include "super.h" #include "super.h"
#include "mds_client.h" #include "mds_client.h"
...@@ -334,7 +335,7 @@ static void destroy_reply_info(struct ceph_mds_reply_info_parsed *info) ...@@ -334,7 +335,7 @@ static void destroy_reply_info(struct ceph_mds_reply_info_parsed *info)
/* /*
* sessions * sessions
*/ */
static const char *session_state_name(int s) const char *ceph_session_state_name(int s)
{ {
switch (s) { switch (s) {
case CEPH_MDS_SESSION_NEW: return "new"; case CEPH_MDS_SESSION_NEW: return "new";
...@@ -542,6 +543,8 @@ void ceph_mdsc_release_request(struct kref *kref) ...@@ -542,6 +543,8 @@ void ceph_mdsc_release_request(struct kref *kref)
} }
kfree(req->r_path1); kfree(req->r_path1);
kfree(req->r_path2); kfree(req->r_path2);
if (req->r_pagelist)
ceph_pagelist_release(req->r_pagelist);
put_request_session(req); put_request_session(req);
ceph_unreserve_caps(req->r_mdsc, &req->r_caps_reservation); ceph_unreserve_caps(req->r_mdsc, &req->r_caps_reservation);
kfree(req); kfree(req);
...@@ -812,6 +815,74 @@ static struct ceph_msg *create_session_msg(u32 op, u64 seq) ...@@ -812,6 +815,74 @@ static struct ceph_msg *create_session_msg(u32 op, u64 seq)
h = msg->front.iov_base; h = msg->front.iov_base;
h->op = cpu_to_le32(op); h->op = cpu_to_le32(op);
h->seq = cpu_to_le64(seq); h->seq = cpu_to_le64(seq);
return msg;
}
/*
* session message, specialization for CEPH_SESSION_REQUEST_OPEN
* to include additional client metadata fields.
*/
static struct ceph_msg *create_session_open_msg(struct ceph_mds_client *mdsc, u64 seq)
{
struct ceph_msg *msg;
struct ceph_mds_session_head *h;
int i = -1;
int metadata_bytes = 0;
int metadata_key_count = 0;
struct ceph_options *opt = mdsc->fsc->client->options;
void *p;
const char* metadata[3][2] = {
{"hostname", utsname()->nodename},
{"entity_id", opt->name ? opt->name : ""},
{NULL, NULL}
};
/* Calculate serialized length of metadata */
metadata_bytes = 4; /* map length */
for (i = 0; metadata[i][0] != NULL; ++i) {
metadata_bytes += 8 + strlen(metadata[i][0]) +
strlen(metadata[i][1]);
metadata_key_count++;
}
/* Allocate the message */
msg = ceph_msg_new(CEPH_MSG_CLIENT_SESSION, sizeof(*h) + metadata_bytes,
GFP_NOFS, false);
if (!msg) {
pr_err("create_session_msg ENOMEM creating msg\n");
return NULL;
}
h = msg->front.iov_base;
h->op = cpu_to_le32(CEPH_SESSION_REQUEST_OPEN);
h->seq = cpu_to_le64(seq);
/*
* Serialize client metadata into waiting buffer space, using
* the format that userspace expects for map<string, string>
*/
msg->hdr.version = 2; /* ClientSession messages with metadata are v2 */
/* The write pointer, following the session_head structure */
p = msg->front.iov_base + sizeof(*h);
/* Number of entries in the map */
ceph_encode_32(&p, metadata_key_count);
/* Two length-prefixed strings for each entry in the map */
for (i = 0; metadata[i][0] != NULL; ++i) {
size_t const key_len = strlen(metadata[i][0]);
size_t const val_len = strlen(metadata[i][1]);
ceph_encode_32(&p, key_len);
memcpy(p, metadata[i][0], key_len);
p += key_len;
ceph_encode_32(&p, val_len);
memcpy(p, metadata[i][1], val_len);
p += val_len;
}
return msg; return msg;
} }
...@@ -835,7 +906,7 @@ static int __open_session(struct ceph_mds_client *mdsc, ...@@ -835,7 +906,7 @@ static int __open_session(struct ceph_mds_client *mdsc,
session->s_renew_requested = jiffies; session->s_renew_requested = jiffies;
/* send connect message */ /* send connect message */
msg = create_session_msg(CEPH_SESSION_REQUEST_OPEN, session->s_seq); msg = create_session_open_msg(mdsc, session->s_seq);
if (!msg) if (!msg)
return -ENOMEM; return -ENOMEM;
ceph_con_send(&session->s_con, msg); ceph_con_send(&session->s_con, msg);
...@@ -1164,7 +1235,7 @@ static int send_flushmsg_ack(struct ceph_mds_client *mdsc, ...@@ -1164,7 +1235,7 @@ static int send_flushmsg_ack(struct ceph_mds_client *mdsc,
struct ceph_msg *msg; struct ceph_msg *msg;
dout("send_flushmsg_ack to mds%d (%s)s seq %lld\n", dout("send_flushmsg_ack to mds%d (%s)s seq %lld\n",
session->s_mds, session_state_name(session->s_state), seq); session->s_mds, ceph_session_state_name(session->s_state), seq);
msg = create_session_msg(CEPH_SESSION_FLUSHMSG_ACK, seq); msg = create_session_msg(CEPH_SESSION_FLUSHMSG_ACK, seq);
if (!msg) if (!msg)
return -ENOMEM; return -ENOMEM;
...@@ -1216,7 +1287,7 @@ static int request_close_session(struct ceph_mds_client *mdsc, ...@@ -1216,7 +1287,7 @@ static int request_close_session(struct ceph_mds_client *mdsc,
struct ceph_msg *msg; struct ceph_msg *msg;
dout("request_close_session mds%d state %s seq %lld\n", dout("request_close_session mds%d state %s seq %lld\n",
session->s_mds, session_state_name(session->s_state), session->s_mds, ceph_session_state_name(session->s_state),
session->s_seq); session->s_seq);
msg = create_session_msg(CEPH_SESSION_REQUEST_CLOSE, session->s_seq); msg = create_session_msg(CEPH_SESSION_REQUEST_CLOSE, session->s_seq);
if (!msg) if (!msg)
...@@ -1847,13 +1918,15 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, ...@@ -1847,13 +1918,15 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
msg->front.iov_len = p - msg->front.iov_base; msg->front.iov_len = p - msg->front.iov_base;
msg->hdr.front_len = cpu_to_le32(msg->front.iov_len); msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
if (req->r_data_len) { if (req->r_pagelist) {
/* outbound data set only by ceph_sync_setxattr() */ struct ceph_pagelist *pagelist = req->r_pagelist;
BUG_ON(!req->r_pages); atomic_inc(&pagelist->refcnt);
ceph_msg_data_add_pages(msg, req->r_pages, req->r_data_len, 0); ceph_msg_data_add_pagelist(msg, pagelist);
msg->hdr.data_len = cpu_to_le32(pagelist->length);
} else {
msg->hdr.data_len = 0;
} }
msg->hdr.data_len = cpu_to_le32(req->r_data_len);
msg->hdr.data_off = cpu_to_le16(0); msg->hdr.data_off = cpu_to_le16(0);
out_free2: out_free2:
...@@ -2007,7 +2080,7 @@ static int __do_request(struct ceph_mds_client *mdsc, ...@@ -2007,7 +2080,7 @@ static int __do_request(struct ceph_mds_client *mdsc,
req->r_session = get_session(session); req->r_session = get_session(session);
dout("do_request mds%d session %p state %s\n", mds, session, dout("do_request mds%d session %p state %s\n", mds, session,
session_state_name(session->s_state)); ceph_session_state_name(session->s_state));
if (session->s_state != CEPH_MDS_SESSION_OPEN && if (session->s_state != CEPH_MDS_SESSION_OPEN &&
session->s_state != CEPH_MDS_SESSION_HUNG) { session->s_state != CEPH_MDS_SESSION_HUNG) {
if (session->s_state == CEPH_MDS_SESSION_NEW || if (session->s_state == CEPH_MDS_SESSION_NEW ||
...@@ -2078,6 +2151,7 @@ static void kick_requests(struct ceph_mds_client *mdsc, int mds) ...@@ -2078,6 +2151,7 @@ static void kick_requests(struct ceph_mds_client *mdsc, int mds)
if (req->r_session && if (req->r_session &&
req->r_session->s_mds == mds) { req->r_session->s_mds == mds) {
dout(" kicking tid %llu\n", req->r_tid); dout(" kicking tid %llu\n", req->r_tid);
list_del_init(&req->r_wait);
__do_request(mdsc, req); __do_request(mdsc, req);
} }
} }
...@@ -2444,7 +2518,7 @@ static void handle_session(struct ceph_mds_session *session, ...@@ -2444,7 +2518,7 @@ static void handle_session(struct ceph_mds_session *session,
dout("handle_session mds%d %s %p state %s seq %llu\n", dout("handle_session mds%d %s %p state %s seq %llu\n",
mds, ceph_session_op_name(op), session, mds, ceph_session_op_name(op), session,
session_state_name(session->s_state), seq); ceph_session_state_name(session->s_state), seq);
if (session->s_state == CEPH_MDS_SESSION_HUNG) { if (session->s_state == CEPH_MDS_SESSION_HUNG) {
session->s_state = CEPH_MDS_SESSION_OPEN; session->s_state = CEPH_MDS_SESSION_OPEN;
...@@ -2471,9 +2545,8 @@ static void handle_session(struct ceph_mds_session *session, ...@@ -2471,9 +2545,8 @@ static void handle_session(struct ceph_mds_session *session,
if (session->s_state == CEPH_MDS_SESSION_RECONNECTING) if (session->s_state == CEPH_MDS_SESSION_RECONNECTING)
pr_info("mds%d reconnect denied\n", session->s_mds); pr_info("mds%d reconnect denied\n", session->s_mds);
remove_session_caps(session); remove_session_caps(session);
wake = 1; /* for good measure */ wake = 2; /* for good measure */
wake_up_all(&mdsc->session_close_wq); wake_up_all(&mdsc->session_close_wq);
kick_requests(mdsc, mds);
break; break;
case CEPH_SESSION_STALE: case CEPH_SESSION_STALE:
...@@ -2503,6 +2576,8 @@ static void handle_session(struct ceph_mds_session *session, ...@@ -2503,6 +2576,8 @@ static void handle_session(struct ceph_mds_session *session,
if (wake) { if (wake) {
mutex_lock(&mdsc->mutex); mutex_lock(&mdsc->mutex);
__wake_requests(mdsc, &session->s_waiting); __wake_requests(mdsc, &session->s_waiting);
if (wake == 2)
kick_requests(mdsc, mds);
mutex_unlock(&mdsc->mutex); mutex_unlock(&mdsc->mutex);
} }
return; return;
...@@ -2695,18 +2770,8 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, ...@@ -2695,18 +2770,8 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
session->s_state = CEPH_MDS_SESSION_RECONNECTING; session->s_state = CEPH_MDS_SESSION_RECONNECTING;
session->s_seq = 0; session->s_seq = 0;
ceph_con_close(&session->s_con);
ceph_con_open(&session->s_con,
CEPH_ENTITY_TYPE_MDS, mds,
ceph_mdsmap_get_addr(mdsc->mdsmap, mds));
/* replay unsafe requests */
replay_unsafe_requests(mdsc, session);
down_read(&mdsc->snap_rwsem);
dout("session %p state %s\n", session, dout("session %p state %s\n", session,
session_state_name(session->s_state)); ceph_session_state_name(session->s_state));
spin_lock(&session->s_gen_ttl_lock); spin_lock(&session->s_gen_ttl_lock);
session->s_cap_gen++; session->s_cap_gen++;
...@@ -2723,6 +2788,19 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, ...@@ -2723,6 +2788,19 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
discard_cap_releases(mdsc, session); discard_cap_releases(mdsc, session);
spin_unlock(&session->s_cap_lock); spin_unlock(&session->s_cap_lock);
/* trim unused caps to reduce MDS's cache rejoin time */
shrink_dcache_parent(mdsc->fsc->sb->s_root);
ceph_con_close(&session->s_con);
ceph_con_open(&session->s_con,
CEPH_ENTITY_TYPE_MDS, mds,
ceph_mdsmap_get_addr(mdsc->mdsmap, mds));
/* replay unsafe requests */
replay_unsafe_requests(mdsc, session);
down_read(&mdsc->snap_rwsem);
/* traverse this session's caps */ /* traverse this session's caps */
s_nr_caps = session->s_nr_caps; s_nr_caps = session->s_nr_caps;
err = ceph_pagelist_encode_32(pagelist, s_nr_caps); err = ceph_pagelist_encode_32(pagelist, s_nr_caps);
...@@ -2791,7 +2869,6 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, ...@@ -2791,7 +2869,6 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
mutex_unlock(&session->s_mutex); mutex_unlock(&session->s_mutex);
fail_nomsg: fail_nomsg:
ceph_pagelist_release(pagelist); ceph_pagelist_release(pagelist);
kfree(pagelist);
fail_nopagelist: fail_nopagelist:
pr_err("error %d preparing reconnect for mds%d\n", err, mds); pr_err("error %d preparing reconnect for mds%d\n", err, mds);
return; return;
...@@ -2827,7 +2904,7 @@ static void check_new_map(struct ceph_mds_client *mdsc, ...@@ -2827,7 +2904,7 @@ static void check_new_map(struct ceph_mds_client *mdsc,
ceph_mdsmap_is_laggy(oldmap, i) ? " (laggy)" : "", ceph_mdsmap_is_laggy(oldmap, i) ? " (laggy)" : "",
ceph_mds_state_name(newstate), ceph_mds_state_name(newstate),
ceph_mdsmap_is_laggy(newmap, i) ? " (laggy)" : "", ceph_mdsmap_is_laggy(newmap, i) ? " (laggy)" : "",
session_state_name(s->s_state)); ceph_session_state_name(s->s_state));
if (i >= newmap->m_max_mds || if (i >= newmap->m_max_mds ||
memcmp(ceph_mdsmap_get_addr(oldmap, i), memcmp(ceph_mdsmap_get_addr(oldmap, i),
...@@ -2939,14 +3016,15 @@ static void handle_lease(struct ceph_mds_client *mdsc, ...@@ -2939,14 +3016,15 @@ static void handle_lease(struct ceph_mds_client *mdsc,
if (dname.len != get_unaligned_le32(h+1)) if (dname.len != get_unaligned_le32(h+1))
goto bad; goto bad;
mutex_lock(&session->s_mutex);
session->s_seq++;
/* lookup inode */ /* lookup inode */
inode = ceph_find_inode(sb, vino); inode = ceph_find_inode(sb, vino);
dout("handle_lease %s, ino %llx %p %.*s\n", dout("handle_lease %s, ino %llx %p %.*s\n",
ceph_lease_op_name(h->action), vino.ino, inode, ceph_lease_op_name(h->action), vino.ino, inode,
dname.len, dname.name); dname.len, dname.name);
mutex_lock(&session->s_mutex);
session->s_seq++;
if (inode == NULL) { if (inode == NULL) {
dout("handle_lease no inode %llx\n", vino.ino); dout("handle_lease no inode %llx\n", vino.ino);
goto release; goto release;
......
...@@ -202,9 +202,7 @@ struct ceph_mds_request { ...@@ -202,9 +202,7 @@ struct ceph_mds_request {
bool r_direct_is_hash; /* true if r_direct_hash is valid */ bool r_direct_is_hash; /* true if r_direct_hash is valid */
/* data payload is used for xattr ops */ /* data payload is used for xattr ops */
struct page **r_pages; struct ceph_pagelist *r_pagelist;
int r_num_pages;
int r_data_len;
/* what caps shall we drop? */ /* what caps shall we drop? */
int r_inode_drop, r_inode_unless; int r_inode_drop, r_inode_unless;
...@@ -332,6 +330,8 @@ ceph_get_mds_session(struct ceph_mds_session *s) ...@@ -332,6 +330,8 @@ ceph_get_mds_session(struct ceph_mds_session *s)
return s; return s;
} }
extern const char *ceph_session_state_name(int s);
extern void ceph_put_mds_session(struct ceph_mds_session *s); extern void ceph_put_mds_session(struct ceph_mds_session *s);
extern int ceph_send_msg_mds(struct ceph_mds_client *mdsc, extern int ceph_send_msg_mds(struct ceph_mds_client *mdsc,
......
...@@ -95,6 +95,7 @@ struct ceph_fs_client { ...@@ -95,6 +95,7 @@ struct ceph_fs_client {
struct dentry *debugfs_congestion_kb; struct dentry *debugfs_congestion_kb;
struct dentry *debugfs_bdi; struct dentry *debugfs_bdi;
struct dentry *debugfs_mdsc, *debugfs_mdsmap; struct dentry *debugfs_mdsc, *debugfs_mdsmap;
struct dentry *debugfs_mds_sessions;
#endif #endif
#ifdef CONFIG_CEPH_FSCACHE #ifdef CONFIG_CEPH_FSCACHE
...@@ -714,7 +715,7 @@ extern void ceph_queue_vmtruncate(struct inode *inode); ...@@ -714,7 +715,7 @@ extern void ceph_queue_vmtruncate(struct inode *inode);
extern void ceph_queue_invalidate(struct inode *inode); extern void ceph_queue_invalidate(struct inode *inode);
extern void ceph_queue_writeback(struct inode *inode); extern void ceph_queue_writeback(struct inode *inode);
extern int ceph_do_getattr(struct inode *inode, int mask); extern int ceph_do_getattr(struct inode *inode, int mask, bool force);
extern int ceph_permission(struct inode *inode, int mask); extern int ceph_permission(struct inode *inode, int mask);
extern int ceph_setattr(struct dentry *dentry, struct iattr *attr); extern int ceph_setattr(struct dentry *dentry, struct iattr *attr);
extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry, extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
...@@ -733,15 +734,23 @@ extern void __ceph_build_xattrs_blob(struct ceph_inode_info *ci); ...@@ -733,15 +734,23 @@ extern void __ceph_build_xattrs_blob(struct ceph_inode_info *ci);
extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci); extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci);
extern void __init ceph_xattr_init(void); extern void __init ceph_xattr_init(void);
extern void ceph_xattr_exit(void); extern void ceph_xattr_exit(void);
extern const struct xattr_handler *ceph_xattr_handlers[];
/* acl.c */ /* acl.c */
extern const struct xattr_handler *ceph_xattr_handlers[]; struct ceph_acls_info {
void *default_acl;
void *acl;
struct ceph_pagelist *pagelist;
};
#ifdef CONFIG_CEPH_FS_POSIX_ACL #ifdef CONFIG_CEPH_FS_POSIX_ACL
struct posix_acl *ceph_get_acl(struct inode *, int); struct posix_acl *ceph_get_acl(struct inode *, int);
int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type); int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type);
int ceph_init_acl(struct dentry *, struct inode *, struct inode *); int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
struct ceph_acls_info *info);
void ceph_init_inode_acls(struct inode *inode, struct ceph_acls_info *info);
void ceph_release_acls_info(struct ceph_acls_info *info);
static inline void ceph_forget_all_cached_acls(struct inode *inode) static inline void ceph_forget_all_cached_acls(struct inode *inode)
{ {
...@@ -753,12 +762,18 @@ static inline void ceph_forget_all_cached_acls(struct inode *inode) ...@@ -753,12 +762,18 @@ static inline void ceph_forget_all_cached_acls(struct inode *inode)
#define ceph_get_acl NULL #define ceph_get_acl NULL
#define ceph_set_acl NULL #define ceph_set_acl NULL
static inline int ceph_init_acl(struct dentry *dentry, struct inode *inode, static inline int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
struct inode *dir) struct ceph_acls_info *info)
{ {
return 0; return 0;
} }
static inline void ceph_init_inode_acls(struct inode *inode,
struct ceph_acls_info *info)
{
}
static inline void ceph_release_acls_info(struct ceph_acls_info *info)
{
}
static inline int ceph_acl_chmod(struct dentry *dentry, struct inode *inode) static inline int ceph_acl_chmod(struct dentry *dentry, struct inode *inode)
{ {
return 0; return 0;
......
#include <linux/ceph/ceph_debug.h> #include <linux/ceph/ceph_debug.h>
#include <linux/ceph/pagelist.h>
#include "super.h" #include "super.h"
#include "mds_client.h" #include "mds_client.h"
...@@ -284,8 +285,7 @@ static size_t ceph_vxattrs_name_size(struct ceph_vxattr *vxattrs) ...@@ -284,8 +285,7 @@ static size_t ceph_vxattrs_name_size(struct ceph_vxattr *vxattrs)
return ceph_dir_vxattrs_name_size; return ceph_dir_vxattrs_name_size;
if (vxattrs == ceph_file_vxattrs) if (vxattrs == ceph_file_vxattrs)
return ceph_file_vxattrs_name_size; return ceph_file_vxattrs_name_size;
BUG(); BUG_ON(vxattrs);
return 0; return 0;
} }
...@@ -736,24 +736,20 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, ...@@ -736,24 +736,20 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
dout("getxattr %p ver=%lld index_ver=%lld\n", inode, dout("getxattr %p ver=%lld index_ver=%lld\n", inode,
ci->i_xattrs.version, ci->i_xattrs.index_version); ci->i_xattrs.version, ci->i_xattrs.index_version);
if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1) && if (ci->i_xattrs.version == 0 ||
(ci->i_xattrs.index_version >= ci->i_xattrs.version)) { !__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1)) {
goto get_xattr;
} else {
spin_unlock(&ci->i_ceph_lock); spin_unlock(&ci->i_ceph_lock);
/* get xattrs from mds (if we don't already have them) */ /* get xattrs from mds (if we don't already have them) */
err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR); err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true);
if (err) if (err)
return err; return err;
spin_lock(&ci->i_ceph_lock);
} }
spin_lock(&ci->i_ceph_lock);
err = __build_xattrs(inode); err = __build_xattrs(inode);
if (err < 0) if (err < 0)
goto out; goto out;
get_xattr:
err = -ENODATA; /* == ENOATTR */ err = -ENODATA; /* == ENOATTR */
xattr = __get_xattr(ci, name); xattr = __get_xattr(ci, name);
if (!xattr) if (!xattr)
...@@ -798,23 +794,18 @@ ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) ...@@ -798,23 +794,18 @@ ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
dout("listxattr %p ver=%lld index_ver=%lld\n", inode, dout("listxattr %p ver=%lld index_ver=%lld\n", inode,
ci->i_xattrs.version, ci->i_xattrs.index_version); ci->i_xattrs.version, ci->i_xattrs.index_version);
if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1) && if (ci->i_xattrs.version == 0 ||
(ci->i_xattrs.index_version >= ci->i_xattrs.version)) { !__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1)) {
goto list_xattr;
} else {
spin_unlock(&ci->i_ceph_lock); spin_unlock(&ci->i_ceph_lock);
err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR); err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true);
if (err) if (err)
return err; return err;
spin_lock(&ci->i_ceph_lock);
} }
spin_lock(&ci->i_ceph_lock);
err = __build_xattrs(inode); err = __build_xattrs(inode);
if (err < 0) if (err < 0)
goto out; goto out;
list_xattr:
/* /*
* Start with virtual dir xattr names (if any) (including * Start with virtual dir xattr names (if any) (including
* terminating '\0' characters for each). * terminating '\0' characters for each).
...@@ -860,35 +851,25 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name, ...@@ -860,35 +851,25 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_mds_request *req; struct ceph_mds_request *req;
struct ceph_mds_client *mdsc = fsc->mdsc; struct ceph_mds_client *mdsc = fsc->mdsc;
struct ceph_pagelist *pagelist = NULL;
int err; int err;
int i, nr_pages;
struct page **pages = NULL; if (value) {
void *kaddr; /* copy value into pagelist */
pagelist = kmalloc(sizeof(*pagelist), GFP_NOFS);
/* copy value into some pages */ if (!pagelist)
nr_pages = calc_pages_for(0, size);
if (nr_pages) {
pages = kmalloc(sizeof(pages[0])*nr_pages, GFP_NOFS);
if (!pages)
return -ENOMEM; return -ENOMEM;
err = -ENOMEM;
for (i = 0; i < nr_pages; i++) { ceph_pagelist_init(pagelist);
pages[i] = __page_cache_alloc(GFP_NOFS); err = ceph_pagelist_append(pagelist, value, size);
if (!pages[i]) { if (err)
nr_pages = i; goto out;
goto out; } else {
} flags |= CEPH_XATTR_REMOVE;
kaddr = kmap(pages[i]);
memcpy(kaddr, value + i*PAGE_CACHE_SIZE,
min(PAGE_CACHE_SIZE, size-i*PAGE_CACHE_SIZE));
}
} }
dout("setxattr value=%.*s\n", (int)size, value); dout("setxattr value=%.*s\n", (int)size, value);
if (!value)
flags |= CEPH_XATTR_REMOVE;
/* do request */ /* do request */
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETXATTR, req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETXATTR,
USE_AUTH_MDS); USE_AUTH_MDS);
...@@ -903,9 +884,8 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name, ...@@ -903,9 +884,8 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
req->r_args.setxattr.flags = cpu_to_le32(flags); req->r_args.setxattr.flags = cpu_to_le32(flags);
req->r_path2 = kstrdup(name, GFP_NOFS); req->r_path2 = kstrdup(name, GFP_NOFS);
req->r_pages = pages; req->r_pagelist = pagelist;
req->r_num_pages = nr_pages; pagelist = NULL;
req->r_data_len = size;
dout("xattr.ver (before): %lld\n", ci->i_xattrs.version); dout("xattr.ver (before): %lld\n", ci->i_xattrs.version);
err = ceph_mdsc_do_request(mdsc, NULL, req); err = ceph_mdsc_do_request(mdsc, NULL, req);
...@@ -913,11 +893,8 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name, ...@@ -913,11 +893,8 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
dout("xattr.ver (after): %lld\n", ci->i_xattrs.version); dout("xattr.ver (after): %lld\n", ci->i_xattrs.version);
out: out:
if (pages) { if (pagelist)
for (i = 0; i < nr_pages; i++) ceph_pagelist_release(pagelist);
__free_page(pages[i]);
kfree(pages);
}
return err; return err;
} }
...@@ -968,7 +945,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name, ...@@ -968,7 +945,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name,
retry: retry:
issued = __ceph_caps_issued(ci, NULL); issued = __ceph_caps_issued(ci, NULL);
dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued)); dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued));
if (!(issued & CEPH_CAP_XATTR_EXCL)) if (ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL))
goto do_sync; goto do_sync;
__build_xattrs(inode); __build_xattrs(inode);
...@@ -1077,7 +1054,7 @@ int __ceph_removexattr(struct dentry *dentry, const char *name) ...@@ -1077,7 +1054,7 @@ int __ceph_removexattr(struct dentry *dentry, const char *name)
issued = __ceph_caps_issued(ci, NULL); issued = __ceph_caps_issued(ci, NULL);
dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued)); dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued));
if (!(issued & CEPH_CAP_XATTR_EXCL)) if (ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL))
goto do_sync; goto do_sync;
__build_xattrs(inode); __build_xattrs(inode);
......
...@@ -211,7 +211,6 @@ extern struct page **ceph_get_direct_page_vector(const void __user *data, ...@@ -211,7 +211,6 @@ extern struct page **ceph_get_direct_page_vector(const void __user *data,
bool write_page); bool write_page);
extern void ceph_put_page_vector(struct page **pages, int num_pages, extern void ceph_put_page_vector(struct page **pages, int num_pages,
bool dirty); bool dirty);
extern void ceph_release_page_vector(struct page **pages, int num_pages);
extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags); extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags);
extern int ceph_copy_user_to_page_vector(struct page **pages, extern int ceph_copy_user_to_page_vector(struct page **pages,
const void __user *data, const void __user *data,
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define __FS_CEPH_PAGELIST_H #define __FS_CEPH_PAGELIST_H
#include <linux/list.h> #include <linux/list.h>
#include <linux/atomic.h>
struct ceph_pagelist { struct ceph_pagelist {
struct list_head head; struct list_head head;
...@@ -10,6 +11,7 @@ struct ceph_pagelist { ...@@ -10,6 +11,7 @@ struct ceph_pagelist {
size_t room; size_t room;
struct list_head free_list; struct list_head free_list;
size_t num_pages_free; size_t num_pages_free;
atomic_t refcnt;
}; };
struct ceph_pagelist_cursor { struct ceph_pagelist_cursor {
...@@ -26,9 +28,10 @@ static inline void ceph_pagelist_init(struct ceph_pagelist *pl) ...@@ -26,9 +28,10 @@ static inline void ceph_pagelist_init(struct ceph_pagelist *pl)
pl->room = 0; pl->room = 0;
INIT_LIST_HEAD(&pl->free_list); INIT_LIST_HEAD(&pl->free_list);
pl->num_pages_free = 0; pl->num_pages_free = 0;
atomic_set(&pl->refcnt, 1);
} }
extern int ceph_pagelist_release(struct ceph_pagelist *pl); extern void ceph_pagelist_release(struct ceph_pagelist *pl);
extern int ceph_pagelist_append(struct ceph_pagelist *pl, const void *d, size_t l); extern int ceph_pagelist_append(struct ceph_pagelist *pl, const void *d, size_t l);
......
This diff is collapsed.
...@@ -3,6 +3,7 @@ config CEPH_LIB ...@@ -3,6 +3,7 @@ config CEPH_LIB
depends on INET depends on INET
select LIBCRC32C select LIBCRC32C
select CRYPTO_AES select CRYPTO_AES
select CRYPTO_CBC
select CRYPTO select CRYPTO
select KEYS select KEYS
default n default n
......
...@@ -293,17 +293,20 @@ static int get_secret(struct ceph_crypto_key *dst, const char *name) { ...@@ -293,17 +293,20 @@ static int get_secret(struct ceph_crypto_key *dst, const char *name) {
key_err = PTR_ERR(ukey); key_err = PTR_ERR(ukey);
switch (key_err) { switch (key_err) {
case -ENOKEY: case -ENOKEY:
pr_warning("ceph: Mount failed due to key not found: %s\n", name); pr_warn("ceph: Mount failed due to key not found: %s\n",
name);
break; break;
case -EKEYEXPIRED: case -EKEYEXPIRED:
pr_warning("ceph: Mount failed due to expired key: %s\n", name); pr_warn("ceph: Mount failed due to expired key: %s\n",
name);
break; break;
case -EKEYREVOKED: case -EKEYREVOKED:
pr_warning("ceph: Mount failed due to revoked key: %s\n", name); pr_warn("ceph: Mount failed due to revoked key: %s\n",
name);
break; break;
default: default:
pr_warning("ceph: Mount failed due to unknown key error" pr_warn("ceph: Mount failed due to unknown key error %d: %s\n",
" %d: %s\n", key_err, name); key_err, name);
} }
err = -EPERM; err = -EPERM;
goto out; goto out;
...@@ -433,7 +436,7 @@ ceph_parse_options(char *options, const char *dev_name, ...@@ -433,7 +436,7 @@ ceph_parse_options(char *options, const char *dev_name,
/* misc */ /* misc */
case Opt_osdtimeout: case Opt_osdtimeout:
pr_warning("ignoring deprecated osdtimeout option\n"); pr_warn("ignoring deprecated osdtimeout option\n");
break; break;
case Opt_osdkeepalivetimeout: case Opt_osdkeepalivetimeout:
opt->osd_keepalive_timeout = intval; opt->osd_keepalive_timeout = intval;
......
...@@ -19,77 +19,12 @@ const char *ceph_entity_type_name(int type) ...@@ -19,77 +19,12 @@ const char *ceph_entity_type_name(int type)
const char *ceph_osd_op_name(int op) const char *ceph_osd_op_name(int op)
{ {
switch (op) { switch (op) {
case CEPH_OSD_OP_READ: return "read"; #define GENERATE_CASE(op, opcode, str) case CEPH_OSD_OP_##op: return (str);
case CEPH_OSD_OP_STAT: return "stat"; __CEPH_FORALL_OSD_OPS(GENERATE_CASE)
case CEPH_OSD_OP_MAPEXT: return "mapext"; #undef GENERATE_CASE
case CEPH_OSD_OP_SPARSE_READ: return "sparse-read"; default:
case CEPH_OSD_OP_NOTIFY: return "notify"; return "???";
case CEPH_OSD_OP_NOTIFY_ACK: return "notify-ack";
case CEPH_OSD_OP_ASSERT_VER: return "assert-version";
case CEPH_OSD_OP_MASKTRUNC: return "masktrunc";
case CEPH_OSD_OP_CREATE: return "create";
case CEPH_OSD_OP_WRITE: return "write";
case CEPH_OSD_OP_DELETE: return "delete";
case CEPH_OSD_OP_TRUNCATE: return "truncate";
case CEPH_OSD_OP_ZERO: return "zero";
case CEPH_OSD_OP_WRITEFULL: return "writefull";
case CEPH_OSD_OP_ROLLBACK: return "rollback";
case CEPH_OSD_OP_APPEND: return "append";
case CEPH_OSD_OP_STARTSYNC: return "startsync";
case CEPH_OSD_OP_SETTRUNC: return "settrunc";
case CEPH_OSD_OP_TRIMTRUNC: return "trimtrunc";
case CEPH_OSD_OP_TMAPUP: return "tmapup";
case CEPH_OSD_OP_TMAPGET: return "tmapget";
case CEPH_OSD_OP_TMAPPUT: return "tmapput";
case CEPH_OSD_OP_WATCH: return "watch";
case CEPH_OSD_OP_CLONERANGE: return "clonerange";
case CEPH_OSD_OP_ASSERT_SRC_VERSION: return "assert-src-version";
case CEPH_OSD_OP_SRC_CMPXATTR: return "src-cmpxattr";
case CEPH_OSD_OP_GETXATTR: return "getxattr";
case CEPH_OSD_OP_GETXATTRS: return "getxattrs";
case CEPH_OSD_OP_SETXATTR: return "setxattr";
case CEPH_OSD_OP_SETXATTRS: return "setxattrs";
case CEPH_OSD_OP_RESETXATTRS: return "resetxattrs";
case CEPH_OSD_OP_RMXATTR: return "rmxattr";
case CEPH_OSD_OP_CMPXATTR: return "cmpxattr";
case CEPH_OSD_OP_PULL: return "pull";
case CEPH_OSD_OP_PUSH: return "push";
case CEPH_OSD_OP_BALANCEREADS: return "balance-reads";
case CEPH_OSD_OP_UNBALANCEREADS: return "unbalance-reads";
case CEPH_OSD_OP_SCRUB: return "scrub";
case CEPH_OSD_OP_SCRUB_RESERVE: return "scrub-reserve";
case CEPH_OSD_OP_SCRUB_UNRESERVE: return "scrub-unreserve";
case CEPH_OSD_OP_SCRUB_STOP: return "scrub-stop";
case CEPH_OSD_OP_SCRUB_MAP: return "scrub-map";
case CEPH_OSD_OP_WRLOCK: return "wrlock";
case CEPH_OSD_OP_WRUNLOCK: return "wrunlock";
case CEPH_OSD_OP_RDLOCK: return "rdlock";
case CEPH_OSD_OP_RDUNLOCK: return "rdunlock";
case CEPH_OSD_OP_UPLOCK: return "uplock";
case CEPH_OSD_OP_DNLOCK: return "dnlock";
case CEPH_OSD_OP_CALL: return "call";
case CEPH_OSD_OP_PGLS: return "pgls";
case CEPH_OSD_OP_PGLS_FILTER: return "pgls-filter";
case CEPH_OSD_OP_OMAPGETKEYS: return "omap-get-keys";
case CEPH_OSD_OP_OMAPGETVALS: return "omap-get-vals";
case CEPH_OSD_OP_OMAPGETHEADER: return "omap-get-header";
case CEPH_OSD_OP_OMAPGETVALSBYKEYS: return "omap-get-vals-by-keys";
case CEPH_OSD_OP_OMAPSETVALS: return "omap-set-vals";
case CEPH_OSD_OP_OMAPSETHEADER: return "omap-set-header";
case CEPH_OSD_OP_OMAPCLEAR: return "omap-clear";
case CEPH_OSD_OP_OMAPRMKEYS: return "omap-rm-keys";
} }
return "???";
} }
const char *ceph_osd_state_name(int s) const char *ceph_osd_state_name(int s)
......
...@@ -169,7 +169,8 @@ static int osdc_show(struct seq_file *s, void *pp) ...@@ -169,7 +169,8 @@ static int osdc_show(struct seq_file *s, void *pp)
for (i = 0; i < req->r_num_ops; i++) { for (i = 0; i < req->r_num_ops; i++) {
opcode = req->r_ops[i].op; opcode = req->r_ops[i].op;
seq_printf(s, "\t%s", ceph_osd_op_name(opcode)); seq_printf(s, "%s%s", (i == 0 ? "\t" : ","),
ceph_osd_op_name(opcode));
} }
seq_printf(s, "\n"); seq_printf(s, "\n");
......
...@@ -292,7 +292,11 @@ int ceph_msgr_init(void) ...@@ -292,7 +292,11 @@ int ceph_msgr_init(void)
if (ceph_msgr_slab_init()) if (ceph_msgr_slab_init())
return -ENOMEM; return -ENOMEM;
ceph_msgr_wq = alloc_workqueue("ceph-msgr", 0, 0); /*
* The number of active work items is limited by the number of
* connections, so leave @max_active at default.
*/
ceph_msgr_wq = alloc_workqueue("ceph-msgr", WQ_MEM_RECLAIM, 0);
if (ceph_msgr_wq) if (ceph_msgr_wq)
return 0; return 0;
...@@ -1937,11 +1941,11 @@ static int process_banner(struct ceph_connection *con) ...@@ -1937,11 +1941,11 @@ static int process_banner(struct ceph_connection *con)
sizeof(con->peer_addr)) != 0 && sizeof(con->peer_addr)) != 0 &&
!(addr_is_blank(&con->actual_peer_addr.in_addr) && !(addr_is_blank(&con->actual_peer_addr.in_addr) &&
con->actual_peer_addr.nonce == con->peer_addr.nonce)) { con->actual_peer_addr.nonce == con->peer_addr.nonce)) {
pr_warning("wrong peer, want %s/%d, got %s/%d\n", pr_warn("wrong peer, want %s/%d, got %s/%d\n",
ceph_pr_addr(&con->peer_addr.in_addr), ceph_pr_addr(&con->peer_addr.in_addr),
(int)le32_to_cpu(con->peer_addr.nonce), (int)le32_to_cpu(con->peer_addr.nonce),
ceph_pr_addr(&con->actual_peer_addr.in_addr), ceph_pr_addr(&con->actual_peer_addr.in_addr),
(int)le32_to_cpu(con->actual_peer_addr.nonce)); (int)le32_to_cpu(con->actual_peer_addr.nonce));
con->error_msg = "wrong peer at address"; con->error_msg = "wrong peer at address";
return -1; return -1;
} }
...@@ -2302,7 +2306,7 @@ static int read_partial_message(struct ceph_connection *con) ...@@ -2302,7 +2306,7 @@ static int read_partial_message(struct ceph_connection *con)
BUG_ON(!con->in_msg ^ skip); BUG_ON(!con->in_msg ^ skip);
if (con->in_msg && data_len > con->in_msg->data_length) { if (con->in_msg && data_len > con->in_msg->data_length) {
pr_warning("%s skipping long message (%u > %zd)\n", pr_warn("%s skipping long message (%u > %zd)\n",
__func__, data_len, con->in_msg->data_length); __func__, data_len, con->in_msg->data_length);
ceph_msg_put(con->in_msg); ceph_msg_put(con->in_msg);
con->in_msg = NULL; con->in_msg = NULL;
...@@ -2712,7 +2716,7 @@ static bool con_sock_closed(struct ceph_connection *con) ...@@ -2712,7 +2716,7 @@ static bool con_sock_closed(struct ceph_connection *con)
CASE(OPEN); CASE(OPEN);
CASE(STANDBY); CASE(STANDBY);
default: default:
pr_warning("%s con %p unrecognized state %lu\n", pr_warn("%s con %p unrecognized state %lu\n",
__func__, con, con->state); __func__, con, con->state);
con->error_msg = "unrecognized con state"; con->error_msg = "unrecognized con state";
BUG(); BUG();
...@@ -2828,8 +2832,8 @@ static void con_work(struct work_struct *work) ...@@ -2828,8 +2832,8 @@ static void con_work(struct work_struct *work)
*/ */
static void con_fault(struct ceph_connection *con) static void con_fault(struct ceph_connection *con)
{ {
pr_warning("%s%lld %s %s\n", ENTITY_NAME(con->peer_name), pr_warn("%s%lld %s %s\n", ENTITY_NAME(con->peer_name),
ceph_pr_addr(&con->peer_addr.in_addr), con->error_msg); ceph_pr_addr(&con->peer_addr.in_addr), con->error_msg);
dout("fault %p state %lu to peer %s\n", dout("fault %p state %lu to peer %s\n",
con, con->state, ceph_pr_addr(&con->peer_addr.in_addr)); con, con->state, ceph_pr_addr(&con->peer_addr.in_addr));
...@@ -3071,10 +3075,8 @@ static void ceph_msg_data_destroy(struct ceph_msg_data *data) ...@@ -3071,10 +3075,8 @@ static void ceph_msg_data_destroy(struct ceph_msg_data *data)
return; return;
WARN_ON(!list_empty(&data->links)); WARN_ON(!list_empty(&data->links));
if (data->type == CEPH_MSG_DATA_PAGELIST) { if (data->type == CEPH_MSG_DATA_PAGELIST)
ceph_pagelist_release(data->pagelist); ceph_pagelist_release(data->pagelist);
kfree(data->pagelist);
}
kmem_cache_free(ceph_msg_data_cache, data); kmem_cache_free(ceph_msg_data_cache, data);
} }
......
...@@ -1182,10 +1182,10 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con, ...@@ -1182,10 +1182,10 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
pr_info("alloc_msg unknown type %d\n", type); pr_info("alloc_msg unknown type %d\n", type);
*skip = 1; *skip = 1;
} else if (front_len > m->front_alloc_len) { } else if (front_len > m->front_alloc_len) {
pr_warning("mon_alloc_msg front %d > prealloc %d (%u#%llu)\n", pr_warn("mon_alloc_msg front %d > prealloc %d (%u#%llu)\n",
front_len, m->front_alloc_len, front_len, m->front_alloc_len,
(unsigned int)con->peer_name.type, (unsigned int)con->peer_name.type,
le64_to_cpu(con->peer_name.num)); le64_to_cpu(con->peer_name.num));
ceph_msg_put(m); ceph_msg_put(m);
m = ceph_msg_new(type, front_len, GFP_NOFS, false); m = ceph_msg_new(type, front_len, GFP_NOFS, false);
} }
......
...@@ -30,8 +30,11 @@ static void __send_queued(struct ceph_osd_client *osdc); ...@@ -30,8 +30,11 @@ static void __send_queued(struct ceph_osd_client *osdc);
static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd); static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd);
static void __register_request(struct ceph_osd_client *osdc, static void __register_request(struct ceph_osd_client *osdc,
struct ceph_osd_request *req); struct ceph_osd_request *req);
static void __unregister_request(struct ceph_osd_client *osdc,
struct ceph_osd_request *req);
static void __unregister_linger_request(struct ceph_osd_client *osdc, static void __unregister_linger_request(struct ceph_osd_client *osdc,
struct ceph_osd_request *req); struct ceph_osd_request *req);
static void __enqueue_request(struct ceph_osd_request *req);
static void __send_request(struct ceph_osd_client *osdc, static void __send_request(struct ceph_osd_client *osdc,
struct ceph_osd_request *req); struct ceph_osd_request *req);
...@@ -428,68 +431,9 @@ EXPORT_SYMBOL(ceph_osdc_alloc_request); ...@@ -428,68 +431,9 @@ EXPORT_SYMBOL(ceph_osdc_alloc_request);
static bool osd_req_opcode_valid(u16 opcode) static bool osd_req_opcode_valid(u16 opcode)
{ {
switch (opcode) { switch (opcode) {
case CEPH_OSD_OP_READ: #define GENERATE_CASE(op, opcode, str) case CEPH_OSD_OP_##op: return true;
case CEPH_OSD_OP_STAT: __CEPH_FORALL_OSD_OPS(GENERATE_CASE)
case CEPH_OSD_OP_MAPEXT: #undef GENERATE_CASE
case CEPH_OSD_OP_MASKTRUNC:
case CEPH_OSD_OP_SPARSE_READ:
case CEPH_OSD_OP_NOTIFY:
case CEPH_OSD_OP_NOTIFY_ACK:
case CEPH_OSD_OP_ASSERT_VER:
case CEPH_OSD_OP_WRITE:
case CEPH_OSD_OP_WRITEFULL:
case CEPH_OSD_OP_TRUNCATE:
case CEPH_OSD_OP_ZERO:
case CEPH_OSD_OP_DELETE:
case CEPH_OSD_OP_APPEND:
case CEPH_OSD_OP_STARTSYNC:
case CEPH_OSD_OP_SETTRUNC:
case CEPH_OSD_OP_TRIMTRUNC:
case CEPH_OSD_OP_TMAPUP:
case CEPH_OSD_OP_TMAPPUT:
case CEPH_OSD_OP_TMAPGET:
case CEPH_OSD_OP_CREATE:
case CEPH_OSD_OP_ROLLBACK:
case CEPH_OSD_OP_WATCH:
case CEPH_OSD_OP_OMAPGETKEYS:
case CEPH_OSD_OP_OMAPGETVALS:
case CEPH_OSD_OP_OMAPGETHEADER:
case CEPH_OSD_OP_OMAPGETVALSBYKEYS:
case CEPH_OSD_OP_OMAPSETVALS:
case CEPH_OSD_OP_OMAPSETHEADER:
case CEPH_OSD_OP_OMAPCLEAR:
case CEPH_OSD_OP_OMAPRMKEYS:
case CEPH_OSD_OP_OMAP_CMP:
case CEPH_OSD_OP_SETALLOCHINT:
case CEPH_OSD_OP_CLONERANGE:
case CEPH_OSD_OP_ASSERT_SRC_VERSION:
case CEPH_OSD_OP_SRC_CMPXATTR:
case CEPH_OSD_OP_GETXATTR:
case CEPH_OSD_OP_GETXATTRS:
case CEPH_OSD_OP_CMPXATTR:
case CEPH_OSD_OP_SETXATTR:
case CEPH_OSD_OP_SETXATTRS:
case CEPH_OSD_OP_RESETXATTRS:
case CEPH_OSD_OP_RMXATTR:
case CEPH_OSD_OP_PULL:
case CEPH_OSD_OP_PUSH:
case CEPH_OSD_OP_BALANCEREADS:
case CEPH_OSD_OP_UNBALANCEREADS:
case CEPH_OSD_OP_SCRUB:
case CEPH_OSD_OP_SCRUB_RESERVE:
case CEPH_OSD_OP_SCRUB_UNRESERVE:
case CEPH_OSD_OP_SCRUB_STOP:
case CEPH_OSD_OP_SCRUB_MAP:
case CEPH_OSD_OP_WRLOCK:
case CEPH_OSD_OP_WRUNLOCK:
case CEPH_OSD_OP_RDLOCK:
case CEPH_OSD_OP_RDUNLOCK:
case CEPH_OSD_OP_UPLOCK:
case CEPH_OSD_OP_DNLOCK:
case CEPH_OSD_OP_CALL:
case CEPH_OSD_OP_PGLS:
case CEPH_OSD_OP_PGLS_FILTER:
return true;
default: default:
return false; return false;
} }
...@@ -892,6 +836,37 @@ __lookup_request_ge(struct ceph_osd_client *osdc, ...@@ -892,6 +836,37 @@ __lookup_request_ge(struct ceph_osd_client *osdc,
return NULL; return NULL;
} }
static void __kick_linger_request(struct ceph_osd_request *req)
{
struct ceph_osd_client *osdc = req->r_osdc;
struct ceph_osd *osd = req->r_osd;
/*
* Linger requests need to be resent with a new tid to avoid
* the dup op detection logic on the OSDs. Achieve this with
* a re-register dance instead of open-coding.
*/
ceph_osdc_get_request(req);
if (!list_empty(&req->r_linger_item))
__unregister_linger_request(osdc, req);
else
__unregister_request(osdc, req);
__register_request(osdc, req);
ceph_osdc_put_request(req);
/*
* Unless request has been registered as both normal and
* lingering, __unregister{,_linger}_request clears r_osd.
* However, here we need to preserve r_osd to make sure we
* requeue on the same OSD.
*/
WARN_ON(req->r_osd || !osd);
req->r_osd = osd;
dout("%s requeueing %p tid %llu\n", __func__, req, req->r_tid);
__enqueue_request(req);
}
/* /*
* Resubmit requests pending on the given osd. * Resubmit requests pending on the given osd.
*/ */
...@@ -900,12 +875,14 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc, ...@@ -900,12 +875,14 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc,
{ {
struct ceph_osd_request *req, *nreq; struct ceph_osd_request *req, *nreq;
LIST_HEAD(resend); LIST_HEAD(resend);
LIST_HEAD(resend_linger);
int err; int err;
dout("__kick_osd_requests osd%d\n", osd->o_osd); dout("%s osd%d\n", __func__, osd->o_osd);
err = __reset_osd(osdc, osd); err = __reset_osd(osdc, osd);
if (err) if (err)
return; return;
/* /*
* Build up a list of requests to resend by traversing the * Build up a list of requests to resend by traversing the
* osd's list of requests. Requests for a given object are * osd's list of requests. Requests for a given object are
...@@ -926,33 +903,32 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc, ...@@ -926,33 +903,32 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc,
list_for_each_entry(req, &osd->o_requests, r_osd_item) { list_for_each_entry(req, &osd->o_requests, r_osd_item) {
if (!req->r_sent) if (!req->r_sent)
break; break;
list_move_tail(&req->r_req_lru_item, &resend);
dout("requeueing %p tid %llu osd%d\n", req, req->r_tid, if (!req->r_linger) {
osd->o_osd); dout("%s requeueing %p tid %llu\n", __func__, req,
if (!req->r_linger) req->r_tid);
list_move_tail(&req->r_req_lru_item, &resend);
req->r_flags |= CEPH_OSD_FLAG_RETRY; req->r_flags |= CEPH_OSD_FLAG_RETRY;
} else {
list_move_tail(&req->r_req_lru_item, &resend_linger);
}
} }
list_splice(&resend, &osdc->req_unsent); list_splice(&resend, &osdc->req_unsent);
/* /*
* Linger requests are re-registered before sending, which * Both registered and not yet registered linger requests are
* sets up a new tid for each. We add them to the unsent * enqueued with a new tid on the same OSD. We add/move them
* list at the end to keep things in tid order. * to req_unsent/o_requests at the end to keep things in tid
* order.
*/ */
list_for_each_entry_safe(req, nreq, &osd->o_linger_requests, list_for_each_entry_safe(req, nreq, &osd->o_linger_requests,
r_linger_osd_item) { r_linger_osd_item) {
/* WARN_ON(!list_empty(&req->r_req_lru_item));
* reregister request prior to unregistering linger so __kick_linger_request(req);
* that r_osd is preserved.
*/
BUG_ON(!list_empty(&req->r_req_lru_item));
__register_request(osdc, req);
list_add_tail(&req->r_req_lru_item, &osdc->req_unsent);
list_add_tail(&req->r_osd_item, &req->r_osd->o_requests);
__unregister_linger_request(osdc, req);
dout("requeued lingering %p tid %llu osd%d\n", req, req->r_tid,
osd->o_osd);
} }
list_for_each_entry_safe(req, nreq, &resend_linger, r_req_lru_item)
__kick_linger_request(req);
} }
/* /*
...@@ -1346,6 +1322,22 @@ static int __calc_request_pg(struct ceph_osdmap *osdmap, ...@@ -1346,6 +1322,22 @@ static int __calc_request_pg(struct ceph_osdmap *osdmap,
&req->r_target_oid, pg_out); &req->r_target_oid, pg_out);
} }
static void __enqueue_request(struct ceph_osd_request *req)
{
struct ceph_osd_client *osdc = req->r_osdc;
dout("%s %p tid %llu to osd%d\n", __func__, req, req->r_tid,
req->r_osd ? req->r_osd->o_osd : -1);
if (req->r_osd) {
__remove_osd_from_lru(req->r_osd);
list_add_tail(&req->r_osd_item, &req->r_osd->o_requests);
list_move_tail(&req->r_req_lru_item, &osdc->req_unsent);
} else {
list_move_tail(&req->r_req_lru_item, &osdc->req_notarget);
}
}
/* /*
* Pick an osd (the first 'up' osd in the pg), allocate the osd struct * Pick an osd (the first 'up' osd in the pg), allocate the osd struct
* (as needed), and set the request r_osd appropriately. If there is * (as needed), and set the request r_osd appropriately. If there is
...@@ -1423,13 +1415,7 @@ static int __map_request(struct ceph_osd_client *osdc, ...@@ -1423,13 +1415,7 @@ static int __map_request(struct ceph_osd_client *osdc,
&osdc->osdmap->osd_addr[o]); &osdc->osdmap->osd_addr[o]);
} }
if (req->r_osd) { __enqueue_request(req);
__remove_osd_from_lru(req->r_osd);
list_add_tail(&req->r_osd_item, &req->r_osd->o_requests);
list_move_tail(&req->r_req_lru_item, &osdc->req_unsent);
} else {
list_move_tail(&req->r_req_lru_item, &osdc->req_notarget);
}
err = 1; /* osd or pg changed */ err = 1; /* osd or pg changed */
out: out:
...@@ -1774,8 +1760,8 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg, ...@@ -1774,8 +1760,8 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg,
} }
bytes = le32_to_cpu(msg->hdr.data_len); bytes = le32_to_cpu(msg->hdr.data_len);
if (payload_len != bytes) { if (payload_len != bytes) {
pr_warning("sum of op payload lens %d != data_len %d", pr_warn("sum of op payload lens %d != data_len %d\n",
payload_len, bytes); payload_len, bytes);
goto bad_put; goto bad_put;
} }
...@@ -2313,24 +2299,19 @@ static void handle_watch_notify(struct ceph_osd_client *osdc, ...@@ -2313,24 +2299,19 @@ static void handle_watch_notify(struct ceph_osd_client *osdc,
if (event) { if (event) {
event_work = kmalloc(sizeof(*event_work), GFP_NOIO); event_work = kmalloc(sizeof(*event_work), GFP_NOIO);
if (!event_work) { if (!event_work) {
dout("ERROR: could not allocate event_work\n"); pr_err("couldn't allocate event_work\n");
goto done_err; ceph_osdc_put_event(event);
return;
} }
INIT_WORK(&event_work->work, do_event_work); INIT_WORK(&event_work->work, do_event_work);
event_work->event = event; event_work->event = event;
event_work->ver = ver; event_work->ver = ver;
event_work->notify_id = notify_id; event_work->notify_id = notify_id;
event_work->opcode = opcode; event_work->opcode = opcode;
if (!queue_work(osdc->notify_wq, &event_work->work)) {
dout("WARNING: failed to queue notify event work\n");
goto done_err;
}
}
return; queue_work(osdc->notify_wq, &event_work->work);
}
done_err:
ceph_osdc_put_event(event);
return; return;
bad: bad:
...@@ -2797,10 +2778,10 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, ...@@ -2797,10 +2778,10 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
ceph_msg_revoke_incoming(req->r_reply); ceph_msg_revoke_incoming(req->r_reply);
if (front_len > req->r_reply->front_alloc_len) { if (front_len > req->r_reply->front_alloc_len) {
pr_warning("get_reply front %d > preallocated %d (%u#%llu)\n", pr_warn("get_reply front %d > preallocated %d (%u#%llu)\n",
front_len, req->r_reply->front_alloc_len, front_len, req->r_reply->front_alloc_len,
(unsigned int)con->peer_name.type, (unsigned int)con->peer_name.type,
le64_to_cpu(con->peer_name.num)); le64_to_cpu(con->peer_name.num));
m = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, front_len, GFP_NOFS, m = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, front_len, GFP_NOFS,
false); false);
if (!m) if (!m)
...@@ -2823,8 +2804,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, ...@@ -2823,8 +2804,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
if (osd_data->pages && if (osd_data->pages &&
unlikely(osd_data->length < data_len)) { unlikely(osd_data->length < data_len)) {
pr_warning("tid %lld reply has %d bytes " pr_warn("tid %lld reply has %d bytes we had only %llu bytes ready\n",
"we had only %llu bytes ready\n",
tid, data_len, osd_data->length); tid, data_len, osd_data->length);
*skip = 1; *skip = 1;
ceph_msg_put(m); ceph_msg_put(m);
......
...@@ -521,11 +521,11 @@ static int decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi) ...@@ -521,11 +521,11 @@ static int decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi)
ev = ceph_decode_8(p); /* encoding version */ ev = ceph_decode_8(p); /* encoding version */
cv = ceph_decode_8(p); /* compat version */ cv = ceph_decode_8(p); /* compat version */
if (ev < 5) { if (ev < 5) {
pr_warning("got v %d < 5 cv %d of ceph_pg_pool\n", ev, cv); pr_warn("got v %d < 5 cv %d of ceph_pg_pool\n", ev, cv);
return -EINVAL; return -EINVAL;
} }
if (cv > 9) { if (cv > 9) {
pr_warning("got v %d cv %d > 9 of ceph_pg_pool\n", ev, cv); pr_warn("got v %d cv %d > 9 of ceph_pg_pool\n", ev, cv);
return -EINVAL; return -EINVAL;
} }
len = ceph_decode_32(p); len = ceph_decode_32(p);
...@@ -671,26 +671,26 @@ static int osdmap_set_max_osd(struct ceph_osdmap *map, int max) ...@@ -671,26 +671,26 @@ static int osdmap_set_max_osd(struct ceph_osdmap *map, int max)
int i; int i;
state = krealloc(map->osd_state, max*sizeof(*state), GFP_NOFS); state = krealloc(map->osd_state, max*sizeof(*state), GFP_NOFS);
if (!state)
return -ENOMEM;
map->osd_state = state;
weight = krealloc(map->osd_weight, max*sizeof(*weight), GFP_NOFS); weight = krealloc(map->osd_weight, max*sizeof(*weight), GFP_NOFS);
addr = krealloc(map->osd_addr, max*sizeof(*addr), GFP_NOFS); if (!weight)
if (!state || !weight || !addr) { return -ENOMEM;
kfree(state); map->osd_weight = weight;
kfree(weight);
kfree(addr);
addr = krealloc(map->osd_addr, max*sizeof(*addr), GFP_NOFS);
if (!addr)
return -ENOMEM; return -ENOMEM;
} map->osd_addr = addr;
for (i = map->max_osd; i < max; i++) { for (i = map->max_osd; i < max; i++) {
state[i] = 0; map->osd_state[i] = 0;
weight[i] = CEPH_OSD_OUT; map->osd_weight[i] = CEPH_OSD_OUT;
memset(addr + i, 0, sizeof(*addr)); memset(map->osd_addr + i, 0, sizeof(*map->osd_addr));
} }
map->osd_state = state;
map->osd_weight = weight;
map->osd_addr = addr;
if (map->osd_primary_affinity) { if (map->osd_primary_affinity) {
u32 *affinity; u32 *affinity;
...@@ -698,11 +698,11 @@ static int osdmap_set_max_osd(struct ceph_osdmap *map, int max) ...@@ -698,11 +698,11 @@ static int osdmap_set_max_osd(struct ceph_osdmap *map, int max)
max*sizeof(*affinity), GFP_NOFS); max*sizeof(*affinity), GFP_NOFS);
if (!affinity) if (!affinity)
return -ENOMEM; return -ENOMEM;
map->osd_primary_affinity = affinity;
for (i = map->max_osd; i < max; i++) for (i = map->max_osd; i < max; i++)
affinity[i] = CEPH_OSD_DEFAULT_PRIMARY_AFFINITY; map->osd_primary_affinity[i] =
CEPH_OSD_DEFAULT_PRIMARY_AFFINITY;
map->osd_primary_affinity = affinity;
} }
map->max_osd = max; map->max_osd = max;
...@@ -729,9 +729,9 @@ static int get_osdmap_client_data_v(void **p, void *end, ...@@ -729,9 +729,9 @@ static int get_osdmap_client_data_v(void **p, void *end,
ceph_decode_8_safe(p, end, struct_compat, e_inval); ceph_decode_8_safe(p, end, struct_compat, e_inval);
if (struct_compat > OSDMAP_WRAPPER_COMPAT_VER) { if (struct_compat > OSDMAP_WRAPPER_COMPAT_VER) {
pr_warning("got v %d cv %d > %d of %s ceph_osdmap\n", pr_warn("got v %d cv %d > %d of %s ceph_osdmap\n",
struct_v, struct_compat, struct_v, struct_compat,
OSDMAP_WRAPPER_COMPAT_VER, prefix); OSDMAP_WRAPPER_COMPAT_VER, prefix);
return -EINVAL; return -EINVAL;
} }
*p += 4; /* ignore wrapper struct_len */ *p += 4; /* ignore wrapper struct_len */
...@@ -739,9 +739,9 @@ static int get_osdmap_client_data_v(void **p, void *end, ...@@ -739,9 +739,9 @@ static int get_osdmap_client_data_v(void **p, void *end,
ceph_decode_8_safe(p, end, struct_v, e_inval); ceph_decode_8_safe(p, end, struct_v, e_inval);
ceph_decode_8_safe(p, end, struct_compat, e_inval); ceph_decode_8_safe(p, end, struct_compat, e_inval);
if (struct_compat > OSDMAP_CLIENT_DATA_COMPAT_VER) { if (struct_compat > OSDMAP_CLIENT_DATA_COMPAT_VER) {
pr_warning("got v %d cv %d > %d of %s ceph_osdmap client data\n", pr_warn("got v %d cv %d > %d of %s ceph_osdmap client data\n",
struct_v, struct_compat, struct_v, struct_compat,
OSDMAP_CLIENT_DATA_COMPAT_VER, prefix); OSDMAP_CLIENT_DATA_COMPAT_VER, prefix);
return -EINVAL; return -EINVAL;
} }
*p += 4; /* ignore client data struct_len */ *p += 4; /* ignore client data struct_len */
...@@ -751,8 +751,8 @@ static int get_osdmap_client_data_v(void **p, void *end, ...@@ -751,8 +751,8 @@ static int get_osdmap_client_data_v(void **p, void *end,
*p -= 1; *p -= 1;
ceph_decode_16_safe(p, end, version, e_inval); ceph_decode_16_safe(p, end, version, e_inval);
if (version < 6) { if (version < 6) {
pr_warning("got v %d < 6 of %s ceph_osdmap\n", version, pr_warn("got v %d < 6 of %s ceph_osdmap\n",
prefix); version, prefix);
return -EINVAL; return -EINVAL;
} }
......
#include <linux/module.h> #include <linux/module.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/slab.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/ceph/pagelist.h> #include <linux/ceph/pagelist.h>
...@@ -13,8 +14,10 @@ static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl) ...@@ -13,8 +14,10 @@ static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl)
} }
} }
int ceph_pagelist_release(struct ceph_pagelist *pl) void ceph_pagelist_release(struct ceph_pagelist *pl)
{ {
if (!atomic_dec_and_test(&pl->refcnt))
return;
ceph_pagelist_unmap_tail(pl); ceph_pagelist_unmap_tail(pl);
while (!list_empty(&pl->head)) { while (!list_empty(&pl->head)) {
struct page *page = list_first_entry(&pl->head, struct page, struct page *page = list_first_entry(&pl->head, struct page,
...@@ -23,7 +26,7 @@ int ceph_pagelist_release(struct ceph_pagelist *pl) ...@@ -23,7 +26,7 @@ int ceph_pagelist_release(struct ceph_pagelist *pl)
__free_page(page); __free_page(page);
} }
ceph_pagelist_free_reserve(pl); ceph_pagelist_free_reserve(pl);
return 0; kfree(pl);
} }
EXPORT_SYMBOL(ceph_pagelist_release); EXPORT_SYMBOL(ceph_pagelist_release);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment