mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
ceph: factor out libceph from Ceph file system
This factors out protocol and low-level storage parts of ceph into a separate libceph module living in net/ceph and include/linux/ceph. This is mostly a matter of moving files around. However, a few key pieces of the interface change as well: - ceph_client becomes ceph_fs_client and ceph_client, where the latter captures the mon and osd clients, and the fs_client gets the mds client and file system specific pieces. - Mount option parsing and debugfs setup is correspondingly broken into two pieces. - The mon client gets a generic handler callback for otherwise unknown messages (mds map, in this case). - The basic supported/required feature bits can be expanded (and are by ceph_fs_client). No functional change, aside from some subtle error handling cases that got cleaned up in the refactoring process. Signed-off-by: Sage Weil <[email protected]>
This commit is contained in:
parent
ae1533b62b
commit
3d14c5d2b6
73 changed files with 2566 additions and 1838 deletions
|
|
@ -1,9 +1,11 @@
|
|||
config CEPH_FS
|
||||
tristate "Ceph distributed file system (EXPERIMENTAL)"
|
||||
depends on INET && EXPERIMENTAL
|
||||
select CEPH_LIB
|
||||
select LIBCRC32C
|
||||
select CRYPTO_AES
|
||||
select CRYPTO
|
||||
default n
|
||||
help
|
||||
Choose Y or M here to include support for mounting the
|
||||
experimental Ceph distributed file system. Ceph is an extremely
|
||||
|
|
@ -14,15 +16,3 @@ config CEPH_FS
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config CEPH_FS_PRETTYDEBUG
|
||||
bool "Include file:line in ceph debug output"
|
||||
depends on CEPH_FS
|
||||
default n
|
||||
help
|
||||
If you say Y here, debug output will include a filename and
|
||||
line to aid debugging. This icnreases kernel size and slows
|
||||
execution slightly when debug call sites are enabled (e.g.,
|
||||
via CONFIG_DYNAMIC_DEBUG).
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
|
|
|
|||
|
|
@ -8,15 +8,8 @@ obj-$(CONFIG_CEPH_FS) += ceph.o
|
|||
|
||||
ceph-objs := super.o inode.o dir.o file.o locks.o addr.o ioctl.o \
|
||||
export.o caps.o snap.o xattr.o \
|
||||
messenger.o msgpool.o buffer.o pagelist.o \
|
||||
mds_client.o mdsmap.o \
|
||||
mon_client.o \
|
||||
osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \
|
||||
debugfs.o \
|
||||
auth.o auth_none.o \
|
||||
crypto.o armor.o \
|
||||
auth_x.o \
|
||||
ceph_fs.o ceph_strings.o ceph_hash.o ceph_frag.o
|
||||
mds_client.o mdsmap.o strings.o ceph_frag.o \
|
||||
debugfs.o
|
||||
|
||||
else
|
||||
#Otherwise we were called directly from the command
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
#
|
||||
# The following files are shared by (and manually synchronized
|
||||
# between) the Ceph userland and kernel client.
|
||||
#
|
||||
# userland kernel
|
||||
src/include/ceph_fs.h fs/ceph/ceph_fs.h
|
||||
src/include/ceph_fs.cc fs/ceph/ceph_fs.c
|
||||
src/include/msgr.h fs/ceph/msgr.h
|
||||
src/include/rados.h fs/ceph/rados.h
|
||||
src/include/ceph_strings.cc fs/ceph/ceph_strings.c
|
||||
src/include/ceph_frag.h fs/ceph/ceph_frag.h
|
||||
src/include/ceph_frag.cc fs/ceph/ceph_frag.c
|
||||
src/include/ceph_hash.h fs/ceph/ceph_hash.h
|
||||
src/include/ceph_hash.cc fs/ceph/ceph_hash.c
|
||||
src/crush/crush.c fs/ceph/crush/crush.c
|
||||
src/crush/crush.h fs/ceph/crush/crush.h
|
||||
src/crush/mapper.c fs/ceph/crush/mapper.c
|
||||
src/crush/mapper.h fs/ceph/crush/mapper.h
|
||||
src/crush/hash.h fs/ceph/crush/hash.h
|
||||
src/crush/hash.c fs/ceph/crush/hash.c
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "ceph_debug.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/fs.h>
|
||||
|
|
@ -10,7 +10,8 @@
|
|||
#include <linux/task_io_accounting_ops.h>
|
||||
|
||||
#include "super.h"
|
||||
#include "osd_client.h"
|
||||
#include "mds_client.h"
|
||||
#include <linux/ceph/osd_client.h>
|
||||
|
||||
/*
|
||||
* Ceph address space ops.
|
||||
|
|
@ -193,7 +194,8 @@ static int readpage_nounlock(struct file *filp, struct page *page)
|
|||
{
|
||||
struct inode *inode = filp->f_dentry->d_inode;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_osd_client *osdc = &ceph_inode_to_client(inode)->osdc;
|
||||
struct ceph_osd_client *osdc =
|
||||
&ceph_inode_to_client(inode)->client->osdc;
|
||||
int err = 0;
|
||||
u64 len = PAGE_CACHE_SIZE;
|
||||
|
||||
|
|
@ -265,7 +267,8 @@ static int ceph_readpages(struct file *file, struct address_space *mapping,
|
|||
{
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_osd_client *osdc = &ceph_inode_to_client(inode)->osdc;
|
||||
struct ceph_osd_client *osdc =
|
||||
&ceph_inode_to_client(inode)->client->osdc;
|
||||
int rc = 0;
|
||||
struct page **pages;
|
||||
loff_t offset;
|
||||
|
|
@ -365,7 +368,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
|
|||
{
|
||||
struct inode *inode;
|
||||
struct ceph_inode_info *ci;
|
||||
struct ceph_client *client;
|
||||
struct ceph_fs_client *fsc;
|
||||
struct ceph_osd_client *osdc;
|
||||
loff_t page_off = page->index << PAGE_CACHE_SHIFT;
|
||||
int len = PAGE_CACHE_SIZE;
|
||||
|
|
@ -383,8 +386,8 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
|
|||
}
|
||||
inode = page->mapping->host;
|
||||
ci = ceph_inode(inode);
|
||||
client = ceph_inode_to_client(inode);
|
||||
osdc = &client->osdc;
|
||||
fsc = ceph_inode_to_client(inode);
|
||||
osdc = &fsc->client->osdc;
|
||||
|
||||
/* verify this is a writeable snap context */
|
||||
snapc = (void *)page->private;
|
||||
|
|
@ -414,10 +417,10 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
|
|||
dout("writepage %p page %p index %lu on %llu~%u snapc %p\n",
|
||||
inode, page, page->index, page_off, len, snapc);
|
||||
|
||||
writeback_stat = atomic_long_inc_return(&client->writeback_count);
|
||||
writeback_stat = atomic_long_inc_return(&fsc->writeback_count);
|
||||
if (writeback_stat >
|
||||
CONGESTION_ON_THRESH(client->mount_args->congestion_kb))
|
||||
set_bdi_congested(&client->backing_dev_info, BLK_RW_ASYNC);
|
||||
CONGESTION_ON_THRESH(fsc->mount_options->congestion_kb))
|
||||
set_bdi_congested(&fsc->backing_dev_info, BLK_RW_ASYNC);
|
||||
|
||||
set_page_writeback(page);
|
||||
err = ceph_osdc_writepages(osdc, ceph_vino(inode),
|
||||
|
|
@ -496,7 +499,7 @@ static void writepages_finish(struct ceph_osd_request *req,
|
|||
struct address_space *mapping = inode->i_mapping;
|
||||
__s32 rc = -EIO;
|
||||
u64 bytes = 0;
|
||||
struct ceph_client *client = ceph_inode_to_client(inode);
|
||||
struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
|
||||
long writeback_stat;
|
||||
unsigned issued = ceph_caps_issued(ci);
|
||||
|
||||
|
|
@ -529,10 +532,10 @@ static void writepages_finish(struct ceph_osd_request *req,
|
|||
WARN_ON(!PageUptodate(page));
|
||||
|
||||
writeback_stat =
|
||||
atomic_long_dec_return(&client->writeback_count);
|
||||
atomic_long_dec_return(&fsc->writeback_count);
|
||||
if (writeback_stat <
|
||||
CONGESTION_OFF_THRESH(client->mount_args->congestion_kb))
|
||||
clear_bdi_congested(&client->backing_dev_info,
|
||||
CONGESTION_OFF_THRESH(fsc->mount_options->congestion_kb))
|
||||
clear_bdi_congested(&fsc->backing_dev_info,
|
||||
BLK_RW_ASYNC);
|
||||
|
||||
ceph_put_snap_context((void *)page->private);
|
||||
|
|
@ -569,13 +572,13 @@ static void writepages_finish(struct ceph_osd_request *req,
|
|||
* mempool. we avoid the mempool if we can because req->r_num_pages
|
||||
* may be less than the maximum write size.
|
||||
*/
|
||||
static void alloc_page_vec(struct ceph_client *client,
|
||||
static void alloc_page_vec(struct ceph_fs_client *fsc,
|
||||
struct ceph_osd_request *req)
|
||||
{
|
||||
req->r_pages = kmalloc(sizeof(struct page *) * req->r_num_pages,
|
||||
GFP_NOFS);
|
||||
if (!req->r_pages) {
|
||||
req->r_pages = mempool_alloc(client->wb_pagevec_pool, GFP_NOFS);
|
||||
req->r_pages = mempool_alloc(fsc->wb_pagevec_pool, GFP_NOFS);
|
||||
req->r_pages_from_pool = 1;
|
||||
WARN_ON(!req->r_pages);
|
||||
}
|
||||
|
|
@ -590,7 +593,7 @@ static int ceph_writepages_start(struct address_space *mapping,
|
|||
struct inode *inode = mapping->host;
|
||||
struct backing_dev_info *bdi = mapping->backing_dev_info;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_client *client;
|
||||
struct ceph_fs_client *fsc;
|
||||
pgoff_t index, start, end;
|
||||
int range_whole = 0;
|
||||
int should_loop = 1;
|
||||
|
|
@ -617,13 +620,13 @@ static int ceph_writepages_start(struct address_space *mapping,
|
|||
wbc->sync_mode == WB_SYNC_NONE ? "NONE" :
|
||||
(wbc->sync_mode == WB_SYNC_ALL ? "ALL" : "HOLD"));
|
||||
|
||||
client = ceph_inode_to_client(inode);
|
||||
if (client->mount_state == CEPH_MOUNT_SHUTDOWN) {
|
||||
fsc = ceph_inode_to_client(inode);
|
||||
if (fsc->mount_state == CEPH_MOUNT_SHUTDOWN) {
|
||||
pr_warning("writepage_start %p on forced umount\n", inode);
|
||||
return -EIO; /* we're in a forced umount, don't write! */
|
||||
}
|
||||
if (client->mount_args->wsize && client->mount_args->wsize < wsize)
|
||||
wsize = client->mount_args->wsize;
|
||||
if (fsc->mount_options->wsize && fsc->mount_options->wsize < wsize)
|
||||
wsize = fsc->mount_options->wsize;
|
||||
if (wsize < PAGE_CACHE_SIZE)
|
||||
wsize = PAGE_CACHE_SIZE;
|
||||
max_pages_ever = wsize >> PAGE_CACHE_SHIFT;
|
||||
|
|
@ -769,7 +772,7 @@ get_more_pages:
|
|||
offset = (unsigned long long)page->index
|
||||
<< PAGE_CACHE_SHIFT;
|
||||
len = wsize;
|
||||
req = ceph_osdc_new_request(&client->osdc,
|
||||
req = ceph_osdc_new_request(&fsc->client->osdc,
|
||||
&ci->i_layout,
|
||||
ceph_vino(inode),
|
||||
offset, &len,
|
||||
|
|
@ -782,7 +785,7 @@ get_more_pages:
|
|||
&inode->i_mtime, true, 1);
|
||||
max_pages = req->r_num_pages;
|
||||
|
||||
alloc_page_vec(client, req);
|
||||
alloc_page_vec(fsc, req);
|
||||
req->r_callback = writepages_finish;
|
||||
req->r_inode = inode;
|
||||
}
|
||||
|
|
@ -794,10 +797,10 @@ get_more_pages:
|
|||
inode, page, page->index);
|
||||
|
||||
writeback_stat =
|
||||
atomic_long_inc_return(&client->writeback_count);
|
||||
atomic_long_inc_return(&fsc->writeback_count);
|
||||
if (writeback_stat > CONGESTION_ON_THRESH(
|
||||
client->mount_args->congestion_kb)) {
|
||||
set_bdi_congested(&client->backing_dev_info,
|
||||
fsc->mount_options->congestion_kb)) {
|
||||
set_bdi_congested(&fsc->backing_dev_info,
|
||||
BLK_RW_ASYNC);
|
||||
}
|
||||
|
||||
|
|
@ -846,7 +849,7 @@ get_more_pages:
|
|||
op->payload_len = cpu_to_le32(len);
|
||||
req->r_request->hdr.data_len = cpu_to_le32(len);
|
||||
|
||||
ceph_osdc_start_request(&client->osdc, req, true);
|
||||
ceph_osdc_start_request(&fsc->client->osdc, req, true);
|
||||
req = NULL;
|
||||
|
||||
/* continue? */
|
||||
|
|
@ -915,7 +918,7 @@ static int ceph_update_writeable_page(struct file *file,
|
|||
{
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
|
||||
struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
|
||||
loff_t page_off = pos & PAGE_CACHE_MASK;
|
||||
int pos_in_page = pos & ~PAGE_CACHE_MASK;
|
||||
int end_in_page = pos_in_page + len;
|
||||
|
|
@ -1053,8 +1056,8 @@ static int ceph_write_end(struct file *file, struct address_space *mapping,
|
|||
struct page *page, void *fsdata)
|
||||
{
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
struct ceph_client *client = ceph_inode_to_client(inode);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
unsigned from = pos & (PAGE_CACHE_SIZE - 1);
|
||||
int check_cap = 0;
|
||||
|
||||
|
|
@ -1123,7 +1126,7 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
{
|
||||
struct inode *inode = vma->vm_file->f_dentry->d_inode;
|
||||
struct page *page = vmf->page;
|
||||
struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
|
||||
struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
|
||||
loff_t off = page->index << PAGE_CACHE_SHIFT;
|
||||
loff_t size, len;
|
||||
int ret;
|
||||
|
|
|
|||
103
fs/ceph/armor.c
103
fs/ceph/armor.c
|
|
@ -1,103 +0,0 @@
|
|||
|
||||
#include <linux/errno.h>
|
||||
|
||||
int ceph_armor(char *dst, const char *src, const char *end);
|
||||
int ceph_unarmor(char *dst, const char *src, const char *end);
|
||||
|
||||
/*
|
||||
* base64 encode/decode.
|
||||
*/
|
||||
|
||||
static const char *pem_key =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static int encode_bits(int c)
|
||||
{
|
||||
return pem_key[c];
|
||||
}
|
||||
|
||||
static int decode_bits(char c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
return c - 'A';
|
||||
if (c >= 'a' && c <= 'z')
|
||||
return c - 'a' + 26;
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0' + 52;
|
||||
if (c == '+')
|
||||
return 62;
|
||||
if (c == '/')
|
||||
return 63;
|
||||
if (c == '=')
|
||||
return 0; /* just non-negative, please */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int ceph_armor(char *dst, const char *src, const char *end)
|
||||
{
|
||||
int olen = 0;
|
||||
int line = 0;
|
||||
|
||||
while (src < end) {
|
||||
unsigned char a, b, c;
|
||||
|
||||
a = *src++;
|
||||
*dst++ = encode_bits(a >> 2);
|
||||
if (src < end) {
|
||||
b = *src++;
|
||||
*dst++ = encode_bits(((a & 3) << 4) | (b >> 4));
|
||||
if (src < end) {
|
||||
c = *src++;
|
||||
*dst++ = encode_bits(((b & 15) << 2) |
|
||||
(c >> 6));
|
||||
*dst++ = encode_bits(c & 63);
|
||||
} else {
|
||||
*dst++ = encode_bits((b & 15) << 2);
|
||||
*dst++ = '=';
|
||||
}
|
||||
} else {
|
||||
*dst++ = encode_bits(((a & 3) << 4));
|
||||
*dst++ = '=';
|
||||
*dst++ = '=';
|
||||
}
|
||||
olen += 4;
|
||||
line += 4;
|
||||
if (line == 64) {
|
||||
line = 0;
|
||||
*(dst++) = '\n';
|
||||
olen++;
|
||||
}
|
||||
}
|
||||
return olen;
|
||||
}
|
||||
|
||||
int ceph_unarmor(char *dst, const char *src, const char *end)
|
||||
{
|
||||
int olen = 0;
|
||||
|
||||
while (src < end) {
|
||||
int a, b, c, d;
|
||||
|
||||
if (src < end && src[0] == '\n')
|
||||
src++;
|
||||
if (src + 4 > end)
|
||||
return -EINVAL;
|
||||
a = decode_bits(src[0]);
|
||||
b = decode_bits(src[1]);
|
||||
c = decode_bits(src[2]);
|
||||
d = decode_bits(src[3]);
|
||||
if (a < 0 || b < 0 || c < 0 || d < 0)
|
||||
return -EINVAL;
|
||||
|
||||
*dst++ = (a << 2) | (b >> 4);
|
||||
if (src[2] == '=')
|
||||
return olen + 1;
|
||||
*dst++ = ((b & 15) << 4) | (c >> 2);
|
||||
if (src[3] == '=')
|
||||
return olen + 2;
|
||||
*dst++ = ((c & 3) << 6) | d;
|
||||
olen += 3;
|
||||
src += 4;
|
||||
}
|
||||
return olen;
|
||||
}
|
||||
259
fs/ceph/auth.c
259
fs/ceph/auth.c
|
|
@ -1,259 +0,0 @@
|
|||
#include "ceph_debug.h"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "auth_none.h"
|
||||
#include "auth_x.h"
|
||||
#include "decode.h"
|
||||
#include "super.h"
|
||||
|
||||
#include "messenger.h"
|
||||
|
||||
/*
|
||||
* get protocol handler
|
||||
*/
|
||||
static u32 supported_protocols[] = {
|
||||
CEPH_AUTH_NONE,
|
||||
CEPH_AUTH_CEPHX
|
||||
};
|
||||
|
||||
static int ceph_auth_init_protocol(struct ceph_auth_client *ac, int protocol)
|
||||
{
|
||||
switch (protocol) {
|
||||
case CEPH_AUTH_NONE:
|
||||
return ceph_auth_none_init(ac);
|
||||
case CEPH_AUTH_CEPHX:
|
||||
return ceph_x_init(ac);
|
||||
default:
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* setup, teardown.
|
||||
*/
|
||||
struct ceph_auth_client *ceph_auth_init(const char *name, const char *secret)
|
||||
{
|
||||
struct ceph_auth_client *ac;
|
||||
int ret;
|
||||
|
||||
dout("auth_init name '%s' secret '%s'\n", name, secret);
|
||||
|
||||
ret = -ENOMEM;
|
||||
ac = kzalloc(sizeof(*ac), GFP_NOFS);
|
||||
if (!ac)
|
||||
goto out;
|
||||
|
||||
ac->negotiating = true;
|
||||
if (name)
|
||||
ac->name = name;
|
||||
else
|
||||
ac->name = CEPH_AUTH_NAME_DEFAULT;
|
||||
dout("auth_init name %s secret %s\n", ac->name, secret);
|
||||
ac->secret = secret;
|
||||
return ac;
|
||||
|
||||
out:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
void ceph_auth_destroy(struct ceph_auth_client *ac)
|
||||
{
|
||||
dout("auth_destroy %p\n", ac);
|
||||
if (ac->ops)
|
||||
ac->ops->destroy(ac);
|
||||
kfree(ac);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset occurs when reconnecting to the monitor.
|
||||
*/
|
||||
void ceph_auth_reset(struct ceph_auth_client *ac)
|
||||
{
|
||||
dout("auth_reset %p\n", ac);
|
||||
if (ac->ops && !ac->negotiating)
|
||||
ac->ops->reset(ac);
|
||||
ac->negotiating = true;
|
||||
}
|
||||
|
||||
int ceph_entity_name_encode(const char *name, void **p, void *end)
|
||||
{
|
||||
int len = strlen(name);
|
||||
|
||||
if (*p + 2*sizeof(u32) + len > end)
|
||||
return -ERANGE;
|
||||
ceph_encode_32(p, CEPH_ENTITY_TYPE_CLIENT);
|
||||
ceph_encode_32(p, len);
|
||||
ceph_encode_copy(p, name, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate protocol negotiation with monitor. Include entity name
|
||||
* and list supported protocols.
|
||||
*/
|
||||
int ceph_auth_build_hello(struct ceph_auth_client *ac, void *buf, size_t len)
|
||||
{
|
||||
struct ceph_mon_request_header *monhdr = buf;
|
||||
void *p = monhdr + 1, *end = buf + len, *lenp;
|
||||
int i, num;
|
||||
int ret;
|
||||
|
||||
dout("auth_build_hello\n");
|
||||
monhdr->have_version = 0;
|
||||
monhdr->session_mon = cpu_to_le16(-1);
|
||||
monhdr->session_mon_tid = 0;
|
||||
|
||||
ceph_encode_32(&p, 0); /* no protocol, yet */
|
||||
|
||||
lenp = p;
|
||||
p += sizeof(u32);
|
||||
|
||||
ceph_decode_need(&p, end, 1 + sizeof(u32), bad);
|
||||
ceph_encode_8(&p, 1);
|
||||
num = ARRAY_SIZE(supported_protocols);
|
||||
ceph_encode_32(&p, num);
|
||||
ceph_decode_need(&p, end, num * sizeof(u32), bad);
|
||||
for (i = 0; i < num; i++)
|
||||
ceph_encode_32(&p, supported_protocols[i]);
|
||||
|
||||
ret = ceph_entity_name_encode(ac->name, &p, end);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ceph_decode_need(&p, end, sizeof(u64), bad);
|
||||
ceph_encode_64(&p, ac->global_id);
|
||||
|
||||
ceph_encode_32(&lenp, p - lenp - sizeof(u32));
|
||||
return p - buf;
|
||||
|
||||
bad:
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
static int ceph_build_auth_request(struct ceph_auth_client *ac,
|
||||
void *msg_buf, size_t msg_len)
|
||||
{
|
||||
struct ceph_mon_request_header *monhdr = msg_buf;
|
||||
void *p = monhdr + 1;
|
||||
void *end = msg_buf + msg_len;
|
||||
int ret;
|
||||
|
||||
monhdr->have_version = 0;
|
||||
monhdr->session_mon = cpu_to_le16(-1);
|
||||
monhdr->session_mon_tid = 0;
|
||||
|
||||
ceph_encode_32(&p, ac->protocol);
|
||||
|
||||
ret = ac->ops->build_request(ac, p + sizeof(u32), end);
|
||||
if (ret < 0) {
|
||||
pr_err("error %d building auth method %s request\n", ret,
|
||||
ac->ops->name);
|
||||
return ret;
|
||||
}
|
||||
dout(" built request %d bytes\n", ret);
|
||||
ceph_encode_32(&p, ret);
|
||||
return p + ret - msg_buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle auth message from monitor.
|
||||
*/
|
||||
int ceph_handle_auth_reply(struct ceph_auth_client *ac,
|
||||
void *buf, size_t len,
|
||||
void *reply_buf, size_t reply_len)
|
||||
{
|
||||
void *p = buf;
|
||||
void *end = buf + len;
|
||||
int protocol;
|
||||
s32 result;
|
||||
u64 global_id;
|
||||
void *payload, *payload_end;
|
||||
int payload_len;
|
||||
char *result_msg;
|
||||
int result_msg_len;
|
||||
int ret = -EINVAL;
|
||||
|
||||
dout("handle_auth_reply %p %p\n", p, end);
|
||||
ceph_decode_need(&p, end, sizeof(u32) * 3 + sizeof(u64), bad);
|
||||
protocol = ceph_decode_32(&p);
|
||||
result = ceph_decode_32(&p);
|
||||
global_id = ceph_decode_64(&p);
|
||||
payload_len = ceph_decode_32(&p);
|
||||
payload = p;
|
||||
p += payload_len;
|
||||
ceph_decode_need(&p, end, sizeof(u32), bad);
|
||||
result_msg_len = ceph_decode_32(&p);
|
||||
result_msg = p;
|
||||
p += result_msg_len;
|
||||
if (p != end)
|
||||
goto bad;
|
||||
|
||||
dout(" result %d '%.*s' gid %llu len %d\n", result, result_msg_len,
|
||||
result_msg, global_id, payload_len);
|
||||
|
||||
payload_end = payload + payload_len;
|
||||
|
||||
if (global_id && ac->global_id != global_id) {
|
||||
dout(" set global_id %lld -> %lld\n", ac->global_id, global_id);
|
||||
ac->global_id = global_id;
|
||||
}
|
||||
|
||||
if (ac->negotiating) {
|
||||
/* server does not support our protocols? */
|
||||
if (!protocol && result < 0) {
|
||||
ret = result;
|
||||
goto out;
|
||||
}
|
||||
/* set up (new) protocol handler? */
|
||||
if (ac->protocol && ac->protocol != protocol) {
|
||||
ac->ops->destroy(ac);
|
||||
ac->protocol = 0;
|
||||
ac->ops = NULL;
|
||||
}
|
||||
if (ac->protocol != protocol) {
|
||||
ret = ceph_auth_init_protocol(ac, protocol);
|
||||
if (ret) {
|
||||
pr_err("error %d on auth protocol %d init\n",
|
||||
ret, protocol);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ac->negotiating = false;
|
||||
}
|
||||
|
||||
ret = ac->ops->handle_reply(ac, result, payload, payload_end);
|
||||
if (ret == -EAGAIN) {
|
||||
return ceph_build_auth_request(ac, reply_buf, reply_len);
|
||||
} else if (ret) {
|
||||
pr_err("auth method '%s' error %d\n", ac->ops->name, ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
pr_err("failed to decode auth msg\n");
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ceph_build_auth(struct ceph_auth_client *ac,
|
||||
void *msg_buf, size_t msg_len)
|
||||
{
|
||||
if (!ac->protocol)
|
||||
return ceph_auth_build_hello(ac, msg_buf, msg_len);
|
||||
BUG_ON(!ac->ops);
|
||||
if (ac->ops->should_authenticate(ac))
|
||||
return ceph_build_auth_request(ac, msg_buf, msg_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ceph_auth_is_authenticated(struct ceph_auth_client *ac)
|
||||
{
|
||||
if (!ac->ops)
|
||||
return 0;
|
||||
return ac->ops->is_authenticated(ac);
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
#ifndef _FS_CEPH_AUTH_H
|
||||
#define _FS_CEPH_AUTH_H
|
||||
|
||||
#include "types.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/*
|
||||
* Abstract interface for communicating with the authenticate module.
|
||||
* There is some handshake that takes place between us and the monitor
|
||||
* to acquire the necessary keys. These are used to generate an
|
||||
* 'authorizer' that we use when connecting to a service (mds, osd).
|
||||
*/
|
||||
|
||||
struct ceph_auth_client;
|
||||
struct ceph_authorizer;
|
||||
|
||||
struct ceph_auth_client_ops {
|
||||
const char *name;
|
||||
|
||||
/*
|
||||
* true if we are authenticated and can connect to
|
||||
* services.
|
||||
*/
|
||||
int (*is_authenticated)(struct ceph_auth_client *ac);
|
||||
|
||||
/*
|
||||
* true if we should (re)authenticate, e.g., when our tickets
|
||||
* are getting old and crusty.
|
||||
*/
|
||||
int (*should_authenticate)(struct ceph_auth_client *ac);
|
||||
|
||||
/*
|
||||
* build requests and process replies during monitor
|
||||
* handshake. if handle_reply returns -EAGAIN, we build
|
||||
* another request.
|
||||
*/
|
||||
int (*build_request)(struct ceph_auth_client *ac, void *buf, void *end);
|
||||
int (*handle_reply)(struct ceph_auth_client *ac, int result,
|
||||
void *buf, void *end);
|
||||
|
||||
/*
|
||||
* Create authorizer for connecting to a service, and verify
|
||||
* the response to authenticate the service.
|
||||
*/
|
||||
int (*create_authorizer)(struct ceph_auth_client *ac, int peer_type,
|
||||
struct ceph_authorizer **a,
|
||||
void **buf, size_t *len,
|
||||
void **reply_buf, size_t *reply_len);
|
||||
int (*verify_authorizer_reply)(struct ceph_auth_client *ac,
|
||||
struct ceph_authorizer *a, size_t len);
|
||||
void (*destroy_authorizer)(struct ceph_auth_client *ac,
|
||||
struct ceph_authorizer *a);
|
||||
void (*invalidate_authorizer)(struct ceph_auth_client *ac,
|
||||
int peer_type);
|
||||
|
||||
/* reset when we (re)connect to a monitor */
|
||||
void (*reset)(struct ceph_auth_client *ac);
|
||||
|
||||
void (*destroy)(struct ceph_auth_client *ac);
|
||||
};
|
||||
|
||||
struct ceph_auth_client {
|
||||
u32 protocol; /* CEPH_AUTH_* */
|
||||
void *private; /* for use by protocol implementation */
|
||||
const struct ceph_auth_client_ops *ops; /* null iff protocol==0 */
|
||||
|
||||
bool negotiating; /* true if negotiating protocol */
|
||||
const char *name; /* entity name */
|
||||
u64 global_id; /* our unique id in system */
|
||||
const char *secret; /* our secret key */
|
||||
unsigned want_keys; /* which services we want */
|
||||
};
|
||||
|
||||
extern struct ceph_auth_client *ceph_auth_init(const char *name,
|
||||
const char *secret);
|
||||
extern void ceph_auth_destroy(struct ceph_auth_client *ac);
|
||||
|
||||
extern void ceph_auth_reset(struct ceph_auth_client *ac);
|
||||
|
||||
extern int ceph_auth_build_hello(struct ceph_auth_client *ac,
|
||||
void *buf, size_t len);
|
||||
extern int ceph_handle_auth_reply(struct ceph_auth_client *ac,
|
||||
void *buf, size_t len,
|
||||
void *reply_buf, size_t reply_len);
|
||||
extern int ceph_entity_name_encode(const char *name, void **p, void *end);
|
||||
|
||||
extern int ceph_build_auth(struct ceph_auth_client *ac,
|
||||
void *msg_buf, size_t msg_len);
|
||||
|
||||
extern int ceph_auth_is_authenticated(struct ceph_auth_client *ac);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
|
||||
#include "ceph_debug.h"
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "auth_none.h"
|
||||
#include "auth.h"
|
||||
#include "decode.h"
|
||||
|
||||
static void reset(struct ceph_auth_client *ac)
|
||||
{
|
||||
struct ceph_auth_none_info *xi = ac->private;
|
||||
|
||||
xi->starting = true;
|
||||
xi->built_authorizer = false;
|
||||
}
|
||||
|
||||
static void destroy(struct ceph_auth_client *ac)
|
||||
{
|
||||
kfree(ac->private);
|
||||
ac->private = NULL;
|
||||
}
|
||||
|
||||
static int is_authenticated(struct ceph_auth_client *ac)
|
||||
{
|
||||
struct ceph_auth_none_info *xi = ac->private;
|
||||
|
||||
return !xi->starting;
|
||||
}
|
||||
|
||||
static int should_authenticate(struct ceph_auth_client *ac)
|
||||
{
|
||||
struct ceph_auth_none_info *xi = ac->private;
|
||||
|
||||
return xi->starting;
|
||||
}
|
||||
|
||||
/*
|
||||
* the generic auth code decode the global_id, and we carry no actual
|
||||
* authenticate state, so nothing happens here.
|
||||
*/
|
||||
static int handle_reply(struct ceph_auth_client *ac, int result,
|
||||
void *buf, void *end)
|
||||
{
|
||||
struct ceph_auth_none_info *xi = ac->private;
|
||||
|
||||
xi->starting = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* build an 'authorizer' with our entity_name and global_id. we can
|
||||
* reuse a single static copy since it is identical for all services
|
||||
* we connect to.
|
||||
*/
|
||||
static int ceph_auth_none_create_authorizer(
|
||||
struct ceph_auth_client *ac, int peer_type,
|
||||
struct ceph_authorizer **a,
|
||||
void **buf, size_t *len,
|
||||
void **reply_buf, size_t *reply_len)
|
||||
{
|
||||
struct ceph_auth_none_info *ai = ac->private;
|
||||
struct ceph_none_authorizer *au = &ai->au;
|
||||
void *p, *end;
|
||||
int ret;
|
||||
|
||||
if (!ai->built_authorizer) {
|
||||
p = au->buf;
|
||||
end = p + sizeof(au->buf);
|
||||
ceph_encode_8(&p, 1);
|
||||
ret = ceph_entity_name_encode(ac->name, &p, end - 8);
|
||||
if (ret < 0)
|
||||
goto bad;
|
||||
ceph_decode_need(&p, end, sizeof(u64), bad2);
|
||||
ceph_encode_64(&p, ac->global_id);
|
||||
au->buf_len = p - (void *)au->buf;
|
||||
ai->built_authorizer = true;
|
||||
dout("built authorizer len %d\n", au->buf_len);
|
||||
}
|
||||
|
||||
*a = (struct ceph_authorizer *)au;
|
||||
*buf = au->buf;
|
||||
*len = au->buf_len;
|
||||
*reply_buf = au->reply_buf;
|
||||
*reply_len = sizeof(au->reply_buf);
|
||||
return 0;
|
||||
|
||||
bad2:
|
||||
ret = -ERANGE;
|
||||
bad:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ceph_auth_none_destroy_authorizer(struct ceph_auth_client *ac,
|
||||
struct ceph_authorizer *a)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
|
||||
static const struct ceph_auth_client_ops ceph_auth_none_ops = {
|
||||
.name = "none",
|
||||
.reset = reset,
|
||||
.destroy = destroy,
|
||||
.is_authenticated = is_authenticated,
|
||||
.should_authenticate = should_authenticate,
|
||||
.handle_reply = handle_reply,
|
||||
.create_authorizer = ceph_auth_none_create_authorizer,
|
||||
.destroy_authorizer = ceph_auth_none_destroy_authorizer,
|
||||
};
|
||||
|
||||
int ceph_auth_none_init(struct ceph_auth_client *ac)
|
||||
{
|
||||
struct ceph_auth_none_info *xi;
|
||||
|
||||
dout("ceph_auth_none_init %p\n", ac);
|
||||
xi = kzalloc(sizeof(*xi), GFP_NOFS);
|
||||
if (!xi)
|
||||
return -ENOMEM;
|
||||
|
||||
xi->starting = true;
|
||||
xi->built_authorizer = false;
|
||||
|
||||
ac->protocol = CEPH_AUTH_NONE;
|
||||
ac->private = xi;
|
||||
ac->ops = &ceph_auth_none_ops;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#ifndef _FS_CEPH_AUTH_NONE_H
|
||||
#define _FS_CEPH_AUTH_NONE_H
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "auth.h"
|
||||
|
||||
/*
|
||||
* null security mode.
|
||||
*
|
||||
* we use a single static authorizer that simply encodes our entity name
|
||||
* and global id.
|
||||
*/
|
||||
|
||||
struct ceph_none_authorizer {
|
||||
char buf[128];
|
||||
int buf_len;
|
||||
char reply_buf[0];
|
||||
};
|
||||
|
||||
struct ceph_auth_none_info {
|
||||
bool starting;
|
||||
bool built_authorizer;
|
||||
struct ceph_none_authorizer au; /* we only need one; it's static */
|
||||
};
|
||||
|
||||
extern int ceph_auth_none_init(struct ceph_auth_client *ac);
|
||||
|
||||
#endif
|
||||
|
||||
687
fs/ceph/auth_x.c
687
fs/ceph/auth_x.c
|
|
@ -1,687 +0,0 @@
|
|||
|
||||
#include "ceph_debug.h"
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "auth_x.h"
|
||||
#include "auth_x_protocol.h"
|
||||
#include "crypto.h"
|
||||
#include "auth.h"
|
||||
#include "decode.h"
|
||||
|
||||
#define TEMP_TICKET_BUF_LEN 256
|
||||
|
||||
static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed);
|
||||
|
||||
static int ceph_x_is_authenticated(struct ceph_auth_client *ac)
|
||||
{
|
||||
struct ceph_x_info *xi = ac->private;
|
||||
int need;
|
||||
|
||||
ceph_x_validate_tickets(ac, &need);
|
||||
dout("ceph_x_is_authenticated want=%d need=%d have=%d\n",
|
||||
ac->want_keys, need, xi->have_keys);
|
||||
return (ac->want_keys & xi->have_keys) == ac->want_keys;
|
||||
}
|
||||
|
||||
static int ceph_x_should_authenticate(struct ceph_auth_client *ac)
|
||||
{
|
||||
struct ceph_x_info *xi = ac->private;
|
||||
int need;
|
||||
|
||||
ceph_x_validate_tickets(ac, &need);
|
||||
dout("ceph_x_should_authenticate want=%d need=%d have=%d\n",
|
||||
ac->want_keys, need, xi->have_keys);
|
||||
return need != 0;
|
||||
}
|
||||
|
||||
static int ceph_x_encrypt_buflen(int ilen)
|
||||
{
|
||||
return sizeof(struct ceph_x_encrypt_header) + ilen + 16 +
|
||||
sizeof(u32);
|
||||
}
|
||||
|
||||
static int ceph_x_encrypt(struct ceph_crypto_key *secret,
|
||||
void *ibuf, int ilen, void *obuf, size_t olen)
|
||||
{
|
||||
struct ceph_x_encrypt_header head = {
|
||||
.struct_v = 1,
|
||||
.magic = cpu_to_le64(CEPHX_ENC_MAGIC)
|
||||
};
|
||||
size_t len = olen - sizeof(u32);
|
||||
int ret;
|
||||
|
||||
ret = ceph_encrypt2(secret, obuf + sizeof(u32), &len,
|
||||
&head, sizeof(head), ibuf, ilen);
|
||||
if (ret)
|
||||
return ret;
|
||||
ceph_encode_32(&obuf, len);
|
||||
return len + sizeof(u32);
|
||||
}
|
||||
|
||||
static int ceph_x_decrypt(struct ceph_crypto_key *secret,
|
||||
void **p, void *end, void *obuf, size_t olen)
|
||||
{
|
||||
struct ceph_x_encrypt_header head;
|
||||
size_t head_len = sizeof(head);
|
||||
int len, ret;
|
||||
|
||||
len = ceph_decode_32(p);
|
||||
if (*p + len > end)
|
||||
return -EINVAL;
|
||||
|
||||
dout("ceph_x_decrypt len %d\n", len);
|
||||
ret = ceph_decrypt2(secret, &head, &head_len, obuf, &olen,
|
||||
*p, len);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (head.struct_v != 1 || le64_to_cpu(head.magic) != CEPHX_ENC_MAGIC)
|
||||
return -EPERM;
|
||||
*p += len;
|
||||
return olen;
|
||||
}
|
||||
|
||||
/*
|
||||
* get existing (or insert new) ticket handler
|
||||
*/
|
||||
static struct ceph_x_ticket_handler *
|
||||
get_ticket_handler(struct ceph_auth_client *ac, int service)
|
||||
{
|
||||
struct ceph_x_ticket_handler *th;
|
||||
struct ceph_x_info *xi = ac->private;
|
||||
struct rb_node *parent = NULL, **p = &xi->ticket_handlers.rb_node;
|
||||
|
||||
while (*p) {
|
||||
parent = *p;
|
||||
th = rb_entry(parent, struct ceph_x_ticket_handler, node);
|
||||
if (service < th->service)
|
||||
p = &(*p)->rb_left;
|
||||
else if (service > th->service)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return th;
|
||||
}
|
||||
|
||||
/* add it */
|
||||
th = kzalloc(sizeof(*th), GFP_NOFS);
|
||||
if (!th)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
th->service = service;
|
||||
rb_link_node(&th->node, parent, p);
|
||||
rb_insert_color(&th->node, &xi->ticket_handlers);
|
||||
return th;
|
||||
}
|
||||
|
||||
static void remove_ticket_handler(struct ceph_auth_client *ac,
|
||||
struct ceph_x_ticket_handler *th)
|
||||
{
|
||||
struct ceph_x_info *xi = ac->private;
|
||||
|
||||
dout("remove_ticket_handler %p %d\n", th, th->service);
|
||||
rb_erase(&th->node, &xi->ticket_handlers);
|
||||
ceph_crypto_key_destroy(&th->session_key);
|
||||
if (th->ticket_blob)
|
||||
ceph_buffer_put(th->ticket_blob);
|
||||
kfree(th);
|
||||
}
|
||||
|
||||
static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
|
||||
struct ceph_crypto_key *secret,
|
||||
void *buf, void *end)
|
||||
{
|
||||
struct ceph_x_info *xi = ac->private;
|
||||
int num;
|
||||
void *p = buf;
|
||||
int ret;
|
||||
char *dbuf;
|
||||
char *ticket_buf;
|
||||
u8 reply_struct_v;
|
||||
|
||||
dbuf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS);
|
||||
if (!dbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = -ENOMEM;
|
||||
ticket_buf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS);
|
||||
if (!ticket_buf)
|
||||
goto out_dbuf;
|
||||
|
||||
ceph_decode_need(&p, end, 1 + sizeof(u32), bad);
|
||||
reply_struct_v = ceph_decode_8(&p);
|
||||
if (reply_struct_v != 1)
|
||||
goto bad;
|
||||
num = ceph_decode_32(&p);
|
||||
dout("%d tickets\n", num);
|
||||
while (num--) {
|
||||
int type;
|
||||
u8 tkt_struct_v, blob_struct_v;
|
||||
struct ceph_x_ticket_handler *th;
|
||||
void *dp, *dend;
|
||||
int dlen;
|
||||
char is_enc;
|
||||
struct timespec validity;
|
||||
struct ceph_crypto_key old_key;
|
||||
void *tp, *tpend;
|
||||
struct ceph_timespec new_validity;
|
||||
struct ceph_crypto_key new_session_key;
|
||||
struct ceph_buffer *new_ticket_blob;
|
||||
unsigned long new_expires, new_renew_after;
|
||||
u64 new_secret_id;
|
||||
|
||||
ceph_decode_need(&p, end, sizeof(u32) + 1, bad);
|
||||
|
||||
type = ceph_decode_32(&p);
|
||||
dout(" ticket type %d %s\n", type, ceph_entity_type_name(type));
|
||||
|
||||
tkt_struct_v = ceph_decode_8(&p);
|
||||
if (tkt_struct_v != 1)
|
||||
goto bad;
|
||||
|
||||
th = get_ticket_handler(ac, type);
|
||||
if (IS_ERR(th)) {
|
||||
ret = PTR_ERR(th);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* blob for me */
|
||||
dlen = ceph_x_decrypt(secret, &p, end, dbuf,
|
||||
TEMP_TICKET_BUF_LEN);
|
||||
if (dlen <= 0) {
|
||||
ret = dlen;
|
||||
goto out;
|
||||
}
|
||||
dout(" decrypted %d bytes\n", dlen);
|
||||
dend = dbuf + dlen;
|
||||
dp = dbuf;
|
||||
|
||||
tkt_struct_v = ceph_decode_8(&dp);
|
||||
if (tkt_struct_v != 1)
|
||||
goto bad;
|
||||
|
||||
memcpy(&old_key, &th->session_key, sizeof(old_key));
|
||||
ret = ceph_crypto_key_decode(&new_session_key, &dp, dend);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ceph_decode_copy(&dp, &new_validity, sizeof(new_validity));
|
||||
ceph_decode_timespec(&validity, &new_validity);
|
||||
new_expires = get_seconds() + validity.tv_sec;
|
||||
new_renew_after = new_expires - (validity.tv_sec / 4);
|
||||
dout(" expires=%lu renew_after=%lu\n", new_expires,
|
||||
new_renew_after);
|
||||
|
||||
/* ticket blob for service */
|
||||
ceph_decode_8_safe(&p, end, is_enc, bad);
|
||||
tp = ticket_buf;
|
||||
if (is_enc) {
|
||||
/* encrypted */
|
||||
dout(" encrypted ticket\n");
|
||||
dlen = ceph_x_decrypt(&old_key, &p, end, ticket_buf,
|
||||
TEMP_TICKET_BUF_LEN);
|
||||
if (dlen < 0) {
|
||||
ret = dlen;
|
||||
goto out;
|
||||
}
|
||||
dlen = ceph_decode_32(&tp);
|
||||
} else {
|
||||
/* unencrypted */
|
||||
ceph_decode_32_safe(&p, end, dlen, bad);
|
||||
ceph_decode_need(&p, end, dlen, bad);
|
||||
ceph_decode_copy(&p, ticket_buf, dlen);
|
||||
}
|
||||
tpend = tp + dlen;
|
||||
dout(" ticket blob is %d bytes\n", dlen);
|
||||
ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad);
|
||||
blob_struct_v = ceph_decode_8(&tp);
|
||||
new_secret_id = ceph_decode_64(&tp);
|
||||
ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* all is well, update our ticket */
|
||||
ceph_crypto_key_destroy(&th->session_key);
|
||||
if (th->ticket_blob)
|
||||
ceph_buffer_put(th->ticket_blob);
|
||||
th->session_key = new_session_key;
|
||||
th->ticket_blob = new_ticket_blob;
|
||||
th->validity = new_validity;
|
||||
th->secret_id = new_secret_id;
|
||||
th->expires = new_expires;
|
||||
th->renew_after = new_renew_after;
|
||||
dout(" got ticket service %d (%s) secret_id %lld len %d\n",
|
||||
type, ceph_entity_type_name(type), th->secret_id,
|
||||
(int)th->ticket_blob->vec.iov_len);
|
||||
xi->have_keys |= th->service;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
kfree(ticket_buf);
|
||||
out_dbuf:
|
||||
kfree(dbuf);
|
||||
return ret;
|
||||
|
||||
bad:
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
|
||||
struct ceph_x_ticket_handler *th,
|
||||
struct ceph_x_authorizer *au)
|
||||
{
|
||||
int maxlen;
|
||||
struct ceph_x_authorize_a *msg_a;
|
||||
struct ceph_x_authorize_b msg_b;
|
||||
void *p, *end;
|
||||
int ret;
|
||||
int ticket_blob_len =
|
||||
(th->ticket_blob ? th->ticket_blob->vec.iov_len : 0);
|
||||
|
||||
dout("build_authorizer for %s %p\n",
|
||||
ceph_entity_type_name(th->service), au);
|
||||
|
||||
maxlen = sizeof(*msg_a) + sizeof(msg_b) +
|
||||
ceph_x_encrypt_buflen(ticket_blob_len);
|
||||
dout(" need len %d\n", maxlen);
|
||||
if (au->buf && au->buf->alloc_len < maxlen) {
|
||||
ceph_buffer_put(au->buf);
|
||||
au->buf = NULL;
|
||||
}
|
||||
if (!au->buf) {
|
||||
au->buf = ceph_buffer_new(maxlen, GFP_NOFS);
|
||||
if (!au->buf)
|
||||
return -ENOMEM;
|
||||
}
|
||||
au->service = th->service;
|
||||
|
||||
msg_a = au->buf->vec.iov_base;
|
||||
msg_a->struct_v = 1;
|
||||
msg_a->global_id = cpu_to_le64(ac->global_id);
|
||||
msg_a->service_id = cpu_to_le32(th->service);
|
||||
msg_a->ticket_blob.struct_v = 1;
|
||||
msg_a->ticket_blob.secret_id = cpu_to_le64(th->secret_id);
|
||||
msg_a->ticket_blob.blob_len = cpu_to_le32(ticket_blob_len);
|
||||
if (ticket_blob_len) {
|
||||
memcpy(msg_a->ticket_blob.blob, th->ticket_blob->vec.iov_base,
|
||||
th->ticket_blob->vec.iov_len);
|
||||
}
|
||||
dout(" th %p secret_id %lld %lld\n", th, th->secret_id,
|
||||
le64_to_cpu(msg_a->ticket_blob.secret_id));
|
||||
|
||||
p = msg_a + 1;
|
||||
p += ticket_blob_len;
|
||||
end = au->buf->vec.iov_base + au->buf->vec.iov_len;
|
||||
|
||||
get_random_bytes(&au->nonce, sizeof(au->nonce));
|
||||
msg_b.struct_v = 1;
|
||||
msg_b.nonce = cpu_to_le64(au->nonce);
|
||||
ret = ceph_x_encrypt(&th->session_key, &msg_b, sizeof(msg_b),
|
||||
p, end - p);
|
||||
if (ret < 0)
|
||||
goto out_buf;
|
||||
p += ret;
|
||||
au->buf->vec.iov_len = p - au->buf->vec.iov_base;
|
||||
dout(" built authorizer nonce %llx len %d\n", au->nonce,
|
||||
(int)au->buf->vec.iov_len);
|
||||
BUG_ON(au->buf->vec.iov_len > maxlen);
|
||||
return 0;
|
||||
|
||||
out_buf:
|
||||
ceph_buffer_put(au->buf);
|
||||
au->buf = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ceph_x_encode_ticket(struct ceph_x_ticket_handler *th,
|
||||
void **p, void *end)
|
||||
{
|
||||
ceph_decode_need(p, end, 1 + sizeof(u64), bad);
|
||||
ceph_encode_8(p, 1);
|
||||
ceph_encode_64(p, th->secret_id);
|
||||
if (th->ticket_blob) {
|
||||
const char *buf = th->ticket_blob->vec.iov_base;
|
||||
u32 len = th->ticket_blob->vec.iov_len;
|
||||
|
||||
ceph_encode_32_safe(p, end, len, bad);
|
||||
ceph_encode_copy_safe(p, end, buf, len, bad);
|
||||
} else {
|
||||
ceph_encode_32_safe(p, end, 0, bad);
|
||||
}
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed)
|
||||
{
|
||||
int want = ac->want_keys;
|
||||
struct ceph_x_info *xi = ac->private;
|
||||
int service;
|
||||
|
||||
*pneed = ac->want_keys & ~(xi->have_keys);
|
||||
|
||||
for (service = 1; service <= want; service <<= 1) {
|
||||
struct ceph_x_ticket_handler *th;
|
||||
|
||||
if (!(ac->want_keys & service))
|
||||
continue;
|
||||
|
||||
if (*pneed & service)
|
||||
continue;
|
||||
|
||||
th = get_ticket_handler(ac, service);
|
||||
|
||||
if (IS_ERR(th)) {
|
||||
*pneed |= service;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (get_seconds() >= th->renew_after)
|
||||
*pneed |= service;
|
||||
if (get_seconds() >= th->expires)
|
||||
xi->have_keys &= ~service;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int ceph_x_build_request(struct ceph_auth_client *ac,
|
||||
void *buf, void *end)
|
||||
{
|
||||
struct ceph_x_info *xi = ac->private;
|
||||
int need;
|
||||
struct ceph_x_request_header *head = buf;
|
||||
int ret;
|
||||
struct ceph_x_ticket_handler *th =
|
||||
get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH);
|
||||
|
||||
if (IS_ERR(th))
|
||||
return PTR_ERR(th);
|
||||
|
||||
ceph_x_validate_tickets(ac, &need);
|
||||
|
||||
dout("build_request want %x have %x need %x\n",
|
||||
ac->want_keys, xi->have_keys, need);
|
||||
|
||||
if (need & CEPH_ENTITY_TYPE_AUTH) {
|
||||
struct ceph_x_authenticate *auth = (void *)(head + 1);
|
||||
void *p = auth + 1;
|
||||
struct ceph_x_challenge_blob tmp;
|
||||
char tmp_enc[40];
|
||||
u64 *u;
|
||||
|
||||
if (p > end)
|
||||
return -ERANGE;
|
||||
|
||||
dout(" get_auth_session_key\n");
|
||||
head->op = cpu_to_le16(CEPHX_GET_AUTH_SESSION_KEY);
|
||||
|
||||
/* encrypt and hash */
|
||||
get_random_bytes(&auth->client_challenge, sizeof(u64));
|
||||
tmp.client_challenge = auth->client_challenge;
|
||||
tmp.server_challenge = cpu_to_le64(xi->server_challenge);
|
||||
ret = ceph_x_encrypt(&xi->secret, &tmp, sizeof(tmp),
|
||||
tmp_enc, sizeof(tmp_enc));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
auth->struct_v = 1;
|
||||
auth->key = 0;
|
||||
for (u = (u64 *)tmp_enc; u + 1 <= (u64 *)(tmp_enc + ret); u++)
|
||||
auth->key ^= *(__le64 *)u;
|
||||
dout(" server_challenge %llx client_challenge %llx key %llx\n",
|
||||
xi->server_challenge, le64_to_cpu(auth->client_challenge),
|
||||
le64_to_cpu(auth->key));
|
||||
|
||||
/* now encode the old ticket if exists */
|
||||
ret = ceph_x_encode_ticket(th, &p, end);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
if (need) {
|
||||
void *p = head + 1;
|
||||
struct ceph_x_service_ticket_request *req;
|
||||
|
||||
if (p > end)
|
||||
return -ERANGE;
|
||||
head->op = cpu_to_le16(CEPHX_GET_PRINCIPAL_SESSION_KEY);
|
||||
|
||||
ret = ceph_x_build_authorizer(ac, th, &xi->auth_authorizer);
|
||||
if (ret)
|
||||
return ret;
|
||||
ceph_encode_copy(&p, xi->auth_authorizer.buf->vec.iov_base,
|
||||
xi->auth_authorizer.buf->vec.iov_len);
|
||||
|
||||
req = p;
|
||||
req->keys = cpu_to_le32(need);
|
||||
p += sizeof(*req);
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result,
|
||||
void *buf, void *end)
|
||||
{
|
||||
struct ceph_x_info *xi = ac->private;
|
||||
struct ceph_x_reply_header *head = buf;
|
||||
struct ceph_x_ticket_handler *th;
|
||||
int len = end - buf;
|
||||
int op;
|
||||
int ret;
|
||||
|
||||
if (result)
|
||||
return result; /* XXX hmm? */
|
||||
|
||||
if (xi->starting) {
|
||||
/* it's a hello */
|
||||
struct ceph_x_server_challenge *sc = buf;
|
||||
|
||||
if (len != sizeof(*sc))
|
||||
return -EINVAL;
|
||||
xi->server_challenge = le64_to_cpu(sc->server_challenge);
|
||||
dout("handle_reply got server challenge %llx\n",
|
||||
xi->server_challenge);
|
||||
xi->starting = false;
|
||||
xi->have_keys &= ~CEPH_ENTITY_TYPE_AUTH;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
op = le16_to_cpu(head->op);
|
||||
result = le32_to_cpu(head->result);
|
||||
dout("handle_reply op %d result %d\n", op, result);
|
||||
switch (op) {
|
||||
case CEPHX_GET_AUTH_SESSION_KEY:
|
||||
/* verify auth key */
|
||||
ret = ceph_x_proc_ticket_reply(ac, &xi->secret,
|
||||
buf + sizeof(*head), end);
|
||||
break;
|
||||
|
||||
case CEPHX_GET_PRINCIPAL_SESSION_KEY:
|
||||
th = get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH);
|
||||
if (IS_ERR(th))
|
||||
return PTR_ERR(th);
|
||||
ret = ceph_x_proc_ticket_reply(ac, &th->session_key,
|
||||
buf + sizeof(*head), end);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ac->want_keys == xi->have_keys)
|
||||
return 0;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static int ceph_x_create_authorizer(
|
||||
struct ceph_auth_client *ac, int peer_type,
|
||||
struct ceph_authorizer **a,
|
||||
void **buf, size_t *len,
|
||||
void **reply_buf, size_t *reply_len)
|
||||
{
|
||||
struct ceph_x_authorizer *au;
|
||||
struct ceph_x_ticket_handler *th;
|
||||
int ret;
|
||||
|
||||
th = get_ticket_handler(ac, peer_type);
|
||||
if (IS_ERR(th))
|
||||
return PTR_ERR(th);
|
||||
|
||||
au = kzalloc(sizeof(*au), GFP_NOFS);
|
||||
if (!au)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = ceph_x_build_authorizer(ac, th, au);
|
||||
if (ret) {
|
||||
kfree(au);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*a = (struct ceph_authorizer *)au;
|
||||
*buf = au->buf->vec.iov_base;
|
||||
*len = au->buf->vec.iov_len;
|
||||
*reply_buf = au->reply_buf;
|
||||
*reply_len = sizeof(au->reply_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac,
|
||||
struct ceph_authorizer *a, size_t len)
|
||||
{
|
||||
struct ceph_x_authorizer *au = (void *)a;
|
||||
struct ceph_x_ticket_handler *th;
|
||||
int ret = 0;
|
||||
struct ceph_x_authorize_reply reply;
|
||||
void *p = au->reply_buf;
|
||||
void *end = p + sizeof(au->reply_buf);
|
||||
|
||||
th = get_ticket_handler(ac, au->service);
|
||||
if (IS_ERR(th))
|
||||
return PTR_ERR(th);
|
||||
ret = ceph_x_decrypt(&th->session_key, &p, end, &reply, sizeof(reply));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != sizeof(reply))
|
||||
return -EPERM;
|
||||
|
||||
if (au->nonce + 1 != le64_to_cpu(reply.nonce_plus_one))
|
||||
ret = -EPERM;
|
||||
else
|
||||
ret = 0;
|
||||
dout("verify_authorizer_reply nonce %llx got %llx ret %d\n",
|
||||
au->nonce, le64_to_cpu(reply.nonce_plus_one), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ceph_x_destroy_authorizer(struct ceph_auth_client *ac,
|
||||
struct ceph_authorizer *a)
|
||||
{
|
||||
struct ceph_x_authorizer *au = (void *)a;
|
||||
|
||||
ceph_buffer_put(au->buf);
|
||||
kfree(au);
|
||||
}
|
||||
|
||||
|
||||
static void ceph_x_reset(struct ceph_auth_client *ac)
|
||||
{
|
||||
struct ceph_x_info *xi = ac->private;
|
||||
|
||||
dout("reset\n");
|
||||
xi->starting = true;
|
||||
xi->server_challenge = 0;
|
||||
}
|
||||
|
||||
static void ceph_x_destroy(struct ceph_auth_client *ac)
|
||||
{
|
||||
struct ceph_x_info *xi = ac->private;
|
||||
struct rb_node *p;
|
||||
|
||||
dout("ceph_x_destroy %p\n", ac);
|
||||
ceph_crypto_key_destroy(&xi->secret);
|
||||
|
||||
while ((p = rb_first(&xi->ticket_handlers)) != NULL) {
|
||||
struct ceph_x_ticket_handler *th =
|
||||
rb_entry(p, struct ceph_x_ticket_handler, node);
|
||||
remove_ticket_handler(ac, th);
|
||||
}
|
||||
|
||||
if (xi->auth_authorizer.buf)
|
||||
ceph_buffer_put(xi->auth_authorizer.buf);
|
||||
|
||||
kfree(ac->private);
|
||||
ac->private = NULL;
|
||||
}
|
||||
|
||||
static void ceph_x_invalidate_authorizer(struct ceph_auth_client *ac,
|
||||
int peer_type)
|
||||
{
|
||||
struct ceph_x_ticket_handler *th;
|
||||
|
||||
th = get_ticket_handler(ac, peer_type);
|
||||
if (!IS_ERR(th))
|
||||
remove_ticket_handler(ac, th);
|
||||
}
|
||||
|
||||
|
||||
static const struct ceph_auth_client_ops ceph_x_ops = {
|
||||
.name = "x",
|
||||
.is_authenticated = ceph_x_is_authenticated,
|
||||
.should_authenticate = ceph_x_should_authenticate,
|
||||
.build_request = ceph_x_build_request,
|
||||
.handle_reply = ceph_x_handle_reply,
|
||||
.create_authorizer = ceph_x_create_authorizer,
|
||||
.verify_authorizer_reply = ceph_x_verify_authorizer_reply,
|
||||
.destroy_authorizer = ceph_x_destroy_authorizer,
|
||||
.invalidate_authorizer = ceph_x_invalidate_authorizer,
|
||||
.reset = ceph_x_reset,
|
||||
.destroy = ceph_x_destroy,
|
||||
};
|
||||
|
||||
|
||||
int ceph_x_init(struct ceph_auth_client *ac)
|
||||
{
|
||||
struct ceph_x_info *xi;
|
||||
int ret;
|
||||
|
||||
dout("ceph_x_init %p\n", ac);
|
||||
ret = -ENOMEM;
|
||||
xi = kzalloc(sizeof(*xi), GFP_NOFS);
|
||||
if (!xi)
|
||||
goto out;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (!ac->secret) {
|
||||
pr_err("no secret set (for auth_x protocol)\n");
|
||||
goto out_nomem;
|
||||
}
|
||||
|
||||
ret = ceph_crypto_key_unarmor(&xi->secret, ac->secret);
|
||||
if (ret)
|
||||
goto out_nomem;
|
||||
|
||||
xi->starting = true;
|
||||
xi->ticket_handlers = RB_ROOT;
|
||||
|
||||
ac->protocol = CEPH_AUTH_CEPHX;
|
||||
ac->private = xi;
|
||||
ac->ops = &ceph_x_ops;
|
||||
return 0;
|
||||
|
||||
out_nomem:
|
||||
kfree(xi);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
#ifndef _FS_CEPH_AUTH_X_H
|
||||
#define _FS_CEPH_AUTH_X_H
|
||||
|
||||
#include <linux/rbtree.h>
|
||||
|
||||
#include "crypto.h"
|
||||
#include "auth.h"
|
||||
#include "auth_x_protocol.h"
|
||||
|
||||
/*
|
||||
* Handle ticket for a single service.
|
||||
*/
|
||||
struct ceph_x_ticket_handler {
|
||||
struct rb_node node;
|
||||
unsigned service;
|
||||
|
||||
struct ceph_crypto_key session_key;
|
||||
struct ceph_timespec validity;
|
||||
|
||||
u64 secret_id;
|
||||
struct ceph_buffer *ticket_blob;
|
||||
|
||||
unsigned long renew_after, expires;
|
||||
};
|
||||
|
||||
|
||||
struct ceph_x_authorizer {
|
||||
struct ceph_buffer *buf;
|
||||
unsigned service;
|
||||
u64 nonce;
|
||||
char reply_buf[128]; /* big enough for encrypted blob */
|
||||
};
|
||||
|
||||
struct ceph_x_info {
|
||||
struct ceph_crypto_key secret;
|
||||
|
||||
bool starting;
|
||||
u64 server_challenge;
|
||||
|
||||
unsigned have_keys;
|
||||
struct rb_root ticket_handlers;
|
||||
|
||||
struct ceph_x_authorizer auth_authorizer;
|
||||
};
|
||||
|
||||
extern int ceph_x_init(struct ceph_auth_client *ac);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
#ifndef __FS_CEPH_AUTH_X_PROTOCOL
|
||||
#define __FS_CEPH_AUTH_X_PROTOCOL
|
||||
|
||||
#define CEPHX_GET_AUTH_SESSION_KEY 0x0100
|
||||
#define CEPHX_GET_PRINCIPAL_SESSION_KEY 0x0200
|
||||
#define CEPHX_GET_ROTATING_KEY 0x0400
|
||||
|
||||
/* common bits */
|
||||
struct ceph_x_ticket_blob {
|
||||
__u8 struct_v;
|
||||
__le64 secret_id;
|
||||
__le32 blob_len;
|
||||
char blob[];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* common request/reply headers */
|
||||
struct ceph_x_request_header {
|
||||
__le16 op;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_x_reply_header {
|
||||
__le16 op;
|
||||
__le32 result;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* authenticate handshake */
|
||||
|
||||
/* initial hello (no reply header) */
|
||||
struct ceph_x_server_challenge {
|
||||
__u8 struct_v;
|
||||
__le64 server_challenge;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_x_authenticate {
|
||||
__u8 struct_v;
|
||||
__le64 client_challenge;
|
||||
__le64 key;
|
||||
/* ticket blob */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_x_service_ticket_request {
|
||||
__u8 struct_v;
|
||||
__le32 keys;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_x_challenge_blob {
|
||||
__le64 server_challenge;
|
||||
__le64 client_challenge;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
|
||||
/* authorize handshake */
|
||||
|
||||
/*
|
||||
* The authorizer consists of two pieces:
|
||||
* a - service id, ticket blob
|
||||
* b - encrypted with session key
|
||||
*/
|
||||
struct ceph_x_authorize_a {
|
||||
__u8 struct_v;
|
||||
__le64 global_id;
|
||||
__le32 service_id;
|
||||
struct ceph_x_ticket_blob ticket_blob;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_x_authorize_b {
|
||||
__u8 struct_v;
|
||||
__le64 nonce;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_x_authorize_reply {
|
||||
__u8 struct_v;
|
||||
__le64 nonce_plus_one;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/*
|
||||
* encyption bundle
|
||||
*/
|
||||
#define CEPHX_ENC_MAGIC 0xff009cad8826aa55ull
|
||||
|
||||
struct ceph_x_encrypt_header {
|
||||
__u8 struct_v;
|
||||
__le64 magic;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
|
||||
#include "ceph_debug.h"
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "decode.h"
|
||||
|
||||
struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp)
|
||||
{
|
||||
struct ceph_buffer *b;
|
||||
|
||||
b = kmalloc(sizeof(*b), gfp);
|
||||
if (!b)
|
||||
return NULL;
|
||||
|
||||
b->vec.iov_base = kmalloc(len, gfp | __GFP_NOWARN);
|
||||
if (b->vec.iov_base) {
|
||||
b->is_vmalloc = false;
|
||||
} else {
|
||||
b->vec.iov_base = __vmalloc(len, gfp, PAGE_KERNEL);
|
||||
if (!b->vec.iov_base) {
|
||||
kfree(b);
|
||||
return NULL;
|
||||
}
|
||||
b->is_vmalloc = true;
|
||||
}
|
||||
|
||||
kref_init(&b->kref);
|
||||
b->alloc_len = len;
|
||||
b->vec.iov_len = len;
|
||||
dout("buffer_new %p\n", b);
|
||||
return b;
|
||||
}
|
||||
|
||||
void ceph_buffer_release(struct kref *kref)
|
||||
{
|
||||
struct ceph_buffer *b = container_of(kref, struct ceph_buffer, kref);
|
||||
|
||||
dout("buffer_release %p\n", b);
|
||||
if (b->vec.iov_base) {
|
||||
if (b->is_vmalloc)
|
||||
vfree(b->vec.iov_base);
|
||||
else
|
||||
kfree(b->vec.iov_base);
|
||||
}
|
||||
kfree(b);
|
||||
}
|
||||
|
||||
int ceph_decode_buffer(struct ceph_buffer **b, void **p, void *end)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
ceph_decode_need(p, end, sizeof(u32), bad);
|
||||
len = ceph_decode_32(p);
|
||||
dout("decode_buffer len %d\n", (int)len);
|
||||
ceph_decode_need(p, end, len, bad);
|
||||
*b = ceph_buffer_new(len, GFP_NOFS);
|
||||
if (!*b)
|
||||
return -ENOMEM;
|
||||
ceph_decode_copy(p, (*b)->vec.iov_base, len);
|
||||
return 0;
|
||||
bad:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
#ifndef __FS_CEPH_BUFFER_H
|
||||
#define __FS_CEPH_BUFFER_H
|
||||
|
||||
#include <linux/kref.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uio.h>
|
||||
|
||||
/*
|
||||
* a simple reference counted buffer.
|
||||
*
|
||||
* use kmalloc for small sizes (<= one page), vmalloc for larger
|
||||
* sizes.
|
||||
*/
|
||||
struct ceph_buffer {
|
||||
struct kref kref;
|
||||
struct kvec vec;
|
||||
size_t alloc_len;
|
||||
bool is_vmalloc;
|
||||
};
|
||||
|
||||
extern struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp);
|
||||
extern void ceph_buffer_release(struct kref *kref);
|
||||
|
||||
static inline struct ceph_buffer *ceph_buffer_get(struct ceph_buffer *b)
|
||||
{
|
||||
kref_get(&b->kref);
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline void ceph_buffer_put(struct ceph_buffer *b)
|
||||
{
|
||||
kref_put(&b->kref, ceph_buffer_release);
|
||||
}
|
||||
|
||||
extern int ceph_decode_buffer(struct ceph_buffer **b, void **p, void *end);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "ceph_debug.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -9,8 +9,9 @@
|
|||
#include <linux/writeback.h>
|
||||
|
||||
#include "super.h"
|
||||
#include "decode.h"
|
||||
#include "messenger.h"
|
||||
#include "mds_client.h"
|
||||
#include <linux/ceph/decode.h>
|
||||
#include <linux/ceph/messenger.h>
|
||||
|
||||
/*
|
||||
* Capability management
|
||||
|
|
@ -287,11 +288,11 @@ void ceph_put_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap)
|
|||
spin_unlock(&mdsc->caps_list_lock);
|
||||
}
|
||||
|
||||
void ceph_reservation_status(struct ceph_client *client,
|
||||
void ceph_reservation_status(struct ceph_fs_client *fsc,
|
||||
int *total, int *avail, int *used, int *reserved,
|
||||
int *min)
|
||||
{
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
|
||||
if (total)
|
||||
*total = mdsc->caps_total_count;
|
||||
|
|
@ -399,7 +400,7 @@ static void __insert_cap_node(struct ceph_inode_info *ci,
|
|||
static void __cap_set_timeouts(struct ceph_mds_client *mdsc,
|
||||
struct ceph_inode_info *ci)
|
||||
{
|
||||
struct ceph_mount_args *ma = mdsc->client->mount_args;
|
||||
struct ceph_mount_options *ma = mdsc->fsc->mount_options;
|
||||
|
||||
ci->i_hold_caps_min = round_jiffies(jiffies +
|
||||
ma->caps_wanted_delay_min * HZ);
|
||||
|
|
@ -515,7 +516,7 @@ int ceph_add_cap(struct inode *inode,
|
|||
unsigned seq, unsigned mseq, u64 realmino, int flags,
|
||||
struct ceph_cap_reservation *caps_reservation)
|
||||
{
|
||||
struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
|
||||
struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_cap *new_cap = NULL;
|
||||
struct ceph_cap *cap;
|
||||
|
|
@ -873,7 +874,7 @@ void __ceph_remove_cap(struct ceph_cap *cap)
|
|||
struct ceph_mds_session *session = cap->session;
|
||||
struct ceph_inode_info *ci = cap->ci;
|
||||
struct ceph_mds_client *mdsc =
|
||||
&ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
|
||||
ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
|
||||
int removed = 0;
|
||||
|
||||
dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode);
|
||||
|
|
@ -1210,7 +1211,7 @@ void __ceph_flush_snaps(struct ceph_inode_info *ci,
|
|||
int mds;
|
||||
struct ceph_cap_snap *capsnap;
|
||||
u32 mseq;
|
||||
struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
|
||||
struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
|
||||
struct ceph_mds_session *session = NULL; /* if session != NULL, we hold
|
||||
session->s_mutex */
|
||||
u64 next_follows = 0; /* keep track of how far we've gotten through the
|
||||
|
|
@ -1336,7 +1337,7 @@ static void ceph_flush_snaps(struct ceph_inode_info *ci)
|
|||
void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
|
||||
{
|
||||
struct ceph_mds_client *mdsc =
|
||||
&ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
|
||||
ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
|
||||
struct inode *inode = &ci->vfs_inode;
|
||||
int was = ci->i_dirty_caps;
|
||||
int dirty = 0;
|
||||
|
|
@ -1378,7 +1379,7 @@ void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
|
|||
static int __mark_caps_flushing(struct inode *inode,
|
||||
struct ceph_mds_session *session)
|
||||
{
|
||||
struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
int flushing;
|
||||
|
||||
|
|
@ -1462,8 +1463,8 @@ static int try_nonblocking_invalidate(struct inode *inode)
|
|||
void ceph_check_caps(struct ceph_inode_info *ci, int flags,
|
||||
struct ceph_mds_session *session)
|
||||
{
|
||||
struct ceph_client *client = ceph_inode_to_client(&ci->vfs_inode);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_inode_to_client(&ci->vfs_inode);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct inode *inode = &ci->vfs_inode;
|
||||
struct ceph_cap *cap;
|
||||
int file_wanted, used;
|
||||
|
|
@ -1706,7 +1707,7 @@ ack:
|
|||
static int try_flush_caps(struct inode *inode, struct ceph_mds_session *session,
|
||||
unsigned *flush_tid)
|
||||
{
|
||||
struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
int unlock_session = session ? 0 : 1;
|
||||
int flushing = 0;
|
||||
|
|
@ -1872,7 +1873,7 @@ int ceph_write_inode(struct inode *inode, struct writeback_control *wbc)
|
|||
caps_are_flushed(inode, flush_tid));
|
||||
} else {
|
||||
struct ceph_mds_client *mdsc =
|
||||
&ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
if (__ceph_caps_dirty(ci))
|
||||
|
|
@ -2465,7 +2466,7 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid,
|
|||
__releases(inode->i_lock)
|
||||
{
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
unsigned seq = le32_to_cpu(m->seq);
|
||||
int dirty = le32_to_cpu(m->dirty);
|
||||
int cleaned = 0;
|
||||
|
|
@ -2713,7 +2714,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
|
|||
struct ceph_msg *msg)
|
||||
{
|
||||
struct ceph_mds_client *mdsc = session->s_mdsc;
|
||||
struct super_block *sb = mdsc->client->sb;
|
||||
struct super_block *sb = mdsc->fsc->sb;
|
||||
struct inode *inode;
|
||||
struct ceph_cap *cap;
|
||||
struct ceph_mds_caps *h;
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
#ifndef _FS_CEPH_DEBUG_H
|
||||
#define _FS_CEPH_DEBUG_H
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#ifdef CONFIG_CEPH_FS_PRETTYDEBUG
|
||||
|
||||
/*
|
||||
* wrap pr_debug to include a filename:lineno prefix on each line.
|
||||
* this incurs some overhead (kernel size and execution time) due to
|
||||
* the extra function call at each call site.
|
||||
*/
|
||||
|
||||
# if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
|
||||
extern const char *ceph_file_part(const char *s, int len);
|
||||
# define dout(fmt, ...) \
|
||||
pr_debug(" %12.12s:%-4d : " fmt, \
|
||||
ceph_file_part(__FILE__, sizeof(__FILE__)), \
|
||||
__LINE__, ##__VA_ARGS__)
|
||||
# else
|
||||
/* faux printk call just to see any compiler warnings. */
|
||||
# define dout(fmt, ...) do { \
|
||||
if (0) \
|
||||
printk(KERN_DEBUG fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* or, just wrap pr_debug
|
||||
*/
|
||||
# define dout(fmt, ...) pr_debug(" " fmt, ##__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* Ceph 'frag' type
|
||||
*/
|
||||
#include "types.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ceph/types.h>
|
||||
|
||||
int ceph_frag_compare(__u32 a, __u32 b)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,109 +0,0 @@
|
|||
#ifndef FS_CEPH_FRAG_H
|
||||
#define FS_CEPH_FRAG_H
|
||||
|
||||
/*
|
||||
* "Frags" are a way to describe a subset of a 32-bit number space,
|
||||
* using a mask and a value to match against that mask. Any given frag
|
||||
* (subset of the number space) can be partitioned into 2^n sub-frags.
|
||||
*
|
||||
* Frags are encoded into a 32-bit word:
|
||||
* 8 upper bits = "bits"
|
||||
* 24 lower bits = "value"
|
||||
* (We could go to 5+27 bits, but who cares.)
|
||||
*
|
||||
* We use the _most_ significant bits of the 24 bit value. This makes
|
||||
* values logically sort.
|
||||
*
|
||||
* Unfortunately, because the "bits" field is still in the high bits, we
|
||||
* can't sort encoded frags numerically. However, it does allow you
|
||||
* to feed encoded frags as values into frag_contains_value.
|
||||
*/
|
||||
static inline __u32 ceph_frag_make(__u32 b, __u32 v)
|
||||
{
|
||||
return (b << 24) |
|
||||
(v & (0xffffffu << (24-b)) & 0xffffffu);
|
||||
}
|
||||
static inline __u32 ceph_frag_bits(__u32 f)
|
||||
{
|
||||
return f >> 24;
|
||||
}
|
||||
static inline __u32 ceph_frag_value(__u32 f)
|
||||
{
|
||||
return f & 0xffffffu;
|
||||
}
|
||||
static inline __u32 ceph_frag_mask(__u32 f)
|
||||
{
|
||||
return (0xffffffu << (24-ceph_frag_bits(f))) & 0xffffffu;
|
||||
}
|
||||
static inline __u32 ceph_frag_mask_shift(__u32 f)
|
||||
{
|
||||
return 24 - ceph_frag_bits(f);
|
||||
}
|
||||
|
||||
static inline int ceph_frag_contains_value(__u32 f, __u32 v)
|
||||
{
|
||||
return (v & ceph_frag_mask(f)) == ceph_frag_value(f);
|
||||
}
|
||||
static inline int ceph_frag_contains_frag(__u32 f, __u32 sub)
|
||||
{
|
||||
/* is sub as specific as us, and contained by us? */
|
||||
return ceph_frag_bits(sub) >= ceph_frag_bits(f) &&
|
||||
(ceph_frag_value(sub) & ceph_frag_mask(f)) == ceph_frag_value(f);
|
||||
}
|
||||
|
||||
static inline __u32 ceph_frag_parent(__u32 f)
|
||||
{
|
||||
return ceph_frag_make(ceph_frag_bits(f) - 1,
|
||||
ceph_frag_value(f) & (ceph_frag_mask(f) << 1));
|
||||
}
|
||||
static inline int ceph_frag_is_left_child(__u32 f)
|
||||
{
|
||||
return ceph_frag_bits(f) > 0 &&
|
||||
(ceph_frag_value(f) & (0x1000000 >> ceph_frag_bits(f))) == 0;
|
||||
}
|
||||
static inline int ceph_frag_is_right_child(__u32 f)
|
||||
{
|
||||
return ceph_frag_bits(f) > 0 &&
|
||||
(ceph_frag_value(f) & (0x1000000 >> ceph_frag_bits(f))) == 1;
|
||||
}
|
||||
static inline __u32 ceph_frag_sibling(__u32 f)
|
||||
{
|
||||
return ceph_frag_make(ceph_frag_bits(f),
|
||||
ceph_frag_value(f) ^ (0x1000000 >> ceph_frag_bits(f)));
|
||||
}
|
||||
static inline __u32 ceph_frag_left_child(__u32 f)
|
||||
{
|
||||
return ceph_frag_make(ceph_frag_bits(f)+1, ceph_frag_value(f));
|
||||
}
|
||||
static inline __u32 ceph_frag_right_child(__u32 f)
|
||||
{
|
||||
return ceph_frag_make(ceph_frag_bits(f)+1,
|
||||
ceph_frag_value(f) | (0x1000000 >> (1+ceph_frag_bits(f))));
|
||||
}
|
||||
static inline __u32 ceph_frag_make_child(__u32 f, int by, int i)
|
||||
{
|
||||
int newbits = ceph_frag_bits(f) + by;
|
||||
return ceph_frag_make(newbits,
|
||||
ceph_frag_value(f) | (i << (24 - newbits)));
|
||||
}
|
||||
static inline int ceph_frag_is_leftmost(__u32 f)
|
||||
{
|
||||
return ceph_frag_value(f) == 0;
|
||||
}
|
||||
static inline int ceph_frag_is_rightmost(__u32 f)
|
||||
{
|
||||
return ceph_frag_value(f) == ceph_frag_mask(f);
|
||||
}
|
||||
static inline __u32 ceph_frag_next(__u32 f)
|
||||
{
|
||||
return ceph_frag_make(ceph_frag_bits(f),
|
||||
ceph_frag_value(f) + (0x1000000 >> ceph_frag_bits(f)));
|
||||
}
|
||||
|
||||
/*
|
||||
* comparator to sort frags logically, as when traversing the
|
||||
* number space in ascending order...
|
||||
*/
|
||||
int ceph_frag_compare(__u32 a, __u32 b);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* Some non-inline ceph helpers
|
||||
*/
|
||||
#include "types.h"
|
||||
|
||||
/*
|
||||
* return true if @layout appears to be valid
|
||||
*/
|
||||
int ceph_file_layout_is_valid(const struct ceph_file_layout *layout)
|
||||
{
|
||||
__u32 su = le32_to_cpu(layout->fl_stripe_unit);
|
||||
__u32 sc = le32_to_cpu(layout->fl_stripe_count);
|
||||
__u32 os = le32_to_cpu(layout->fl_object_size);
|
||||
|
||||
/* stripe unit, object size must be non-zero, 64k increment */
|
||||
if (!su || (su & (CEPH_MIN_STRIPE_UNIT-1)))
|
||||
return 0;
|
||||
if (!os || (os & (CEPH_MIN_STRIPE_UNIT-1)))
|
||||
return 0;
|
||||
/* object size must be a multiple of stripe unit */
|
||||
if (os < su || os % su)
|
||||
return 0;
|
||||
/* stripe count must be non-zero */
|
||||
if (!sc)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int ceph_flags_to_mode(int flags)
|
||||
{
|
||||
int mode;
|
||||
|
||||
#ifdef O_DIRECTORY /* fixme */
|
||||
if ((flags & O_DIRECTORY) == O_DIRECTORY)
|
||||
return CEPH_FILE_MODE_PIN;
|
||||
#endif
|
||||
if ((flags & O_APPEND) == O_APPEND)
|
||||
flags |= O_WRONLY;
|
||||
|
||||
if ((flags & O_ACCMODE) == O_RDWR)
|
||||
mode = CEPH_FILE_MODE_RDWR;
|
||||
else if ((flags & O_ACCMODE) == O_WRONLY)
|
||||
mode = CEPH_FILE_MODE_WR;
|
||||
else
|
||||
mode = CEPH_FILE_MODE_RD;
|
||||
|
||||
#ifdef O_LAZY
|
||||
if (flags & O_LAZY)
|
||||
mode |= CEPH_FILE_MODE_LAZY;
|
||||
#endif
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
int ceph_caps_for_mode(int mode)
|
||||
{
|
||||
int caps = CEPH_CAP_PIN;
|
||||
|
||||
if (mode & CEPH_FILE_MODE_RD)
|
||||
caps |= CEPH_CAP_FILE_SHARED |
|
||||
CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE;
|
||||
if (mode & CEPH_FILE_MODE_WR)
|
||||
caps |= CEPH_CAP_FILE_EXCL |
|
||||
CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER |
|
||||
CEPH_CAP_AUTH_SHARED | CEPH_CAP_AUTH_EXCL |
|
||||
CEPH_CAP_XATTR_SHARED | CEPH_CAP_XATTR_EXCL;
|
||||
if (mode & CEPH_FILE_MODE_LAZY)
|
||||
caps |= CEPH_CAP_FILE_LAZYIO;
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
|
@ -1,728 +0,0 @@
|
|||
/*
|
||||
* ceph_fs.h - Ceph constants and data types to share between kernel and
|
||||
* user space.
|
||||
*
|
||||
* Most types in this file are defined as little-endian, and are
|
||||
* primarily intended to describe data structures that pass over the
|
||||
* wire or that are stored on disk.
|
||||
*
|
||||
* LGPL2
|
||||
*/
|
||||
|
||||
#ifndef CEPH_FS_H
|
||||
#define CEPH_FS_H
|
||||
|
||||
#include "msgr.h"
|
||||
#include "rados.h"
|
||||
|
||||
/*
|
||||
* subprotocol versions. when specific messages types or high-level
|
||||
* protocols change, bump the affected components. we keep rev
|
||||
* internal cluster protocols separately from the public,
|
||||
* client-facing protocol.
|
||||
*/
|
||||
#define CEPH_OSD_PROTOCOL 8 /* cluster internal */
|
||||
#define CEPH_MDS_PROTOCOL 12 /* cluster internal */
|
||||
#define CEPH_MON_PROTOCOL 5 /* cluster internal */
|
||||
#define CEPH_OSDC_PROTOCOL 24 /* server/client */
|
||||
#define CEPH_MDSC_PROTOCOL 32 /* server/client */
|
||||
#define CEPH_MONC_PROTOCOL 15 /* server/client */
|
||||
|
||||
|
||||
#define CEPH_INO_ROOT 1
|
||||
#define CEPH_INO_CEPH 2 /* hidden .ceph dir */
|
||||
|
||||
/* arbitrary limit on max # of monitors (cluster of 3 is typical) */
|
||||
#define CEPH_MAX_MON 31
|
||||
|
||||
|
||||
/*
|
||||
* feature bits
|
||||
*/
|
||||
#define CEPH_FEATURE_UID (1<<0)
|
||||
#define CEPH_FEATURE_NOSRCADDR (1<<1)
|
||||
#define CEPH_FEATURE_MONCLOCKCHECK (1<<2)
|
||||
#define CEPH_FEATURE_FLOCK (1<<3)
|
||||
|
||||
|
||||
/*
|
||||
* ceph_file_layout - describe data layout for a file/inode
|
||||
*/
|
||||
struct ceph_file_layout {
|
||||
/* file -> object mapping */
|
||||
__le32 fl_stripe_unit; /* stripe unit, in bytes. must be multiple
|
||||
of page size. */
|
||||
__le32 fl_stripe_count; /* over this many objects */
|
||||
__le32 fl_object_size; /* until objects are this big, then move to
|
||||
new objects */
|
||||
__le32 fl_cas_hash; /* 0 = none; 1 = sha256 */
|
||||
|
||||
/* pg -> disk layout */
|
||||
__le32 fl_object_stripe_unit; /* for per-object parity, if any */
|
||||
|
||||
/* object -> pg layout */
|
||||
__le32 fl_pg_preferred; /* preferred primary for pg (-1 for none) */
|
||||
__le32 fl_pg_pool; /* namespace, crush ruleset, rep level */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define CEPH_MIN_STRIPE_UNIT 65536
|
||||
|
||||
int ceph_file_layout_is_valid(const struct ceph_file_layout *layout);
|
||||
|
||||
|
||||
/* crypto algorithms */
|
||||
#define CEPH_CRYPTO_NONE 0x0
|
||||
#define CEPH_CRYPTO_AES 0x1
|
||||
|
||||
#define CEPH_AES_IV "cephsageyudagreg"
|
||||
|
||||
/* security/authentication protocols */
|
||||
#define CEPH_AUTH_UNKNOWN 0x0
|
||||
#define CEPH_AUTH_NONE 0x1
|
||||
#define CEPH_AUTH_CEPHX 0x2
|
||||
|
||||
#define CEPH_AUTH_UID_DEFAULT ((__u64) -1)
|
||||
|
||||
|
||||
/*********************************************
|
||||
* message layer
|
||||
*/
|
||||
|
||||
/*
|
||||
* message types
|
||||
*/
|
||||
|
||||
/* misc */
|
||||
#define CEPH_MSG_SHUTDOWN 1
|
||||
#define CEPH_MSG_PING 2
|
||||
|
||||
/* client <-> monitor */
|
||||
#define CEPH_MSG_MON_MAP 4
|
||||
#define CEPH_MSG_MON_GET_MAP 5
|
||||
#define CEPH_MSG_STATFS 13
|
||||
#define CEPH_MSG_STATFS_REPLY 14
|
||||
#define CEPH_MSG_MON_SUBSCRIBE 15
|
||||
#define CEPH_MSG_MON_SUBSCRIBE_ACK 16
|
||||
#define CEPH_MSG_AUTH 17
|
||||
#define CEPH_MSG_AUTH_REPLY 18
|
||||
|
||||
/* client <-> mds */
|
||||
#define CEPH_MSG_MDS_MAP 21
|
||||
|
||||
#define CEPH_MSG_CLIENT_SESSION 22
|
||||
#define CEPH_MSG_CLIENT_RECONNECT 23
|
||||
|
||||
#define CEPH_MSG_CLIENT_REQUEST 24
|
||||
#define CEPH_MSG_CLIENT_REQUEST_FORWARD 25
|
||||
#define CEPH_MSG_CLIENT_REPLY 26
|
||||
#define CEPH_MSG_CLIENT_CAPS 0x310
|
||||
#define CEPH_MSG_CLIENT_LEASE 0x311
|
||||
#define CEPH_MSG_CLIENT_SNAP 0x312
|
||||
#define CEPH_MSG_CLIENT_CAPRELEASE 0x313
|
||||
|
||||
/* pool ops */
|
||||
#define CEPH_MSG_POOLOP_REPLY 48
|
||||
#define CEPH_MSG_POOLOP 49
|
||||
|
||||
|
||||
/* osd */
|
||||
#define CEPH_MSG_OSD_MAP 41
|
||||
#define CEPH_MSG_OSD_OP 42
|
||||
#define CEPH_MSG_OSD_OPREPLY 43
|
||||
|
||||
/* pool operations */
|
||||
enum {
|
||||
POOL_OP_CREATE = 0x01,
|
||||
POOL_OP_DELETE = 0x02,
|
||||
POOL_OP_AUID_CHANGE = 0x03,
|
||||
POOL_OP_CREATE_SNAP = 0x11,
|
||||
POOL_OP_DELETE_SNAP = 0x12,
|
||||
POOL_OP_CREATE_UNMANAGED_SNAP = 0x21,
|
||||
POOL_OP_DELETE_UNMANAGED_SNAP = 0x22,
|
||||
};
|
||||
|
||||
struct ceph_mon_request_header {
|
||||
__le64 have_version;
|
||||
__le16 session_mon;
|
||||
__le64 session_mon_tid;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_mon_statfs {
|
||||
struct ceph_mon_request_header monhdr;
|
||||
struct ceph_fsid fsid;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_statfs {
|
||||
__le64 kb, kb_used, kb_avail;
|
||||
__le64 num_objects;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_mon_statfs_reply {
|
||||
struct ceph_fsid fsid;
|
||||
__le64 version;
|
||||
struct ceph_statfs st;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
const char *ceph_pool_op_name(int op);
|
||||
|
||||
struct ceph_mon_poolop {
|
||||
struct ceph_mon_request_header monhdr;
|
||||
struct ceph_fsid fsid;
|
||||
__le32 pool;
|
||||
__le32 op;
|
||||
__le64 auid;
|
||||
__le64 snapid;
|
||||
__le32 name_len;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_mon_poolop_reply {
|
||||
struct ceph_mon_request_header monhdr;
|
||||
struct ceph_fsid fsid;
|
||||
__le32 reply_code;
|
||||
__le32 epoch;
|
||||
char has_data;
|
||||
char data[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_mon_unmanaged_snap {
|
||||
__le64 snapid;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_osd_getmap {
|
||||
struct ceph_mon_request_header monhdr;
|
||||
struct ceph_fsid fsid;
|
||||
__le32 start;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_mds_getmap {
|
||||
struct ceph_mon_request_header monhdr;
|
||||
struct ceph_fsid fsid;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_client_mount {
|
||||
struct ceph_mon_request_header monhdr;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_mon_subscribe_item {
|
||||
__le64 have_version; __le64 have;
|
||||
__u8 onetime;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_mon_subscribe_ack {
|
||||
__le32 duration; /* seconds */
|
||||
struct ceph_fsid fsid;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* mds states
|
||||
* > 0 -> in
|
||||
* <= 0 -> out
|
||||
*/
|
||||
#define CEPH_MDS_STATE_DNE 0 /* down, does not exist. */
|
||||
#define CEPH_MDS_STATE_STOPPED -1 /* down, once existed, but no subtrees.
|
||||
empty log. */
|
||||
#define CEPH_MDS_STATE_BOOT -4 /* up, boot announcement. */
|
||||
#define CEPH_MDS_STATE_STANDBY -5 /* up, idle. waiting for assignment. */
|
||||
#define CEPH_MDS_STATE_CREATING -6 /* up, creating MDS instance. */
|
||||
#define CEPH_MDS_STATE_STARTING -7 /* up, starting previously stopped mds */
|
||||
#define CEPH_MDS_STATE_STANDBY_REPLAY -8 /* up, tailing active node's journal */
|
||||
|
||||
#define CEPH_MDS_STATE_REPLAY 8 /* up, replaying journal. */
|
||||
#define CEPH_MDS_STATE_RESOLVE 9 /* up, disambiguating distributed
|
||||
operations (import, rename, etc.) */
|
||||
#define CEPH_MDS_STATE_RECONNECT 10 /* up, reconnect to clients */
|
||||
#define CEPH_MDS_STATE_REJOIN 11 /* up, rejoining distributed cache */
|
||||
#define CEPH_MDS_STATE_CLIENTREPLAY 12 /* up, replaying client operations */
|
||||
#define CEPH_MDS_STATE_ACTIVE 13 /* up, active */
|
||||
#define CEPH_MDS_STATE_STOPPING 14 /* up, but exporting metadata */
|
||||
|
||||
extern const char *ceph_mds_state_name(int s);
|
||||
|
||||
|
||||
/*
|
||||
* metadata lock types.
|
||||
* - these are bitmasks.. we can compose them
|
||||
* - they also define the lock ordering by the MDS
|
||||
* - a few of these are internal to the mds
|
||||
*/
|
||||
#define CEPH_LOCK_DVERSION 1
|
||||
#define CEPH_LOCK_DN 2
|
||||
#define CEPH_LOCK_ISNAP 16
|
||||
#define CEPH_LOCK_IVERSION 32 /* mds internal */
|
||||
#define CEPH_LOCK_IFILE 64
|
||||
#define CEPH_LOCK_IAUTH 128
|
||||
#define CEPH_LOCK_ILINK 256
|
||||
#define CEPH_LOCK_IDFT 512 /* dir frag tree */
|
||||
#define CEPH_LOCK_INEST 1024 /* mds internal */
|
||||
#define CEPH_LOCK_IXATTR 2048
|
||||
#define CEPH_LOCK_IFLOCK 4096 /* advisory file locks */
|
||||
#define CEPH_LOCK_INO 8192 /* immutable inode bits; not a lock */
|
||||
|
||||
/* client_session ops */
|
||||
enum {
|
||||
CEPH_SESSION_REQUEST_OPEN,
|
||||
CEPH_SESSION_OPEN,
|
||||
CEPH_SESSION_REQUEST_CLOSE,
|
||||
CEPH_SESSION_CLOSE,
|
||||
CEPH_SESSION_REQUEST_RENEWCAPS,
|
||||
CEPH_SESSION_RENEWCAPS,
|
||||
CEPH_SESSION_STALE,
|
||||
CEPH_SESSION_RECALL_STATE,
|
||||
};
|
||||
|
||||
extern const char *ceph_session_op_name(int op);
|
||||
|
||||
struct ceph_mds_session_head {
|
||||
__le32 op;
|
||||
__le64 seq;
|
||||
struct ceph_timespec stamp;
|
||||
__le32 max_caps, max_leases;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* client_request */
|
||||
/*
|
||||
* metadata ops.
|
||||
* & 0x001000 -> write op
|
||||
* & 0x010000 -> follow symlink (e.g. stat(), not lstat()).
|
||||
& & 0x100000 -> use weird ino/path trace
|
||||
*/
|
||||
#define CEPH_MDS_OP_WRITE 0x001000
|
||||
enum {
|
||||
CEPH_MDS_OP_LOOKUP = 0x00100,
|
||||
CEPH_MDS_OP_GETATTR = 0x00101,
|
||||
CEPH_MDS_OP_LOOKUPHASH = 0x00102,
|
||||
CEPH_MDS_OP_LOOKUPPARENT = 0x00103,
|
||||
|
||||
CEPH_MDS_OP_SETXATTR = 0x01105,
|
||||
CEPH_MDS_OP_RMXATTR = 0x01106,
|
||||
CEPH_MDS_OP_SETLAYOUT = 0x01107,
|
||||
CEPH_MDS_OP_SETATTR = 0x01108,
|
||||
CEPH_MDS_OP_SETFILELOCK= 0x01109,
|
||||
CEPH_MDS_OP_GETFILELOCK= 0x00110,
|
||||
|
||||
CEPH_MDS_OP_MKNOD = 0x01201,
|
||||
CEPH_MDS_OP_LINK = 0x01202,
|
||||
CEPH_MDS_OP_UNLINK = 0x01203,
|
||||
CEPH_MDS_OP_RENAME = 0x01204,
|
||||
CEPH_MDS_OP_MKDIR = 0x01220,
|
||||
CEPH_MDS_OP_RMDIR = 0x01221,
|
||||
CEPH_MDS_OP_SYMLINK = 0x01222,
|
||||
|
||||
CEPH_MDS_OP_CREATE = 0x01301,
|
||||
CEPH_MDS_OP_OPEN = 0x00302,
|
||||
CEPH_MDS_OP_READDIR = 0x00305,
|
||||
|
||||
CEPH_MDS_OP_LOOKUPSNAP = 0x00400,
|
||||
CEPH_MDS_OP_MKSNAP = 0x01400,
|
||||
CEPH_MDS_OP_RMSNAP = 0x01401,
|
||||
CEPH_MDS_OP_LSSNAP = 0x00402,
|
||||
};
|
||||
|
||||
extern const char *ceph_mds_op_name(int op);
|
||||
|
||||
|
||||
#define CEPH_SETATTR_MODE 1
|
||||
#define CEPH_SETATTR_UID 2
|
||||
#define CEPH_SETATTR_GID 4
|
||||
#define CEPH_SETATTR_MTIME 8
|
||||
#define CEPH_SETATTR_ATIME 16
|
||||
#define CEPH_SETATTR_SIZE 32
|
||||
#define CEPH_SETATTR_CTIME 64
|
||||
|
||||
union ceph_mds_request_args {
|
||||
struct {
|
||||
__le32 mask; /* CEPH_CAP_* */
|
||||
} __attribute__ ((packed)) getattr;
|
||||
struct {
|
||||
__le32 mode;
|
||||
__le32 uid;
|
||||
__le32 gid;
|
||||
struct ceph_timespec mtime;
|
||||
struct ceph_timespec atime;
|
||||
__le64 size, old_size; /* old_size needed by truncate */
|
||||
__le32 mask; /* CEPH_SETATTR_* */
|
||||
} __attribute__ ((packed)) setattr;
|
||||
struct {
|
||||
__le32 frag; /* which dir fragment */
|
||||
__le32 max_entries; /* how many dentries to grab */
|
||||
__le32 max_bytes;
|
||||
} __attribute__ ((packed)) readdir;
|
||||
struct {
|
||||
__le32 mode;
|
||||
__le32 rdev;
|
||||
} __attribute__ ((packed)) mknod;
|
||||
struct {
|
||||
__le32 mode;
|
||||
} __attribute__ ((packed)) mkdir;
|
||||
struct {
|
||||
__le32 flags;
|
||||
__le32 mode;
|
||||
__le32 stripe_unit; /* layout for newly created file */
|
||||
__le32 stripe_count; /* ... */
|
||||
__le32 object_size;
|
||||
__le32 file_replication;
|
||||
__le32 preferred;
|
||||
} __attribute__ ((packed)) open;
|
||||
struct {
|
||||
__le32 flags;
|
||||
} __attribute__ ((packed)) setxattr;
|
||||
struct {
|
||||
struct ceph_file_layout layout;
|
||||
} __attribute__ ((packed)) setlayout;
|
||||
struct {
|
||||
__u8 rule; /* currently fcntl or flock */
|
||||
__u8 type; /* shared, exclusive, remove*/
|
||||
__le64 pid; /* process id requesting the lock */
|
||||
__le64 pid_namespace;
|
||||
__le64 start; /* initial location to lock */
|
||||
__le64 length; /* num bytes to lock from start */
|
||||
__u8 wait; /* will caller wait for lock to become available? */
|
||||
} __attribute__ ((packed)) filelock_change;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define CEPH_MDS_FLAG_REPLAY 1 /* this is a replayed op */
|
||||
#define CEPH_MDS_FLAG_WANT_DENTRY 2 /* want dentry in reply */
|
||||
|
||||
struct ceph_mds_request_head {
|
||||
__le64 oldest_client_tid;
|
||||
__le32 mdsmap_epoch; /* on client */
|
||||
__le32 flags; /* CEPH_MDS_FLAG_* */
|
||||
__u8 num_retry, num_fwd; /* count retry, fwd attempts */
|
||||
__le16 num_releases; /* # include cap/lease release records */
|
||||
__le32 op; /* mds op code */
|
||||
__le32 caller_uid, caller_gid;
|
||||
__le64 ino; /* use this ino for openc, mkdir, mknod,
|
||||
etc. (if replaying) */
|
||||
union ceph_mds_request_args args;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* cap/lease release record */
|
||||
struct ceph_mds_request_release {
|
||||
__le64 ino, cap_id; /* ino and unique cap id */
|
||||
__le32 caps, wanted; /* new issued, wanted */
|
||||
__le32 seq, issue_seq, mseq;
|
||||
__le32 dname_seq; /* if releasing a dentry lease, a */
|
||||
__le32 dname_len; /* string follows. */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* client reply */
|
||||
struct ceph_mds_reply_head {
|
||||
__le32 op;
|
||||
__le32 result;
|
||||
__le32 mdsmap_epoch;
|
||||
__u8 safe; /* true if committed to disk */
|
||||
__u8 is_dentry, is_target; /* true if dentry, target inode records
|
||||
are included with reply */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* one for each node split */
|
||||
struct ceph_frag_tree_split {
|
||||
__le32 frag; /* this frag splits... */
|
||||
__le32 by; /* ...by this many bits */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_frag_tree_head {
|
||||
__le32 nsplits; /* num ceph_frag_tree_split records */
|
||||
struct ceph_frag_tree_split splits[];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* capability issue, for bundling with mds reply */
|
||||
struct ceph_mds_reply_cap {
|
||||
__le32 caps, wanted; /* caps issued, wanted */
|
||||
__le64 cap_id;
|
||||
__le32 seq, mseq;
|
||||
__le64 realm; /* snap realm */
|
||||
__u8 flags; /* CEPH_CAP_FLAG_* */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define CEPH_CAP_FLAG_AUTH 1 /* cap is issued by auth mds */
|
||||
|
||||
/* inode record, for bundling with mds reply */
|
||||
struct ceph_mds_reply_inode {
|
||||
__le64 ino;
|
||||
__le64 snapid;
|
||||
__le32 rdev;
|
||||
__le64 version; /* inode version */
|
||||
__le64 xattr_version; /* version for xattr blob */
|
||||
struct ceph_mds_reply_cap cap; /* caps issued for this inode */
|
||||
struct ceph_file_layout layout;
|
||||
struct ceph_timespec ctime, mtime, atime;
|
||||
__le32 time_warp_seq;
|
||||
__le64 size, max_size, truncate_size;
|
||||
__le32 truncate_seq;
|
||||
__le32 mode, uid, gid;
|
||||
__le32 nlink;
|
||||
__le64 files, subdirs, rbytes, rfiles, rsubdirs; /* dir stats */
|
||||
struct ceph_timespec rctime;
|
||||
struct ceph_frag_tree_head fragtree; /* (must be at end of struct) */
|
||||
} __attribute__ ((packed));
|
||||
/* followed by frag array, then symlink string, then xattr blob */
|
||||
|
||||
/* reply_lease follows dname, and reply_inode */
|
||||
struct ceph_mds_reply_lease {
|
||||
__le16 mask; /* lease type(s) */
|
||||
__le32 duration_ms; /* lease duration */
|
||||
__le32 seq;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_mds_reply_dirfrag {
|
||||
__le32 frag; /* fragment */
|
||||
__le32 auth; /* auth mds, if this is a delegation point */
|
||||
__le32 ndist; /* number of mds' this is replicated on */
|
||||
__le32 dist[];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define CEPH_LOCK_FCNTL 1
|
||||
#define CEPH_LOCK_FLOCK 2
|
||||
|
||||
#define CEPH_LOCK_SHARED 1
|
||||
#define CEPH_LOCK_EXCL 2
|
||||
#define CEPH_LOCK_UNLOCK 4
|
||||
|
||||
struct ceph_filelock {
|
||||
__le64 start;/* file offset to start lock at */
|
||||
__le64 length; /* num bytes to lock; 0 for all following start */
|
||||
__le64 client; /* which client holds the lock */
|
||||
__le64 pid; /* process id holding the lock on the client */
|
||||
__le64 pid_namespace;
|
||||
__u8 type; /* shared lock, exclusive lock, or unlock */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* file access modes */
|
||||
#define CEPH_FILE_MODE_PIN 0
|
||||
#define CEPH_FILE_MODE_RD 1
|
||||
#define CEPH_FILE_MODE_WR 2
|
||||
#define CEPH_FILE_MODE_RDWR 3 /* RD | WR */
|
||||
#define CEPH_FILE_MODE_LAZY 4 /* lazy io */
|
||||
#define CEPH_FILE_MODE_NUM 8 /* bc these are bit fields.. mostly */
|
||||
|
||||
int ceph_flags_to_mode(int flags);
|
||||
|
||||
|
||||
/* capability bits */
|
||||
#define CEPH_CAP_PIN 1 /* no specific capabilities beyond the pin */
|
||||
|
||||
/* generic cap bits */
|
||||
#define CEPH_CAP_GSHARED 1 /* client can reads */
|
||||
#define CEPH_CAP_GEXCL 2 /* client can read and update */
|
||||
#define CEPH_CAP_GCACHE 4 /* (file) client can cache reads */
|
||||
#define CEPH_CAP_GRD 8 /* (file) client can read */
|
||||
#define CEPH_CAP_GWR 16 /* (file) client can write */
|
||||
#define CEPH_CAP_GBUFFER 32 /* (file) client can buffer writes */
|
||||
#define CEPH_CAP_GWREXTEND 64 /* (file) client can extend EOF */
|
||||
#define CEPH_CAP_GLAZYIO 128 /* (file) client can perform lazy io */
|
||||
|
||||
/* per-lock shift */
|
||||
#define CEPH_CAP_SAUTH 2
|
||||
#define CEPH_CAP_SLINK 4
|
||||
#define CEPH_CAP_SXATTR 6
|
||||
#define CEPH_CAP_SFILE 8
|
||||
#define CEPH_CAP_SFLOCK 20
|
||||
|
||||
#define CEPH_CAP_BITS 22
|
||||
|
||||
/* composed values */
|
||||
#define CEPH_CAP_AUTH_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SAUTH)
|
||||
#define CEPH_CAP_AUTH_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SAUTH)
|
||||
#define CEPH_CAP_LINK_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SLINK)
|
||||
#define CEPH_CAP_LINK_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SLINK)
|
||||
#define CEPH_CAP_XATTR_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SXATTR)
|
||||
#define CEPH_CAP_XATTR_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SXATTR)
|
||||
#define CEPH_CAP_FILE(x) (x << CEPH_CAP_SFILE)
|
||||
#define CEPH_CAP_FILE_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SFILE)
|
||||
#define CEPH_CAP_FILE_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SFILE)
|
||||
#define CEPH_CAP_FILE_CACHE (CEPH_CAP_GCACHE << CEPH_CAP_SFILE)
|
||||
#define CEPH_CAP_FILE_RD (CEPH_CAP_GRD << CEPH_CAP_SFILE)
|
||||
#define CEPH_CAP_FILE_WR (CEPH_CAP_GWR << CEPH_CAP_SFILE)
|
||||
#define CEPH_CAP_FILE_BUFFER (CEPH_CAP_GBUFFER << CEPH_CAP_SFILE)
|
||||
#define CEPH_CAP_FILE_WREXTEND (CEPH_CAP_GWREXTEND << CEPH_CAP_SFILE)
|
||||
#define CEPH_CAP_FILE_LAZYIO (CEPH_CAP_GLAZYIO << CEPH_CAP_SFILE)
|
||||
#define CEPH_CAP_FLOCK_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SFLOCK)
|
||||
#define CEPH_CAP_FLOCK_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SFLOCK)
|
||||
|
||||
|
||||
/* cap masks (for getattr) */
|
||||
#define CEPH_STAT_CAP_INODE CEPH_CAP_PIN
|
||||
#define CEPH_STAT_CAP_TYPE CEPH_CAP_PIN /* mode >> 12 */
|
||||
#define CEPH_STAT_CAP_SYMLINK CEPH_CAP_PIN
|
||||
#define CEPH_STAT_CAP_UID CEPH_CAP_AUTH_SHARED
|
||||
#define CEPH_STAT_CAP_GID CEPH_CAP_AUTH_SHARED
|
||||
#define CEPH_STAT_CAP_MODE CEPH_CAP_AUTH_SHARED
|
||||
#define CEPH_STAT_CAP_NLINK CEPH_CAP_LINK_SHARED
|
||||
#define CEPH_STAT_CAP_LAYOUT CEPH_CAP_FILE_SHARED
|
||||
#define CEPH_STAT_CAP_MTIME CEPH_CAP_FILE_SHARED
|
||||
#define CEPH_STAT_CAP_SIZE CEPH_CAP_FILE_SHARED
|
||||
#define CEPH_STAT_CAP_ATIME CEPH_CAP_FILE_SHARED /* fixme */
|
||||
#define CEPH_STAT_CAP_XATTR CEPH_CAP_XATTR_SHARED
|
||||
#define CEPH_STAT_CAP_INODE_ALL (CEPH_CAP_PIN | \
|
||||
CEPH_CAP_AUTH_SHARED | \
|
||||
CEPH_CAP_LINK_SHARED | \
|
||||
CEPH_CAP_FILE_SHARED | \
|
||||
CEPH_CAP_XATTR_SHARED)
|
||||
|
||||
#define CEPH_CAP_ANY_SHARED (CEPH_CAP_AUTH_SHARED | \
|
||||
CEPH_CAP_LINK_SHARED | \
|
||||
CEPH_CAP_XATTR_SHARED | \
|
||||
CEPH_CAP_FILE_SHARED)
|
||||
#define CEPH_CAP_ANY_RD (CEPH_CAP_ANY_SHARED | CEPH_CAP_FILE_RD | \
|
||||
CEPH_CAP_FILE_CACHE)
|
||||
|
||||
#define CEPH_CAP_ANY_EXCL (CEPH_CAP_AUTH_EXCL | \
|
||||
CEPH_CAP_LINK_EXCL | \
|
||||
CEPH_CAP_XATTR_EXCL | \
|
||||
CEPH_CAP_FILE_EXCL)
|
||||
#define CEPH_CAP_ANY_FILE_WR (CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER | \
|
||||
CEPH_CAP_FILE_EXCL)
|
||||
#define CEPH_CAP_ANY_WR (CEPH_CAP_ANY_EXCL | CEPH_CAP_ANY_FILE_WR)
|
||||
#define CEPH_CAP_ANY (CEPH_CAP_ANY_RD | CEPH_CAP_ANY_EXCL | \
|
||||
CEPH_CAP_ANY_FILE_WR | CEPH_CAP_FILE_LAZYIO | \
|
||||
CEPH_CAP_PIN)
|
||||
|
||||
#define CEPH_CAP_LOCKS (CEPH_LOCK_IFILE | CEPH_LOCK_IAUTH | CEPH_LOCK_ILINK | \
|
||||
CEPH_LOCK_IXATTR)
|
||||
|
||||
int ceph_caps_for_mode(int mode);
|
||||
|
||||
enum {
|
||||
CEPH_CAP_OP_GRANT, /* mds->client grant */
|
||||
CEPH_CAP_OP_REVOKE, /* mds->client revoke */
|
||||
CEPH_CAP_OP_TRUNC, /* mds->client trunc notify */
|
||||
CEPH_CAP_OP_EXPORT, /* mds has exported the cap */
|
||||
CEPH_CAP_OP_IMPORT, /* mds has imported the cap */
|
||||
CEPH_CAP_OP_UPDATE, /* client->mds update */
|
||||
CEPH_CAP_OP_DROP, /* client->mds drop cap bits */
|
||||
CEPH_CAP_OP_FLUSH, /* client->mds cap writeback */
|
||||
CEPH_CAP_OP_FLUSH_ACK, /* mds->client flushed */
|
||||
CEPH_CAP_OP_FLUSHSNAP, /* client->mds flush snapped metadata */
|
||||
CEPH_CAP_OP_FLUSHSNAP_ACK, /* mds->client flushed snapped metadata */
|
||||
CEPH_CAP_OP_RELEASE, /* client->mds release (clean) cap */
|
||||
CEPH_CAP_OP_RENEW, /* client->mds renewal request */
|
||||
};
|
||||
|
||||
extern const char *ceph_cap_op_name(int op);
|
||||
|
||||
/*
|
||||
* caps message, used for capability callbacks, acks, requests, etc.
|
||||
*/
|
||||
struct ceph_mds_caps {
|
||||
__le32 op; /* CEPH_CAP_OP_* */
|
||||
__le64 ino, realm;
|
||||
__le64 cap_id;
|
||||
__le32 seq, issue_seq;
|
||||
__le32 caps, wanted, dirty; /* latest issued/wanted/dirty */
|
||||
__le32 migrate_seq;
|
||||
__le64 snap_follows;
|
||||
__le32 snap_trace_len;
|
||||
|
||||
/* authlock */
|
||||
__le32 uid, gid, mode;
|
||||
|
||||
/* linklock */
|
||||
__le32 nlink;
|
||||
|
||||
/* xattrlock */
|
||||
__le32 xattr_len;
|
||||
__le64 xattr_version;
|
||||
|
||||
/* filelock */
|
||||
__le64 size, max_size, truncate_size;
|
||||
__le32 truncate_seq;
|
||||
struct ceph_timespec mtime, atime, ctime;
|
||||
struct ceph_file_layout layout;
|
||||
__le32 time_warp_seq;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* cap release msg head */
|
||||
struct ceph_mds_cap_release {
|
||||
__le32 num; /* number of cap_items that follow */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_mds_cap_item {
|
||||
__le64 ino;
|
||||
__le64 cap_id;
|
||||
__le32 migrate_seq, seq;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define CEPH_MDS_LEASE_REVOKE 1 /* mds -> client */
|
||||
#define CEPH_MDS_LEASE_RELEASE 2 /* client -> mds */
|
||||
#define CEPH_MDS_LEASE_RENEW 3 /* client <-> mds */
|
||||
#define CEPH_MDS_LEASE_REVOKE_ACK 4 /* client -> mds */
|
||||
|
||||
extern const char *ceph_lease_op_name(int o);
|
||||
|
||||
/* lease msg header */
|
||||
struct ceph_mds_lease {
|
||||
__u8 action; /* CEPH_MDS_LEASE_* */
|
||||
__le16 mask; /* which lease */
|
||||
__le64 ino;
|
||||
__le64 first, last; /* snap range */
|
||||
__le32 seq;
|
||||
__le32 duration_ms; /* duration of renewal */
|
||||
} __attribute__ ((packed));
|
||||
/* followed by a __le32+string for dname */
|
||||
|
||||
/* client reconnect */
|
||||
struct ceph_mds_cap_reconnect {
|
||||
__le64 cap_id;
|
||||
__le32 wanted;
|
||||
__le32 issued;
|
||||
__le64 snaprealm;
|
||||
__le64 pathbase; /* base ino for our path to this ino */
|
||||
__le32 flock_len; /* size of flock state blob, if any */
|
||||
} __attribute__ ((packed));
|
||||
/* followed by flock blob */
|
||||
|
||||
struct ceph_mds_cap_reconnect_v1 {
|
||||
__le64 cap_id;
|
||||
__le32 wanted;
|
||||
__le32 issued;
|
||||
__le64 size;
|
||||
struct ceph_timespec mtime, atime;
|
||||
__le64 snaprealm;
|
||||
__le64 pathbase; /* base ino for our path to this ino */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_mds_snaprealm_reconnect {
|
||||
__le64 ino; /* snap realm base */
|
||||
__le64 seq; /* snap seq for this snap realm */
|
||||
__le64 parent; /* parent realm */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* snaps
|
||||
*/
|
||||
enum {
|
||||
CEPH_SNAP_OP_UPDATE, /* CREATE or DESTROY */
|
||||
CEPH_SNAP_OP_CREATE,
|
||||
CEPH_SNAP_OP_DESTROY,
|
||||
CEPH_SNAP_OP_SPLIT,
|
||||
};
|
||||
|
||||
extern const char *ceph_snap_op_name(int o);
|
||||
|
||||
/* snap msg header */
|
||||
struct ceph_mds_snap_head {
|
||||
__le32 op; /* CEPH_SNAP_OP_* */
|
||||
__le64 split; /* ino to split off, if any */
|
||||
__le32 num_split_inos; /* # inos belonging to new child realm */
|
||||
__le32 num_split_realms; /* # child realms udner new child realm */
|
||||
__le32 trace_len; /* size of snap trace blob */
|
||||
} __attribute__ ((packed));
|
||||
/* followed by split ino list, then split realms, then the trace blob */
|
||||
|
||||
/*
|
||||
* encode info about a snaprealm, as viewed by a client
|
||||
*/
|
||||
struct ceph_mds_snap_realm {
|
||||
__le64 ino; /* ino */
|
||||
__le64 created; /* snap: when created */
|
||||
__le64 parent; /* ino: parent realm */
|
||||
__le64 parent_since; /* snap: same parent since */
|
||||
__le64 seq; /* snap: version */
|
||||
__le32 num_snaps;
|
||||
__le32 num_prior_parent_snaps;
|
||||
} __attribute__ ((packed));
|
||||
/* followed by my snap list, then prior parent snap list */
|
||||
|
||||
#endif
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
|
||||
#include "types.h"
|
||||
|
||||
/*
|
||||
* Robert Jenkin's hash function.
|
||||
* http://burtleburtle.net/bob/hash/evahash.html
|
||||
* This is in the public domain.
|
||||
*/
|
||||
#define mix(a, b, c) \
|
||||
do { \
|
||||
a = a - b; a = a - c; a = a ^ (c >> 13); \
|
||||
b = b - c; b = b - a; b = b ^ (a << 8); \
|
||||
c = c - a; c = c - b; c = c ^ (b >> 13); \
|
||||
a = a - b; a = a - c; a = a ^ (c >> 12); \
|
||||
b = b - c; b = b - a; b = b ^ (a << 16); \
|
||||
c = c - a; c = c - b; c = c ^ (b >> 5); \
|
||||
a = a - b; a = a - c; a = a ^ (c >> 3); \
|
||||
b = b - c; b = b - a; b = b ^ (a << 10); \
|
||||
c = c - a; c = c - b; c = c ^ (b >> 15); \
|
||||
} while (0)
|
||||
|
||||
unsigned ceph_str_hash_rjenkins(const char *str, unsigned length)
|
||||
{
|
||||
const unsigned char *k = (const unsigned char *)str;
|
||||
__u32 a, b, c; /* the internal state */
|
||||
__u32 len; /* how many key bytes still need mixing */
|
||||
|
||||
/* Set up the internal state */
|
||||
len = length;
|
||||
a = 0x9e3779b9; /* the golden ratio; an arbitrary value */
|
||||
b = a;
|
||||
c = 0; /* variable initialization of internal state */
|
||||
|
||||
/* handle most of the key */
|
||||
while (len >= 12) {
|
||||
a = a + (k[0] + ((__u32)k[1] << 8) + ((__u32)k[2] << 16) +
|
||||
((__u32)k[3] << 24));
|
||||
b = b + (k[4] + ((__u32)k[5] << 8) + ((__u32)k[6] << 16) +
|
||||
((__u32)k[7] << 24));
|
||||
c = c + (k[8] + ((__u32)k[9] << 8) + ((__u32)k[10] << 16) +
|
||||
((__u32)k[11] << 24));
|
||||
mix(a, b, c);
|
||||
k = k + 12;
|
||||
len = len - 12;
|
||||
}
|
||||
|
||||
/* handle the last 11 bytes */
|
||||
c = c + length;
|
||||
switch (len) { /* all the case statements fall through */
|
||||
case 11:
|
||||
c = c + ((__u32)k[10] << 24);
|
||||
case 10:
|
||||
c = c + ((__u32)k[9] << 16);
|
||||
case 9:
|
||||
c = c + ((__u32)k[8] << 8);
|
||||
/* the first byte of c is reserved for the length */
|
||||
case 8:
|
||||
b = b + ((__u32)k[7] << 24);
|
||||
case 7:
|
||||
b = b + ((__u32)k[6] << 16);
|
||||
case 6:
|
||||
b = b + ((__u32)k[5] << 8);
|
||||
case 5:
|
||||
b = b + k[4];
|
||||
case 4:
|
||||
a = a + ((__u32)k[3] << 24);
|
||||
case 3:
|
||||
a = a + ((__u32)k[2] << 16);
|
||||
case 2:
|
||||
a = a + ((__u32)k[1] << 8);
|
||||
case 1:
|
||||
a = a + k[0];
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
mix(a, b, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* linux dcache hash
|
||||
*/
|
||||
unsigned ceph_str_hash_linux(const char *str, unsigned length)
|
||||
{
|
||||
unsigned long hash = 0;
|
||||
unsigned char c;
|
||||
|
||||
while (length--) {
|
||||
c = *str++;
|
||||
hash = (hash + (c << 4) + (c >> 4)) * 11;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
unsigned ceph_str_hash(int type, const char *s, unsigned len)
|
||||
{
|
||||
switch (type) {
|
||||
case CEPH_STR_HASH_LINUX:
|
||||
return ceph_str_hash_linux(s, len);
|
||||
case CEPH_STR_HASH_RJENKINS:
|
||||
return ceph_str_hash_rjenkins(s, len);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const char *ceph_str_hash_name(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case CEPH_STR_HASH_LINUX:
|
||||
return "linux";
|
||||
case CEPH_STR_HASH_RJENKINS:
|
||||
return "rjenkins";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#ifndef FS_CEPH_HASH_H
|
||||
#define FS_CEPH_HASH_H
|
||||
|
||||
#define CEPH_STR_HASH_LINUX 0x1 /* linux dcache hash */
|
||||
#define CEPH_STR_HASH_RJENKINS 0x2 /* robert jenkins' */
|
||||
|
||||
extern unsigned ceph_str_hash_linux(const char *s, unsigned len);
|
||||
extern unsigned ceph_str_hash_rjenkins(const char *s, unsigned len);
|
||||
|
||||
extern unsigned ceph_str_hash(int type, const char *s, unsigned len);
|
||||
extern const char *ceph_str_hash_name(int type);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
|
||||
#ifdef __KERNEL__
|
||||
# include <linux/slab.h>
|
||||
#else
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
# define kfree(x) do { if (x) free(x); } while (0)
|
||||
# define BUG_ON(x) assert(!(x))
|
||||
#endif
|
||||
|
||||
#include "crush.h"
|
||||
|
||||
const char *crush_bucket_alg_name(int alg)
|
||||
{
|
||||
switch (alg) {
|
||||
case CRUSH_BUCKET_UNIFORM: return "uniform";
|
||||
case CRUSH_BUCKET_LIST: return "list";
|
||||
case CRUSH_BUCKET_TREE: return "tree";
|
||||
case CRUSH_BUCKET_STRAW: return "straw";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* crush_get_bucket_item_weight - Get weight of an item in given bucket
|
||||
* @b: bucket pointer
|
||||
* @p: item index in bucket
|
||||
*/
|
||||
int crush_get_bucket_item_weight(struct crush_bucket *b, int p)
|
||||
{
|
||||
if (p >= b->size)
|
||||
return 0;
|
||||
|
||||
switch (b->alg) {
|
||||
case CRUSH_BUCKET_UNIFORM:
|
||||
return ((struct crush_bucket_uniform *)b)->item_weight;
|
||||
case CRUSH_BUCKET_LIST:
|
||||
return ((struct crush_bucket_list *)b)->item_weights[p];
|
||||
case CRUSH_BUCKET_TREE:
|
||||
if (p & 1)
|
||||
return ((struct crush_bucket_tree *)b)->node_weights[p];
|
||||
return 0;
|
||||
case CRUSH_BUCKET_STRAW:
|
||||
return ((struct crush_bucket_straw *)b)->item_weights[p];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* crush_calc_parents - Calculate parent vectors for the given crush map.
|
||||
* @map: crush_map pointer
|
||||
*/
|
||||
void crush_calc_parents(struct crush_map *map)
|
||||
{
|
||||
int i, b, c;
|
||||
|
||||
for (b = 0; b < map->max_buckets; b++) {
|
||||
if (map->buckets[b] == NULL)
|
||||
continue;
|
||||
for (i = 0; i < map->buckets[b]->size; i++) {
|
||||
c = map->buckets[b]->items[i];
|
||||
BUG_ON(c >= map->max_devices ||
|
||||
c < -map->max_buckets);
|
||||
if (c >= 0)
|
||||
map->device_parents[c] = map->buckets[b]->id;
|
||||
else
|
||||
map->bucket_parents[-1-c] = map->buckets[b]->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b)
|
||||
{
|
||||
kfree(b->h.perm);
|
||||
kfree(b->h.items);
|
||||
kfree(b);
|
||||
}
|
||||
|
||||
void crush_destroy_bucket_list(struct crush_bucket_list *b)
|
||||
{
|
||||
kfree(b->item_weights);
|
||||
kfree(b->sum_weights);
|
||||
kfree(b->h.perm);
|
||||
kfree(b->h.items);
|
||||
kfree(b);
|
||||
}
|
||||
|
||||
void crush_destroy_bucket_tree(struct crush_bucket_tree *b)
|
||||
{
|
||||
kfree(b->node_weights);
|
||||
kfree(b);
|
||||
}
|
||||
|
||||
void crush_destroy_bucket_straw(struct crush_bucket_straw *b)
|
||||
{
|
||||
kfree(b->straws);
|
||||
kfree(b->item_weights);
|
||||
kfree(b->h.perm);
|
||||
kfree(b->h.items);
|
||||
kfree(b);
|
||||
}
|
||||
|
||||
void crush_destroy_bucket(struct crush_bucket *b)
|
||||
{
|
||||
switch (b->alg) {
|
||||
case CRUSH_BUCKET_UNIFORM:
|
||||
crush_destroy_bucket_uniform((struct crush_bucket_uniform *)b);
|
||||
break;
|
||||
case CRUSH_BUCKET_LIST:
|
||||
crush_destroy_bucket_list((struct crush_bucket_list *)b);
|
||||
break;
|
||||
case CRUSH_BUCKET_TREE:
|
||||
crush_destroy_bucket_tree((struct crush_bucket_tree *)b);
|
||||
break;
|
||||
case CRUSH_BUCKET_STRAW:
|
||||
crush_destroy_bucket_straw((struct crush_bucket_straw *)b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* crush_destroy - Destroy a crush_map
|
||||
* @map: crush_map pointer
|
||||
*/
|
||||
void crush_destroy(struct crush_map *map)
|
||||
{
|
||||
int b;
|
||||
|
||||
/* buckets */
|
||||
if (map->buckets) {
|
||||
for (b = 0; b < map->max_buckets; b++) {
|
||||
if (map->buckets[b] == NULL)
|
||||
continue;
|
||||
crush_destroy_bucket(map->buckets[b]);
|
||||
}
|
||||
kfree(map->buckets);
|
||||
}
|
||||
|
||||
/* rules */
|
||||
if (map->rules) {
|
||||
for (b = 0; b < map->max_rules; b++)
|
||||
kfree(map->rules[b]);
|
||||
kfree(map->rules);
|
||||
}
|
||||
|
||||
kfree(map->bucket_parents);
|
||||
kfree(map->device_parents);
|
||||
kfree(map);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
#ifndef CEPH_CRUSH_CRUSH_H
|
||||
#define CEPH_CRUSH_CRUSH_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* CRUSH is a pseudo-random data distribution algorithm that
|
||||
* efficiently distributes input values (typically, data objects)
|
||||
* across a heterogeneous, structured storage cluster.
|
||||
*
|
||||
* The algorithm was originally described in detail in this paper
|
||||
* (although the algorithm has evolved somewhat since then):
|
||||
*
|
||||
* http://www.ssrc.ucsc.edu/Papers/weil-sc06.pdf
|
||||
*
|
||||
* LGPL2
|
||||
*/
|
||||
|
||||
|
||||
#define CRUSH_MAGIC 0x00010000ul /* for detecting algorithm revisions */
|
||||
|
||||
|
||||
#define CRUSH_MAX_DEPTH 10 /* max crush hierarchy depth */
|
||||
#define CRUSH_MAX_SET 10 /* max size of a mapping result */
|
||||
|
||||
|
||||
/*
|
||||
* CRUSH uses user-defined "rules" to describe how inputs should be
|
||||
* mapped to devices. A rule consists of sequence of steps to perform
|
||||
* to generate the set of output devices.
|
||||
*/
|
||||
struct crush_rule_step {
|
||||
__u32 op;
|
||||
__s32 arg1;
|
||||
__s32 arg2;
|
||||
};
|
||||
|
||||
/* step op codes */
|
||||
enum {
|
||||
CRUSH_RULE_NOOP = 0,
|
||||
CRUSH_RULE_TAKE = 1, /* arg1 = value to start with */
|
||||
CRUSH_RULE_CHOOSE_FIRSTN = 2, /* arg1 = num items to pick */
|
||||
/* arg2 = type */
|
||||
CRUSH_RULE_CHOOSE_INDEP = 3, /* same */
|
||||
CRUSH_RULE_EMIT = 4, /* no args */
|
||||
CRUSH_RULE_CHOOSE_LEAF_FIRSTN = 6,
|
||||
CRUSH_RULE_CHOOSE_LEAF_INDEP = 7,
|
||||
};
|
||||
|
||||
/*
|
||||
* for specifying choose num (arg1) relative to the max parameter
|
||||
* passed to do_rule
|
||||
*/
|
||||
#define CRUSH_CHOOSE_N 0
|
||||
#define CRUSH_CHOOSE_N_MINUS(x) (-(x))
|
||||
|
||||
/*
|
||||
* The rule mask is used to describe what the rule is intended for.
|
||||
* Given a ruleset and size of output set, we search through the
|
||||
* rule list for a matching rule_mask.
|
||||
*/
|
||||
struct crush_rule_mask {
|
||||
__u8 ruleset;
|
||||
__u8 type;
|
||||
__u8 min_size;
|
||||
__u8 max_size;
|
||||
};
|
||||
|
||||
struct crush_rule {
|
||||
__u32 len;
|
||||
struct crush_rule_mask mask;
|
||||
struct crush_rule_step steps[0];
|
||||
};
|
||||
|
||||
#define crush_rule_size(len) (sizeof(struct crush_rule) + \
|
||||
(len)*sizeof(struct crush_rule_step))
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* A bucket is a named container of other items (either devices or
|
||||
* other buckets). Items within a bucket are chosen using one of a
|
||||
* few different algorithms. The table summarizes how the speed of
|
||||
* each option measures up against mapping stability when items are
|
||||
* added or removed.
|
||||
*
|
||||
* Bucket Alg Speed Additions Removals
|
||||
* ------------------------------------------------
|
||||
* uniform O(1) poor poor
|
||||
* list O(n) optimal poor
|
||||
* tree O(log n) good good
|
||||
* straw O(n) optimal optimal
|
||||
*/
|
||||
enum {
|
||||
CRUSH_BUCKET_UNIFORM = 1,
|
||||
CRUSH_BUCKET_LIST = 2,
|
||||
CRUSH_BUCKET_TREE = 3,
|
||||
CRUSH_BUCKET_STRAW = 4
|
||||
};
|
||||
extern const char *crush_bucket_alg_name(int alg);
|
||||
|
||||
struct crush_bucket {
|
||||
__s32 id; /* this'll be negative */
|
||||
__u16 type; /* non-zero; type=0 is reserved for devices */
|
||||
__u8 alg; /* one of CRUSH_BUCKET_* */
|
||||
__u8 hash; /* which hash function to use, CRUSH_HASH_* */
|
||||
__u32 weight; /* 16-bit fixed point */
|
||||
__u32 size; /* num items */
|
||||
__s32 *items;
|
||||
|
||||
/*
|
||||
* cached random permutation: used for uniform bucket and for
|
||||
* the linear search fallback for the other bucket types.
|
||||
*/
|
||||
__u32 perm_x; /* @x for which *perm is defined */
|
||||
__u32 perm_n; /* num elements of *perm that are permuted/defined */
|
||||
__u32 *perm;
|
||||
};
|
||||
|
||||
struct crush_bucket_uniform {
|
||||
struct crush_bucket h;
|
||||
__u32 item_weight; /* 16-bit fixed point; all items equally weighted */
|
||||
};
|
||||
|
||||
struct crush_bucket_list {
|
||||
struct crush_bucket h;
|
||||
__u32 *item_weights; /* 16-bit fixed point */
|
||||
__u32 *sum_weights; /* 16-bit fixed point. element i is sum
|
||||
of weights 0..i, inclusive */
|
||||
};
|
||||
|
||||
struct crush_bucket_tree {
|
||||
struct crush_bucket h; /* note: h.size is _tree_ size, not number of
|
||||
actual items */
|
||||
__u8 num_nodes;
|
||||
__u32 *node_weights;
|
||||
};
|
||||
|
||||
struct crush_bucket_straw {
|
||||
struct crush_bucket h;
|
||||
__u32 *item_weights; /* 16-bit fixed point */
|
||||
__u32 *straws; /* 16-bit fixed point */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* CRUSH map includes all buckets, rules, etc.
|
||||
*/
|
||||
struct crush_map {
|
||||
struct crush_bucket **buckets;
|
||||
struct crush_rule **rules;
|
||||
|
||||
/*
|
||||
* Parent pointers to identify the parent bucket a device or
|
||||
* bucket in the hierarchy. If an item appears more than
|
||||
* once, this is the _last_ time it appeared (where buckets
|
||||
* are processed in bucket id order, from -1 on down to
|
||||
* -max_buckets.
|
||||
*/
|
||||
__u32 *bucket_parents;
|
||||
__u32 *device_parents;
|
||||
|
||||
__s32 max_buckets;
|
||||
__u32 max_rules;
|
||||
__s32 max_devices;
|
||||
};
|
||||
|
||||
|
||||
/* crush.c */
|
||||
extern int crush_get_bucket_item_weight(struct crush_bucket *b, int pos);
|
||||
extern void crush_calc_parents(struct crush_map *map);
|
||||
extern void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b);
|
||||
extern void crush_destroy_bucket_list(struct crush_bucket_list *b);
|
||||
extern void crush_destroy_bucket_tree(struct crush_bucket_tree *b);
|
||||
extern void crush_destroy_bucket_straw(struct crush_bucket_straw *b);
|
||||
extern void crush_destroy_bucket(struct crush_bucket *b);
|
||||
extern void crush_destroy(struct crush_map *map);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include "hash.h"
|
||||
|
||||
/*
|
||||
* Robert Jenkins' function for mixing 32-bit values
|
||||
* http://burtleburtle.net/bob/hash/evahash.html
|
||||
* a, b = random bits, c = input and output
|
||||
*/
|
||||
#define crush_hashmix(a, b, c) do { \
|
||||
a = a-b; a = a-c; a = a^(c>>13); \
|
||||
b = b-c; b = b-a; b = b^(a<<8); \
|
||||
c = c-a; c = c-b; c = c^(b>>13); \
|
||||
a = a-b; a = a-c; a = a^(c>>12); \
|
||||
b = b-c; b = b-a; b = b^(a<<16); \
|
||||
c = c-a; c = c-b; c = c^(b>>5); \
|
||||
a = a-b; a = a-c; a = a^(c>>3); \
|
||||
b = b-c; b = b-a; b = b^(a<<10); \
|
||||
c = c-a; c = c-b; c = c^(b>>15); \
|
||||
} while (0)
|
||||
|
||||
#define crush_hash_seed 1315423911
|
||||
|
||||
static __u32 crush_hash32_rjenkins1(__u32 a)
|
||||
{
|
||||
__u32 hash = crush_hash_seed ^ a;
|
||||
__u32 b = a;
|
||||
__u32 x = 231232;
|
||||
__u32 y = 1232;
|
||||
crush_hashmix(b, x, hash);
|
||||
crush_hashmix(y, a, hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
static __u32 crush_hash32_rjenkins1_2(__u32 a, __u32 b)
|
||||
{
|
||||
__u32 hash = crush_hash_seed ^ a ^ b;
|
||||
__u32 x = 231232;
|
||||
__u32 y = 1232;
|
||||
crush_hashmix(a, b, hash);
|
||||
crush_hashmix(x, a, hash);
|
||||
crush_hashmix(b, y, hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
static __u32 crush_hash32_rjenkins1_3(__u32 a, __u32 b, __u32 c)
|
||||
{
|
||||
__u32 hash = crush_hash_seed ^ a ^ b ^ c;
|
||||
__u32 x = 231232;
|
||||
__u32 y = 1232;
|
||||
crush_hashmix(a, b, hash);
|
||||
crush_hashmix(c, x, hash);
|
||||
crush_hashmix(y, a, hash);
|
||||
crush_hashmix(b, x, hash);
|
||||
crush_hashmix(y, c, hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
static __u32 crush_hash32_rjenkins1_4(__u32 a, __u32 b, __u32 c, __u32 d)
|
||||
{
|
||||
__u32 hash = crush_hash_seed ^ a ^ b ^ c ^ d;
|
||||
__u32 x = 231232;
|
||||
__u32 y = 1232;
|
||||
crush_hashmix(a, b, hash);
|
||||
crush_hashmix(c, d, hash);
|
||||
crush_hashmix(a, x, hash);
|
||||
crush_hashmix(y, b, hash);
|
||||
crush_hashmix(c, x, hash);
|
||||
crush_hashmix(y, d, hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
static __u32 crush_hash32_rjenkins1_5(__u32 a, __u32 b, __u32 c, __u32 d,
|
||||
__u32 e)
|
||||
{
|
||||
__u32 hash = crush_hash_seed ^ a ^ b ^ c ^ d ^ e;
|
||||
__u32 x = 231232;
|
||||
__u32 y = 1232;
|
||||
crush_hashmix(a, b, hash);
|
||||
crush_hashmix(c, d, hash);
|
||||
crush_hashmix(e, x, hash);
|
||||
crush_hashmix(y, a, hash);
|
||||
crush_hashmix(b, x, hash);
|
||||
crush_hashmix(y, c, hash);
|
||||
crush_hashmix(d, x, hash);
|
||||
crush_hashmix(y, e, hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
__u32 crush_hash32(int type, __u32 a)
|
||||
{
|
||||
switch (type) {
|
||||
case CRUSH_HASH_RJENKINS1:
|
||||
return crush_hash32_rjenkins1(a);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
__u32 crush_hash32_2(int type, __u32 a, __u32 b)
|
||||
{
|
||||
switch (type) {
|
||||
case CRUSH_HASH_RJENKINS1:
|
||||
return crush_hash32_rjenkins1_2(a, b);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
__u32 crush_hash32_3(int type, __u32 a, __u32 b, __u32 c)
|
||||
{
|
||||
switch (type) {
|
||||
case CRUSH_HASH_RJENKINS1:
|
||||
return crush_hash32_rjenkins1_3(a, b, c);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
__u32 crush_hash32_4(int type, __u32 a, __u32 b, __u32 c, __u32 d)
|
||||
{
|
||||
switch (type) {
|
||||
case CRUSH_HASH_RJENKINS1:
|
||||
return crush_hash32_rjenkins1_4(a, b, c, d);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
__u32 crush_hash32_5(int type, __u32 a, __u32 b, __u32 c, __u32 d, __u32 e)
|
||||
{
|
||||
switch (type) {
|
||||
case CRUSH_HASH_RJENKINS1:
|
||||
return crush_hash32_rjenkins1_5(a, b, c, d, e);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const char *crush_hash_name(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case CRUSH_HASH_RJENKINS1:
|
||||
return "rjenkins1";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#ifndef CEPH_CRUSH_HASH_H
|
||||
#define CEPH_CRUSH_HASH_H
|
||||
|
||||
#define CRUSH_HASH_RJENKINS1 0
|
||||
|
||||
#define CRUSH_HASH_DEFAULT CRUSH_HASH_RJENKINS1
|
||||
|
||||
extern const char *crush_hash_name(int type);
|
||||
|
||||
extern __u32 crush_hash32(int type, __u32 a);
|
||||
extern __u32 crush_hash32_2(int type, __u32 a, __u32 b);
|
||||
extern __u32 crush_hash32_3(int type, __u32 a, __u32 b, __u32 c);
|
||||
extern __u32 crush_hash32_4(int type, __u32 a, __u32 b, __u32 c, __u32 d);
|
||||
extern __u32 crush_hash32_5(int type, __u32 a, __u32 b, __u32 c, __u32 d,
|
||||
__u32 e);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,609 +0,0 @@
|
|||
|
||||
#ifdef __KERNEL__
|
||||
# include <linux/string.h>
|
||||
# include <linux/slab.h>
|
||||
# include <linux/bug.h>
|
||||
# include <linux/kernel.h>
|
||||
# ifndef dprintk
|
||||
# define dprintk(args...)
|
||||
# endif
|
||||
#else
|
||||
# include <string.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
# define BUG_ON(x) assert(!(x))
|
||||
# define dprintk(args...) /* printf(args) */
|
||||
# define kmalloc(x, f) malloc(x)
|
||||
# define kfree(x) free(x)
|
||||
#endif
|
||||
|
||||
#include "crush.h"
|
||||
#include "hash.h"
|
||||
|
||||
/*
|
||||
* Implement the core CRUSH mapping algorithm.
|
||||
*/
|
||||
|
||||
/**
|
||||
* crush_find_rule - find a crush_rule id for a given ruleset, type, and size.
|
||||
* @map: the crush_map
|
||||
* @ruleset: the storage ruleset id (user defined)
|
||||
* @type: storage ruleset type (user defined)
|
||||
* @size: output set size
|
||||
*/
|
||||
int crush_find_rule(struct crush_map *map, int ruleset, int type, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < map->max_rules; i++) {
|
||||
if (map->rules[i] &&
|
||||
map->rules[i]->mask.ruleset == ruleset &&
|
||||
map->rules[i]->mask.type == type &&
|
||||
map->rules[i]->mask.min_size <= size &&
|
||||
map->rules[i]->mask.max_size >= size)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucket choose methods
|
||||
*
|
||||
* For each bucket algorithm, we have a "choose" method that, given a
|
||||
* crush input @x and replica position (usually, position in output set) @r,
|
||||
* will produce an item in the bucket.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Choose based on a random permutation of the bucket.
|
||||
*
|
||||
* We used to use some prime number arithmetic to do this, but it
|
||||
* wasn't very random, and had some other bad behaviors. Instead, we
|
||||
* calculate an actual random permutation of the bucket members.
|
||||
* Since this is expensive, we optimize for the r=0 case, which
|
||||
* captures the vast majority of calls.
|
||||
*/
|
||||
static int bucket_perm_choose(struct crush_bucket *bucket,
|
||||
int x, int r)
|
||||
{
|
||||
unsigned pr = r % bucket->size;
|
||||
unsigned i, s;
|
||||
|
||||
/* start a new permutation if @x has changed */
|
||||
if (bucket->perm_x != x || bucket->perm_n == 0) {
|
||||
dprintk("bucket %d new x=%d\n", bucket->id, x);
|
||||
bucket->perm_x = x;
|
||||
|
||||
/* optimize common r=0 case */
|
||||
if (pr == 0) {
|
||||
s = crush_hash32_3(bucket->hash, x, bucket->id, 0) %
|
||||
bucket->size;
|
||||
bucket->perm[0] = s;
|
||||
bucket->perm_n = 0xffff; /* magic value, see below */
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < bucket->size; i++)
|
||||
bucket->perm[i] = i;
|
||||
bucket->perm_n = 0;
|
||||
} else if (bucket->perm_n == 0xffff) {
|
||||
/* clean up after the r=0 case above */
|
||||
for (i = 1; i < bucket->size; i++)
|
||||
bucket->perm[i] = i;
|
||||
bucket->perm[bucket->perm[0]] = 0;
|
||||
bucket->perm_n = 1;
|
||||
}
|
||||
|
||||
/* calculate permutation up to pr */
|
||||
for (i = 0; i < bucket->perm_n; i++)
|
||||
dprintk(" perm_choose have %d: %d\n", i, bucket->perm[i]);
|
||||
while (bucket->perm_n <= pr) {
|
||||
unsigned p = bucket->perm_n;
|
||||
/* no point in swapping the final entry */
|
||||
if (p < bucket->size - 1) {
|
||||
i = crush_hash32_3(bucket->hash, x, bucket->id, p) %
|
||||
(bucket->size - p);
|
||||
if (i) {
|
||||
unsigned t = bucket->perm[p + i];
|
||||
bucket->perm[p + i] = bucket->perm[p];
|
||||
bucket->perm[p] = t;
|
||||
}
|
||||
dprintk(" perm_choose swap %d with %d\n", p, p+i);
|
||||
}
|
||||
bucket->perm_n++;
|
||||
}
|
||||
for (i = 0; i < bucket->size; i++)
|
||||
dprintk(" perm_choose %d: %d\n", i, bucket->perm[i]);
|
||||
|
||||
s = bucket->perm[pr];
|
||||
out:
|
||||
dprintk(" perm_choose %d sz=%d x=%d r=%d (%d) s=%d\n", bucket->id,
|
||||
bucket->size, x, r, pr, s);
|
||||
return bucket->items[s];
|
||||
}
|
||||
|
||||
/* uniform */
|
||||
static int bucket_uniform_choose(struct crush_bucket_uniform *bucket,
|
||||
int x, int r)
|
||||
{
|
||||
return bucket_perm_choose(&bucket->h, x, r);
|
||||
}
|
||||
|
||||
/* list */
|
||||
static int bucket_list_choose(struct crush_bucket_list *bucket,
|
||||
int x, int r)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = bucket->h.size-1; i >= 0; i--) {
|
||||
__u64 w = crush_hash32_4(bucket->h.hash,x, bucket->h.items[i],
|
||||
r, bucket->h.id);
|
||||
w &= 0xffff;
|
||||
dprintk("list_choose i=%d x=%d r=%d item %d weight %x "
|
||||
"sw %x rand %llx",
|
||||
i, x, r, bucket->h.items[i], bucket->item_weights[i],
|
||||
bucket->sum_weights[i], w);
|
||||
w *= bucket->sum_weights[i];
|
||||
w = w >> 16;
|
||||
/*dprintk(" scaled %llx\n", w);*/
|
||||
if (w < bucket->item_weights[i])
|
||||
return bucket->h.items[i];
|
||||
}
|
||||
|
||||
BUG_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* (binary) tree */
|
||||
static int height(int n)
|
||||
{
|
||||
int h = 0;
|
||||
while ((n & 1) == 0) {
|
||||
h++;
|
||||
n = n >> 1;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static int left(int x)
|
||||
{
|
||||
int h = height(x);
|
||||
return x - (1 << (h-1));
|
||||
}
|
||||
|
||||
static int right(int x)
|
||||
{
|
||||
int h = height(x);
|
||||
return x + (1 << (h-1));
|
||||
}
|
||||
|
||||
static int terminal(int x)
|
||||
{
|
||||
return x & 1;
|
||||
}
|
||||
|
||||
static int bucket_tree_choose(struct crush_bucket_tree *bucket,
|
||||
int x, int r)
|
||||
{
|
||||
int n, l;
|
||||
__u32 w;
|
||||
__u64 t;
|
||||
|
||||
/* start at root */
|
||||
n = bucket->num_nodes >> 1;
|
||||
|
||||
while (!terminal(n)) {
|
||||
/* pick point in [0, w) */
|
||||
w = bucket->node_weights[n];
|
||||
t = (__u64)crush_hash32_4(bucket->h.hash, x, n, r,
|
||||
bucket->h.id) * (__u64)w;
|
||||
t = t >> 32;
|
||||
|
||||
/* descend to the left or right? */
|
||||
l = left(n);
|
||||
if (t < bucket->node_weights[l])
|
||||
n = l;
|
||||
else
|
||||
n = right(n);
|
||||
}
|
||||
|
||||
return bucket->h.items[n >> 1];
|
||||
}
|
||||
|
||||
|
||||
/* straw */
|
||||
|
||||
static int bucket_straw_choose(struct crush_bucket_straw *bucket,
|
||||
int x, int r)
|
||||
{
|
||||
int i;
|
||||
int high = 0;
|
||||
__u64 high_draw = 0;
|
||||
__u64 draw;
|
||||
|
||||
for (i = 0; i < bucket->h.size; i++) {
|
||||
draw = crush_hash32_3(bucket->h.hash, x, bucket->h.items[i], r);
|
||||
draw &= 0xffff;
|
||||
draw *= bucket->straws[i];
|
||||
if (i == 0 || draw > high_draw) {
|
||||
high = i;
|
||||
high_draw = draw;
|
||||
}
|
||||
}
|
||||
return bucket->h.items[high];
|
||||
}
|
||||
|
||||
static int crush_bucket_choose(struct crush_bucket *in, int x, int r)
|
||||
{
|
||||
dprintk(" crush_bucket_choose %d x=%d r=%d\n", in->id, x, r);
|
||||
switch (in->alg) {
|
||||
case CRUSH_BUCKET_UNIFORM:
|
||||
return bucket_uniform_choose((struct crush_bucket_uniform *)in,
|
||||
x, r);
|
||||
case CRUSH_BUCKET_LIST:
|
||||
return bucket_list_choose((struct crush_bucket_list *)in,
|
||||
x, r);
|
||||
case CRUSH_BUCKET_TREE:
|
||||
return bucket_tree_choose((struct crush_bucket_tree *)in,
|
||||
x, r);
|
||||
case CRUSH_BUCKET_STRAW:
|
||||
return bucket_straw_choose((struct crush_bucket_straw *)in,
|
||||
x, r);
|
||||
default:
|
||||
BUG_ON(1);
|
||||
return in->items[0];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* true if device is marked "out" (failed, fully offloaded)
|
||||
* of the cluster
|
||||
*/
|
||||
static int is_out(struct crush_map *map, __u32 *weight, int item, int x)
|
||||
{
|
||||
if (weight[item] >= 0x10000)
|
||||
return 0;
|
||||
if (weight[item] == 0)
|
||||
return 1;
|
||||
if ((crush_hash32_2(CRUSH_HASH_RJENKINS1, x, item) & 0xffff)
|
||||
< weight[item])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* crush_choose - choose numrep distinct items of given type
|
||||
* @map: the crush_map
|
||||
* @bucket: the bucket we are choose an item from
|
||||
* @x: crush input value
|
||||
* @numrep: the number of items to choose
|
||||
* @type: the type of item to choose
|
||||
* @out: pointer to output vector
|
||||
* @outpos: our position in that vector
|
||||
* @firstn: true if choosing "first n" items, false if choosing "indep"
|
||||
* @recurse_to_leaf: true if we want one device under each item of given type
|
||||
* @out2: second output vector for leaf items (if @recurse_to_leaf)
|
||||
*/
|
||||
static int crush_choose(struct crush_map *map,
|
||||
struct crush_bucket *bucket,
|
||||
__u32 *weight,
|
||||
int x, int numrep, int type,
|
||||
int *out, int outpos,
|
||||
int firstn, int recurse_to_leaf,
|
||||
int *out2)
|
||||
{
|
||||
int rep;
|
||||
int ftotal, flocal;
|
||||
int retry_descent, retry_bucket, skip_rep;
|
||||
struct crush_bucket *in = bucket;
|
||||
int r;
|
||||
int i;
|
||||
int item = 0;
|
||||
int itemtype;
|
||||
int collide, reject;
|
||||
const int orig_tries = 5; /* attempts before we fall back to search */
|
||||
|
||||
dprintk("CHOOSE%s bucket %d x %d outpos %d numrep %d\n", recurse_to_leaf ? "_LEAF" : "",
|
||||
bucket->id, x, outpos, numrep);
|
||||
|
||||
for (rep = outpos; rep < numrep; rep++) {
|
||||
/* keep trying until we get a non-out, non-colliding item */
|
||||
ftotal = 0;
|
||||
skip_rep = 0;
|
||||
do {
|
||||
retry_descent = 0;
|
||||
in = bucket; /* initial bucket */
|
||||
|
||||
/* choose through intervening buckets */
|
||||
flocal = 0;
|
||||
do {
|
||||
collide = 0;
|
||||
retry_bucket = 0;
|
||||
r = rep;
|
||||
if (in->alg == CRUSH_BUCKET_UNIFORM) {
|
||||
/* be careful */
|
||||
if (firstn || numrep >= in->size)
|
||||
/* r' = r + f_total */
|
||||
r += ftotal;
|
||||
else if (in->size % numrep == 0)
|
||||
/* r'=r+(n+1)*f_local */
|
||||
r += (numrep+1) *
|
||||
(flocal+ftotal);
|
||||
else
|
||||
/* r' = r + n*f_local */
|
||||
r += numrep * (flocal+ftotal);
|
||||
} else {
|
||||
if (firstn)
|
||||
/* r' = r + f_total */
|
||||
r += ftotal;
|
||||
else
|
||||
/* r' = r + n*f_local */
|
||||
r += numrep * (flocal+ftotal);
|
||||
}
|
||||
|
||||
/* bucket choose */
|
||||
if (in->size == 0) {
|
||||
reject = 1;
|
||||
goto reject;
|
||||
}
|
||||
if (flocal >= (in->size>>1) &&
|
||||
flocal > orig_tries)
|
||||
item = bucket_perm_choose(in, x, r);
|
||||
else
|
||||
item = crush_bucket_choose(in, x, r);
|
||||
BUG_ON(item >= map->max_devices);
|
||||
|
||||
/* desired type? */
|
||||
if (item < 0)
|
||||
itemtype = map->buckets[-1-item]->type;
|
||||
else
|
||||
itemtype = 0;
|
||||
dprintk(" item %d type %d\n", item, itemtype);
|
||||
|
||||
/* keep going? */
|
||||
if (itemtype != type) {
|
||||
BUG_ON(item >= 0 ||
|
||||
(-1-item) >= map->max_buckets);
|
||||
in = map->buckets[-1-item];
|
||||
retry_bucket = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* collision? */
|
||||
for (i = 0; i < outpos; i++) {
|
||||
if (out[i] == item) {
|
||||
collide = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
reject = 0;
|
||||
if (recurse_to_leaf) {
|
||||
if (item < 0) {
|
||||
if (crush_choose(map,
|
||||
map->buckets[-1-item],
|
||||
weight,
|
||||
x, outpos+1, 0,
|
||||
out2, outpos,
|
||||
firstn, 0,
|
||||
NULL) <= outpos)
|
||||
/* didn't get leaf */
|
||||
reject = 1;
|
||||
} else {
|
||||
/* we already have a leaf! */
|
||||
out2[outpos] = item;
|
||||
}
|
||||
}
|
||||
|
||||
if (!reject) {
|
||||
/* out? */
|
||||
if (itemtype == 0)
|
||||
reject = is_out(map, weight,
|
||||
item, x);
|
||||
else
|
||||
reject = 0;
|
||||
}
|
||||
|
||||
reject:
|
||||
if (reject || collide) {
|
||||
ftotal++;
|
||||
flocal++;
|
||||
|
||||
if (collide && flocal < 3)
|
||||
/* retry locally a few times */
|
||||
retry_bucket = 1;
|
||||
else if (flocal < in->size + orig_tries)
|
||||
/* exhaustive bucket search */
|
||||
retry_bucket = 1;
|
||||
else if (ftotal < 20)
|
||||
/* then retry descent */
|
||||
retry_descent = 1;
|
||||
else
|
||||
/* else give up */
|
||||
skip_rep = 1;
|
||||
dprintk(" reject %d collide %d "
|
||||
"ftotal %d flocal %d\n",
|
||||
reject, collide, ftotal,
|
||||
flocal);
|
||||
}
|
||||
} while (retry_bucket);
|
||||
} while (retry_descent);
|
||||
|
||||
if (skip_rep) {
|
||||
dprintk("skip rep\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
dprintk("CHOOSE got %d\n", item);
|
||||
out[outpos] = item;
|
||||
outpos++;
|
||||
}
|
||||
|
||||
dprintk("CHOOSE returns %d\n", outpos);
|
||||
return outpos;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* crush_do_rule - calculate a mapping with the given input and rule
|
||||
* @map: the crush_map
|
||||
* @ruleno: the rule id
|
||||
* @x: hash input
|
||||
* @result: pointer to result vector
|
||||
* @result_max: maximum result size
|
||||
* @force: force initial replica choice; -1 for none
|
||||
*/
|
||||
int crush_do_rule(struct crush_map *map,
|
||||
int ruleno, int x, int *result, int result_max,
|
||||
int force, __u32 *weight)
|
||||
{
|
||||
int result_len;
|
||||
int force_context[CRUSH_MAX_DEPTH];
|
||||
int force_pos = -1;
|
||||
int a[CRUSH_MAX_SET];
|
||||
int b[CRUSH_MAX_SET];
|
||||
int c[CRUSH_MAX_SET];
|
||||
int recurse_to_leaf;
|
||||
int *w;
|
||||
int wsize = 0;
|
||||
int *o;
|
||||
int osize;
|
||||
int *tmp;
|
||||
struct crush_rule *rule;
|
||||
int step;
|
||||
int i, j;
|
||||
int numrep;
|
||||
int firstn;
|
||||
int rc = -1;
|
||||
|
||||
BUG_ON(ruleno >= map->max_rules);
|
||||
|
||||
rule = map->rules[ruleno];
|
||||
result_len = 0;
|
||||
w = a;
|
||||
o = b;
|
||||
|
||||
/*
|
||||
* determine hierarchical context of force, if any. note
|
||||
* that this may or may not correspond to the specific types
|
||||
* referenced by the crush rule.
|
||||
*/
|
||||
if (force >= 0) {
|
||||
if (force >= map->max_devices ||
|
||||
map->device_parents[force] == 0) {
|
||||
/*dprintk("CRUSH: forcefed device dne\n");*/
|
||||
rc = -1; /* force fed device dne */
|
||||
goto out;
|
||||
}
|
||||
if (!is_out(map, weight, force, x)) {
|
||||
while (1) {
|
||||
force_context[++force_pos] = force;
|
||||
if (force >= 0)
|
||||
force = map->device_parents[force];
|
||||
else
|
||||
force = map->bucket_parents[-1-force];
|
||||
if (force == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (step = 0; step < rule->len; step++) {
|
||||
firstn = 0;
|
||||
switch (rule->steps[step].op) {
|
||||
case CRUSH_RULE_TAKE:
|
||||
w[0] = rule->steps[step].arg1;
|
||||
if (force_pos >= 0) {
|
||||
BUG_ON(force_context[force_pos] != w[0]);
|
||||
force_pos--;
|
||||
}
|
||||
wsize = 1;
|
||||
break;
|
||||
|
||||
case CRUSH_RULE_CHOOSE_LEAF_FIRSTN:
|
||||
case CRUSH_RULE_CHOOSE_FIRSTN:
|
||||
firstn = 1;
|
||||
case CRUSH_RULE_CHOOSE_LEAF_INDEP:
|
||||
case CRUSH_RULE_CHOOSE_INDEP:
|
||||
BUG_ON(wsize == 0);
|
||||
|
||||
recurse_to_leaf =
|
||||
rule->steps[step].op ==
|
||||
CRUSH_RULE_CHOOSE_LEAF_FIRSTN ||
|
||||
rule->steps[step].op ==
|
||||
CRUSH_RULE_CHOOSE_LEAF_INDEP;
|
||||
|
||||
/* reset output */
|
||||
osize = 0;
|
||||
|
||||
for (i = 0; i < wsize; i++) {
|
||||
/*
|
||||
* see CRUSH_N, CRUSH_N_MINUS macros.
|
||||
* basically, numrep <= 0 means relative to
|
||||
* the provided result_max
|
||||
*/
|
||||
numrep = rule->steps[step].arg1;
|
||||
if (numrep <= 0) {
|
||||
numrep += result_max;
|
||||
if (numrep <= 0)
|
||||
continue;
|
||||
}
|
||||
j = 0;
|
||||
if (osize == 0 && force_pos >= 0) {
|
||||
/* skip any intermediate types */
|
||||
while (force_pos &&
|
||||
force_context[force_pos] < 0 &&
|
||||
rule->steps[step].arg2 !=
|
||||
map->buckets[-1 -
|
||||
force_context[force_pos]]->type)
|
||||
force_pos--;
|
||||
o[osize] = force_context[force_pos];
|
||||
if (recurse_to_leaf)
|
||||
c[osize] = force_context[0];
|
||||
j++;
|
||||
force_pos--;
|
||||
}
|
||||
osize += crush_choose(map,
|
||||
map->buckets[-1-w[i]],
|
||||
weight,
|
||||
x, numrep,
|
||||
rule->steps[step].arg2,
|
||||
o+osize, j,
|
||||
firstn,
|
||||
recurse_to_leaf, c+osize);
|
||||
}
|
||||
|
||||
if (recurse_to_leaf)
|
||||
/* copy final _leaf_ values to output set */
|
||||
memcpy(o, c, osize*sizeof(*o));
|
||||
|
||||
/* swap t and w arrays */
|
||||
tmp = o;
|
||||
o = w;
|
||||
w = tmp;
|
||||
wsize = osize;
|
||||
break;
|
||||
|
||||
|
||||
case CRUSH_RULE_EMIT:
|
||||
for (i = 0; i < wsize && result_len < result_max; i++) {
|
||||
result[result_len] = w[i];
|
||||
result_len++;
|
||||
}
|
||||
wsize = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
}
|
||||
rc = result_len;
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef CEPH_CRUSH_MAPPER_H
|
||||
#define CEPH_CRUSH_MAPPER_H
|
||||
|
||||
/*
|
||||
* CRUSH functions for find rules and then mapping an input to an
|
||||
* output set.
|
||||
*
|
||||
* LGPL2
|
||||
*/
|
||||
|
||||
#include "crush.h"
|
||||
|
||||
extern int crush_find_rule(struct crush_map *map, int pool, int type, int size);
|
||||
extern int crush_do_rule(struct crush_map *map,
|
||||
int ruleno,
|
||||
int x, int *result, int result_max,
|
||||
int forcefeed, /* -1 for none */
|
||||
__u32 *weights);
|
||||
|
||||
#endif
|
||||
412
fs/ceph/crypto.c
412
fs/ceph/crypto.c
|
|
@ -1,412 +0,0 @@
|
|||
|
||||
#include "ceph_debug.h"
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/slab.h>
|
||||
#include <crypto/hash.h>
|
||||
|
||||
#include "crypto.h"
|
||||
#include "decode.h"
|
||||
|
||||
int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end)
|
||||
{
|
||||
if (*p + sizeof(u16) + sizeof(key->created) +
|
||||
sizeof(u16) + key->len > end)
|
||||
return -ERANGE;
|
||||
ceph_encode_16(p, key->type);
|
||||
ceph_encode_copy(p, &key->created, sizeof(key->created));
|
||||
ceph_encode_16(p, key->len);
|
||||
ceph_encode_copy(p, key->key, key->len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end)
|
||||
{
|
||||
ceph_decode_need(p, end, 2*sizeof(u16) + sizeof(key->created), bad);
|
||||
key->type = ceph_decode_16(p);
|
||||
ceph_decode_copy(p, &key->created, sizeof(key->created));
|
||||
key->len = ceph_decode_16(p);
|
||||
ceph_decode_need(p, end, key->len, bad);
|
||||
key->key = kmalloc(key->len, GFP_NOFS);
|
||||
if (!key->key)
|
||||
return -ENOMEM;
|
||||
ceph_decode_copy(p, key->key, key->len);
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
dout("failed to decode crypto key\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey)
|
||||
{
|
||||
int inlen = strlen(inkey);
|
||||
int blen = inlen * 3 / 4;
|
||||
void *buf, *p;
|
||||
int ret;
|
||||
|
||||
dout("crypto_key_unarmor %s\n", inkey);
|
||||
buf = kmalloc(blen, GFP_NOFS);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
blen = ceph_unarmor(buf, inkey, inkey+inlen);
|
||||
if (blen < 0) {
|
||||
kfree(buf);
|
||||
return blen;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
ret = ceph_crypto_key_decode(key, &p, p + blen);
|
||||
kfree(buf);
|
||||
if (ret)
|
||||
return ret;
|
||||
dout("crypto_key_unarmor key %p type %d len %d\n", key,
|
||||
key->type, key->len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define AES_KEY_SIZE 16
|
||||
|
||||
static struct crypto_blkcipher *ceph_crypto_alloc_cipher(void)
|
||||
{
|
||||
return crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
|
||||
}
|
||||
|
||||
static const u8 *aes_iv = (u8 *)CEPH_AES_IV;
|
||||
|
||||
static int ceph_aes_encrypt(const void *key, int key_len,
|
||||
void *dst, size_t *dst_len,
|
||||
const void *src, size_t src_len)
|
||||
{
|
||||
struct scatterlist sg_in[2], sg_out[1];
|
||||
struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
|
||||
struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
|
||||
int ret;
|
||||
void *iv;
|
||||
int ivsize;
|
||||
size_t zero_padding = (0x10 - (src_len & 0x0f));
|
||||
char pad[16];
|
||||
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
|
||||
memset(pad, zero_padding, zero_padding);
|
||||
|
||||
*dst_len = src_len + zero_padding;
|
||||
|
||||
crypto_blkcipher_setkey((void *)tfm, key, key_len);
|
||||
sg_init_table(sg_in, 2);
|
||||
sg_set_buf(&sg_in[0], src, src_len);
|
||||
sg_set_buf(&sg_in[1], pad, zero_padding);
|
||||
sg_init_table(sg_out, 1);
|
||||
sg_set_buf(sg_out, dst, *dst_len);
|
||||
iv = crypto_blkcipher_crt(tfm)->iv;
|
||||
ivsize = crypto_blkcipher_ivsize(tfm);
|
||||
|
||||
memcpy(iv, aes_iv, ivsize);
|
||||
/*
|
||||
print_hex_dump(KERN_ERR, "enc key: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
key, key_len, 1);
|
||||
print_hex_dump(KERN_ERR, "enc src: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
src, src_len, 1);
|
||||
print_hex_dump(KERN_ERR, "enc pad: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
pad, zero_padding, 1);
|
||||
*/
|
||||
ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
|
||||
src_len + zero_padding);
|
||||
crypto_free_blkcipher(tfm);
|
||||
if (ret < 0)
|
||||
pr_err("ceph_aes_crypt failed %d\n", ret);
|
||||
/*
|
||||
print_hex_dump(KERN_ERR, "enc out: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
dst, *dst_len, 1);
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ceph_aes_encrypt2(const void *key, int key_len, void *dst,
|
||||
size_t *dst_len,
|
||||
const void *src1, size_t src1_len,
|
||||
const void *src2, size_t src2_len)
|
||||
{
|
||||
struct scatterlist sg_in[3], sg_out[1];
|
||||
struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
|
||||
struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
|
||||
int ret;
|
||||
void *iv;
|
||||
int ivsize;
|
||||
size_t zero_padding = (0x10 - ((src1_len + src2_len) & 0x0f));
|
||||
char pad[16];
|
||||
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
|
||||
memset(pad, zero_padding, zero_padding);
|
||||
|
||||
*dst_len = src1_len + src2_len + zero_padding;
|
||||
|
||||
crypto_blkcipher_setkey((void *)tfm, key, key_len);
|
||||
sg_init_table(sg_in, 3);
|
||||
sg_set_buf(&sg_in[0], src1, src1_len);
|
||||
sg_set_buf(&sg_in[1], src2, src2_len);
|
||||
sg_set_buf(&sg_in[2], pad, zero_padding);
|
||||
sg_init_table(sg_out, 1);
|
||||
sg_set_buf(sg_out, dst, *dst_len);
|
||||
iv = crypto_blkcipher_crt(tfm)->iv;
|
||||
ivsize = crypto_blkcipher_ivsize(tfm);
|
||||
|
||||
memcpy(iv, aes_iv, ivsize);
|
||||
/*
|
||||
print_hex_dump(KERN_ERR, "enc key: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
key, key_len, 1);
|
||||
print_hex_dump(KERN_ERR, "enc src1: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
src1, src1_len, 1);
|
||||
print_hex_dump(KERN_ERR, "enc src2: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
src2, src2_len, 1);
|
||||
print_hex_dump(KERN_ERR, "enc pad: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
pad, zero_padding, 1);
|
||||
*/
|
||||
ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
|
||||
src1_len + src2_len + zero_padding);
|
||||
crypto_free_blkcipher(tfm);
|
||||
if (ret < 0)
|
||||
pr_err("ceph_aes_crypt2 failed %d\n", ret);
|
||||
/*
|
||||
print_hex_dump(KERN_ERR, "enc out: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
dst, *dst_len, 1);
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ceph_aes_decrypt(const void *key, int key_len,
|
||||
void *dst, size_t *dst_len,
|
||||
const void *src, size_t src_len)
|
||||
{
|
||||
struct scatterlist sg_in[1], sg_out[2];
|
||||
struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
|
||||
struct blkcipher_desc desc = { .tfm = tfm };
|
||||
char pad[16];
|
||||
void *iv;
|
||||
int ivsize;
|
||||
int ret;
|
||||
int last_byte;
|
||||
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
|
||||
crypto_blkcipher_setkey((void *)tfm, key, key_len);
|
||||
sg_init_table(sg_in, 1);
|
||||
sg_init_table(sg_out, 2);
|
||||
sg_set_buf(sg_in, src, src_len);
|
||||
sg_set_buf(&sg_out[0], dst, *dst_len);
|
||||
sg_set_buf(&sg_out[1], pad, sizeof(pad));
|
||||
|
||||
iv = crypto_blkcipher_crt(tfm)->iv;
|
||||
ivsize = crypto_blkcipher_ivsize(tfm);
|
||||
|
||||
memcpy(iv, aes_iv, ivsize);
|
||||
|
||||
/*
|
||||
print_hex_dump(KERN_ERR, "dec key: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
key, key_len, 1);
|
||||
print_hex_dump(KERN_ERR, "dec in: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
src, src_len, 1);
|
||||
*/
|
||||
|
||||
ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len);
|
||||
crypto_free_blkcipher(tfm);
|
||||
if (ret < 0) {
|
||||
pr_err("ceph_aes_decrypt failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (src_len <= *dst_len)
|
||||
last_byte = ((char *)dst)[src_len - 1];
|
||||
else
|
||||
last_byte = pad[src_len - *dst_len - 1];
|
||||
if (last_byte <= 16 && src_len >= last_byte) {
|
||||
*dst_len = src_len - last_byte;
|
||||
} else {
|
||||
pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
|
||||
last_byte, (int)src_len);
|
||||
return -EPERM; /* bad padding */
|
||||
}
|
||||
/*
|
||||
print_hex_dump(KERN_ERR, "dec out: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
dst, *dst_len, 1);
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ceph_aes_decrypt2(const void *key, int key_len,
|
||||
void *dst1, size_t *dst1_len,
|
||||
void *dst2, size_t *dst2_len,
|
||||
const void *src, size_t src_len)
|
||||
{
|
||||
struct scatterlist sg_in[1], sg_out[3];
|
||||
struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
|
||||
struct blkcipher_desc desc = { .tfm = tfm };
|
||||
char pad[16];
|
||||
void *iv;
|
||||
int ivsize;
|
||||
int ret;
|
||||
int last_byte;
|
||||
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
|
||||
sg_init_table(sg_in, 1);
|
||||
sg_set_buf(sg_in, src, src_len);
|
||||
sg_init_table(sg_out, 3);
|
||||
sg_set_buf(&sg_out[0], dst1, *dst1_len);
|
||||
sg_set_buf(&sg_out[1], dst2, *dst2_len);
|
||||
sg_set_buf(&sg_out[2], pad, sizeof(pad));
|
||||
|
||||
crypto_blkcipher_setkey((void *)tfm, key, key_len);
|
||||
iv = crypto_blkcipher_crt(tfm)->iv;
|
||||
ivsize = crypto_blkcipher_ivsize(tfm);
|
||||
|
||||
memcpy(iv, aes_iv, ivsize);
|
||||
|
||||
/*
|
||||
print_hex_dump(KERN_ERR, "dec key: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
key, key_len, 1);
|
||||
print_hex_dump(KERN_ERR, "dec in: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
src, src_len, 1);
|
||||
*/
|
||||
|
||||
ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len);
|
||||
crypto_free_blkcipher(tfm);
|
||||
if (ret < 0) {
|
||||
pr_err("ceph_aes_decrypt failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (src_len <= *dst1_len)
|
||||
last_byte = ((char *)dst1)[src_len - 1];
|
||||
else if (src_len <= *dst1_len + *dst2_len)
|
||||
last_byte = ((char *)dst2)[src_len - *dst1_len - 1];
|
||||
else
|
||||
last_byte = pad[src_len - *dst1_len - *dst2_len - 1];
|
||||
if (last_byte <= 16 && src_len >= last_byte) {
|
||||
src_len -= last_byte;
|
||||
} else {
|
||||
pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
|
||||
last_byte, (int)src_len);
|
||||
return -EPERM; /* bad padding */
|
||||
}
|
||||
|
||||
if (src_len < *dst1_len) {
|
||||
*dst1_len = src_len;
|
||||
*dst2_len = 0;
|
||||
} else {
|
||||
*dst2_len = src_len - *dst1_len;
|
||||
}
|
||||
/*
|
||||
print_hex_dump(KERN_ERR, "dec out1: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
dst1, *dst1_len, 1);
|
||||
print_hex_dump(KERN_ERR, "dec out2: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
dst2, *dst2_len, 1);
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ceph_decrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
|
||||
const void *src, size_t src_len)
|
||||
{
|
||||
switch (secret->type) {
|
||||
case CEPH_CRYPTO_NONE:
|
||||
if (*dst_len < src_len)
|
||||
return -ERANGE;
|
||||
memcpy(dst, src, src_len);
|
||||
*dst_len = src_len;
|
||||
return 0;
|
||||
|
||||
case CEPH_CRYPTO_AES:
|
||||
return ceph_aes_decrypt(secret->key, secret->len, dst,
|
||||
dst_len, src, src_len);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int ceph_decrypt2(struct ceph_crypto_key *secret,
|
||||
void *dst1, size_t *dst1_len,
|
||||
void *dst2, size_t *dst2_len,
|
||||
const void *src, size_t src_len)
|
||||
{
|
||||
size_t t;
|
||||
|
||||
switch (secret->type) {
|
||||
case CEPH_CRYPTO_NONE:
|
||||
if (*dst1_len + *dst2_len < src_len)
|
||||
return -ERANGE;
|
||||
t = min(*dst1_len, src_len);
|
||||
memcpy(dst1, src, t);
|
||||
*dst1_len = t;
|
||||
src += t;
|
||||
src_len -= t;
|
||||
if (src_len) {
|
||||
t = min(*dst2_len, src_len);
|
||||
memcpy(dst2, src, t);
|
||||
*dst2_len = t;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case CEPH_CRYPTO_AES:
|
||||
return ceph_aes_decrypt2(secret->key, secret->len,
|
||||
dst1, dst1_len, dst2, dst2_len,
|
||||
src, src_len);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int ceph_encrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
|
||||
const void *src, size_t src_len)
|
||||
{
|
||||
switch (secret->type) {
|
||||
case CEPH_CRYPTO_NONE:
|
||||
if (*dst_len < src_len)
|
||||
return -ERANGE;
|
||||
memcpy(dst, src, src_len);
|
||||
*dst_len = src_len;
|
||||
return 0;
|
||||
|
||||
case CEPH_CRYPTO_AES:
|
||||
return ceph_aes_encrypt(secret->key, secret->len, dst,
|
||||
dst_len, src, src_len);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
|
||||
const void *src1, size_t src1_len,
|
||||
const void *src2, size_t src2_len)
|
||||
{
|
||||
switch (secret->type) {
|
||||
case CEPH_CRYPTO_NONE:
|
||||
if (*dst_len < src1_len + src2_len)
|
||||
return -ERANGE;
|
||||
memcpy(dst, src1, src1_len);
|
||||
memcpy(dst + src1_len, src2, src2_len);
|
||||
*dst_len = src1_len + src2_len;
|
||||
return 0;
|
||||
|
||||
case CEPH_CRYPTO_AES:
|
||||
return ceph_aes_encrypt2(secret->key, secret->len, dst, dst_len,
|
||||
src1, src1_len, src2, src2_len);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
#ifndef _FS_CEPH_CRYPTO_H
|
||||
#define _FS_CEPH_CRYPTO_H
|
||||
|
||||
#include "types.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/*
|
||||
* cryptographic secret
|
||||
*/
|
||||
struct ceph_crypto_key {
|
||||
int type;
|
||||
struct ceph_timespec created;
|
||||
int len;
|
||||
void *key;
|
||||
};
|
||||
|
||||
static inline void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
|
||||
{
|
||||
kfree(key->key);
|
||||
}
|
||||
|
||||
extern int ceph_crypto_key_encode(struct ceph_crypto_key *key,
|
||||
void **p, void *end);
|
||||
extern int ceph_crypto_key_decode(struct ceph_crypto_key *key,
|
||||
void **p, void *end);
|
||||
extern int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *in);
|
||||
|
||||
/* crypto.c */
|
||||
extern int ceph_decrypt(struct ceph_crypto_key *secret,
|
||||
void *dst, size_t *dst_len,
|
||||
const void *src, size_t src_len);
|
||||
extern int ceph_encrypt(struct ceph_crypto_key *secret,
|
||||
void *dst, size_t *dst_len,
|
||||
const void *src, size_t src_len);
|
||||
extern int ceph_decrypt2(struct ceph_crypto_key *secret,
|
||||
void *dst1, size_t *dst1_len,
|
||||
void *dst2, size_t *dst2_len,
|
||||
const void *src, size_t src_len);
|
||||
extern int ceph_encrypt2(struct ceph_crypto_key *secret,
|
||||
void *dst, size_t *dst_len,
|
||||
const void *src1, size_t src1_len,
|
||||
const void *src2, size_t src2_len);
|
||||
|
||||
/* armor.c */
|
||||
extern int ceph_armor(char *dst, const char *src, const char *end);
|
||||
extern int ceph_unarmor(char *dst, const char *src, const char *end);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "ceph_debug.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -7,143 +7,48 @@
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include "super.h"
|
||||
#include "mds_client.h"
|
||||
#include "mon_client.h"
|
||||
#include "auth.h"
|
||||
#include <linux/ceph/libceph.h>
|
||||
#include <linux/ceph/mon_client.h>
|
||||
#include <linux/ceph/auth.h>
|
||||
#include <linux/ceph/debugfs.h>
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
/*
|
||||
* Implement /sys/kernel/debug/ceph fun
|
||||
*
|
||||
* /sys/kernel/debug/ceph/client* - an instance of the ceph client
|
||||
* .../osdmap - current osdmap
|
||||
* .../mdsmap - current mdsmap
|
||||
* .../monmap - current monmap
|
||||
* .../osdc - active osd requests
|
||||
* .../mdsc - active mds requests
|
||||
* .../monc - mon client state
|
||||
* .../dentry_lru - dump contents of dentry lru
|
||||
* .../caps - expose cap (reservation) stats
|
||||
* .../bdi - symlink to ../../bdi/something
|
||||
*/
|
||||
|
||||
static struct dentry *ceph_debugfs_dir;
|
||||
|
||||
static int monmap_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int i;
|
||||
struct ceph_client *client = s->private;
|
||||
|
||||
if (client->monc.monmap == NULL)
|
||||
return 0;
|
||||
|
||||
seq_printf(s, "epoch %d\n", client->monc.monmap->epoch);
|
||||
for (i = 0; i < client->monc.monmap->num_mon; i++) {
|
||||
struct ceph_entity_inst *inst =
|
||||
&client->monc.monmap->mon_inst[i];
|
||||
|
||||
seq_printf(s, "\t%s%lld\t%s\n",
|
||||
ENTITY_NAME(inst->name),
|
||||
pr_addr(&inst->addr.in_addr));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#include "super.h"
|
||||
#include "mds_client.h"
|
||||
|
||||
static int mdsmap_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int i;
|
||||
struct ceph_client *client = s->private;
|
||||
struct ceph_fs_client *fsc = s->private;
|
||||
|
||||
if (client->mdsc.mdsmap == NULL)
|
||||
if (fsc->mdsc == NULL || fsc->mdsc->mdsmap == NULL)
|
||||
return 0;
|
||||
seq_printf(s, "epoch %d\n", client->mdsc.mdsmap->m_epoch);
|
||||
seq_printf(s, "root %d\n", client->mdsc.mdsmap->m_root);
|
||||
seq_printf(s, "epoch %d\n", fsc->mdsc->mdsmap->m_epoch);
|
||||
seq_printf(s, "root %d\n", fsc->mdsc->mdsmap->m_root);
|
||||
seq_printf(s, "session_timeout %d\n",
|
||||
client->mdsc.mdsmap->m_session_timeout);
|
||||
fsc->mdsc->mdsmap->m_session_timeout);
|
||||
seq_printf(s, "session_autoclose %d\n",
|
||||
client->mdsc.mdsmap->m_session_autoclose);
|
||||
for (i = 0; i < client->mdsc.mdsmap->m_max_mds; i++) {
|
||||
fsc->mdsc->mdsmap->m_session_autoclose);
|
||||
for (i = 0; i < fsc->mdsc->mdsmap->m_max_mds; i++) {
|
||||
struct ceph_entity_addr *addr =
|
||||
&client->mdsc.mdsmap->m_info[i].addr;
|
||||
int state = client->mdsc.mdsmap->m_info[i].state;
|
||||
&fsc->mdsc->mdsmap->m_info[i].addr;
|
||||
int state = fsc->mdsc->mdsmap->m_info[i].state;
|
||||
|
||||
seq_printf(s, "\tmds%d\t%s\t(%s)\n", i, pr_addr(&addr->in_addr),
|
||||
seq_printf(s, "\tmds%d\t%s\t(%s)\n", i,
|
||||
ceph_pr_addr(&addr->in_addr),
|
||||
ceph_mds_state_name(state));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int osdmap_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int i;
|
||||
struct ceph_client *client = s->private;
|
||||
struct rb_node *n;
|
||||
|
||||
if (client->osdc.osdmap == NULL)
|
||||
return 0;
|
||||
seq_printf(s, "epoch %d\n", client->osdc.osdmap->epoch);
|
||||
seq_printf(s, "flags%s%s\n",
|
||||
(client->osdc.osdmap->flags & CEPH_OSDMAP_NEARFULL) ?
|
||||
" NEARFULL" : "",
|
||||
(client->osdc.osdmap->flags & CEPH_OSDMAP_FULL) ?
|
||||
" FULL" : "");
|
||||
for (n = rb_first(&client->osdc.osdmap->pg_pools); n; n = rb_next(n)) {
|
||||
struct ceph_pg_pool_info *pool =
|
||||
rb_entry(n, struct ceph_pg_pool_info, node);
|
||||
seq_printf(s, "pg_pool %d pg_num %d / %d, lpg_num %d / %d\n",
|
||||
pool->id, pool->v.pg_num, pool->pg_num_mask,
|
||||
pool->v.lpg_num, pool->lpg_num_mask);
|
||||
}
|
||||
for (i = 0; i < client->osdc.osdmap->max_osd; i++) {
|
||||
struct ceph_entity_addr *addr =
|
||||
&client->osdc.osdmap->osd_addr[i];
|
||||
int state = client->osdc.osdmap->osd_state[i];
|
||||
char sb[64];
|
||||
|
||||
seq_printf(s, "\tosd%d\t%s\t%3d%%\t(%s)\n",
|
||||
i, pr_addr(&addr->in_addr),
|
||||
((client->osdc.osdmap->osd_weight[i]*100) >> 16),
|
||||
ceph_osdmap_state_str(sb, sizeof(sb), state));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int monc_show(struct seq_file *s, void *p)
|
||||
{
|
||||
struct ceph_client *client = s->private;
|
||||
struct ceph_mon_generic_request *req;
|
||||
struct ceph_mon_client *monc = &client->monc;
|
||||
struct rb_node *rp;
|
||||
|
||||
mutex_lock(&monc->mutex);
|
||||
|
||||
if (monc->have_mdsmap)
|
||||
seq_printf(s, "have mdsmap %u\n", (unsigned)monc->have_mdsmap);
|
||||
if (monc->have_osdmap)
|
||||
seq_printf(s, "have osdmap %u\n", (unsigned)monc->have_osdmap);
|
||||
if (monc->want_next_osdmap)
|
||||
seq_printf(s, "want next osdmap\n");
|
||||
|
||||
for (rp = rb_first(&monc->generic_request_tree); rp; rp = rb_next(rp)) {
|
||||
__u16 op;
|
||||
req = rb_entry(rp, struct ceph_mon_generic_request, node);
|
||||
op = le16_to_cpu(req->request->hdr.type);
|
||||
if (op == CEPH_MSG_STATFS)
|
||||
seq_printf(s, "%lld statfs\n", req->tid);
|
||||
else
|
||||
seq_printf(s, "%lld unknown\n", req->tid);
|
||||
}
|
||||
|
||||
mutex_unlock(&monc->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* mdsc debugfs
|
||||
*/
|
||||
static int mdsc_show(struct seq_file *s, void *p)
|
||||
{
|
||||
struct ceph_client *client = s->private;
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = s->private;
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct ceph_mds_request *req;
|
||||
struct rb_node *rp;
|
||||
int pathlen;
|
||||
|
|
@ -214,61 +119,12 @@ static int mdsc_show(struct seq_file *s, void *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int osdc_show(struct seq_file *s, void *pp)
|
||||
{
|
||||
struct ceph_client *client = s->private;
|
||||
struct ceph_osd_client *osdc = &client->osdc;
|
||||
struct rb_node *p;
|
||||
|
||||
mutex_lock(&osdc->request_mutex);
|
||||
for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
|
||||
struct ceph_osd_request *req;
|
||||
struct ceph_osd_request_head *head;
|
||||
struct ceph_osd_op *op;
|
||||
int num_ops;
|
||||
int opcode, olen;
|
||||
int i;
|
||||
|
||||
req = rb_entry(p, struct ceph_osd_request, r_node);
|
||||
|
||||
seq_printf(s, "%lld\tosd%d\t%d.%x\t", req->r_tid,
|
||||
req->r_osd ? req->r_osd->o_osd : -1,
|
||||
le32_to_cpu(req->r_pgid.pool),
|
||||
le16_to_cpu(req->r_pgid.ps));
|
||||
|
||||
head = req->r_request->front.iov_base;
|
||||
op = (void *)(head + 1);
|
||||
|
||||
num_ops = le16_to_cpu(head->num_ops);
|
||||
olen = le32_to_cpu(head->object_len);
|
||||
seq_printf(s, "%.*s", olen,
|
||||
(const char *)(head->ops + num_ops));
|
||||
|
||||
if (req->r_reassert_version.epoch)
|
||||
seq_printf(s, "\t%u'%llu",
|
||||
(unsigned)le32_to_cpu(req->r_reassert_version.epoch),
|
||||
le64_to_cpu(req->r_reassert_version.version));
|
||||
else
|
||||
seq_printf(s, "\t");
|
||||
|
||||
for (i = 0; i < num_ops; i++) {
|
||||
opcode = le16_to_cpu(op->op);
|
||||
seq_printf(s, "\t%s", ceph_osd_op_name(opcode));
|
||||
op++;
|
||||
}
|
||||
|
||||
seq_printf(s, "\n");
|
||||
}
|
||||
mutex_unlock(&osdc->request_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int caps_show(struct seq_file *s, void *p)
|
||||
{
|
||||
struct ceph_client *client = s->private;
|
||||
struct ceph_fs_client *fsc = s->private;
|
||||
int total, avail, used, reserved, min;
|
||||
|
||||
ceph_reservation_status(client, &total, &avail, &used, &reserved, &min);
|
||||
ceph_reservation_status(fsc, &total, &avail, &used, &reserved, &min);
|
||||
seq_printf(s, "total\t\t%d\n"
|
||||
"avail\t\t%d\n"
|
||||
"used\t\t%d\n"
|
||||
|
|
@ -280,8 +136,8 @@ static int caps_show(struct seq_file *s, void *p)
|
|||
|
||||
static int dentry_lru_show(struct seq_file *s, void *ptr)
|
||||
{
|
||||
struct ceph_client *client = s->private;
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = s->private;
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct ceph_dentry_info *di;
|
||||
|
||||
spin_lock(&mdsc->dentry_lru_lock);
|
||||
|
|
@ -295,199 +151,124 @@ static int dentry_lru_show(struct seq_file *s, void *ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define DEFINE_SHOW_FUNC(name) \
|
||||
static int name##_open(struct inode *inode, struct file *file) \
|
||||
{ \
|
||||
struct seq_file *sf; \
|
||||
int ret; \
|
||||
\
|
||||
ret = single_open(file, name, NULL); \
|
||||
sf = file->private_data; \
|
||||
sf->private = inode->i_private; \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations name##_fops = { \
|
||||
.open = name##_open, \
|
||||
.read = seq_read, \
|
||||
.llseek = seq_lseek, \
|
||||
.release = single_release, \
|
||||
};
|
||||
CEPH_DEFINE_SHOW_FUNC(mdsmap_show)
|
||||
CEPH_DEFINE_SHOW_FUNC(mdsc_show)
|
||||
CEPH_DEFINE_SHOW_FUNC(caps_show)
|
||||
CEPH_DEFINE_SHOW_FUNC(dentry_lru_show)
|
||||
|
||||
DEFINE_SHOW_FUNC(monmap_show)
|
||||
DEFINE_SHOW_FUNC(mdsmap_show)
|
||||
DEFINE_SHOW_FUNC(osdmap_show)
|
||||
DEFINE_SHOW_FUNC(monc_show)
|
||||
DEFINE_SHOW_FUNC(mdsc_show)
|
||||
DEFINE_SHOW_FUNC(osdc_show)
|
||||
DEFINE_SHOW_FUNC(dentry_lru_show)
|
||||
DEFINE_SHOW_FUNC(caps_show)
|
||||
|
||||
/*
|
||||
* debugfs
|
||||
*/
|
||||
static int congestion_kb_set(void *data, u64 val)
|
||||
{
|
||||
struct ceph_client *client = (struct ceph_client *)data;
|
||||
|
||||
if (client)
|
||||
client->mount_args->congestion_kb = (int)val;
|
||||
struct ceph_fs_client *fsc = (struct ceph_fs_client *)data;
|
||||
|
||||
fsc->mount_options->congestion_kb = (int)val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int congestion_kb_get(void *data, u64 *val)
|
||||
{
|
||||
struct ceph_client *client = (struct ceph_client *)data;
|
||||
|
||||
if (client)
|
||||
*val = (u64)client->mount_args->congestion_kb;
|
||||
struct ceph_fs_client *fsc = (struct ceph_fs_client *)data;
|
||||
|
||||
*val = (u64)fsc->mount_options->congestion_kb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(congestion_kb_fops, congestion_kb_get,
|
||||
congestion_kb_set, "%llu\n");
|
||||
|
||||
int __init ceph_debugfs_init(void)
|
||||
|
||||
void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc)
|
||||
{
|
||||
ceph_debugfs_dir = debugfs_create_dir("ceph", NULL);
|
||||
if (!ceph_debugfs_dir)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
dout("ceph_fs_debugfs_cleanup\n");
|
||||
debugfs_remove(fsc->debugfs_bdi);
|
||||
debugfs_remove(fsc->debugfs_congestion_kb);
|
||||
debugfs_remove(fsc->debugfs_mdsmap);
|
||||
debugfs_remove(fsc->debugfs_caps);
|
||||
debugfs_remove(fsc->debugfs_mdsc);
|
||||
debugfs_remove(fsc->debugfs_dentry_lru);
|
||||
}
|
||||
|
||||
void ceph_debugfs_cleanup(void)
|
||||
int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
|
||||
{
|
||||
debugfs_remove(ceph_debugfs_dir);
|
||||
}
|
||||
char name[100];
|
||||
int err = -ENOMEM;
|
||||
|
||||
int ceph_debugfs_client_init(struct ceph_client *client)
|
||||
{
|
||||
int ret = 0;
|
||||
char name[80];
|
||||
|
||||
snprintf(name, sizeof(name), "%pU.client%lld", &client->fsid,
|
||||
client->monc.auth->global_id);
|
||||
|
||||
client->debugfs_dir = debugfs_create_dir(name, ceph_debugfs_dir);
|
||||
if (!client->debugfs_dir)
|
||||
goto out;
|
||||
|
||||
client->monc.debugfs_file = debugfs_create_file("monc",
|
||||
0600,
|
||||
client->debugfs_dir,
|
||||
client,
|
||||
&monc_show_fops);
|
||||
if (!client->monc.debugfs_file)
|
||||
goto out;
|
||||
|
||||
client->mdsc.debugfs_file = debugfs_create_file("mdsc",
|
||||
0600,
|
||||
client->debugfs_dir,
|
||||
client,
|
||||
&mdsc_show_fops);
|
||||
if (!client->mdsc.debugfs_file)
|
||||
goto out;
|
||||
|
||||
client->osdc.debugfs_file = debugfs_create_file("osdc",
|
||||
0600,
|
||||
client->debugfs_dir,
|
||||
client,
|
||||
&osdc_show_fops);
|
||||
if (!client->osdc.debugfs_file)
|
||||
goto out;
|
||||
|
||||
client->debugfs_monmap = debugfs_create_file("monmap",
|
||||
0600,
|
||||
client->debugfs_dir,
|
||||
client,
|
||||
&monmap_show_fops);
|
||||
if (!client->debugfs_monmap)
|
||||
goto out;
|
||||
|
||||
client->debugfs_mdsmap = debugfs_create_file("mdsmap",
|
||||
0600,
|
||||
client->debugfs_dir,
|
||||
client,
|
||||
&mdsmap_show_fops);
|
||||
if (!client->debugfs_mdsmap)
|
||||
goto out;
|
||||
|
||||
client->debugfs_osdmap = debugfs_create_file("osdmap",
|
||||
0600,
|
||||
client->debugfs_dir,
|
||||
client,
|
||||
&osdmap_show_fops);
|
||||
if (!client->debugfs_osdmap)
|
||||
goto out;
|
||||
|
||||
client->debugfs_dentry_lru = debugfs_create_file("dentry_lru",
|
||||
0600,
|
||||
client->debugfs_dir,
|
||||
client,
|
||||
&dentry_lru_show_fops);
|
||||
if (!client->debugfs_dentry_lru)
|
||||
goto out;
|
||||
|
||||
client->debugfs_caps = debugfs_create_file("caps",
|
||||
0400,
|
||||
client->debugfs_dir,
|
||||
client,
|
||||
&caps_show_fops);
|
||||
if (!client->debugfs_caps)
|
||||
goto out;
|
||||
|
||||
client->debugfs_congestion_kb =
|
||||
dout("ceph_fs_debugfs_init\n");
|
||||
fsc->debugfs_congestion_kb =
|
||||
debugfs_create_file("writeback_congestion_kb",
|
||||
0600,
|
||||
client->debugfs_dir,
|
||||
client,
|
||||
fsc->client->debugfs_dir,
|
||||
fsc,
|
||||
&congestion_kb_fops);
|
||||
if (!client->debugfs_congestion_kb)
|
||||
if (!fsc->debugfs_congestion_kb)
|
||||
goto out;
|
||||
|
||||
sprintf(name, "../../bdi/%s", dev_name(client->sb->s_bdi->dev));
|
||||
client->debugfs_bdi = debugfs_create_symlink("bdi", client->debugfs_dir,
|
||||
name);
|
||||
dout("a\n");
|
||||
|
||||
snprintf(name, sizeof(name), "../../bdi/%s",
|
||||
dev_name(fsc->backing_dev_info.dev));
|
||||
fsc->debugfs_bdi =
|
||||
debugfs_create_symlink("bdi",
|
||||
fsc->client->debugfs_dir,
|
||||
name);
|
||||
if (!fsc->debugfs_bdi)
|
||||
goto out;
|
||||
|
||||
dout("b\n");
|
||||
fsc->debugfs_mdsmap = debugfs_create_file("mdsmap",
|
||||
0600,
|
||||
fsc->client->debugfs_dir,
|
||||
fsc,
|
||||
&mdsmap_show_fops);
|
||||
if (!fsc->debugfs_mdsmap)
|
||||
goto out;
|
||||
|
||||
dout("ca\n");
|
||||
fsc->debugfs_mdsc = debugfs_create_file("mdsc",
|
||||
0600,
|
||||
fsc->client->debugfs_dir,
|
||||
fsc,
|
||||
&mdsc_show_fops);
|
||||
if (!fsc->debugfs_mdsc)
|
||||
goto out;
|
||||
|
||||
dout("da\n");
|
||||
fsc->debugfs_caps = debugfs_create_file("caps",
|
||||
0400,
|
||||
fsc->client->debugfs_dir,
|
||||
fsc,
|
||||
&caps_show_fops);
|
||||
if (!fsc->debugfs_caps)
|
||||
goto out;
|
||||
|
||||
dout("ea\n");
|
||||
fsc->debugfs_dentry_lru = debugfs_create_file("dentry_lru",
|
||||
0600,
|
||||
fsc->client->debugfs_dir,
|
||||
fsc,
|
||||
&dentry_lru_show_fops);
|
||||
if (!fsc->debugfs_dentry_lru)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
ceph_debugfs_client_cleanup(client);
|
||||
return ret;
|
||||
ceph_fs_debugfs_cleanup(fsc);
|
||||
return err;
|
||||
}
|
||||
|
||||
void ceph_debugfs_client_cleanup(struct ceph_client *client)
|
||||
{
|
||||
debugfs_remove(client->debugfs_bdi);
|
||||
debugfs_remove(client->debugfs_caps);
|
||||
debugfs_remove(client->debugfs_dentry_lru);
|
||||
debugfs_remove(client->debugfs_osdmap);
|
||||
debugfs_remove(client->debugfs_mdsmap);
|
||||
debugfs_remove(client->debugfs_monmap);
|
||||
debugfs_remove(client->osdc.debugfs_file);
|
||||
debugfs_remove(client->mdsc.debugfs_file);
|
||||
debugfs_remove(client->monc.debugfs_file);
|
||||
debugfs_remove(client->debugfs_congestion_kb);
|
||||
debugfs_remove(client->debugfs_dir);
|
||||
}
|
||||
|
||||
#else /* CONFIG_DEBUG_FS */
|
||||
|
||||
int __init ceph_debugfs_init(void)
|
||||
int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ceph_debugfs_cleanup(void)
|
||||
{
|
||||
}
|
||||
|
||||
int ceph_debugfs_client_init(struct ceph_client *client)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ceph_debugfs_client_cleanup(struct ceph_client *client)
|
||||
void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
201
fs/ceph/decode.h
201
fs/ceph/decode.h
|
|
@ -1,201 +0,0 @@
|
|||
#ifndef __CEPH_DECODE_H
|
||||
#define __CEPH_DECODE_H
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/*
|
||||
* in all cases,
|
||||
* void **p pointer to position pointer
|
||||
* void *end pointer to end of buffer (last byte + 1)
|
||||
*/
|
||||
|
||||
static inline u64 ceph_decode_64(void **p)
|
||||
{
|
||||
u64 v = get_unaligned_le64(*p);
|
||||
*p += sizeof(u64);
|
||||
return v;
|
||||
}
|
||||
static inline u32 ceph_decode_32(void **p)
|
||||
{
|
||||
u32 v = get_unaligned_le32(*p);
|
||||
*p += sizeof(u32);
|
||||
return v;
|
||||
}
|
||||
static inline u16 ceph_decode_16(void **p)
|
||||
{
|
||||
u16 v = get_unaligned_le16(*p);
|
||||
*p += sizeof(u16);
|
||||
return v;
|
||||
}
|
||||
static inline u8 ceph_decode_8(void **p)
|
||||
{
|
||||
u8 v = *(u8 *)*p;
|
||||
(*p)++;
|
||||
return v;
|
||||
}
|
||||
static inline void ceph_decode_copy(void **p, void *pv, size_t n)
|
||||
{
|
||||
memcpy(pv, *p, n);
|
||||
*p += n;
|
||||
}
|
||||
|
||||
/*
|
||||
* bounds check input.
|
||||
*/
|
||||
#define ceph_decode_need(p, end, n, bad) \
|
||||
do { \
|
||||
if (unlikely(*(p) + (n) > (end))) \
|
||||
goto bad; \
|
||||
} while (0)
|
||||
|
||||
#define ceph_decode_64_safe(p, end, v, bad) \
|
||||
do { \
|
||||
ceph_decode_need(p, end, sizeof(u64), bad); \
|
||||
v = ceph_decode_64(p); \
|
||||
} while (0)
|
||||
#define ceph_decode_32_safe(p, end, v, bad) \
|
||||
do { \
|
||||
ceph_decode_need(p, end, sizeof(u32), bad); \
|
||||
v = ceph_decode_32(p); \
|
||||
} while (0)
|
||||
#define ceph_decode_16_safe(p, end, v, bad) \
|
||||
do { \
|
||||
ceph_decode_need(p, end, sizeof(u16), bad); \
|
||||
v = ceph_decode_16(p); \
|
||||
} while (0)
|
||||
#define ceph_decode_8_safe(p, end, v, bad) \
|
||||
do { \
|
||||
ceph_decode_need(p, end, sizeof(u8), bad); \
|
||||
v = ceph_decode_8(p); \
|
||||
} while (0)
|
||||
|
||||
#define ceph_decode_copy_safe(p, end, pv, n, bad) \
|
||||
do { \
|
||||
ceph_decode_need(p, end, n, bad); \
|
||||
ceph_decode_copy(p, pv, n); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* struct ceph_timespec <-> struct timespec
|
||||
*/
|
||||
static inline void ceph_decode_timespec(struct timespec *ts,
|
||||
const struct ceph_timespec *tv)
|
||||
{
|
||||
ts->tv_sec = le32_to_cpu(tv->tv_sec);
|
||||
ts->tv_nsec = le32_to_cpu(tv->tv_nsec);
|
||||
}
|
||||
static inline void ceph_encode_timespec(struct ceph_timespec *tv,
|
||||
const struct timespec *ts)
|
||||
{
|
||||
tv->tv_sec = cpu_to_le32(ts->tv_sec);
|
||||
tv->tv_nsec = cpu_to_le32(ts->tv_nsec);
|
||||
}
|
||||
|
||||
/*
|
||||
* sockaddr_storage <-> ceph_sockaddr
|
||||
*/
|
||||
static inline void ceph_encode_addr(struct ceph_entity_addr *a)
|
||||
{
|
||||
__be16 ss_family = htons(a->in_addr.ss_family);
|
||||
a->in_addr.ss_family = *(__u16 *)&ss_family;
|
||||
}
|
||||
static inline void ceph_decode_addr(struct ceph_entity_addr *a)
|
||||
{
|
||||
__be16 ss_family = *(__be16 *)&a->in_addr.ss_family;
|
||||
a->in_addr.ss_family = ntohs(ss_family);
|
||||
WARN_ON(a->in_addr.ss_family == 512);
|
||||
}
|
||||
|
||||
/*
|
||||
* encoders
|
||||
*/
|
||||
static inline void ceph_encode_64(void **p, u64 v)
|
||||
{
|
||||
put_unaligned_le64(v, (__le64 *)*p);
|
||||
*p += sizeof(u64);
|
||||
}
|
||||
static inline void ceph_encode_32(void **p, u32 v)
|
||||
{
|
||||
put_unaligned_le32(v, (__le32 *)*p);
|
||||
*p += sizeof(u32);
|
||||
}
|
||||
static inline void ceph_encode_16(void **p, u16 v)
|
||||
{
|
||||
put_unaligned_le16(v, (__le16 *)*p);
|
||||
*p += sizeof(u16);
|
||||
}
|
||||
static inline void ceph_encode_8(void **p, u8 v)
|
||||
{
|
||||
*(u8 *)*p = v;
|
||||
(*p)++;
|
||||
}
|
||||
static inline void ceph_encode_copy(void **p, const void *s, int len)
|
||||
{
|
||||
memcpy(*p, s, len);
|
||||
*p += len;
|
||||
}
|
||||
|
||||
/*
|
||||
* filepath, string encoders
|
||||
*/
|
||||
static inline void ceph_encode_filepath(void **p, void *end,
|
||||
u64 ino, const char *path)
|
||||
{
|
||||
u32 len = path ? strlen(path) : 0;
|
||||
BUG_ON(*p + sizeof(ino) + sizeof(len) + len > end);
|
||||
ceph_encode_8(p, 1);
|
||||
ceph_encode_64(p, ino);
|
||||
ceph_encode_32(p, len);
|
||||
if (len)
|
||||
memcpy(*p, path, len);
|
||||
*p += len;
|
||||
}
|
||||
|
||||
static inline void ceph_encode_string(void **p, void *end,
|
||||
const char *s, u32 len)
|
||||
{
|
||||
BUG_ON(*p + sizeof(len) + len > end);
|
||||
ceph_encode_32(p, len);
|
||||
if (len)
|
||||
memcpy(*p, s, len);
|
||||
*p += len;
|
||||
}
|
||||
|
||||
#define ceph_encode_need(p, end, n, bad) \
|
||||
do { \
|
||||
if (unlikely(*(p) + (n) > (end))) \
|
||||
goto bad; \
|
||||
} while (0)
|
||||
|
||||
#define ceph_encode_64_safe(p, end, v, bad) \
|
||||
do { \
|
||||
ceph_encode_need(p, end, sizeof(u64), bad); \
|
||||
ceph_encode_64(p, v); \
|
||||
} while (0)
|
||||
#define ceph_encode_32_safe(p, end, v, bad) \
|
||||
do { \
|
||||
ceph_encode_need(p, end, sizeof(u32), bad); \
|
||||
ceph_encode_32(p, v); \
|
||||
} while (0)
|
||||
#define ceph_encode_16_safe(p, end, v, bad) \
|
||||
do { \
|
||||
ceph_encode_need(p, end, sizeof(u16), bad); \
|
||||
ceph_encode_16(p, v); \
|
||||
} while (0)
|
||||
|
||||
#define ceph_encode_copy_safe(p, end, pv, n, bad) \
|
||||
do { \
|
||||
ceph_encode_need(p, end, n, bad); \
|
||||
ceph_encode_copy(p, pv, n); \
|
||||
} while (0)
|
||||
#define ceph_encode_string_safe(p, end, s, n, bad) \
|
||||
do { \
|
||||
ceph_encode_need(p, end, n, bad); \
|
||||
ceph_encode_string(p, end, s, n); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "ceph_debug.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/fs_struct.h>
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/sched.h>
|
||||
|
||||
#include "super.h"
|
||||
#include "mds_client.h"
|
||||
|
||||
/*
|
||||
* Directory operations: readdir, lookup, create, link, unlink,
|
||||
|
|
@ -227,15 +228,15 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
|||
struct ceph_file_info *fi = filp->private_data;
|
||||
struct inode *inode = filp->f_dentry->d_inode;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_client *client = ceph_inode_to_client(inode);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
unsigned frag = fpos_frag(filp->f_pos);
|
||||
int off = fpos_off(filp->f_pos);
|
||||
int err;
|
||||
u32 ftype;
|
||||
struct ceph_mds_reply_info_parsed *rinfo;
|
||||
const int max_entries = client->mount_args->max_readdir;
|
||||
const int max_bytes = client->mount_args->max_readdir_bytes;
|
||||
const int max_entries = fsc->mount_options->max_readdir;
|
||||
const int max_bytes = fsc->mount_options->max_readdir_bytes;
|
||||
|
||||
dout("readdir %p filp %p frag %u off %u\n", inode, filp, frag, off);
|
||||
if (fi->at_end)
|
||||
|
|
@ -267,7 +268,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
|||
/* can we use the dcache? */
|
||||
spin_lock(&inode->i_lock);
|
||||
if ((filp->f_pos == 2 || fi->dentry) &&
|
||||
!ceph_test_opt(client, NOASYNCREADDIR) &&
|
||||
!ceph_test_mount_opt(fsc, NOASYNCREADDIR) &&
|
||||
ceph_snap(inode) != CEPH_SNAPDIR &&
|
||||
(ci->i_ceph_flags & CEPH_I_COMPLETE) &&
|
||||
__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
|
||||
|
|
@ -487,14 +488,14 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin)
|
|||
struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
|
||||
struct dentry *dentry, int err)
|
||||
{
|
||||
struct ceph_client *client = ceph_sb_to_client(dentry->d_sb);
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
|
||||
struct inode *parent = dentry->d_parent->d_inode;
|
||||
|
||||
/* .snap dir? */
|
||||
if (err == -ENOENT &&
|
||||
ceph_vino(parent).ino != CEPH_INO_ROOT && /* no .snap in root dir */
|
||||
strcmp(dentry->d_name.name,
|
||||
client->mount_args->snapdir_name) == 0) {
|
||||
fsc->mount_options->snapdir_name) == 0) {
|
||||
struct inode *inode = ceph_get_snapdir(parent);
|
||||
dout("ENOENT on snapdir %p '%.*s', linking to snapdir %p\n",
|
||||
dentry, dentry->d_name.len, dentry->d_name.name, inode);
|
||||
|
|
@ -539,8 +540,8 @@ static int is_root_ceph_dentry(struct inode *inode, struct dentry *dentry)
|
|||
static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
{
|
||||
struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct ceph_mds_request *req;
|
||||
int op;
|
||||
int err;
|
||||
|
|
@ -572,7 +573,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
|
|||
spin_lock(&dir->i_lock);
|
||||
dout(" dir %p flags are %d\n", dir, ci->i_ceph_flags);
|
||||
if (strncmp(dentry->d_name.name,
|
||||
client->mount_args->snapdir_name,
|
||||
fsc->mount_options->snapdir_name,
|
||||
dentry->d_name.len) &&
|
||||
!is_root_ceph_dentry(dir, dentry) &&
|
||||
(ci->i_ceph_flags & CEPH_I_COMPLETE) &&
|
||||
|
|
@ -629,8 +630,8 @@ int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry)
|
|||
static int ceph_mknod(struct inode *dir, struct dentry *dentry,
|
||||
int mode, dev_t rdev)
|
||||
{
|
||||
struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct ceph_mds_request *req;
|
||||
int err;
|
||||
|
||||
|
|
@ -685,8 +686,8 @@ static int ceph_create(struct inode *dir, struct dentry *dentry, int mode,
|
|||
static int ceph_symlink(struct inode *dir, struct dentry *dentry,
|
||||
const char *dest)
|
||||
{
|
||||
struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct ceph_mds_request *req;
|
||||
int err;
|
||||
|
||||
|
|
@ -716,8 +717,8 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry,
|
|||
|
||||
static int ceph_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
||||
{
|
||||
struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct ceph_mds_request *req;
|
||||
int err = -EROFS;
|
||||
int op;
|
||||
|
|
@ -758,8 +759,8 @@ out:
|
|||
static int ceph_link(struct dentry *old_dentry, struct inode *dir,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct ceph_mds_request *req;
|
||||
int err;
|
||||
|
||||
|
|
@ -813,8 +814,8 @@ static int drop_caps_for_unlink(struct inode *inode)
|
|||
*/
|
||||
static int ceph_unlink(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct ceph_mds_request *req;
|
||||
int err = -EROFS;
|
||||
|
|
@ -854,8 +855,8 @@ out:
|
|||
static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry)
|
||||
{
|
||||
struct ceph_client *client = ceph_sb_to_client(old_dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(old_dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct ceph_mds_request *req;
|
||||
int err;
|
||||
|
||||
|
|
@ -1076,7 +1077,7 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
|
|||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
int left;
|
||||
|
||||
if (!ceph_test_opt(ceph_sb_to_client(inode->i_sb), DIRSTAT))
|
||||
if (!ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb), DIRSTAT))
|
||||
return -EISDIR;
|
||||
|
||||
if (!cf->dir_info) {
|
||||
|
|
@ -1177,7 +1178,7 @@ void ceph_dentry_lru_add(struct dentry *dn)
|
|||
dout("dentry_lru_add %p %p '%.*s'\n", di, dn,
|
||||
dn->d_name.len, dn->d_name.name);
|
||||
if (di) {
|
||||
mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc;
|
||||
mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
|
||||
spin_lock(&mdsc->dentry_lru_lock);
|
||||
list_add_tail(&di->lru, &mdsc->dentry_lru);
|
||||
mdsc->num_dentry++;
|
||||
|
|
@ -1193,7 +1194,7 @@ void ceph_dentry_lru_touch(struct dentry *dn)
|
|||
dout("dentry_lru_touch %p %p '%.*s' (offset %lld)\n", di, dn,
|
||||
dn->d_name.len, dn->d_name.name, di->offset);
|
||||
if (di) {
|
||||
mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc;
|
||||
mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
|
||||
spin_lock(&mdsc->dentry_lru_lock);
|
||||
list_move_tail(&di->lru, &mdsc->dentry_lru);
|
||||
spin_unlock(&mdsc->dentry_lru_lock);
|
||||
|
|
@ -1208,7 +1209,7 @@ void ceph_dentry_lru_del(struct dentry *dn)
|
|||
dout("dentry_lru_del %p %p '%.*s'\n", di, dn,
|
||||
dn->d_name.len, dn->d_name.name);
|
||||
if (di) {
|
||||
mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc;
|
||||
mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
|
||||
spin_lock(&mdsc->dentry_lru_lock);
|
||||
list_del_init(&di->lru);
|
||||
mdsc->num_dentry--;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
#include "ceph_debug.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include <linux/exportfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "super.h"
|
||||
#include "mds_client.h"
|
||||
|
||||
/*
|
||||
* NFS export support
|
||||
|
|
@ -120,7 +121,7 @@ static struct dentry *__fh_to_dentry(struct super_block *sb,
|
|||
static struct dentry *__cfh_to_dentry(struct super_block *sb,
|
||||
struct ceph_nfs_confh *cfh)
|
||||
{
|
||||
struct ceph_mds_client *mdsc = &ceph_sb_to_client(sb)->mdsc;
|
||||
struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
|
||||
struct inode *inode;
|
||||
struct dentry *dentry;
|
||||
struct ceph_vino vino;
|
||||
|
|
|
|||
207
fs/ceph/file.c
207
fs/ceph/file.c
|
|
@ -1,5 +1,6 @@
|
|||
#include "ceph_debug.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/file.h>
|
||||
|
|
@ -38,8 +39,8 @@
|
|||
static struct ceph_mds_request *
|
||||
prepare_open_request(struct super_block *sb, int flags, int create_mode)
|
||||
{
|
||||
struct ceph_client *client = ceph_sb_to_client(sb);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct ceph_mds_request *req;
|
||||
int want_auth = USE_ANY_MDS;
|
||||
int op = (flags & O_CREAT) ? CEPH_MDS_OP_CREATE : CEPH_MDS_OP_OPEN;
|
||||
|
|
@ -117,8 +118,8 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
|
|||
int ceph_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_client *client = ceph_sb_to_client(inode->i_sb);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct ceph_mds_request *req;
|
||||
struct ceph_file_info *cf = file->private_data;
|
||||
struct inode *parent_inode = file->f_dentry->d_parent->d_inode;
|
||||
|
|
@ -216,8 +217,8 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
|
|||
struct nameidata *nd, int mode,
|
||||
int locked_dir)
|
||||
{
|
||||
struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct file *file = nd->intent.open.file;
|
||||
struct inode *parent_inode = get_dentry_parent_inode(file->f_dentry);
|
||||
struct ceph_mds_request *req;
|
||||
|
|
@ -269,163 +270,6 @@ int ceph_release(struct inode *inode, struct file *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* build a vector of user pages
|
||||
*/
|
||||
static struct page **get_direct_page_vector(const char __user *data,
|
||||
int num_pages,
|
||||
loff_t off, size_t len)
|
||||
{
|
||||
struct page **pages;
|
||||
int rc;
|
||||
|
||||
pages = kmalloc(sizeof(*pages) * num_pages, GFP_NOFS);
|
||||
if (!pages)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
rc = get_user_pages(current, current->mm, (unsigned long)data,
|
||||
num_pages, 0, 0, pages, NULL);
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
return pages;
|
||||
|
||||
fail:
|
||||
kfree(pages);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
static void put_page_vector(struct page **pages, int num_pages)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_pages; i++)
|
||||
put_page(pages[i]);
|
||||
kfree(pages);
|
||||
}
|
||||
|
||||
void ceph_release_page_vector(struct page **pages, int num_pages)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_pages; i++)
|
||||
__free_pages(pages[i], 0);
|
||||
kfree(pages);
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate a vector new pages
|
||||
*/
|
||||
static struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags)
|
||||
{
|
||||
struct page **pages;
|
||||
int i;
|
||||
|
||||
pages = kmalloc(sizeof(*pages) * num_pages, flags);
|
||||
if (!pages)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
for (i = 0; i < num_pages; i++) {
|
||||
pages[i] = __page_cache_alloc(flags);
|
||||
if (pages[i] == NULL) {
|
||||
ceph_release_page_vector(pages, i);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
}
|
||||
return pages;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy user data into a page vector
|
||||
*/
|
||||
static int copy_user_to_page_vector(struct page **pages,
|
||||
const char __user *data,
|
||||
loff_t off, size_t len)
|
||||
{
|
||||
int i = 0;
|
||||
int po = off & ~PAGE_CACHE_MASK;
|
||||
int left = len;
|
||||
int l, bad;
|
||||
|
||||
while (left > 0) {
|
||||
l = min_t(int, PAGE_CACHE_SIZE-po, left);
|
||||
bad = copy_from_user(page_address(pages[i]) + po, data, l);
|
||||
if (bad == l)
|
||||
return -EFAULT;
|
||||
data += l - bad;
|
||||
left -= l - bad;
|
||||
po += l - bad;
|
||||
if (po == PAGE_CACHE_SIZE) {
|
||||
po = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy user data from a page vector into a user pointer
|
||||
*/
|
||||
static int copy_page_vector_to_user(struct page **pages, char __user *data,
|
||||
loff_t off, size_t len)
|
||||
{
|
||||
int i = 0;
|
||||
int po = off & ~PAGE_CACHE_MASK;
|
||||
int left = len;
|
||||
int l, bad;
|
||||
|
||||
while (left > 0) {
|
||||
l = min_t(int, left, PAGE_CACHE_SIZE-po);
|
||||
bad = copy_to_user(data, page_address(pages[i]) + po, l);
|
||||
if (bad == l)
|
||||
return -EFAULT;
|
||||
data += l - bad;
|
||||
left -= l - bad;
|
||||
if (po) {
|
||||
po += l - bad;
|
||||
if (po == PAGE_CACHE_SIZE)
|
||||
po = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Zero an extent within a page vector. Offset is relative to the
|
||||
* start of the first page.
|
||||
*/
|
||||
static void zero_page_vector_range(int off, int len, struct page **pages)
|
||||
{
|
||||
int i = off >> PAGE_CACHE_SHIFT;
|
||||
|
||||
off &= ~PAGE_CACHE_MASK;
|
||||
|
||||
dout("zero_page_vector_page %u~%u\n", off, len);
|
||||
|
||||
/* leading partial page? */
|
||||
if (off) {
|
||||
int end = min((int)PAGE_CACHE_SIZE, off + len);
|
||||
dout("zeroing %d %p head from %d\n", i, pages[i],
|
||||
(int)off);
|
||||
zero_user_segment(pages[i], off, end);
|
||||
len -= (end - off);
|
||||
i++;
|
||||
}
|
||||
while (len >= PAGE_CACHE_SIZE) {
|
||||
dout("zeroing %d %p len=%d\n", i, pages[i], len);
|
||||
zero_user_segment(pages[i], 0, PAGE_CACHE_SIZE);
|
||||
len -= PAGE_CACHE_SIZE;
|
||||
i++;
|
||||
}
|
||||
/* trailing partial page? */
|
||||
if (len) {
|
||||
dout("zeroing %d %p tail to %d\n", i, pages[i], (int)len);
|
||||
zero_user_segment(pages[i], 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read a range of bytes striped over one or more objects. Iterate over
|
||||
* objects we stripe over. (That's not atomic, but good enough for now.)
|
||||
|
|
@ -438,7 +282,7 @@ static int striped_read(struct inode *inode,
|
|||
struct page **pages, int num_pages,
|
||||
int *checkeof)
|
||||
{
|
||||
struct ceph_client *client = ceph_inode_to_client(inode);
|
||||
struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
u64 pos, this_len;
|
||||
int page_off = off & ~PAGE_CACHE_MASK; /* first byte's offset in page */
|
||||
|
|
@ -459,7 +303,7 @@ static int striped_read(struct inode *inode,
|
|||
|
||||
more:
|
||||
this_len = left;
|
||||
ret = ceph_osdc_readpages(&client->osdc, ceph_vino(inode),
|
||||
ret = ceph_osdc_readpages(&fsc->client->osdc, ceph_vino(inode),
|
||||
&ci->i_layout, pos, &this_len,
|
||||
ci->i_truncate_seq,
|
||||
ci->i_truncate_size,
|
||||
|
|
@ -477,8 +321,8 @@ more:
|
|||
|
||||
if (read < pos - off) {
|
||||
dout(" zero gap %llu to %llu\n", off + read, pos);
|
||||
zero_page_vector_range(page_off + read,
|
||||
pos - off - read, pages);
|
||||
ceph_zero_page_vector_range(page_off + read,
|
||||
pos - off - read, pages);
|
||||
}
|
||||
pos += ret;
|
||||
read = pos - off;
|
||||
|
|
@ -495,8 +339,8 @@ more:
|
|||
/* was original extent fully inside i_size? */
|
||||
if (pos + left <= inode->i_size) {
|
||||
dout("zero tail\n");
|
||||
zero_page_vector_range(page_off + read, len - read,
|
||||
pages);
|
||||
ceph_zero_page_vector_range(page_off + read, len - read,
|
||||
pages);
|
||||
read = len;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -531,7 +375,7 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data,
|
|||
(file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
|
||||
|
||||
if (file->f_flags & O_DIRECT) {
|
||||
pages = get_direct_page_vector(data, num_pages, off, len);
|
||||
pages = ceph_get_direct_page_vector(data, num_pages, off, len);
|
||||
|
||||
/*
|
||||
* flush any page cache pages in this range. this
|
||||
|
|
@ -552,13 +396,13 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data,
|
|||
ret = striped_read(inode, off, len, pages, num_pages, checkeof);
|
||||
|
||||
if (ret >= 0 && (file->f_flags & O_DIRECT) == 0)
|
||||
ret = copy_page_vector_to_user(pages, data, off, ret);
|
||||
ret = ceph_copy_page_vector_to_user(pages, data, off, ret);
|
||||
if (ret >= 0)
|
||||
*poff = off + ret;
|
||||
|
||||
done:
|
||||
if (file->f_flags & O_DIRECT)
|
||||
put_page_vector(pages, num_pages);
|
||||
ceph_put_page_vector(pages, num_pages);
|
||||
else
|
||||
ceph_release_page_vector(pages, num_pages);
|
||||
dout("sync_read result %d\n", ret);
|
||||
|
|
@ -594,7 +438,7 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data,
|
|||
{
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_client *client = ceph_inode_to_client(inode);
|
||||
struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
|
||||
struct ceph_osd_request *req;
|
||||
struct page **pages;
|
||||
int num_pages;
|
||||
|
|
@ -642,7 +486,7 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data,
|
|||
*/
|
||||
more:
|
||||
len = left;
|
||||
req = ceph_osdc_new_request(&client->osdc, &ci->i_layout,
|
||||
req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
|
||||
ceph_vino(inode), pos, &len,
|
||||
CEPH_OSD_OP_WRITE, flags,
|
||||
ci->i_snap_realm->cached_context,
|
||||
|
|
@ -655,7 +499,7 @@ more:
|
|||
num_pages = calc_pages_for(pos, len);
|
||||
|
||||
if (file->f_flags & O_DIRECT) {
|
||||
pages = get_direct_page_vector(data, num_pages, pos, len);
|
||||
pages = ceph_get_direct_page_vector(data, num_pages, pos, len);
|
||||
if (IS_ERR(pages)) {
|
||||
ret = PTR_ERR(pages);
|
||||
goto out;
|
||||
|
|
@ -673,7 +517,7 @@ more:
|
|||
ret = PTR_ERR(pages);
|
||||
goto out;
|
||||
}
|
||||
ret = copy_user_to_page_vector(pages, data, pos, len);
|
||||
ret = ceph_copy_user_to_page_vector(pages, data, pos, len);
|
||||
if (ret < 0) {
|
||||
ceph_release_page_vector(pages, num_pages);
|
||||
goto out;
|
||||
|
|
@ -689,7 +533,7 @@ more:
|
|||
req->r_num_pages = num_pages;
|
||||
req->r_inode = inode;
|
||||
|
||||
ret = ceph_osdc_start_request(&client->osdc, req, false);
|
||||
ret = ceph_osdc_start_request(&fsc->client->osdc, req, false);
|
||||
if (!ret) {
|
||||
if (req->r_safe_callback) {
|
||||
/*
|
||||
|
|
@ -701,11 +545,11 @@ more:
|
|||
spin_unlock(&ci->i_unsafe_lock);
|
||||
ceph_get_cap_refs(ci, CEPH_CAP_FILE_WR);
|
||||
}
|
||||
ret = ceph_osdc_wait_request(&client->osdc, req);
|
||||
ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
|
||||
}
|
||||
|
||||
if (file->f_flags & O_DIRECT)
|
||||
put_page_vector(pages, num_pages);
|
||||
ceph_put_page_vector(pages, num_pages);
|
||||
else if (file->f_flags & O_SYNC)
|
||||
ceph_release_page_vector(pages, num_pages);
|
||||
|
||||
|
|
@ -814,7 +658,8 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
|||
struct ceph_file_info *fi = file->private_data;
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->osdc;
|
||||
struct ceph_osd_client *osdc =
|
||||
&ceph_sb_to_client(inode->i_sb)->client->osdc;
|
||||
loff_t endoff = pos + iov->iov_len;
|
||||
int want, got = 0;
|
||||
int ret, err;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include "ceph_debug.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
|
|
@ -13,7 +13,8 @@
|
|||
#include <linux/pagevec.h>
|
||||
|
||||
#include "super.h"
|
||||
#include "decode.h"
|
||||
#include "mds_client.h"
|
||||
#include <linux/ceph/decode.h>
|
||||
|
||||
/*
|
||||
* Ceph inode operations
|
||||
|
|
@ -384,7 +385,7 @@ void ceph_destroy_inode(struct inode *inode)
|
|||
*/
|
||||
if (ci->i_snap_realm) {
|
||||
struct ceph_mds_client *mdsc =
|
||||
&ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
|
||||
ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
|
||||
struct ceph_snap_realm *realm = ci->i_snap_realm;
|
||||
|
||||
dout(" dropping residual ref to snap realm %p\n", realm);
|
||||
|
|
@ -685,7 +686,7 @@ static int fill_inode(struct inode *inode,
|
|||
}
|
||||
|
||||
/* it may be better to set st_size in getattr instead? */
|
||||
if (ceph_test_opt(ceph_sb_to_client(inode->i_sb), RBYTES))
|
||||
if (ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb), RBYTES))
|
||||
inode->i_size = ci->i_rbytes;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -901,7 +902,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
|
|||
struct inode *in = NULL;
|
||||
struct ceph_mds_reply_inode *ininfo;
|
||||
struct ceph_vino vino;
|
||||
struct ceph_client *client = ceph_sb_to_client(sb);
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
|
||||
int i = 0;
|
||||
int err = 0;
|
||||
|
||||
|
|
@ -965,7 +966,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
|
|||
*/
|
||||
if (rinfo->head->is_dentry && !req->r_aborted &&
|
||||
(rinfo->head->is_target || strncmp(req->r_dentry->d_name.name,
|
||||
client->mount_args->snapdir_name,
|
||||
fsc->mount_options->snapdir_name,
|
||||
req->r_dentry->d_name.len))) {
|
||||
/*
|
||||
* lookup link rename : null -> possibly existing inode
|
||||
|
|
@ -1533,7 +1534,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
struct inode *parent_inode = dentry->d_parent->d_inode;
|
||||
const unsigned int ia_valid = attr->ia_valid;
|
||||
struct ceph_mds_request *req;
|
||||
struct ceph_mds_client *mdsc = &ceph_sb_to_client(dentry->d_sb)->mdsc;
|
||||
struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc;
|
||||
int issued;
|
||||
int release = 0, dirtied = 0;
|
||||
int mask = 0;
|
||||
|
|
@ -1728,8 +1729,8 @@ out:
|
|||
*/
|
||||
int ceph_do_getattr(struct inode *inode, int mask)
|
||||
{
|
||||
struct ceph_client *client = ceph_sb_to_client(inode->i_sb);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct ceph_mds_request *req;
|
||||
int err;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#include <linux/in.h>
|
||||
|
||||
#include "ioctl.h"
|
||||
#include "super.h"
|
||||
#include "ceph_debug.h"
|
||||
#include "mds_client.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include "ioctl.h"
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -37,7 +39,7 @@ static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
|
|||
{
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
struct inode *parent_inode = file->f_dentry->d_parent->d_inode;
|
||||
struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
struct ceph_mds_request *req;
|
||||
struct ceph_ioctl_layout l;
|
||||
int err, i;
|
||||
|
|
@ -98,7 +100,8 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
|
|||
struct ceph_ioctl_dataloc dl;
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->osdc;
|
||||
struct ceph_osd_client *osdc =
|
||||
&ceph_sb_to_client(inode->i_sb)->client->osdc;
|
||||
u64 len = 1, olen;
|
||||
u64 tmp;
|
||||
struct ceph_object_layout ol;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
#include "ceph_debug.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include <linux/file.h>
|
||||
#include <linux/namei.h>
|
||||
|
||||
#include "super.h"
|
||||
#include "mds_client.h"
|
||||
#include "pagelist.h"
|
||||
#include <linux/ceph/pagelist.h>
|
||||
|
||||
/**
|
||||
* Implement fcntl and flock locking functions.
|
||||
|
|
@ -16,7 +16,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
|
|||
{
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
struct ceph_mds_client *mdsc =
|
||||
&ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
struct ceph_mds_request *req;
|
||||
int err;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
#include "ceph_debug.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include "mds_client.h"
|
||||
#include "mon_client.h"
|
||||
#include "super.h"
|
||||
#include "messenger.h"
|
||||
#include "decode.h"
|
||||
#include "auth.h"
|
||||
#include "pagelist.h"
|
||||
#include "mds_client.h"
|
||||
|
||||
#include <linux/ceph/messenger.h>
|
||||
#include <linux/ceph/decode.h>
|
||||
#include <linux/ceph/pagelist.h>
|
||||
#include <linux/ceph/auth.h>
|
||||
#include <linux/ceph/debugfs.h>
|
||||
|
||||
/*
|
||||
* A cluster of MDS (metadata server) daemons is responsible for
|
||||
|
|
@ -286,8 +289,9 @@ void ceph_put_mds_session(struct ceph_mds_session *s)
|
|||
atomic_read(&s->s_ref), atomic_read(&s->s_ref)-1);
|
||||
if (atomic_dec_and_test(&s->s_ref)) {
|
||||
if (s->s_authorizer)
|
||||
s->s_mdsc->client->monc.auth->ops->destroy_authorizer(
|
||||
s->s_mdsc->client->monc.auth, s->s_authorizer);
|
||||
s->s_mdsc->fsc->client->monc.auth->ops->destroy_authorizer(
|
||||
s->s_mdsc->fsc->client->monc.auth,
|
||||
s->s_authorizer);
|
||||
kfree(s);
|
||||
}
|
||||
}
|
||||
|
|
@ -344,7 +348,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
|
|||
s->s_seq = 0;
|
||||
mutex_init(&s->s_mutex);
|
||||
|
||||
ceph_con_init(mdsc->client->msgr, &s->s_con);
|
||||
ceph_con_init(mdsc->fsc->client->msgr, &s->s_con);
|
||||
s->s_con.private = s;
|
||||
s->s_con.ops = &mds_con_ops;
|
||||
s->s_con.peer_name.type = CEPH_ENTITY_TYPE_MDS;
|
||||
|
|
@ -599,7 +603,7 @@ static int __choose_mds(struct ceph_mds_client *mdsc,
|
|||
} else if (req->r_dentry) {
|
||||
struct inode *dir = req->r_dentry->d_parent->d_inode;
|
||||
|
||||
if (dir->i_sb != mdsc->client->sb) {
|
||||
if (dir->i_sb != mdsc->fsc->sb) {
|
||||
/* not this fs! */
|
||||
inode = req->r_dentry->d_inode;
|
||||
} else if (ceph_snap(dir) != CEPH_NOSNAP) {
|
||||
|
|
@ -884,7 +888,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
|
|||
__ceph_remove_cap(cap);
|
||||
if (!__ceph_is_any_real_caps(ci)) {
|
||||
struct ceph_mds_client *mdsc =
|
||||
&ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
|
||||
spin_lock(&mdsc->cap_dirty_lock);
|
||||
if (!list_empty(&ci->i_dirty_item)) {
|
||||
|
|
@ -1146,7 +1150,7 @@ int ceph_add_cap_releases(struct ceph_mds_client *mdsc,
|
|||
struct ceph_msg *msg, *partial = NULL;
|
||||
struct ceph_mds_cap_release *head;
|
||||
int err = -ENOMEM;
|
||||
int extra = mdsc->client->mount_args->cap_release_safety;
|
||||
int extra = mdsc->fsc->mount_options->cap_release_safety;
|
||||
int num;
|
||||
|
||||
dout("add_cap_releases %p mds%d extra %d\n", session, session->s_mds,
|
||||
|
|
@ -2085,7 +2089,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
|
|||
|
||||
/* insert trace into our cache */
|
||||
mutex_lock(&req->r_fill_mutex);
|
||||
err = ceph_fill_trace(mdsc->client->sb, req, req->r_session);
|
||||
err = ceph_fill_trace(mdsc->fsc->sb, req, req->r_session);
|
||||
if (err == 0) {
|
||||
if (result == 0 && rinfo->dir_nr)
|
||||
ceph_readdir_prepopulate(req, req->r_session);
|
||||
|
|
@ -2613,7 +2617,7 @@ static void handle_lease(struct ceph_mds_client *mdsc,
|
|||
struct ceph_mds_session *session,
|
||||
struct ceph_msg *msg)
|
||||
{
|
||||
struct super_block *sb = mdsc->client->sb;
|
||||
struct super_block *sb = mdsc->fsc->sb;
|
||||
struct inode *inode;
|
||||
struct ceph_inode_info *ci;
|
||||
struct dentry *parent, *dentry;
|
||||
|
|
@ -2891,10 +2895,16 @@ static void delayed_work(struct work_struct *work)
|
|||
schedule_delayed(mdsc);
|
||||
}
|
||||
|
||||
int ceph_mdsc_init(struct ceph_fs_client *fsc)
|
||||
|
||||
int ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client)
|
||||
{
|
||||
mdsc->client = client;
|
||||
struct ceph_mds_client *mdsc;
|
||||
|
||||
mdsc = kzalloc(sizeof(struct ceph_mds_client), GFP_NOFS);
|
||||
if (!mdsc)
|
||||
return -ENOMEM;
|
||||
mdsc->fsc = fsc;
|
||||
fsc->mdsc = mdsc;
|
||||
mutex_init(&mdsc->mutex);
|
||||
mdsc->mdsmap = kzalloc(sizeof(*mdsc->mdsmap), GFP_NOFS);
|
||||
if (mdsc->mdsmap == NULL)
|
||||
|
|
@ -2927,7 +2937,7 @@ int ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client)
|
|||
INIT_LIST_HEAD(&mdsc->dentry_lru);
|
||||
|
||||
ceph_caps_init(mdsc);
|
||||
ceph_adjust_min_caps(mdsc, client->min_caps);
|
||||
ceph_adjust_min_caps(mdsc, fsc->min_caps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2939,7 +2949,7 @@ int ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client)
|
|||
static void wait_requests(struct ceph_mds_client *mdsc)
|
||||
{
|
||||
struct ceph_mds_request *req;
|
||||
struct ceph_client *client = mdsc->client;
|
||||
struct ceph_fs_client *fsc = mdsc->fsc;
|
||||
|
||||
mutex_lock(&mdsc->mutex);
|
||||
if (__get_oldest_req(mdsc)) {
|
||||
|
|
@ -2947,7 +2957,7 @@ static void wait_requests(struct ceph_mds_client *mdsc)
|
|||
|
||||
dout("wait_requests waiting for requests\n");
|
||||
wait_for_completion_timeout(&mdsc->safe_umount_waiters,
|
||||
client->mount_args->mount_timeout * HZ);
|
||||
fsc->client->options->mount_timeout * HZ);
|
||||
|
||||
/* tear down remaining requests */
|
||||
mutex_lock(&mdsc->mutex);
|
||||
|
|
@ -3030,7 +3040,7 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc)
|
|||
{
|
||||
u64 want_tid, want_flush;
|
||||
|
||||
if (mdsc->client->mount_state == CEPH_MOUNT_SHUTDOWN)
|
||||
if (mdsc->fsc->mount_state == CEPH_MOUNT_SHUTDOWN)
|
||||
return;
|
||||
|
||||
dout("sync\n");
|
||||
|
|
@ -3053,7 +3063,7 @@ bool done_closing_sessions(struct ceph_mds_client *mdsc)
|
|||
{
|
||||
int i, n = 0;
|
||||
|
||||
if (mdsc->client->mount_state == CEPH_MOUNT_SHUTDOWN)
|
||||
if (mdsc->fsc->mount_state == CEPH_MOUNT_SHUTDOWN)
|
||||
return true;
|
||||
|
||||
mutex_lock(&mdsc->mutex);
|
||||
|
|
@ -3071,8 +3081,8 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc)
|
|||
{
|
||||
struct ceph_mds_session *session;
|
||||
int i;
|
||||
struct ceph_client *client = mdsc->client;
|
||||
unsigned long timeout = client->mount_args->mount_timeout * HZ;
|
||||
struct ceph_fs_client *fsc = mdsc->fsc;
|
||||
unsigned long timeout = fsc->client->options->mount_timeout * HZ;
|
||||
|
||||
dout("close_sessions\n");
|
||||
|
||||
|
|
@ -3119,7 +3129,7 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc)
|
|||
dout("stopped\n");
|
||||
}
|
||||
|
||||
void ceph_mdsc_stop(struct ceph_mds_client *mdsc)
|
||||
static void ceph_mdsc_stop(struct ceph_mds_client *mdsc)
|
||||
{
|
||||
dout("stop\n");
|
||||
cancel_delayed_work_sync(&mdsc->delayed_work); /* cancel timer */
|
||||
|
|
@ -3129,6 +3139,15 @@ void ceph_mdsc_stop(struct ceph_mds_client *mdsc)
|
|||
ceph_caps_finalize(mdsc);
|
||||
}
|
||||
|
||||
void ceph_mdsc_destroy(struct ceph_fs_client *fsc)
|
||||
{
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
|
||||
ceph_mdsc_stop(mdsc);
|
||||
fsc->mdsc = NULL;
|
||||
kfree(mdsc);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* handle mds map update.
|
||||
|
|
@ -3145,14 +3164,14 @@ void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
|
|||
|
||||
ceph_decode_need(&p, end, sizeof(fsid)+2*sizeof(u32), bad);
|
||||
ceph_decode_copy(&p, &fsid, sizeof(fsid));
|
||||
if (ceph_check_fsid(mdsc->client, &fsid) < 0)
|
||||
if (ceph_check_fsid(mdsc->fsc->client, &fsid) < 0)
|
||||
return;
|
||||
epoch = ceph_decode_32(&p);
|
||||
maplen = ceph_decode_32(&p);
|
||||
dout("handle_map epoch %u len %d\n", epoch, (int)maplen);
|
||||
|
||||
/* do we need it? */
|
||||
ceph_monc_got_mdsmap(&mdsc->client->monc, epoch);
|
||||
ceph_monc_got_mdsmap(&mdsc->fsc->client->monc, epoch);
|
||||
mutex_lock(&mdsc->mutex);
|
||||
if (mdsc->mdsmap && epoch <= mdsc->mdsmap->m_epoch) {
|
||||
dout("handle_map epoch %u <= our %u\n",
|
||||
|
|
@ -3176,7 +3195,7 @@ void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
|
|||
} else {
|
||||
mdsc->mdsmap = newmap; /* first mds map */
|
||||
}
|
||||
mdsc->client->sb->s_maxbytes = mdsc->mdsmap->m_max_file_size;
|
||||
mdsc->fsc->sb->s_maxbytes = mdsc->mdsmap->m_max_file_size;
|
||||
|
||||
__wake_requests(mdsc, &mdsc->waiting_for_map);
|
||||
|
||||
|
|
@ -3277,7 +3296,7 @@ static int get_authorizer(struct ceph_connection *con,
|
|||
{
|
||||
struct ceph_mds_session *s = con->private;
|
||||
struct ceph_mds_client *mdsc = s->s_mdsc;
|
||||
struct ceph_auth_client *ac = mdsc->client->monc.auth;
|
||||
struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth;
|
||||
int ret = 0;
|
||||
|
||||
if (force_new && s->s_authorizer) {
|
||||
|
|
@ -3311,7 +3330,7 @@ static int verify_authorizer_reply(struct ceph_connection *con, int len)
|
|||
{
|
||||
struct ceph_mds_session *s = con->private;
|
||||
struct ceph_mds_client *mdsc = s->s_mdsc;
|
||||
struct ceph_auth_client *ac = mdsc->client->monc.auth;
|
||||
struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth;
|
||||
|
||||
return ac->ops->verify_authorizer_reply(ac, s->s_authorizer, len);
|
||||
}
|
||||
|
|
@ -3320,12 +3339,12 @@ static int invalidate_authorizer(struct ceph_connection *con)
|
|||
{
|
||||
struct ceph_mds_session *s = con->private;
|
||||
struct ceph_mds_client *mdsc = s->s_mdsc;
|
||||
struct ceph_auth_client *ac = mdsc->client->monc.auth;
|
||||
struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth;
|
||||
|
||||
if (ac->ops->invalidate_authorizer)
|
||||
ac->ops->invalidate_authorizer(ac, CEPH_ENTITY_TYPE_MDS);
|
||||
|
||||
return ceph_monc_validate_auth(&mdsc->client->monc);
|
||||
return ceph_monc_validate_auth(&mdsc->fsc->client->monc);
|
||||
}
|
||||
|
||||
static const struct ceph_connection_operations mds_con_ops = {
|
||||
|
|
@ -3338,7 +3357,4 @@ static const struct ceph_connection_operations mds_con_ops = {
|
|||
.peer_reset = peer_reset,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* eof */
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@
|
|||
#include <linux/rbtree.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "messenger.h"
|
||||
#include "mdsmap.h"
|
||||
#include <linux/ceph/types.h>
|
||||
#include <linux/ceph/messenger.h>
|
||||
#include <linux/ceph/mdsmap.h>
|
||||
|
||||
/*
|
||||
* Some lock dependencies:
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
struct ceph_client;
|
||||
struct ceph_fs_client;
|
||||
struct ceph_cap;
|
||||
|
||||
/*
|
||||
|
|
@ -230,7 +230,7 @@ struct ceph_mds_request {
|
|||
* mds client state
|
||||
*/
|
||||
struct ceph_mds_client {
|
||||
struct ceph_client *client;
|
||||
struct ceph_fs_client *fsc;
|
||||
struct mutex mutex; /* all nested structures */
|
||||
|
||||
struct ceph_mdsmap *mdsmap;
|
||||
|
|
@ -289,11 +289,6 @@ struct ceph_mds_client {
|
|||
int caps_avail_count; /* unused, unreserved */
|
||||
int caps_min_count; /* keep at least this many
|
||||
(unreserved) */
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_file;
|
||||
#endif
|
||||
|
||||
spinlock_t dentry_lru_lock;
|
||||
struct list_head dentry_lru;
|
||||
int num_dentry;
|
||||
|
|
@ -316,10 +311,9 @@ extern void ceph_put_mds_session(struct ceph_mds_session *s);
|
|||
extern int ceph_send_msg_mds(struct ceph_mds_client *mdsc,
|
||||
struct ceph_msg *msg, int mds);
|
||||
|
||||
extern int ceph_mdsc_init(struct ceph_mds_client *mdsc,
|
||||
struct ceph_client *client);
|
||||
extern int ceph_mdsc_init(struct ceph_fs_client *fsc);
|
||||
extern void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc);
|
||||
extern void ceph_mdsc_stop(struct ceph_mds_client *mdsc);
|
||||
extern void ceph_mdsc_destroy(struct ceph_fs_client *fsc);
|
||||
|
||||
extern void ceph_mdsc_sync(struct ceph_mds_client *mdsc);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include "ceph_debug.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/err.h>
|
||||
|
|
@ -6,9 +6,9 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "mdsmap.h"
|
||||
#include "messenger.h"
|
||||
#include "decode.h"
|
||||
#include <linux/ceph/mdsmap.h>
|
||||
#include <linux/ceph/messenger.h>
|
||||
#include <linux/ceph/decode.h>
|
||||
|
||||
#include "super.h"
|
||||
|
||||
|
|
@ -117,7 +117,8 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end)
|
|||
}
|
||||
|
||||
dout("mdsmap_decode %d/%d %lld mds%d.%d %s %s\n",
|
||||
i+1, n, global_id, mds, inc, pr_addr(&addr.in_addr),
|
||||
i+1, n, global_id, mds, inc,
|
||||
ceph_pr_addr(&addr.in_addr),
|
||||
ceph_mds_state_name(state));
|
||||
if (mds >= 0 && mds < m->m_max_mds && state > 0) {
|
||||
m->m_info[mds].global_id = global_id;
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
#ifndef _FS_CEPH_MDSMAP_H
|
||||
#define _FS_CEPH_MDSMAP_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/*
|
||||
* mds map - describe servers in the mds cluster.
|
||||
*
|
||||
* we limit fields to those the client actually xcares about
|
||||
*/
|
||||
struct ceph_mds_info {
|
||||
u64 global_id;
|
||||
struct ceph_entity_addr addr;
|
||||
s32 state;
|
||||
int num_export_targets;
|
||||
bool laggy;
|
||||
u32 *export_targets;
|
||||
};
|
||||
|
||||
struct ceph_mdsmap {
|
||||
u32 m_epoch, m_client_epoch, m_last_failure;
|
||||
u32 m_root;
|
||||
u32 m_session_timeout; /* seconds */
|
||||
u32 m_session_autoclose; /* seconds */
|
||||
u64 m_max_file_size;
|
||||
u32 m_max_mds; /* size of m_addr, m_state arrays */
|
||||
struct ceph_mds_info *m_info;
|
||||
|
||||
/* which object pools file data can be stored in */
|
||||
int m_num_data_pg_pools;
|
||||
u32 *m_data_pg_pools;
|
||||
u32 m_cas_pg_pool;
|
||||
};
|
||||
|
||||
static inline struct ceph_entity_addr *
|
||||
ceph_mdsmap_get_addr(struct ceph_mdsmap *m, int w)
|
||||
{
|
||||
if (w >= m->m_max_mds)
|
||||
return NULL;
|
||||
return &m->m_info[w].addr;
|
||||
}
|
||||
|
||||
static inline int ceph_mdsmap_get_state(struct ceph_mdsmap *m, int w)
|
||||
{
|
||||
BUG_ON(w < 0);
|
||||
if (w >= m->m_max_mds)
|
||||
return CEPH_MDS_STATE_DNE;
|
||||
return m->m_info[w].state;
|
||||
}
|
||||
|
||||
static inline bool ceph_mdsmap_is_laggy(struct ceph_mdsmap *m, int w)
|
||||
{
|
||||
if (w >= 0 && w < m->m_max_mds)
|
||||
return m->m_info[w].laggy;
|
||||
return false;
|
||||
}
|
||||
|
||||
extern int ceph_mdsmap_get_random_mds(struct ceph_mdsmap *m);
|
||||
extern struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end);
|
||||
extern void ceph_mdsmap_destroy(struct ceph_mdsmap *m);
|
||||
|
||||
#endif
|
||||
2432
fs/ceph/messenger.c
2432
fs/ceph/messenger.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,257 +0,0 @@
|
|||
#ifndef __FS_CEPH_MESSENGER_H
|
||||
#define __FS_CEPH_MESSENGER_H
|
||||
|
||||
#include <linux/kref.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/radix-tree.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "buffer.h"
|
||||
|
||||
struct ceph_msg;
|
||||
struct ceph_connection;
|
||||
|
||||
extern struct workqueue_struct *ceph_msgr_wq; /* receive work queue */
|
||||
|
||||
/*
|
||||
* Ceph defines these callbacks for handling connection events.
|
||||
*/
|
||||
struct ceph_connection_operations {
|
||||
struct ceph_connection *(*get)(struct ceph_connection *);
|
||||
void (*put)(struct ceph_connection *);
|
||||
|
||||
/* handle an incoming message. */
|
||||
void (*dispatch) (struct ceph_connection *con, struct ceph_msg *m);
|
||||
|
||||
/* authorize an outgoing connection */
|
||||
int (*get_authorizer) (struct ceph_connection *con,
|
||||
void **buf, int *len, int *proto,
|
||||
void **reply_buf, int *reply_len, int force_new);
|
||||
int (*verify_authorizer_reply) (struct ceph_connection *con, int len);
|
||||
int (*invalidate_authorizer)(struct ceph_connection *con);
|
||||
|
||||
/* protocol version mismatch */
|
||||
void (*bad_proto) (struct ceph_connection *con);
|
||||
|
||||
/* there was some error on the socket (disconnect, whatever) */
|
||||
void (*fault) (struct ceph_connection *con);
|
||||
|
||||
/* a remote host as terminated a message exchange session, and messages
|
||||
* we sent (or they tried to send us) may be lost. */
|
||||
void (*peer_reset) (struct ceph_connection *con);
|
||||
|
||||
struct ceph_msg * (*alloc_msg) (struct ceph_connection *con,
|
||||
struct ceph_msg_header *hdr,
|
||||
int *skip);
|
||||
};
|
||||
|
||||
/* use format string %s%d */
|
||||
#define ENTITY_NAME(n) ceph_entity_type_name((n).type), le64_to_cpu((n).num)
|
||||
|
||||
struct ceph_messenger {
|
||||
struct ceph_entity_inst inst; /* my name+address */
|
||||
struct ceph_entity_addr my_enc_addr;
|
||||
struct page *zero_page; /* used in certain error cases */
|
||||
|
||||
bool nocrc;
|
||||
|
||||
/*
|
||||
* the global_seq counts connections i (attempt to) initiate
|
||||
* in order to disambiguate certain connect race conditions.
|
||||
*/
|
||||
u32 global_seq;
|
||||
spinlock_t global_seq_lock;
|
||||
};
|
||||
|
||||
/*
|
||||
* a single message. it contains a header (src, dest, message type, etc.),
|
||||
* footer (crc values, mainly), a "front" message body, and possibly a
|
||||
* data payload (stored in some number of pages).
|
||||
*/
|
||||
struct ceph_msg {
|
||||
struct ceph_msg_header hdr; /* header */
|
||||
struct ceph_msg_footer footer; /* footer */
|
||||
struct kvec front; /* unaligned blobs of message */
|
||||
struct ceph_buffer *middle;
|
||||
struct page **pages; /* data payload. NOT OWNER. */
|
||||
unsigned nr_pages; /* size of page array */
|
||||
struct ceph_pagelist *pagelist; /* instead of pages */
|
||||
struct list_head list_head;
|
||||
struct kref kref;
|
||||
struct bio *bio; /* instead of pages/pagelist */
|
||||
struct bio *bio_iter; /* bio iterator */
|
||||
int bio_seg; /* current bio segment */
|
||||
struct ceph_pagelist *trail; /* the trailing part of the data */
|
||||
bool front_is_vmalloc;
|
||||
bool more_to_follow;
|
||||
bool needs_out_seq;
|
||||
int front_max;
|
||||
|
||||
struct ceph_msgpool *pool;
|
||||
};
|
||||
|
||||
struct ceph_msg_pos {
|
||||
int page, page_pos; /* which page; offset in page */
|
||||
int data_pos; /* offset in data payload */
|
||||
int did_page_crc; /* true if we've calculated crc for current page */
|
||||
};
|
||||
|
||||
/* ceph connection fault delay defaults, for exponential backoff */
|
||||
#define BASE_DELAY_INTERVAL (HZ/2)
|
||||
#define MAX_DELAY_INTERVAL (5 * 60 * HZ)
|
||||
|
||||
/*
|
||||
* ceph_connection state bit flags
|
||||
*
|
||||
* QUEUED and BUSY are used together to ensure that only a single
|
||||
* thread is currently opening, reading or writing data to the socket.
|
||||
*/
|
||||
#define LOSSYTX 0 /* we can close channel or drop messages on errors */
|
||||
#define CONNECTING 1
|
||||
#define NEGOTIATING 2
|
||||
#define KEEPALIVE_PENDING 3
|
||||
#define WRITE_PENDING 4 /* we have data ready to send */
|
||||
#define QUEUED 5 /* there is work queued on this connection */
|
||||
#define BUSY 6 /* work is being done */
|
||||
#define STANDBY 8 /* no outgoing messages, socket closed. we keep
|
||||
* the ceph_connection around to maintain shared
|
||||
* state with the peer. */
|
||||
#define CLOSED 10 /* we've closed the connection */
|
||||
#define SOCK_CLOSED 11 /* socket state changed to closed */
|
||||
#define OPENING 13 /* open connection w/ (possibly new) peer */
|
||||
#define DEAD 14 /* dead, about to kfree */
|
||||
|
||||
/*
|
||||
* A single connection with another host.
|
||||
*
|
||||
* We maintain a queue of outgoing messages, and some session state to
|
||||
* ensure that we can preserve the lossless, ordered delivery of
|
||||
* messages in the case of a TCP disconnect.
|
||||
*/
|
||||
struct ceph_connection {
|
||||
void *private;
|
||||
atomic_t nref;
|
||||
|
||||
const struct ceph_connection_operations *ops;
|
||||
|
||||
struct ceph_messenger *msgr;
|
||||
struct socket *sock;
|
||||
unsigned long state; /* connection state (see flags above) */
|
||||
const char *error_msg; /* error message, if any */
|
||||
|
||||
struct ceph_entity_addr peer_addr; /* peer address */
|
||||
struct ceph_entity_name peer_name; /* peer name */
|
||||
struct ceph_entity_addr peer_addr_for_me;
|
||||
unsigned peer_features;
|
||||
u32 connect_seq; /* identify the most recent connection
|
||||
attempt for this connection, client */
|
||||
u32 peer_global_seq; /* peer's global seq for this connection */
|
||||
|
||||
int auth_retry; /* true if we need a newer authorizer */
|
||||
void *auth_reply_buf; /* where to put the authorizer reply */
|
||||
int auth_reply_buf_len;
|
||||
|
||||
struct mutex mutex;
|
||||
|
||||
/* out queue */
|
||||
struct list_head out_queue;
|
||||
struct list_head out_sent; /* sending or sent but unacked */
|
||||
u64 out_seq; /* last message queued for send */
|
||||
bool out_keepalive_pending;
|
||||
|
||||
u64 in_seq, in_seq_acked; /* last message received, acked */
|
||||
|
||||
/* connection negotiation temps */
|
||||
char in_banner[CEPH_BANNER_MAX_LEN];
|
||||
union {
|
||||
struct { /* outgoing connection */
|
||||
struct ceph_msg_connect out_connect;
|
||||
struct ceph_msg_connect_reply in_reply;
|
||||
};
|
||||
struct { /* incoming */
|
||||
struct ceph_msg_connect in_connect;
|
||||
struct ceph_msg_connect_reply out_reply;
|
||||
};
|
||||
};
|
||||
struct ceph_entity_addr actual_peer_addr;
|
||||
|
||||
/* message out temps */
|
||||
struct ceph_msg *out_msg; /* sending message (== tail of
|
||||
out_sent) */
|
||||
bool out_msg_done;
|
||||
struct ceph_msg_pos out_msg_pos;
|
||||
|
||||
struct kvec out_kvec[8], /* sending header/footer data */
|
||||
*out_kvec_cur;
|
||||
int out_kvec_left; /* kvec's left in out_kvec */
|
||||
int out_skip; /* skip this many bytes */
|
||||
int out_kvec_bytes; /* total bytes left */
|
||||
bool out_kvec_is_msg; /* kvec refers to out_msg */
|
||||
int out_more; /* there is more data after the kvecs */
|
||||
__le64 out_temp_ack; /* for writing an ack */
|
||||
|
||||
/* message in temps */
|
||||
struct ceph_msg_header in_hdr;
|
||||
struct ceph_msg *in_msg;
|
||||
struct ceph_msg_pos in_msg_pos;
|
||||
u32 in_front_crc, in_middle_crc, in_data_crc; /* calculated crc */
|
||||
|
||||
char in_tag; /* protocol control byte */
|
||||
int in_base_pos; /* bytes read */
|
||||
__le64 in_temp_ack; /* for reading an ack */
|
||||
|
||||
struct delayed_work work; /* send|recv work */
|
||||
unsigned long delay; /* current delay interval */
|
||||
};
|
||||
|
||||
|
||||
extern const char *pr_addr(const struct sockaddr_storage *ss);
|
||||
extern int ceph_parse_ips(const char *c, const char *end,
|
||||
struct ceph_entity_addr *addr,
|
||||
int max_count, int *count);
|
||||
|
||||
|
||||
extern int ceph_msgr_init(void);
|
||||
extern void ceph_msgr_exit(void);
|
||||
extern void ceph_msgr_flush(void);
|
||||
|
||||
extern struct ceph_messenger *ceph_messenger_create(
|
||||
struct ceph_entity_addr *myaddr);
|
||||
extern void ceph_messenger_destroy(struct ceph_messenger *);
|
||||
|
||||
extern void ceph_con_init(struct ceph_messenger *msgr,
|
||||
struct ceph_connection *con);
|
||||
extern void ceph_con_open(struct ceph_connection *con,
|
||||
struct ceph_entity_addr *addr);
|
||||
extern bool ceph_con_opened(struct ceph_connection *con);
|
||||
extern void ceph_con_close(struct ceph_connection *con);
|
||||
extern void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg);
|
||||
extern void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg);
|
||||
extern void ceph_con_revoke_message(struct ceph_connection *con,
|
||||
struct ceph_msg *msg);
|
||||
extern void ceph_con_keepalive(struct ceph_connection *con);
|
||||
extern struct ceph_connection *ceph_con_get(struct ceph_connection *con);
|
||||
extern void ceph_con_put(struct ceph_connection *con);
|
||||
|
||||
extern struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags);
|
||||
extern void ceph_msg_kfree(struct ceph_msg *m);
|
||||
|
||||
|
||||
static inline struct ceph_msg *ceph_msg_get(struct ceph_msg *msg)
|
||||
{
|
||||
kref_get(&msg->kref);
|
||||
return msg;
|
||||
}
|
||||
extern void ceph_msg_last_put(struct kref *kref);
|
||||
static inline void ceph_msg_put(struct ceph_msg *msg)
|
||||
{
|
||||
kref_put(&msg->kref, ceph_msg_last_put);
|
||||
}
|
||||
|
||||
extern void ceph_msg_dump(struct ceph_msg *msg);
|
||||
|
||||
#endif
|
||||
1018
fs/ceph/mon_client.c
1018
fs/ceph/mon_client.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,121 +0,0 @@
|
|||
#ifndef _FS_CEPH_MON_CLIENT_H
|
||||
#define _FS_CEPH_MON_CLIENT_H
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/rbtree.h>
|
||||
|
||||
#include "messenger.h"
|
||||
|
||||
struct ceph_client;
|
||||
struct ceph_mount_args;
|
||||
struct ceph_auth_client;
|
||||
|
||||
/*
|
||||
* The monitor map enumerates the set of all monitors.
|
||||
*/
|
||||
struct ceph_monmap {
|
||||
struct ceph_fsid fsid;
|
||||
u32 epoch;
|
||||
u32 num_mon;
|
||||
struct ceph_entity_inst mon_inst[0];
|
||||
};
|
||||
|
||||
struct ceph_mon_client;
|
||||
struct ceph_mon_generic_request;
|
||||
|
||||
|
||||
/*
|
||||
* Generic mechanism for resending monitor requests.
|
||||
*/
|
||||
typedef void (*ceph_monc_request_func_t)(struct ceph_mon_client *monc,
|
||||
int newmon);
|
||||
|
||||
/* a pending monitor request */
|
||||
struct ceph_mon_request {
|
||||
struct ceph_mon_client *monc;
|
||||
struct delayed_work delayed_work;
|
||||
unsigned long delay;
|
||||
ceph_monc_request_func_t do_request;
|
||||
};
|
||||
|
||||
/*
|
||||
* ceph_mon_generic_request is being used for the statfs and poolop requests
|
||||
* which are bening done a bit differently because we need to get data back
|
||||
* to the caller
|
||||
*/
|
||||
struct ceph_mon_generic_request {
|
||||
struct kref kref;
|
||||
u64 tid;
|
||||
struct rb_node node;
|
||||
int result;
|
||||
void *buf;
|
||||
int buf_len;
|
||||
struct completion completion;
|
||||
struct ceph_msg *request; /* original request */
|
||||
struct ceph_msg *reply; /* and reply */
|
||||
};
|
||||
|
||||
struct ceph_mon_client {
|
||||
struct ceph_client *client;
|
||||
struct ceph_monmap *monmap;
|
||||
|
||||
struct mutex mutex;
|
||||
struct delayed_work delayed_work;
|
||||
|
||||
struct ceph_auth_client *auth;
|
||||
struct ceph_msg *m_auth, *m_auth_reply, *m_subscribe, *m_subscribe_ack;
|
||||
int pending_auth;
|
||||
|
||||
bool hunting;
|
||||
int cur_mon; /* last monitor i contacted */
|
||||
unsigned long sub_sent, sub_renew_after;
|
||||
struct ceph_connection *con;
|
||||
bool have_fsid;
|
||||
|
||||
/* pending generic requests */
|
||||
struct rb_root generic_request_tree;
|
||||
int num_generic_requests;
|
||||
u64 last_tid;
|
||||
|
||||
/* mds/osd map */
|
||||
int want_next_osdmap; /* 1 = want, 2 = want+asked */
|
||||
u32 have_osdmap, have_mdsmap;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_file;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern struct ceph_monmap *ceph_monmap_decode(void *p, void *end);
|
||||
extern int ceph_monmap_contains(struct ceph_monmap *m,
|
||||
struct ceph_entity_addr *addr);
|
||||
|
||||
extern int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl);
|
||||
extern void ceph_monc_stop(struct ceph_mon_client *monc);
|
||||
|
||||
/*
|
||||
* The model here is to indicate that we need a new map of at least
|
||||
* epoch @want, and also call in when we receive a map. We will
|
||||
* periodically rerequest the map from the monitor cluster until we
|
||||
* get what we want.
|
||||
*/
|
||||
extern int ceph_monc_got_mdsmap(struct ceph_mon_client *monc, u32 have);
|
||||
extern int ceph_monc_got_osdmap(struct ceph_mon_client *monc, u32 have);
|
||||
|
||||
extern void ceph_monc_request_next_osdmap(struct ceph_mon_client *monc);
|
||||
|
||||
extern int ceph_monc_do_statfs(struct ceph_mon_client *monc,
|
||||
struct ceph_statfs *buf);
|
||||
|
||||
extern int ceph_monc_open_session(struct ceph_mon_client *monc);
|
||||
|
||||
extern int ceph_monc_validate_auth(struct ceph_mon_client *monc);
|
||||
|
||||
extern int ceph_monc_create_snapid(struct ceph_mon_client *monc,
|
||||
u32 pool, u64 *snapid);
|
||||
|
||||
extern int ceph_monc_delete_snapid(struct ceph_mon_client *monc,
|
||||
u32 pool, u64 snapid);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
#include "ceph_debug.h"
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "msgpool.h"
|
||||
|
||||
static void *alloc_fn(gfp_t gfp_mask, void *arg)
|
||||
{
|
||||
struct ceph_msgpool *pool = arg;
|
||||
void *p;
|
||||
|
||||
p = ceph_msg_new(0, pool->front_len, gfp_mask);
|
||||
if (!p)
|
||||
pr_err("msgpool %s alloc failed\n", pool->name);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void free_fn(void *element, void *arg)
|
||||
{
|
||||
ceph_msg_put(element);
|
||||
}
|
||||
|
||||
int ceph_msgpool_init(struct ceph_msgpool *pool,
|
||||
int front_len, int size, bool blocking, const char *name)
|
||||
{
|
||||
pool->front_len = front_len;
|
||||
pool->pool = mempool_create(size, alloc_fn, free_fn, pool);
|
||||
if (!pool->pool)
|
||||
return -ENOMEM;
|
||||
pool->name = name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ceph_msgpool_destroy(struct ceph_msgpool *pool)
|
||||
{
|
||||
mempool_destroy(pool->pool);
|
||||
}
|
||||
|
||||
struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool,
|
||||
int front_len)
|
||||
{
|
||||
if (front_len > pool->front_len) {
|
||||
pr_err("msgpool_get pool %s need front %d, pool size is %d\n",
|
||||
pool->name, front_len, pool->front_len);
|
||||
WARN_ON(1);
|
||||
|
||||
/* try to alloc a fresh message */
|
||||
return ceph_msg_new(0, front_len, GFP_NOFS);
|
||||
}
|
||||
|
||||
return mempool_alloc(pool->pool, GFP_NOFS);
|
||||
}
|
||||
|
||||
void ceph_msgpool_put(struct ceph_msgpool *pool, struct ceph_msg *msg)
|
||||
{
|
||||
/* reset msg front_len; user may have changed it */
|
||||
msg->front.iov_len = pool->front_len;
|
||||
msg->hdr.front_len = cpu_to_le32(pool->front_len);
|
||||
|
||||
kref_init(&msg->kref); /* retake single ref */
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#ifndef _FS_CEPH_MSGPOOL
|
||||
#define _FS_CEPH_MSGPOOL
|
||||
|
||||
#include <linux/mempool.h>
|
||||
#include "messenger.h"
|
||||
|
||||
/*
|
||||
* we use memory pools for preallocating messages we may receive, to
|
||||
* avoid unexpected OOM conditions.
|
||||
*/
|
||||
struct ceph_msgpool {
|
||||
const char *name;
|
||||
mempool_t *pool;
|
||||
int front_len; /* preallocated payload size */
|
||||
};
|
||||
|
||||
extern int ceph_msgpool_init(struct ceph_msgpool *pool,
|
||||
int front_len, int size, bool blocking,
|
||||
const char *name);
|
||||
extern void ceph_msgpool_destroy(struct ceph_msgpool *pool);
|
||||
extern struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *,
|
||||
int front_len);
|
||||
extern void ceph_msgpool_put(struct ceph_msgpool *, struct ceph_msg *);
|
||||
|
||||
#endif
|
||||
175
fs/ceph/msgr.h
175
fs/ceph/msgr.h
|
|
@ -1,175 +0,0 @@
|
|||
#ifndef CEPH_MSGR_H
|
||||
#define CEPH_MSGR_H
|
||||
|
||||
/*
|
||||
* Data types for message passing layer used by Ceph.
|
||||
*/
|
||||
|
||||
#define CEPH_MON_PORT 6789 /* default monitor port */
|
||||
|
||||
/*
|
||||
* client-side processes will try to bind to ports in this
|
||||
* range, simply for the benefit of tools like nmap or wireshark
|
||||
* that would like to identify the protocol.
|
||||
*/
|
||||
#define CEPH_PORT_FIRST 6789
|
||||
#define CEPH_PORT_START 6800 /* non-monitors start here */
|
||||
#define CEPH_PORT_LAST 6900
|
||||
|
||||
/*
|
||||
* tcp connection banner. include a protocol version. and adjust
|
||||
* whenever the wire protocol changes. try to keep this string length
|
||||
* constant.
|
||||
*/
|
||||
#define CEPH_BANNER "ceph v027"
|
||||
#define CEPH_BANNER_MAX_LEN 30
|
||||
|
||||
|
||||
/*
|
||||
* Rollover-safe type and comparator for 32-bit sequence numbers.
|
||||
* Comparator returns -1, 0, or 1.
|
||||
*/
|
||||
typedef __u32 ceph_seq_t;
|
||||
|
||||
static inline __s32 ceph_seq_cmp(__u32 a, __u32 b)
|
||||
{
|
||||
return (__s32)a - (__s32)b;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* entity_name -- logical name for a process participating in the
|
||||
* network, e.g. 'mds0' or 'osd3'.
|
||||
*/
|
||||
struct ceph_entity_name {
|
||||
__u8 type; /* CEPH_ENTITY_TYPE_* */
|
||||
__le64 num;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define CEPH_ENTITY_TYPE_MON 0x01
|
||||
#define CEPH_ENTITY_TYPE_MDS 0x02
|
||||
#define CEPH_ENTITY_TYPE_OSD 0x04
|
||||
#define CEPH_ENTITY_TYPE_CLIENT 0x08
|
||||
#define CEPH_ENTITY_TYPE_AUTH 0x20
|
||||
|
||||
#define CEPH_ENTITY_TYPE_ANY 0xFF
|
||||
|
||||
extern const char *ceph_entity_type_name(int type);
|
||||
|
||||
/*
|
||||
* entity_addr -- network address
|
||||
*/
|
||||
struct ceph_entity_addr {
|
||||
__le32 type;
|
||||
__le32 nonce; /* unique id for process (e.g. pid) */
|
||||
struct sockaddr_storage in_addr;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_entity_inst {
|
||||
struct ceph_entity_name name;
|
||||
struct ceph_entity_addr addr;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* used by message exchange protocol */
|
||||
#define CEPH_MSGR_TAG_READY 1 /* server->client: ready for messages */
|
||||
#define CEPH_MSGR_TAG_RESETSESSION 2 /* server->client: reset, try again */
|
||||
#define CEPH_MSGR_TAG_WAIT 3 /* server->client: wait for racing
|
||||
incoming connection */
|
||||
#define CEPH_MSGR_TAG_RETRY_SESSION 4 /* server->client + cseq: try again
|
||||
with higher cseq */
|
||||
#define CEPH_MSGR_TAG_RETRY_GLOBAL 5 /* server->client + gseq: try again
|
||||
with higher gseq */
|
||||
#define CEPH_MSGR_TAG_CLOSE 6 /* closing pipe */
|
||||
#define CEPH_MSGR_TAG_MSG 7 /* message */
|
||||
#define CEPH_MSGR_TAG_ACK 8 /* message ack */
|
||||
#define CEPH_MSGR_TAG_KEEPALIVE 9 /* just a keepalive byte! */
|
||||
#define CEPH_MSGR_TAG_BADPROTOVER 10 /* bad protocol version */
|
||||
#define CEPH_MSGR_TAG_BADAUTHORIZER 11 /* bad authorizer */
|
||||
#define CEPH_MSGR_TAG_FEATURES 12 /* insufficient features */
|
||||
|
||||
|
||||
/*
|
||||
* connection negotiation
|
||||
*/
|
||||
struct ceph_msg_connect {
|
||||
__le64 features; /* supported feature bits */
|
||||
__le32 host_type; /* CEPH_ENTITY_TYPE_* */
|
||||
__le32 global_seq; /* count connections initiated by this host */
|
||||
__le32 connect_seq; /* count connections initiated in this session */
|
||||
__le32 protocol_version;
|
||||
__le32 authorizer_protocol;
|
||||
__le32 authorizer_len;
|
||||
__u8 flags; /* CEPH_MSG_CONNECT_* */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_msg_connect_reply {
|
||||
__u8 tag;
|
||||
__le64 features; /* feature bits for this session */
|
||||
__le32 global_seq;
|
||||
__le32 connect_seq;
|
||||
__le32 protocol_version;
|
||||
__le32 authorizer_len;
|
||||
__u8 flags;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define CEPH_MSG_CONNECT_LOSSY 1 /* messages i send may be safely dropped */
|
||||
|
||||
|
||||
/*
|
||||
* message header
|
||||
*/
|
||||
struct ceph_msg_header_old {
|
||||
__le64 seq; /* message seq# for this session */
|
||||
__le64 tid; /* transaction id */
|
||||
__le16 type; /* message type */
|
||||
__le16 priority; /* priority. higher value == higher priority */
|
||||
__le16 version; /* version of message encoding */
|
||||
|
||||
__le32 front_len; /* bytes in main payload */
|
||||
__le32 middle_len;/* bytes in middle payload */
|
||||
__le32 data_len; /* bytes of data payload */
|
||||
__le16 data_off; /* sender: include full offset;
|
||||
receiver: mask against ~PAGE_MASK */
|
||||
|
||||
struct ceph_entity_inst src, orig_src;
|
||||
__le32 reserved;
|
||||
__le32 crc; /* header crc32c */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_msg_header {
|
||||
__le64 seq; /* message seq# for this session */
|
||||
__le64 tid; /* transaction id */
|
||||
__le16 type; /* message type */
|
||||
__le16 priority; /* priority. higher value == higher priority */
|
||||
__le16 version; /* version of message encoding */
|
||||
|
||||
__le32 front_len; /* bytes in main payload */
|
||||
__le32 middle_len;/* bytes in middle payload */
|
||||
__le32 data_len; /* bytes of data payload */
|
||||
__le16 data_off; /* sender: include full offset;
|
||||
receiver: mask against ~PAGE_MASK */
|
||||
|
||||
struct ceph_entity_name src;
|
||||
__le32 reserved;
|
||||
__le32 crc; /* header crc32c */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define CEPH_MSG_PRIO_LOW 64
|
||||
#define CEPH_MSG_PRIO_DEFAULT 127
|
||||
#define CEPH_MSG_PRIO_HIGH 196
|
||||
#define CEPH_MSG_PRIO_HIGHEST 255
|
||||
|
||||
/*
|
||||
* follows data payload
|
||||
*/
|
||||
struct ceph_msg_footer {
|
||||
__le32 front_crc, middle_crc, data_crc;
|
||||
__u8 flags;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define CEPH_MSG_FOOTER_COMPLETE (1<<0) /* msg wasn't aborted */
|
||||
#define CEPH_MSG_FOOTER_NOCRC (1<<1) /* no data crc */
|
||||
|
||||
|
||||
#endif
|
||||
1771
fs/ceph/osd_client.c
1771
fs/ceph/osd_client.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,233 +0,0 @@
|
|||
#ifndef _FS_CEPH_OSD_CLIENT_H
|
||||
#define _FS_CEPH_OSD_CLIENT_H
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/mempool.h>
|
||||
#include <linux/rbtree.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "osdmap.h"
|
||||
#include "messenger.h"
|
||||
|
||||
struct ceph_msg;
|
||||
struct ceph_snap_context;
|
||||
struct ceph_osd_request;
|
||||
struct ceph_osd_client;
|
||||
struct ceph_authorizer;
|
||||
struct ceph_pagelist;
|
||||
|
||||
/*
|
||||
* completion callback for async writepages
|
||||
*/
|
||||
typedef void (*ceph_osdc_callback_t)(struct ceph_osd_request *,
|
||||
struct ceph_msg *);
|
||||
|
||||
/* a given osd we're communicating with */
|
||||
struct ceph_osd {
|
||||
atomic_t o_ref;
|
||||
struct ceph_osd_client *o_osdc;
|
||||
int o_osd;
|
||||
int o_incarnation;
|
||||
struct rb_node o_node;
|
||||
struct ceph_connection o_con;
|
||||
struct list_head o_requests;
|
||||
struct list_head o_osd_lru;
|
||||
struct ceph_authorizer *o_authorizer;
|
||||
void *o_authorizer_buf, *o_authorizer_reply_buf;
|
||||
size_t o_authorizer_buf_len, o_authorizer_reply_buf_len;
|
||||
unsigned long lru_ttl;
|
||||
int o_marked_for_keepalive;
|
||||
struct list_head o_keepalive_item;
|
||||
};
|
||||
|
||||
/* an in-flight request */
|
||||
struct ceph_osd_request {
|
||||
u64 r_tid; /* unique for this client */
|
||||
struct rb_node r_node;
|
||||
struct list_head r_req_lru_item;
|
||||
struct list_head r_osd_item;
|
||||
struct ceph_osd *r_osd;
|
||||
struct ceph_pg r_pgid;
|
||||
int r_pg_osds[CEPH_PG_MAX_SIZE];
|
||||
int r_num_pg_osds;
|
||||
|
||||
struct ceph_connection *r_con_filling_msg;
|
||||
|
||||
struct ceph_msg *r_request, *r_reply;
|
||||
int r_result;
|
||||
int r_flags; /* any additional flags for the osd */
|
||||
u32 r_sent; /* >0 if r_request is sending/sent */
|
||||
int r_got_reply;
|
||||
|
||||
struct ceph_osd_client *r_osdc;
|
||||
struct kref r_kref;
|
||||
bool r_mempool;
|
||||
struct completion r_completion, r_safe_completion;
|
||||
ceph_osdc_callback_t r_callback, r_safe_callback;
|
||||
struct ceph_eversion r_reassert_version;
|
||||
struct list_head r_unsafe_item;
|
||||
|
||||
struct inode *r_inode; /* for use by callbacks */
|
||||
|
||||
char r_oid[40]; /* object name */
|
||||
int r_oid_len;
|
||||
unsigned long r_stamp; /* send OR check time */
|
||||
bool r_resend; /* msg send failed, needs retry */
|
||||
|
||||
struct ceph_file_layout r_file_layout;
|
||||
struct ceph_snap_context *r_snapc; /* snap context for writes */
|
||||
unsigned r_num_pages; /* size of page array (follows) */
|
||||
struct page **r_pages; /* pages for data payload */
|
||||
int r_pages_from_pool;
|
||||
int r_own_pages; /* if true, i own page list */
|
||||
#ifdef CONFIG_BLOCK
|
||||
struct bio *r_bio; /* instead of pages */
|
||||
#endif
|
||||
|
||||
struct ceph_pagelist *r_trail; /* trailing part of the data */
|
||||
};
|
||||
|
||||
struct ceph_osd_client {
|
||||
struct ceph_client *client;
|
||||
|
||||
struct ceph_osdmap *osdmap; /* current map */
|
||||
struct rw_semaphore map_sem;
|
||||
struct completion map_waiters;
|
||||
u64 last_requested_map;
|
||||
|
||||
struct mutex request_mutex;
|
||||
struct rb_root osds; /* osds */
|
||||
struct list_head osd_lru; /* idle osds */
|
||||
u64 timeout_tid; /* tid of timeout triggering rq */
|
||||
u64 last_tid; /* tid of last request */
|
||||
struct rb_root requests; /* pending requests */
|
||||
struct list_head req_lru; /* pending requests lru */
|
||||
int num_requests;
|
||||
struct delayed_work timeout_work;
|
||||
struct delayed_work osds_timeout_work;
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_file;
|
||||
#endif
|
||||
|
||||
mempool_t *req_mempool;
|
||||
|
||||
struct ceph_msgpool msgpool_op;
|
||||
struct ceph_msgpool msgpool_op_reply;
|
||||
};
|
||||
|
||||
struct ceph_osd_req_op {
|
||||
u16 op; /* CEPH_OSD_OP_* */
|
||||
u32 flags; /* CEPH_OSD_FLAG_* */
|
||||
union {
|
||||
struct {
|
||||
u64 offset, length;
|
||||
u64 truncate_size;
|
||||
u32 truncate_seq;
|
||||
} extent;
|
||||
struct {
|
||||
const char *name;
|
||||
u32 name_len;
|
||||
const char *val;
|
||||
u32 value_len;
|
||||
__u8 cmp_op; /* CEPH_OSD_CMPXATTR_OP_* */
|
||||
__u8 cmp_mode; /* CEPH_OSD_CMPXATTR_MODE_* */
|
||||
} xattr;
|
||||
struct {
|
||||
const char *class_name;
|
||||
__u8 class_len;
|
||||
const char *method_name;
|
||||
__u8 method_len;
|
||||
__u8 argc;
|
||||
const char *indata;
|
||||
u32 indata_len;
|
||||
} cls;
|
||||
struct {
|
||||
u64 cookie, count;
|
||||
} pgls;
|
||||
struct {
|
||||
u64 snapid;
|
||||
} snap;
|
||||
};
|
||||
u32 payload_len;
|
||||
};
|
||||
|
||||
extern int ceph_osdc_init(struct ceph_osd_client *osdc,
|
||||
struct ceph_client *client);
|
||||
extern void ceph_osdc_stop(struct ceph_osd_client *osdc);
|
||||
|
||||
extern void ceph_osdc_handle_reply(struct ceph_osd_client *osdc,
|
||||
struct ceph_msg *msg);
|
||||
extern void ceph_osdc_handle_map(struct ceph_osd_client *osdc,
|
||||
struct ceph_msg *msg);
|
||||
|
||||
extern void ceph_calc_raw_layout(struct ceph_osd_client *osdc,
|
||||
struct ceph_file_layout *layout,
|
||||
u64 snapid,
|
||||
u64 off, u64 *plen, u64 *bno,
|
||||
struct ceph_osd_request *req,
|
||||
struct ceph_osd_req_op *op);
|
||||
|
||||
extern struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
|
||||
int flags,
|
||||
struct ceph_snap_context *snapc,
|
||||
struct ceph_osd_req_op *ops,
|
||||
bool use_mempool,
|
||||
gfp_t gfp_flags,
|
||||
struct page **pages,
|
||||
struct bio *bio);
|
||||
|
||||
extern void ceph_osdc_build_request(struct ceph_osd_request *req,
|
||||
u64 off, u64 *plen,
|
||||
struct ceph_osd_req_op *src_ops,
|
||||
struct ceph_snap_context *snapc,
|
||||
struct timespec *mtime,
|
||||
const char *oid,
|
||||
int oid_len);
|
||||
|
||||
extern struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *,
|
||||
struct ceph_file_layout *layout,
|
||||
struct ceph_vino vino,
|
||||
u64 offset, u64 *len, int op, int flags,
|
||||
struct ceph_snap_context *snapc,
|
||||
int do_sync, u32 truncate_seq,
|
||||
u64 truncate_size,
|
||||
struct timespec *mtime,
|
||||
bool use_mempool, int num_reply);
|
||||
|
||||
static inline void ceph_osdc_get_request(struct ceph_osd_request *req)
|
||||
{
|
||||
kref_get(&req->r_kref);
|
||||
}
|
||||
extern void ceph_osdc_release_request(struct kref *kref);
|
||||
static inline void ceph_osdc_put_request(struct ceph_osd_request *req)
|
||||
{
|
||||
kref_put(&req->r_kref, ceph_osdc_release_request);
|
||||
}
|
||||
|
||||
extern int ceph_osdc_start_request(struct ceph_osd_client *osdc,
|
||||
struct ceph_osd_request *req,
|
||||
bool nofail);
|
||||
extern int ceph_osdc_wait_request(struct ceph_osd_client *osdc,
|
||||
struct ceph_osd_request *req);
|
||||
extern void ceph_osdc_sync(struct ceph_osd_client *osdc);
|
||||
|
||||
extern int ceph_osdc_readpages(struct ceph_osd_client *osdc,
|
||||
struct ceph_vino vino,
|
||||
struct ceph_file_layout *layout,
|
||||
u64 off, u64 *plen,
|
||||
u32 truncate_seq, u64 truncate_size,
|
||||
struct page **pages, int nr_pages);
|
||||
|
||||
extern int ceph_osdc_writepages(struct ceph_osd_client *osdc,
|
||||
struct ceph_vino vino,
|
||||
struct ceph_file_layout *layout,
|
||||
struct ceph_snap_context *sc,
|
||||
u64 off, u64 len,
|
||||
u32 truncate_seq, u64 truncate_size,
|
||||
struct timespec *mtime,
|
||||
struct page **pages, int nr_pages,
|
||||
int flags, int do_sync, bool nofail);
|
||||
|
||||
#endif
|
||||
|
||||
1123
fs/ceph/osdmap.c
1123
fs/ceph/osdmap.c
File diff suppressed because it is too large
Load diff
130
fs/ceph/osdmap.h
130
fs/ceph/osdmap.h
|
|
@ -1,130 +0,0 @@
|
|||
#ifndef _FS_CEPH_OSDMAP_H
|
||||
#define _FS_CEPH_OSDMAP_H
|
||||
|
||||
#include <linux/rbtree.h>
|
||||
#include "types.h"
|
||||
#include "ceph_fs.h"
|
||||
#include "crush/crush.h"
|
||||
|
||||
/*
|
||||
* The osd map describes the current membership of the osd cluster and
|
||||
* specifies the mapping of objects to placement groups and placement
|
||||
* groups to (sets of) osds. That is, it completely specifies the
|
||||
* (desired) distribution of all data objects in the system at some
|
||||
* point in time.
|
||||
*
|
||||
* Each map version is identified by an epoch, which increases monotonically.
|
||||
*
|
||||
* The map can be updated either via an incremental map (diff) describing
|
||||
* the change between two successive epochs, or as a fully encoded map.
|
||||
*/
|
||||
struct ceph_pg_pool_info {
|
||||
struct rb_node node;
|
||||
int id;
|
||||
struct ceph_pg_pool v;
|
||||
int pg_num_mask, pgp_num_mask, lpg_num_mask, lpgp_num_mask;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct ceph_pg_mapping {
|
||||
struct rb_node node;
|
||||
struct ceph_pg pgid;
|
||||
int len;
|
||||
int osds[];
|
||||
};
|
||||
|
||||
struct ceph_osdmap {
|
||||
struct ceph_fsid fsid;
|
||||
u32 epoch;
|
||||
u32 mkfs_epoch;
|
||||
struct ceph_timespec created, modified;
|
||||
|
||||
u32 flags; /* CEPH_OSDMAP_* */
|
||||
|
||||
u32 max_osd; /* size of osd_state, _offload, _addr arrays */
|
||||
u8 *osd_state; /* CEPH_OSD_* */
|
||||
u32 *osd_weight; /* 0 = failed, 0x10000 = 100% normal */
|
||||
struct ceph_entity_addr *osd_addr;
|
||||
|
||||
struct rb_root pg_temp;
|
||||
struct rb_root pg_pools;
|
||||
u32 pool_max;
|
||||
|
||||
/* the CRUSH map specifies the mapping of placement groups to
|
||||
* the list of osds that store+replicate them. */
|
||||
struct crush_map *crush;
|
||||
};
|
||||
|
||||
/*
|
||||
* file layout helpers
|
||||
*/
|
||||
#define ceph_file_layout_su(l) ((__s32)le32_to_cpu((l).fl_stripe_unit))
|
||||
#define ceph_file_layout_stripe_count(l) \
|
||||
((__s32)le32_to_cpu((l).fl_stripe_count))
|
||||
#define ceph_file_layout_object_size(l) ((__s32)le32_to_cpu((l).fl_object_size))
|
||||
#define ceph_file_layout_cas_hash(l) ((__s32)le32_to_cpu((l).fl_cas_hash))
|
||||
#define ceph_file_layout_object_su(l) \
|
||||
((__s32)le32_to_cpu((l).fl_object_stripe_unit))
|
||||
#define ceph_file_layout_pg_preferred(l) \
|
||||
((__s32)le32_to_cpu((l).fl_pg_preferred))
|
||||
#define ceph_file_layout_pg_pool(l) \
|
||||
((__s32)le32_to_cpu((l).fl_pg_pool))
|
||||
|
||||
static inline unsigned ceph_file_layout_stripe_width(struct ceph_file_layout *l)
|
||||
{
|
||||
return le32_to_cpu(l->fl_stripe_unit) *
|
||||
le32_to_cpu(l->fl_stripe_count);
|
||||
}
|
||||
|
||||
/* "period" == bytes before i start on a new set of objects */
|
||||
static inline unsigned ceph_file_layout_period(struct ceph_file_layout *l)
|
||||
{
|
||||
return le32_to_cpu(l->fl_object_size) *
|
||||
le32_to_cpu(l->fl_stripe_count);
|
||||
}
|
||||
|
||||
|
||||
static inline int ceph_osd_is_up(struct ceph_osdmap *map, int osd)
|
||||
{
|
||||
return (osd < map->max_osd) && (map->osd_state[osd] & CEPH_OSD_UP);
|
||||
}
|
||||
|
||||
static inline bool ceph_osdmap_flag(struct ceph_osdmap *map, int flag)
|
||||
{
|
||||
return map && (map->flags & flag);
|
||||
}
|
||||
|
||||
extern char *ceph_osdmap_state_str(char *str, int len, int state);
|
||||
|
||||
static inline struct ceph_entity_addr *ceph_osd_addr(struct ceph_osdmap *map,
|
||||
int osd)
|
||||
{
|
||||
if (osd >= map->max_osd)
|
||||
return NULL;
|
||||
return &map->osd_addr[osd];
|
||||
}
|
||||
|
||||
extern struct ceph_osdmap *osdmap_decode(void **p, void *end);
|
||||
extern struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
|
||||
struct ceph_osdmap *map,
|
||||
struct ceph_messenger *msgr);
|
||||
extern void ceph_osdmap_destroy(struct ceph_osdmap *map);
|
||||
|
||||
/* calculate mapping of a file extent to an object */
|
||||
extern void ceph_calc_file_object_mapping(struct ceph_file_layout *layout,
|
||||
u64 off, u64 *plen,
|
||||
u64 *bno, u64 *oxoff, u64 *oxlen);
|
||||
|
||||
/* calculate mapping of object to a placement group */
|
||||
extern int ceph_calc_object_layout(struct ceph_object_layout *ol,
|
||||
const char *oid,
|
||||
struct ceph_file_layout *fl,
|
||||
struct ceph_osdmap *osdmap);
|
||||
extern int ceph_calc_pg_acting(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
|
||||
int *acting);
|
||||
extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap,
|
||||
struct ceph_pg pgid);
|
||||
|
||||
extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/highmem.h>
|
||||
|
||||
#include "pagelist.h"
|
||||
|
||||
static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl)
|
||||
{
|
||||
struct page *page = list_entry(pl->head.prev, struct page,
|
||||
lru);
|
||||
kunmap(page);
|
||||
}
|
||||
|
||||
int ceph_pagelist_release(struct ceph_pagelist *pl)
|
||||
{
|
||||
if (pl->mapped_tail)
|
||||
ceph_pagelist_unmap_tail(pl);
|
||||
|
||||
while (!list_empty(&pl->head)) {
|
||||
struct page *page = list_first_entry(&pl->head, struct page,
|
||||
lru);
|
||||
list_del(&page->lru);
|
||||
__free_page(page);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ceph_pagelist_addpage(struct ceph_pagelist *pl)
|
||||
{
|
||||
struct page *page = __page_cache_alloc(GFP_NOFS);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
pl->room += PAGE_SIZE;
|
||||
list_add_tail(&page->lru, &pl->head);
|
||||
if (pl->mapped_tail)
|
||||
ceph_pagelist_unmap_tail(pl);
|
||||
pl->mapped_tail = kmap(page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ceph_pagelist_append(struct ceph_pagelist *pl, const void *buf, size_t len)
|
||||
{
|
||||
while (pl->room < len) {
|
||||
size_t bit = pl->room;
|
||||
int ret;
|
||||
|
||||
memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK),
|
||||
buf, bit);
|
||||
pl->length += bit;
|
||||
pl->room -= bit;
|
||||
buf += bit;
|
||||
len -= bit;
|
||||
ret = ceph_pagelist_addpage(pl);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK), buf, len);
|
||||
pl->length += len;
|
||||
pl->room -= len;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
#ifndef __FS_CEPH_PAGELIST_H
|
||||
#define __FS_CEPH_PAGELIST_H
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
struct ceph_pagelist {
|
||||
struct list_head head;
|
||||
void *mapped_tail;
|
||||
size_t length;
|
||||
size_t room;
|
||||
};
|
||||
|
||||
static inline void ceph_pagelist_init(struct ceph_pagelist *pl)
|
||||
{
|
||||
INIT_LIST_HEAD(&pl->head);
|
||||
pl->mapped_tail = NULL;
|
||||
pl->length = 0;
|
||||
pl->room = 0;
|
||||
}
|
||||
extern int ceph_pagelist_release(struct ceph_pagelist *pl);
|
||||
|
||||
extern int ceph_pagelist_append(struct ceph_pagelist *pl, const void *d, size_t l);
|
||||
|
||||
static inline int ceph_pagelist_encode_64(struct ceph_pagelist *pl, u64 v)
|
||||
{
|
||||
__le64 ev = cpu_to_le64(v);
|
||||
return ceph_pagelist_append(pl, &ev, sizeof(ev));
|
||||
}
|
||||
static inline int ceph_pagelist_encode_32(struct ceph_pagelist *pl, u32 v)
|
||||
{
|
||||
__le32 ev = cpu_to_le32(v);
|
||||
return ceph_pagelist_append(pl, &ev, sizeof(ev));
|
||||
}
|
||||
static inline int ceph_pagelist_encode_16(struct ceph_pagelist *pl, u16 v)
|
||||
{
|
||||
__le16 ev = cpu_to_le16(v);
|
||||
return ceph_pagelist_append(pl, &ev, sizeof(ev));
|
||||
}
|
||||
static inline int ceph_pagelist_encode_8(struct ceph_pagelist *pl, u8 v)
|
||||
{
|
||||
return ceph_pagelist_append(pl, &v, 1);
|
||||
}
|
||||
static inline int ceph_pagelist_encode_string(struct ceph_pagelist *pl,
|
||||
char *s, size_t len)
|
||||
{
|
||||
int ret = ceph_pagelist_encode_32(pl, len);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (len)
|
||||
return ceph_pagelist_append(pl, s, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
405
fs/ceph/rados.h
405
fs/ceph/rados.h
|
|
@ -1,405 +0,0 @@
|
|||
#ifndef CEPH_RADOS_H
|
||||
#define CEPH_RADOS_H
|
||||
|
||||
/*
|
||||
* Data types for the Ceph distributed object storage layer RADOS
|
||||
* (Reliable Autonomic Distributed Object Store).
|
||||
*/
|
||||
|
||||
#include "msgr.h"
|
||||
|
||||
/*
|
||||
* osdmap encoding versions
|
||||
*/
|
||||
#define CEPH_OSDMAP_INC_VERSION 5
|
||||
#define CEPH_OSDMAP_INC_VERSION_EXT 5
|
||||
#define CEPH_OSDMAP_VERSION 5
|
||||
#define CEPH_OSDMAP_VERSION_EXT 5
|
||||
|
||||
/*
|
||||
* fs id
|
||||
*/
|
||||
struct ceph_fsid {
|
||||
unsigned char fsid[16];
|
||||
};
|
||||
|
||||
static inline int ceph_fsid_compare(const struct ceph_fsid *a,
|
||||
const struct ceph_fsid *b)
|
||||
{
|
||||
return memcmp(a, b, sizeof(*a));
|
||||
}
|
||||
|
||||
/*
|
||||
* ino, object, etc.
|
||||
*/
|
||||
typedef __le64 ceph_snapid_t;
|
||||
#define CEPH_SNAPDIR ((__u64)(-1)) /* reserved for hidden .snap dir */
|
||||
#define CEPH_NOSNAP ((__u64)(-2)) /* "head", "live" revision */
|
||||
#define CEPH_MAXSNAP ((__u64)(-3)) /* largest valid snapid */
|
||||
|
||||
struct ceph_timespec {
|
||||
__le32 tv_sec;
|
||||
__le32 tv_nsec;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/*
|
||||
* object layout - how objects are mapped into PGs
|
||||
*/
|
||||
#define CEPH_OBJECT_LAYOUT_HASH 1
|
||||
#define CEPH_OBJECT_LAYOUT_LINEAR 2
|
||||
#define CEPH_OBJECT_LAYOUT_HASHINO 3
|
||||
|
||||
/*
|
||||
* pg layout -- how PGs are mapped onto (sets of) OSDs
|
||||
*/
|
||||
#define CEPH_PG_LAYOUT_CRUSH 0
|
||||
#define CEPH_PG_LAYOUT_HASH 1
|
||||
#define CEPH_PG_LAYOUT_LINEAR 2
|
||||
#define CEPH_PG_LAYOUT_HYBRID 3
|
||||
|
||||
#define CEPH_PG_MAX_SIZE 16 /* max # osds in a single pg */
|
||||
|
||||
/*
|
||||
* placement group.
|
||||
* we encode this into one __le64.
|
||||
*/
|
||||
struct ceph_pg {
|
||||
__le16 preferred; /* preferred primary osd */
|
||||
__le16 ps; /* placement seed */
|
||||
__le32 pool; /* object pool */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* pg_pool is a set of pgs storing a pool of objects
|
||||
*
|
||||
* pg_num -- base number of pseudorandomly placed pgs
|
||||
*
|
||||
* pgp_num -- effective number when calculating pg placement. this
|
||||
* is used for pg_num increases. new pgs result in data being "split"
|
||||
* into new pgs. for this to proceed smoothly, new pgs are intiially
|
||||
* colocated with their parents; that is, pgp_num doesn't increase
|
||||
* until the new pgs have successfully split. only _then_ are the new
|
||||
* pgs placed independently.
|
||||
*
|
||||
* lpg_num -- localized pg count (per device). replicas are randomly
|
||||
* selected.
|
||||
*
|
||||
* lpgp_num -- as above.
|
||||
*/
|
||||
#define CEPH_PG_TYPE_REP 1
|
||||
#define CEPH_PG_TYPE_RAID4 2
|
||||
#define CEPH_PG_POOL_VERSION 2
|
||||
struct ceph_pg_pool {
|
||||
__u8 type; /* CEPH_PG_TYPE_* */
|
||||
__u8 size; /* number of osds in each pg */
|
||||
__u8 crush_ruleset; /* crush placement rule */
|
||||
__u8 object_hash; /* hash mapping object name to ps */
|
||||
__le32 pg_num, pgp_num; /* number of pg's */
|
||||
__le32 lpg_num, lpgp_num; /* number of localized pg's */
|
||||
__le32 last_change; /* most recent epoch changed */
|
||||
__le64 snap_seq; /* seq for per-pool snapshot */
|
||||
__le32 snap_epoch; /* epoch of last snap */
|
||||
__le32 num_snaps;
|
||||
__le32 num_removed_snap_intervals; /* if non-empty, NO per-pool snaps */
|
||||
__le64 auid; /* who owns the pg */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* stable_mod func is used to control number of placement groups.
|
||||
* similar to straight-up modulo, but produces a stable mapping as b
|
||||
* increases over time. b is the number of bins, and bmask is the
|
||||
* containing power of 2 minus 1.
|
||||
*
|
||||
* b <= bmask and bmask=(2**n)-1
|
||||
* e.g., b=12 -> bmask=15, b=123 -> bmask=127
|
||||
*/
|
||||
static inline int ceph_stable_mod(int x, int b, int bmask)
|
||||
{
|
||||
if ((x & bmask) < b)
|
||||
return x & bmask;
|
||||
else
|
||||
return x & (bmask >> 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* object layout - how a given object should be stored.
|
||||
*/
|
||||
struct ceph_object_layout {
|
||||
struct ceph_pg ol_pgid; /* raw pg, with _full_ ps precision. */
|
||||
__le32 ol_stripe_unit; /* for per-object parity, if any */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* compound epoch+version, used by storage layer to serialize mutations
|
||||
*/
|
||||
struct ceph_eversion {
|
||||
__le32 epoch;
|
||||
__le64 version;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* osd map bits
|
||||
*/
|
||||
|
||||
/* status bits */
|
||||
#define CEPH_OSD_EXISTS 1
|
||||
#define CEPH_OSD_UP 2
|
||||
|
||||
/* osd weights. fixed point value: 0x10000 == 1.0 ("in"), 0 == "out" */
|
||||
#define CEPH_OSD_IN 0x10000
|
||||
#define CEPH_OSD_OUT 0
|
||||
|
||||
|
||||
/*
|
||||
* osd map flag bits
|
||||
*/
|
||||
#define CEPH_OSDMAP_NEARFULL (1<<0) /* sync writes (near ENOSPC) */
|
||||
#define CEPH_OSDMAP_FULL (1<<1) /* no data writes (ENOSPC) */
|
||||
#define CEPH_OSDMAP_PAUSERD (1<<2) /* pause all reads */
|
||||
#define CEPH_OSDMAP_PAUSEWR (1<<3) /* pause all writes */
|
||||
#define CEPH_OSDMAP_PAUSEREC (1<<4) /* pause recovery */
|
||||
|
||||
/*
|
||||
* osd ops
|
||||
*/
|
||||
#define CEPH_OSD_OP_MODE 0xf000
|
||||
#define CEPH_OSD_OP_MODE_RD 0x1000
|
||||
#define CEPH_OSD_OP_MODE_WR 0x2000
|
||||
#define CEPH_OSD_OP_MODE_RMW 0x3000
|
||||
#define CEPH_OSD_OP_MODE_SUB 0x4000
|
||||
|
||||
#define CEPH_OSD_OP_TYPE 0x0f00
|
||||
#define CEPH_OSD_OP_TYPE_LOCK 0x0100
|
||||
#define CEPH_OSD_OP_TYPE_DATA 0x0200
|
||||
#define CEPH_OSD_OP_TYPE_ATTR 0x0300
|
||||
#define CEPH_OSD_OP_TYPE_EXEC 0x0400
|
||||
#define CEPH_OSD_OP_TYPE_PG 0x0500
|
||||
|
||||
enum {
|
||||
/** data **/
|
||||
/* read */
|
||||
CEPH_OSD_OP_READ = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 1,
|
||||
CEPH_OSD_OP_STAT = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 2,
|
||||
|
||||
/* fancy read */
|
||||
CEPH_OSD_OP_MASKTRUNC = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 4,
|
||||
|
||||
/* write */
|
||||
CEPH_OSD_OP_WRITE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 1,
|
||||
CEPH_OSD_OP_WRITEFULL = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 2,
|
||||
CEPH_OSD_OP_TRUNCATE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 3,
|
||||
CEPH_OSD_OP_ZERO = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 4,
|
||||
CEPH_OSD_OP_DELETE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 5,
|
||||
|
||||
/* fancy write */
|
||||
CEPH_OSD_OP_APPEND = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 6,
|
||||
CEPH_OSD_OP_STARTSYNC = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 7,
|
||||
CEPH_OSD_OP_SETTRUNC = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 8,
|
||||
CEPH_OSD_OP_TRIMTRUNC = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 9,
|
||||
|
||||
CEPH_OSD_OP_TMAPUP = CEPH_OSD_OP_MODE_RMW | CEPH_OSD_OP_TYPE_DATA | 10,
|
||||
CEPH_OSD_OP_TMAPPUT = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 11,
|
||||
CEPH_OSD_OP_TMAPGET = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 12,
|
||||
|
||||
CEPH_OSD_OP_CREATE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 13,
|
||||
CEPH_OSD_OP_ROLLBACK= CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 14,
|
||||
|
||||
/** attrs **/
|
||||
/* read */
|
||||
CEPH_OSD_OP_GETXATTR = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 1,
|
||||
CEPH_OSD_OP_GETXATTRS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 2,
|
||||
CEPH_OSD_OP_CMPXATTR = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 3,
|
||||
|
||||
/* write */
|
||||
CEPH_OSD_OP_SETXATTR = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 1,
|
||||
CEPH_OSD_OP_SETXATTRS = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 2,
|
||||
CEPH_OSD_OP_RESETXATTRS = CEPH_OSD_OP_MODE_WR|CEPH_OSD_OP_TYPE_ATTR | 3,
|
||||
CEPH_OSD_OP_RMXATTR = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 4,
|
||||
|
||||
/** subop **/
|
||||
CEPH_OSD_OP_PULL = CEPH_OSD_OP_MODE_SUB | 1,
|
||||
CEPH_OSD_OP_PUSH = CEPH_OSD_OP_MODE_SUB | 2,
|
||||
CEPH_OSD_OP_BALANCEREADS = CEPH_OSD_OP_MODE_SUB | 3,
|
||||
CEPH_OSD_OP_UNBALANCEREADS = CEPH_OSD_OP_MODE_SUB | 4,
|
||||
CEPH_OSD_OP_SCRUB = CEPH_OSD_OP_MODE_SUB | 5,
|
||||
|
||||
/** lock **/
|
||||
CEPH_OSD_OP_WRLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 1,
|
||||
CEPH_OSD_OP_WRUNLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 2,
|
||||
CEPH_OSD_OP_RDLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 3,
|
||||
CEPH_OSD_OP_RDUNLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 4,
|
||||
CEPH_OSD_OP_UPLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 5,
|
||||
CEPH_OSD_OP_DNLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 6,
|
||||
|
||||
/** exec **/
|
||||
CEPH_OSD_OP_CALL = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_EXEC | 1,
|
||||
|
||||
/** pg **/
|
||||
CEPH_OSD_OP_PGLS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_PG | 1,
|
||||
};
|
||||
|
||||
static inline int ceph_osd_op_type_lock(int op)
|
||||
{
|
||||
return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_LOCK;
|
||||
}
|
||||
static inline int ceph_osd_op_type_data(int op)
|
||||
{
|
||||
return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_DATA;
|
||||
}
|
||||
static inline int ceph_osd_op_type_attr(int op)
|
||||
{
|
||||
return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_ATTR;
|
||||
}
|
||||
static inline int ceph_osd_op_type_exec(int op)
|
||||
{
|
||||
return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_EXEC;
|
||||
}
|
||||
static inline int ceph_osd_op_type_pg(int op)
|
||||
{
|
||||
return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_PG;
|
||||
}
|
||||
|
||||
static inline int ceph_osd_op_mode_subop(int op)
|
||||
{
|
||||
return (op & CEPH_OSD_OP_MODE) == CEPH_OSD_OP_MODE_SUB;
|
||||
}
|
||||
static inline int ceph_osd_op_mode_read(int op)
|
||||
{
|
||||
return (op & CEPH_OSD_OP_MODE) == CEPH_OSD_OP_MODE_RD;
|
||||
}
|
||||
static inline int ceph_osd_op_mode_modify(int op)
|
||||
{
|
||||
return (op & CEPH_OSD_OP_MODE) == CEPH_OSD_OP_MODE_WR;
|
||||
}
|
||||
|
||||
/*
|
||||
* note that the following tmap stuff is also defined in the ceph librados.h
|
||||
* any modification here needs to be updated there
|
||||
*/
|
||||
#define CEPH_OSD_TMAP_HDR 'h'
|
||||
#define CEPH_OSD_TMAP_SET 's'
|
||||
#define CEPH_OSD_TMAP_RM 'r'
|
||||
|
||||
extern const char *ceph_osd_op_name(int op);
|
||||
|
||||
|
||||
/*
|
||||
* osd op flags
|
||||
*
|
||||
* An op may be READ, WRITE, or READ|WRITE.
|
||||
*/
|
||||
enum {
|
||||
CEPH_OSD_FLAG_ACK = 1, /* want (or is) "ack" ack */
|
||||
CEPH_OSD_FLAG_ONNVRAM = 2, /* want (or is) "onnvram" ack */
|
||||
CEPH_OSD_FLAG_ONDISK = 4, /* want (or is) "ondisk" ack */
|
||||
CEPH_OSD_FLAG_RETRY = 8, /* resend attempt */
|
||||
CEPH_OSD_FLAG_READ = 16, /* op may read */
|
||||
CEPH_OSD_FLAG_WRITE = 32, /* op may write */
|
||||
CEPH_OSD_FLAG_ORDERSNAP = 64, /* EOLDSNAP if snapc is out of order */
|
||||
CEPH_OSD_FLAG_PEERSTAT = 128, /* msg includes osd_peer_stat */
|
||||
CEPH_OSD_FLAG_BALANCE_READS = 256,
|
||||
CEPH_OSD_FLAG_PARALLELEXEC = 512, /* execute op in parallel */
|
||||
CEPH_OSD_FLAG_PGOP = 1024, /* pg op, no object */
|
||||
CEPH_OSD_FLAG_EXEC = 2048, /* op may exec */
|
||||
CEPH_OSD_FLAG_EXEC_PUBLIC = 4096, /* op may exec (public) */
|
||||
};
|
||||
|
||||
enum {
|
||||
CEPH_OSD_OP_FLAG_EXCL = 1, /* EXCL object create */
|
||||
};
|
||||
|
||||
#define EOLDSNAPC ERESTART /* ORDERSNAP flag set; writer has old snapc*/
|
||||
#define EBLACKLISTED ESHUTDOWN /* blacklisted */
|
||||
|
||||
/* xattr comparison */
|
||||
enum {
|
||||
CEPH_OSD_CMPXATTR_OP_NOP = 0,
|
||||
CEPH_OSD_CMPXATTR_OP_EQ = 1,
|
||||
CEPH_OSD_CMPXATTR_OP_NE = 2,
|
||||
CEPH_OSD_CMPXATTR_OP_GT = 3,
|
||||
CEPH_OSD_CMPXATTR_OP_GTE = 4,
|
||||
CEPH_OSD_CMPXATTR_OP_LT = 5,
|
||||
CEPH_OSD_CMPXATTR_OP_LTE = 6
|
||||
};
|
||||
|
||||
enum {
|
||||
CEPH_OSD_CMPXATTR_MODE_STRING = 1,
|
||||
CEPH_OSD_CMPXATTR_MODE_U64 = 2
|
||||
};
|
||||
|
||||
/*
|
||||
* an individual object operation. each may be accompanied by some data
|
||||
* payload
|
||||
*/
|
||||
struct ceph_osd_op {
|
||||
__le16 op; /* CEPH_OSD_OP_* */
|
||||
__le32 flags; /* CEPH_OSD_FLAG_* */
|
||||
union {
|
||||
struct {
|
||||
__le64 offset, length;
|
||||
__le64 truncate_size;
|
||||
__le32 truncate_seq;
|
||||
} __attribute__ ((packed)) extent;
|
||||
struct {
|
||||
__le32 name_len;
|
||||
__le32 value_len;
|
||||
__u8 cmp_op; /* CEPH_OSD_CMPXATTR_OP_* */
|
||||
__u8 cmp_mode; /* CEPH_OSD_CMPXATTR_MODE_* */
|
||||
} __attribute__ ((packed)) xattr;
|
||||
struct {
|
||||
__u8 class_len;
|
||||
__u8 method_len;
|
||||
__u8 argc;
|
||||
__le32 indata_len;
|
||||
} __attribute__ ((packed)) cls;
|
||||
struct {
|
||||
__le64 cookie, count;
|
||||
} __attribute__ ((packed)) pgls;
|
||||
struct {
|
||||
__le64 snapid;
|
||||
} __attribute__ ((packed)) snap;
|
||||
};
|
||||
__le32 payload_len;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* osd request message header. each request may include multiple
|
||||
* ceph_osd_op object operations.
|
||||
*/
|
||||
struct ceph_osd_request_head {
|
||||
__le32 client_inc; /* client incarnation */
|
||||
struct ceph_object_layout layout; /* pgid */
|
||||
__le32 osdmap_epoch; /* client's osdmap epoch */
|
||||
|
||||
__le32 flags;
|
||||
|
||||
struct ceph_timespec mtime; /* for mutations only */
|
||||
struct ceph_eversion reassert_version; /* if we are replaying op */
|
||||
|
||||
__le32 object_len; /* length of object name */
|
||||
|
||||
__le64 snapid; /* snapid to read */
|
||||
__le64 snap_seq; /* writer's snap context */
|
||||
__le32 num_snaps;
|
||||
|
||||
__le16 num_ops;
|
||||
struct ceph_osd_op ops[]; /* followed by ops[], obj, ticket, snaps */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ceph_osd_reply_head {
|
||||
__le32 client_inc; /* client incarnation */
|
||||
__le32 flags;
|
||||
struct ceph_object_layout layout;
|
||||
__le32 osdmap_epoch;
|
||||
struct ceph_eversion reassert_version; /* for replaying uncommitted */
|
||||
|
||||
__le32 result; /* result code */
|
||||
|
||||
__le32 object_len; /* length of object name */
|
||||
__le32 num_ops;
|
||||
struct ceph_osd_op ops[0]; /* ops[], object */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
#include "ceph_debug.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include <linux/sort.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "super.h"
|
||||
#include "decode.h"
|
||||
#include "mds_client.h"
|
||||
|
||||
#include <linux/ceph/decode.h>
|
||||
|
||||
/*
|
||||
* Snapshots in ceph are driven in large part by cooperation from the
|
||||
|
|
@ -526,7 +528,7 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
|
|||
struct ceph_cap_snap *capsnap)
|
||||
{
|
||||
struct inode *inode = &ci->vfs_inode;
|
||||
struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
|
||||
BUG_ON(capsnap->writing);
|
||||
capsnap->size = inode->i_size;
|
||||
|
|
@ -747,7 +749,7 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc,
|
|||
struct ceph_mds_session *session,
|
||||
struct ceph_msg *msg)
|
||||
{
|
||||
struct super_block *sb = mdsc->client->sb;
|
||||
struct super_block *sb = mdsc->fsc->sb;
|
||||
int mds = session->s_mds;
|
||||
u64 split;
|
||||
int op;
|
||||
|
|
|
|||
|
|
@ -1,71 +1,9 @@
|
|||
/*
|
||||
* Ceph string constants
|
||||
* Ceph fs string constants
|
||||
*/
|
||||
#include "types.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ceph/types.h>
|
||||
|
||||
const char *ceph_entity_type_name(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case CEPH_ENTITY_TYPE_MDS: return "mds";
|
||||
case CEPH_ENTITY_TYPE_OSD: return "osd";
|
||||
case CEPH_ENTITY_TYPE_MON: return "mon";
|
||||
case CEPH_ENTITY_TYPE_CLIENT: return "client";
|
||||
case CEPH_ENTITY_TYPE_AUTH: return "auth";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const char *ceph_osd_op_name(int op)
|
||||
{
|
||||
switch (op) {
|
||||
case CEPH_OSD_OP_READ: return "read";
|
||||
case CEPH_OSD_OP_STAT: return "stat";
|
||||
|
||||
case CEPH_OSD_OP_MASKTRUNC: return "masktrunc";
|
||||
|
||||
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_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_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";
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
|
||||
const char *ceph_mds_state_name(int s)
|
||||
{
|
||||
|
|
@ -177,17 +115,3 @@ const char *ceph_snap_op_name(int o)
|
|||
}
|
||||
return "???";
|
||||
}
|
||||
|
||||
const char *ceph_pool_op_name(int op)
|
||||
{
|
||||
switch (op) {
|
||||
case POOL_OP_CREATE: return "create";
|
||||
case POOL_OP_DELETE: return "delete";
|
||||
case POOL_OP_AUID_CHANGE: return "auid change";
|
||||
case POOL_OP_CREATE_SNAP: return "create snap";
|
||||
case POOL_OP_DELETE_SNAP: return "delete snap";
|
||||
case POOL_OP_CREATE_UNMANAGED_SNAP: return "create unmanaged snap";
|
||||
case POOL_OP_DELETE_UNMANAGED_SNAP: return "delete unmanaged snap";
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
1180
fs/ceph/super.c
1180
fs/ceph/super.c
File diff suppressed because it is too large
Load diff
397
fs/ceph/super.h
397
fs/ceph/super.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef _FS_CEPH_SUPER_H
|
||||
#define _FS_CEPH_SUPER_H
|
||||
|
||||
#include "ceph_debug.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/backing-dev.h>
|
||||
|
|
@ -14,13 +14,7 @@
|
|||
#include <linux/writeback.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "messenger.h"
|
||||
#include "msgpool.h"
|
||||
#include "mon_client.h"
|
||||
#include "mds_client.h"
|
||||
#include "osd_client.h"
|
||||
#include "ceph_fs.h"
|
||||
#include <linux/ceph/libceph.h>
|
||||
|
||||
/* f_type in struct statfs */
|
||||
#define CEPH_SUPER_MAGIC 0x00c36400
|
||||
|
|
@ -30,42 +24,25 @@
|
|||
#define CEPH_BLOCK_SHIFT 20 /* 1 MB */
|
||||
#define CEPH_BLOCK (1 << CEPH_BLOCK_SHIFT)
|
||||
|
||||
/*
|
||||
* Supported features
|
||||
*/
|
||||
#define CEPH_FEATURE_SUPPORTED CEPH_FEATURE_NOSRCADDR | CEPH_FEATURE_FLOCK
|
||||
#define CEPH_FEATURE_REQUIRED CEPH_FEATURE_NOSRCADDR
|
||||
#define CEPH_MOUNT_OPT_DIRSTAT (1<<4) /* `cat dirname` for stats */
|
||||
#define CEPH_MOUNT_OPT_RBYTES (1<<5) /* dir st_bytes = rbytes */
|
||||
#define CEPH_MOUNT_OPT_NOASYNCREADDIR (1<<7) /* no dcache readdir */
|
||||
|
||||
/*
|
||||
* mount options
|
||||
*/
|
||||
#define CEPH_OPT_FSID (1<<0)
|
||||
#define CEPH_OPT_NOSHARE (1<<1) /* don't share client with other sbs */
|
||||
#define CEPH_OPT_MYIP (1<<2) /* specified my ip */
|
||||
#define CEPH_OPT_DIRSTAT (1<<4) /* funky `cat dirname` for stats */
|
||||
#define CEPH_OPT_RBYTES (1<<5) /* dir st_bytes = rbytes */
|
||||
#define CEPH_OPT_NOCRC (1<<6) /* no data crc on writes */
|
||||
#define CEPH_OPT_NOASYNCREADDIR (1<<7) /* no dcache readdir */
|
||||
#define CEPH_MOUNT_OPT_DEFAULT (CEPH_MOUNT_OPT_RBYTES)
|
||||
|
||||
#define CEPH_OPT_DEFAULT (CEPH_OPT_RBYTES)
|
||||
#define ceph_set_mount_opt(fsc, opt) \
|
||||
(fsc)->mount_options->flags |= CEPH_MOUNT_OPT_##opt;
|
||||
#define ceph_test_mount_opt(fsc, opt) \
|
||||
(!!((fsc)->mount_options->flags & CEPH_MOUNT_OPT_##opt))
|
||||
|
||||
#define ceph_set_opt(client, opt) \
|
||||
(client)->mount_args->flags |= CEPH_OPT_##opt;
|
||||
#define ceph_test_opt(client, opt) \
|
||||
(!!((client)->mount_args->flags & CEPH_OPT_##opt))
|
||||
#define CEPH_MAX_READDIR_DEFAULT 1024
|
||||
#define CEPH_MAX_READDIR_BYTES_DEFAULT (512*1024)
|
||||
#define CEPH_SNAPDIRNAME_DEFAULT ".snap"
|
||||
|
||||
|
||||
struct ceph_mount_args {
|
||||
int sb_flags;
|
||||
struct ceph_mount_options {
|
||||
int flags;
|
||||
struct ceph_fsid fsid;
|
||||
struct ceph_entity_addr my_addr;
|
||||
int num_mon;
|
||||
struct ceph_entity_addr *mon_addr;
|
||||
int mount_timeout;
|
||||
int osd_idle_ttl;
|
||||
int osd_timeout;
|
||||
int osd_keepalive_timeout;
|
||||
int sb_flags;
|
||||
|
||||
int wsize;
|
||||
int rsize; /* max readahead */
|
||||
int congestion_kb; /* max writeback in flight */
|
||||
|
|
@ -73,82 +50,25 @@ struct ceph_mount_args {
|
|||
int cap_release_safety;
|
||||
int max_readdir; /* max readdir result (entires) */
|
||||
int max_readdir_bytes; /* max readdir result (bytes) */
|
||||
|
||||
/*
|
||||
* everything above this point can be memcmp'd; everything below
|
||||
* is handled in compare_mount_options()
|
||||
*/
|
||||
|
||||
char *snapdir_name; /* default ".snap" */
|
||||
char *name;
|
||||
char *secret;
|
||||
};
|
||||
|
||||
/*
|
||||
* defaults
|
||||
*/
|
||||
#define CEPH_MOUNT_TIMEOUT_DEFAULT 60
|
||||
#define CEPH_OSD_TIMEOUT_DEFAULT 60 /* seconds */
|
||||
#define CEPH_OSD_KEEPALIVE_DEFAULT 5
|
||||
#define CEPH_OSD_IDLE_TTL_DEFAULT 60
|
||||
#define CEPH_MOUNT_RSIZE_DEFAULT (512*1024) /* readahead */
|
||||
#define CEPH_MAX_READDIR_DEFAULT 1024
|
||||
#define CEPH_MAX_READDIR_BYTES_DEFAULT (512*1024)
|
||||
|
||||
#define CEPH_MSG_MAX_FRONT_LEN (16*1024*1024)
|
||||
#define CEPH_MSG_MAX_DATA_LEN (16*1024*1024)
|
||||
|
||||
#define CEPH_SNAPDIRNAME_DEFAULT ".snap"
|
||||
#define CEPH_AUTH_NAME_DEFAULT "guest"
|
||||
/*
|
||||
* Delay telling the MDS we no longer want caps, in case we reopen
|
||||
* the file. Delay a minimum amount of time, even if we send a cap
|
||||
* message for some other reason. Otherwise, take the oppotunity to
|
||||
* update the mds to avoid sending another message later.
|
||||
*/
|
||||
#define CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT 5 /* cap release delay */
|
||||
#define CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT 60 /* cap release delay */
|
||||
|
||||
#define CEPH_CAP_RELEASE_SAFETY_DEFAULT (CEPH_CAPS_PER_RELEASE * 4)
|
||||
|
||||
/* mount state */
|
||||
enum {
|
||||
CEPH_MOUNT_MOUNTING,
|
||||
CEPH_MOUNT_MOUNTED,
|
||||
CEPH_MOUNT_UNMOUNTING,
|
||||
CEPH_MOUNT_UNMOUNTED,
|
||||
CEPH_MOUNT_SHUTDOWN,
|
||||
};
|
||||
|
||||
/*
|
||||
* subtract jiffies
|
||||
*/
|
||||
static inline unsigned long time_sub(unsigned long a, unsigned long b)
|
||||
{
|
||||
BUG_ON(time_after(b, a));
|
||||
return (long)a - (long)b;
|
||||
}
|
||||
|
||||
/*
|
||||
* per-filesystem client state
|
||||
*
|
||||
* possibly shared by multiple mount points, if they are
|
||||
* mounting the same ceph filesystem/cluster.
|
||||
*/
|
||||
struct ceph_client {
|
||||
struct ceph_fsid fsid;
|
||||
bool have_fsid;
|
||||
|
||||
struct mutex mount_mutex; /* serialize mount attempts */
|
||||
struct ceph_mount_args *mount_args;
|
||||
|
||||
struct ceph_fs_client {
|
||||
struct super_block *sb;
|
||||
|
||||
struct ceph_mount_options *mount_options;
|
||||
struct ceph_client *client;
|
||||
|
||||
unsigned long mount_state;
|
||||
wait_queue_head_t auth_wq;
|
||||
|
||||
int auth_err;
|
||||
|
||||
int min_caps; /* min caps i added */
|
||||
|
||||
struct ceph_messenger *msgr; /* messenger instance */
|
||||
struct ceph_mon_client monc;
|
||||
struct ceph_mds_client mdsc;
|
||||
struct ceph_osd_client osdc;
|
||||
struct ceph_mds_client *mdsc;
|
||||
|
||||
/* writeback */
|
||||
mempool_t *wb_pagevec_pool;
|
||||
|
|
@ -160,14 +80,14 @@ struct ceph_client {
|
|||
struct backing_dev_info backing_dev_info;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_monmap;
|
||||
struct dentry *debugfs_mdsmap, *debugfs_osdmap;
|
||||
struct dentry *debugfs_dir, *debugfs_dentry_lru, *debugfs_caps;
|
||||
struct dentry *debugfs_dentry_lru, *debugfs_caps;
|
||||
struct dentry *debugfs_congestion_kb;
|
||||
struct dentry *debugfs_bdi;
|
||||
struct dentry *debugfs_mdsc, *debugfs_mdsmap;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* File i/o capability. This tracks shared state with the metadata
|
||||
* server that allows us to cache or writeback attributes or to read
|
||||
|
|
@ -275,6 +195,20 @@ struct ceph_inode_xattr {
|
|||
int should_free_val;
|
||||
};
|
||||
|
||||
/*
|
||||
* Ceph dentry state
|
||||
*/
|
||||
struct ceph_dentry_info {
|
||||
struct ceph_mds_session *lease_session;
|
||||
u32 lease_gen, lease_shared_gen;
|
||||
u32 lease_seq;
|
||||
unsigned long lease_renew_after, lease_renew_from;
|
||||
struct list_head lru;
|
||||
struct dentry *dentry;
|
||||
u64 time;
|
||||
u64 offset;
|
||||
};
|
||||
|
||||
struct ceph_inode_xattrs_info {
|
||||
/*
|
||||
* (still encoded) xattr blob. we avoid the overhead of parsing
|
||||
|
|
@ -296,11 +230,6 @@ struct ceph_inode_xattrs_info {
|
|||
/*
|
||||
* Ceph inode.
|
||||
*/
|
||||
#define CEPH_I_COMPLETE 1 /* we have complete directory cached */
|
||||
#define CEPH_I_NODELAY 4 /* do not delay cap release */
|
||||
#define CEPH_I_FLUSH 8 /* do not delay flush of dirty metadata */
|
||||
#define CEPH_I_NOFLUSH 16 /* do not flush dirty caps */
|
||||
|
||||
struct ceph_inode_info {
|
||||
struct ceph_vino i_vino; /* ceph ino + snap */
|
||||
|
||||
|
|
@ -391,6 +320,63 @@ static inline struct ceph_inode_info *ceph_inode(struct inode *inode)
|
|||
return container_of(inode, struct ceph_inode_info, vfs_inode);
|
||||
}
|
||||
|
||||
static inline struct ceph_vino ceph_vino(struct inode *inode)
|
||||
{
|
||||
return ceph_inode(inode)->i_vino;
|
||||
}
|
||||
|
||||
/*
|
||||
* ino_t is <64 bits on many architectures, blech.
|
||||
*
|
||||
* don't include snap in ino hash, at least for now.
|
||||
*/
|
||||
static inline ino_t ceph_vino_to_ino(struct ceph_vino vino)
|
||||
{
|
||||
ino_t ino = (ino_t)vino.ino; /* ^ (vino.snap << 20); */
|
||||
#if BITS_PER_LONG == 32
|
||||
ino ^= vino.ino >> (sizeof(u64)-sizeof(ino_t)) * 8;
|
||||
if (!ino)
|
||||
ino = 1;
|
||||
#endif
|
||||
return ino;
|
||||
}
|
||||
|
||||
/* for printf-style formatting */
|
||||
#define ceph_vinop(i) ceph_inode(i)->i_vino.ino, ceph_inode(i)->i_vino.snap
|
||||
|
||||
static inline u64 ceph_ino(struct inode *inode)
|
||||
{
|
||||
return ceph_inode(inode)->i_vino.ino;
|
||||
}
|
||||
static inline u64 ceph_snap(struct inode *inode)
|
||||
{
|
||||
return ceph_inode(inode)->i_vino.snap;
|
||||
}
|
||||
|
||||
static inline int ceph_ino_compare(struct inode *inode, void *data)
|
||||
{
|
||||
struct ceph_vino *pvino = (struct ceph_vino *)data;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
return ci->i_vino.ino == pvino->ino &&
|
||||
ci->i_vino.snap == pvino->snap;
|
||||
}
|
||||
|
||||
static inline struct inode *ceph_find_inode(struct super_block *sb,
|
||||
struct ceph_vino vino)
|
||||
{
|
||||
ino_t t = ceph_vino_to_ino(vino);
|
||||
return ilookup5(sb, t, ceph_ino_compare, &vino);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Ceph inode.
|
||||
*/
|
||||
#define CEPH_I_COMPLETE 1 /* we have complete directory cached */
|
||||
#define CEPH_I_NODELAY 4 /* do not delay cap release */
|
||||
#define CEPH_I_FLUSH 8 /* do not delay flush of dirty metadata */
|
||||
#define CEPH_I_NOFLUSH 16 /* do not flush dirty caps */
|
||||
|
||||
static inline void ceph_i_clear(struct inode *inode, unsigned mask)
|
||||
{
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
|
|
@ -432,20 +418,6 @@ extern u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v,
|
|||
struct ceph_inode_frag *pfrag,
|
||||
int *found);
|
||||
|
||||
/*
|
||||
* Ceph dentry state
|
||||
*/
|
||||
struct ceph_dentry_info {
|
||||
struct ceph_mds_session *lease_session;
|
||||
u32 lease_gen, lease_shared_gen;
|
||||
u32 lease_seq;
|
||||
unsigned long lease_renew_after, lease_renew_from;
|
||||
struct list_head lru;
|
||||
struct dentry *dentry;
|
||||
u64 time;
|
||||
u64 offset;
|
||||
};
|
||||
|
||||
static inline struct ceph_dentry_info *ceph_dentry(struct dentry *dentry)
|
||||
{
|
||||
return (struct ceph_dentry_info *)dentry->d_fsdata;
|
||||
|
|
@ -456,22 +428,6 @@ static inline loff_t ceph_make_fpos(unsigned frag, unsigned off)
|
|||
return ((loff_t)frag << 32) | (loff_t)off;
|
||||
}
|
||||
|
||||
/*
|
||||
* ino_t is <64 bits on many architectures, blech.
|
||||
*
|
||||
* don't include snap in ino hash, at least for now.
|
||||
*/
|
||||
static inline ino_t ceph_vino_to_ino(struct ceph_vino vino)
|
||||
{
|
||||
ino_t ino = (ino_t)vino.ino; /* ^ (vino.snap << 20); */
|
||||
#if BITS_PER_LONG == 32
|
||||
ino ^= vino.ino >> (sizeof(u64)-sizeof(ino_t)) * 8;
|
||||
if (!ino)
|
||||
ino = 1;
|
||||
#endif
|
||||
return ino;
|
||||
}
|
||||
|
||||
static inline int ceph_set_ino_cb(struct inode *inode, void *data)
|
||||
{
|
||||
ceph_inode(inode)->i_vino = *(struct ceph_vino *)data;
|
||||
|
|
@ -479,39 +435,6 @@ static inline int ceph_set_ino_cb(struct inode *inode, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline struct ceph_vino ceph_vino(struct inode *inode)
|
||||
{
|
||||
return ceph_inode(inode)->i_vino;
|
||||
}
|
||||
|
||||
/* for printf-style formatting */
|
||||
#define ceph_vinop(i) ceph_inode(i)->i_vino.ino, ceph_inode(i)->i_vino.snap
|
||||
|
||||
static inline u64 ceph_ino(struct inode *inode)
|
||||
{
|
||||
return ceph_inode(inode)->i_vino.ino;
|
||||
}
|
||||
static inline u64 ceph_snap(struct inode *inode)
|
||||
{
|
||||
return ceph_inode(inode)->i_vino.snap;
|
||||
}
|
||||
|
||||
static inline int ceph_ino_compare(struct inode *inode, void *data)
|
||||
{
|
||||
struct ceph_vino *pvino = (struct ceph_vino *)data;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
return ci->i_vino.ino == pvino->ino &&
|
||||
ci->i_vino.snap == pvino->snap;
|
||||
}
|
||||
|
||||
static inline struct inode *ceph_find_inode(struct super_block *sb,
|
||||
struct ceph_vino vino)
|
||||
{
|
||||
ino_t t = ceph_vino_to_ino(vino);
|
||||
return ilookup5(sb, t, ceph_ino_compare, &vino);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* caps helpers
|
||||
*/
|
||||
|
|
@ -576,18 +499,18 @@ extern int ceph_reserve_caps(struct ceph_mds_client *mdsc,
|
|||
struct ceph_cap_reservation *ctx, int need);
|
||||
extern int ceph_unreserve_caps(struct ceph_mds_client *mdsc,
|
||||
struct ceph_cap_reservation *ctx);
|
||||
extern void ceph_reservation_status(struct ceph_client *client,
|
||||
extern void ceph_reservation_status(struct ceph_fs_client *client,
|
||||
int *total, int *avail, int *used,
|
||||
int *reserved, int *min);
|
||||
|
||||
static inline struct ceph_client *ceph_inode_to_client(struct inode *inode)
|
||||
static inline struct ceph_fs_client *ceph_inode_to_client(struct inode *inode)
|
||||
{
|
||||
return (struct ceph_client *)inode->i_sb->s_fs_info;
|
||||
return (struct ceph_fs_client *)inode->i_sb->s_fs_info;
|
||||
}
|
||||
|
||||
static inline struct ceph_client *ceph_sb_to_client(struct super_block *sb)
|
||||
static inline struct ceph_fs_client *ceph_sb_to_client(struct super_block *sb)
|
||||
{
|
||||
return (struct ceph_client *)sb->s_fs_info;
|
||||
return (struct ceph_fs_client *)sb->s_fs_info;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -616,51 +539,6 @@ struct ceph_file_info {
|
|||
|
||||
|
||||
|
||||
/*
|
||||
* snapshots
|
||||
*/
|
||||
|
||||
/*
|
||||
* A "snap context" is the set of existing snapshots when we
|
||||
* write data. It is used by the OSD to guide its COW behavior.
|
||||
*
|
||||
* The ceph_snap_context is refcounted, and attached to each dirty
|
||||
* page, indicating which context the dirty data belonged when it was
|
||||
* dirtied.
|
||||
*/
|
||||
struct ceph_snap_context {
|
||||
atomic_t nref;
|
||||
u64 seq;
|
||||
int num_snaps;
|
||||
u64 snaps[];
|
||||
};
|
||||
|
||||
static inline struct ceph_snap_context *
|
||||
ceph_get_snap_context(struct ceph_snap_context *sc)
|
||||
{
|
||||
/*
|
||||
printk("get_snap_context %p %d -> %d\n", sc, atomic_read(&sc->nref),
|
||||
atomic_read(&sc->nref)+1);
|
||||
*/
|
||||
if (sc)
|
||||
atomic_inc(&sc->nref);
|
||||
return sc;
|
||||
}
|
||||
|
||||
static inline void ceph_put_snap_context(struct ceph_snap_context *sc)
|
||||
{
|
||||
if (!sc)
|
||||
return;
|
||||
/*
|
||||
printk("put_snap_context %p %d -> %d\n", sc, atomic_read(&sc->nref),
|
||||
atomic_read(&sc->nref)-1);
|
||||
*/
|
||||
if (atomic_dec_and_test(&sc->nref)) {
|
||||
/*printk(" deleting snap_context %p\n", sc);*/
|
||||
kfree(sc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A "snap realm" describes a subset of the file hierarchy sharing
|
||||
* the same set of snapshots that apply to it. The realms themselves
|
||||
|
|
@ -699,16 +577,33 @@ struct ceph_snap_realm {
|
|||
spinlock_t inodes_with_caps_lock;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* calculate the number of pages a given length and offset map onto,
|
||||
* if we align the data.
|
||||
*/
|
||||
static inline int calc_pages_for(u64 off, u64 len)
|
||||
static inline int default_congestion_kb(void)
|
||||
{
|
||||
return ((off+len+PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT) -
|
||||
(off >> PAGE_CACHE_SHIFT);
|
||||
int congestion_kb;
|
||||
|
||||
/*
|
||||
* Copied from NFS
|
||||
*
|
||||
* congestion size, scale with available memory.
|
||||
*
|
||||
* 64MB: 8192k
|
||||
* 128MB: 11585k
|
||||
* 256MB: 16384k
|
||||
* 512MB: 23170k
|
||||
* 1GB: 32768k
|
||||
* 2GB: 46340k
|
||||
* 4GB: 65536k
|
||||
* 8GB: 92681k
|
||||
* 16GB: 131072k
|
||||
*
|
||||
* This allows larger machines to have larger/more transfers.
|
||||
* Limit the default to 256M
|
||||
*/
|
||||
congestion_kb = (16*int_sqrt(totalram_pages)) << (PAGE_SHIFT-10);
|
||||
if (congestion_kb > 256*1024)
|
||||
congestion_kb = 256*1024;
|
||||
|
||||
return congestion_kb;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -741,16 +636,6 @@ static inline bool __ceph_have_pending_cap_snap(struct ceph_inode_info *ci)
|
|||
ci_item)->writing;
|
||||
}
|
||||
|
||||
|
||||
/* super.c */
|
||||
extern struct kmem_cache *ceph_inode_cachep;
|
||||
extern struct kmem_cache *ceph_cap_cachep;
|
||||
extern struct kmem_cache *ceph_dentry_cachep;
|
||||
extern struct kmem_cache *ceph_file_cachep;
|
||||
|
||||
extern const char *ceph_msg_type_name(int type);
|
||||
extern int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid);
|
||||
|
||||
/* inode.c */
|
||||
extern const struct inode_operations ceph_file_iops;
|
||||
|
||||
|
|
@ -857,12 +742,18 @@ extern int ceph_mmap(struct file *file, struct vm_area_struct *vma);
|
|||
/* file.c */
|
||||
extern const struct file_operations ceph_file_fops;
|
||||
extern const struct address_space_operations ceph_aops;
|
||||
extern int ceph_copy_to_page_vector(struct page **pages,
|
||||
const char *data,
|
||||
loff_t off, size_t len);
|
||||
extern int ceph_copy_from_page_vector(struct page **pages,
|
||||
char *data,
|
||||
loff_t off, size_t len);
|
||||
extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags);
|
||||
extern int ceph_open(struct inode *inode, struct file *file);
|
||||
extern struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd, int mode,
|
||||
int locked_dir);
|
||||
extern int ceph_release(struct inode *inode, struct file *filp);
|
||||
extern void ceph_release_page_vector(struct page **pages, int num_pages);
|
||||
|
||||
/* dir.c */
|
||||
extern const struct file_operations ceph_dir_fops;
|
||||
|
|
@ -892,12 +783,6 @@ extern long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
|||
/* export.c */
|
||||
extern const struct export_operations ceph_export_ops;
|
||||
|
||||
/* debugfs.c */
|
||||
extern int ceph_debugfs_init(void);
|
||||
extern void ceph_debugfs_cleanup(void);
|
||||
extern int ceph_debugfs_client_init(struct ceph_client *client);
|
||||
extern void ceph_debugfs_client_cleanup(struct ceph_client *client);
|
||||
|
||||
/* locks.c */
|
||||
extern int ceph_lock(struct file *file, int cmd, struct file_lock *fl);
|
||||
extern int ceph_flock(struct file *file, int cmd, struct file_lock *fl);
|
||||
|
|
@ -914,4 +799,8 @@ static inline struct inode *get_dentry_parent_inode(struct dentry *dentry)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* debugfs.c */
|
||||
extern int ceph_fs_debugfs_init(struct ceph_fs_client *client);
|
||||
extern void ceph_fs_debugfs_cleanup(struct ceph_fs_client *client);
|
||||
|
||||
#endif /* _FS_CEPH_SUPER_H */
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
#ifndef _FS_CEPH_TYPES_H
|
||||
#define _FS_CEPH_TYPES_H
|
||||
|
||||
/* needed before including ceph_fs.h */
|
||||
#include <linux/in.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "ceph_fs.h"
|
||||
#include "ceph_frag.h"
|
||||
#include "ceph_hash.h"
|
||||
|
||||
/*
|
||||
* Identify inodes by both their ino AND snapshot id (a u64).
|
||||
*/
|
||||
struct ceph_vino {
|
||||
u64 ino;
|
||||
u64 snap;
|
||||
};
|
||||
|
||||
|
||||
/* context for the caps reservation mechanism */
|
||||
struct ceph_cap_reservation {
|
||||
int count;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
#include "ceph_debug.h"
|
||||
#include <linux/ceph/ceph_debug.h>
|
||||
|
||||
#include "super.h"
|
||||
#include "decode.h"
|
||||
#include "mds_client.h"
|
||||
|
||||
#include <linux/ceph/decode.h>
|
||||
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -620,12 +623,12 @@ out:
|
|||
static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
|
||||
const char *value, size_t size, int flags)
|
||||
{
|
||||
struct ceph_client *client = ceph_sb_to_client(dentry->d_sb);
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct inode *parent_inode = dentry->d_parent->d_inode;
|
||||
struct ceph_mds_request *req;
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
int err;
|
||||
int i, nr_pages;
|
||||
struct page **pages = NULL;
|
||||
|
|
@ -777,8 +780,8 @@ out:
|
|||
|
||||
static int ceph_send_removexattr(struct dentry *dentry, const char *name)
|
||||
{
|
||||
struct ceph_client *client = ceph_sb_to_client(dentry->d_sb);
|
||||
struct ceph_mds_client *mdsc = &client->mdsc;
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *parent_inode = dentry->d_parent->d_inode;
|
||||
struct ceph_mds_request *req;
|
||||
|
|
|
|||
Loading…
Reference in a new issue