You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-linus' of git://ceph.newdream.net/git/ceph-client
* 'for-linus' of git://ceph.newdream.net/git/ceph-client: libceph: fix double-free of page vector ceph: fix 32-bit ino numbers libceph: force resend of osd requests if we skip an osdmap ceph: use kernel DNS resolver ceph: fix ceph_monc_init memory leak ceph: let the set_layout ioctl set single traits Revert "ceph: don't truncate dirty pages in invalidate work thread" ceph: replace leading spaces with tabs libceph: warn on msg allocation failures libceph: don't complain on msgpool alloc failures libceph: always preallocate mon connection libceph: create messenger with client ceph: document ioctls ceph: implement (optional) max read size ceph: rename rsize -> rasize ceph: make readpages fully async
This commit is contained in:
+126
-73
@@ -228,36 +228,129 @@ static int ceph_readpage(struct file *filp, struct page *page)
|
||||
}
|
||||
|
||||
/*
|
||||
* Build a vector of contiguous pages from the provided page list.
|
||||
* Finish an async read(ahead) op.
|
||||
*/
|
||||
static struct page **page_vector_from_list(struct list_head *page_list,
|
||||
unsigned *nr_pages)
|
||||
static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg)
|
||||
{
|
||||
struct inode *inode = req->r_inode;
|
||||
struct ceph_osd_reply_head *replyhead;
|
||||
int rc, bytes;
|
||||
int i;
|
||||
|
||||
/* parse reply */
|
||||
replyhead = msg->front.iov_base;
|
||||
WARN_ON(le32_to_cpu(replyhead->num_ops) == 0);
|
||||
rc = le32_to_cpu(replyhead->result);
|
||||
bytes = le32_to_cpu(msg->hdr.data_len);
|
||||
|
||||
dout("finish_read %p req %p rc %d bytes %d\n", inode, req, rc, bytes);
|
||||
|
||||
/* unlock all pages, zeroing any data we didn't read */
|
||||
for (i = 0; i < req->r_num_pages; i++, bytes -= PAGE_CACHE_SIZE) {
|
||||
struct page *page = req->r_pages[i];
|
||||
|
||||
if (bytes < (int)PAGE_CACHE_SIZE) {
|
||||
/* zero (remainder of) page */
|
||||
int s = bytes < 0 ? 0 : bytes;
|
||||
zero_user_segment(page, s, PAGE_CACHE_SIZE);
|
||||
}
|
||||
dout("finish_read %p uptodate %p idx %lu\n", inode, page,
|
||||
page->index);
|
||||
flush_dcache_page(page);
|
||||
SetPageUptodate(page);
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
kfree(req->r_pages);
|
||||
}
|
||||
|
||||
/*
|
||||
* start an async read(ahead) operation. return nr_pages we submitted
|
||||
* a read for on success, or negative error code.
|
||||
*/
|
||||
static int start_read(struct inode *inode, struct list_head *page_list, int max)
|
||||
{
|
||||
struct ceph_osd_client *osdc =
|
||||
&ceph_inode_to_client(inode)->client->osdc;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct page *page = list_entry(page_list->prev, struct page, lru);
|
||||
struct ceph_osd_request *req;
|
||||
u64 off;
|
||||
u64 len;
|
||||
int i;
|
||||
struct page **pages;
|
||||
struct page *page;
|
||||
int next_index, contig_pages = 0;
|
||||
pgoff_t next_index;
|
||||
int nr_pages = 0;
|
||||
int ret;
|
||||
|
||||
off = page->index << PAGE_CACHE_SHIFT;
|
||||
|
||||
/* count pages */
|
||||
next_index = page->index;
|
||||
list_for_each_entry_reverse(page, page_list, lru) {
|
||||
if (page->index != next_index)
|
||||
break;
|
||||
nr_pages++;
|
||||
next_index++;
|
||||
if (max && nr_pages == max)
|
||||
break;
|
||||
}
|
||||
len = nr_pages << PAGE_CACHE_SHIFT;
|
||||
dout("start_read %p nr_pages %d is %lld~%lld\n", inode, nr_pages,
|
||||
off, len);
|
||||
|
||||
req = ceph_osdc_new_request(osdc, &ci->i_layout, ceph_vino(inode),
|
||||
off, &len,
|
||||
CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ,
|
||||
NULL, 0,
|
||||
ci->i_truncate_seq, ci->i_truncate_size,
|
||||
NULL, false, 1, 0);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
/* build page vector */
|
||||
pages = kmalloc(sizeof(*pages) * *nr_pages, GFP_NOFS);
|
||||
nr_pages = len >> PAGE_CACHE_SHIFT;
|
||||
pages = kmalloc(sizeof(*pages) * nr_pages, GFP_NOFS);
|
||||
ret = -ENOMEM;
|
||||
if (!pages)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
BUG_ON(list_empty(page_list));
|
||||
next_index = list_entry(page_list->prev, struct page, lru)->index;
|
||||
list_for_each_entry_reverse(page, page_list, lru) {
|
||||
if (page->index == next_index) {
|
||||
dout("readpages page %d %p\n", contig_pages, page);
|
||||
pages[contig_pages] = page;
|
||||
contig_pages++;
|
||||
next_index++;
|
||||
} else {
|
||||
break;
|
||||
goto out;
|
||||
for (i = 0; i < nr_pages; ++i) {
|
||||
page = list_entry(page_list->prev, struct page, lru);
|
||||
BUG_ON(PageLocked(page));
|
||||
list_del(&page->lru);
|
||||
|
||||
dout("start_read %p adding %p idx %lu\n", inode, page,
|
||||
page->index);
|
||||
if (add_to_page_cache_lru(page, &inode->i_data, page->index,
|
||||
GFP_NOFS)) {
|
||||
page_cache_release(page);
|
||||
dout("start_read %p add_to_page_cache failed %p\n",
|
||||
inode, page);
|
||||
nr_pages = i;
|
||||
goto out_pages;
|
||||
}
|
||||
pages[i] = page;
|
||||
}
|
||||
*nr_pages = contig_pages;
|
||||
return pages;
|
||||
req->r_pages = pages;
|
||||
req->r_num_pages = nr_pages;
|
||||
req->r_callback = finish_read;
|
||||
req->r_inode = inode;
|
||||
|
||||
dout("start_read %p starting %p %lld~%lld\n", inode, req, off, len);
|
||||
ret = ceph_osdc_start_request(osdc, req, false);
|
||||
if (ret < 0)
|
||||
goto out_pages;
|
||||
ceph_osdc_put_request(req);
|
||||
return nr_pages;
|
||||
|
||||
out_pages:
|
||||
ceph_release_page_vector(pages, nr_pages);
|
||||
out:
|
||||
ceph_osdc_put_request(req);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read multiple pages. Leave pages we don't read + unlock in page_list;
|
||||
* the caller (VM) cleans them up.
|
||||
@@ -266,64 +359,24 @@ static int ceph_readpages(struct file *file, struct address_space *mapping,
|
||||
struct list_head *page_list, unsigned nr_pages)
|
||||
{
|
||||
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)->client->osdc;
|
||||
struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
|
||||
int rc = 0;
|
||||
struct page **pages;
|
||||
loff_t offset;
|
||||
u64 len;
|
||||
int max = 0;
|
||||
|
||||
dout("readpages %p file %p nr_pages %d\n",
|
||||
inode, file, nr_pages);
|
||||
if (fsc->mount_options->rsize >= PAGE_CACHE_SIZE)
|
||||
max = (fsc->mount_options->rsize + PAGE_CACHE_SIZE - 1)
|
||||
>> PAGE_SHIFT;
|
||||
|
||||
pages = page_vector_from_list(page_list, &nr_pages);
|
||||
if (IS_ERR(pages))
|
||||
return PTR_ERR(pages);
|
||||
|
||||
/* guess read extent */
|
||||
offset = pages[0]->index << PAGE_CACHE_SHIFT;
|
||||
len = nr_pages << PAGE_CACHE_SHIFT;
|
||||
rc = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout,
|
||||
offset, &len,
|
||||
ci->i_truncate_seq, ci->i_truncate_size,
|
||||
pages, nr_pages, 0);
|
||||
if (rc == -ENOENT)
|
||||
rc = 0;
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
for (; !list_empty(page_list) && len > 0;
|
||||
rc -= PAGE_CACHE_SIZE, len -= PAGE_CACHE_SIZE) {
|
||||
struct page *page =
|
||||
list_entry(page_list->prev, struct page, lru);
|
||||
|
||||
list_del(&page->lru);
|
||||
|
||||
if (rc < (int)PAGE_CACHE_SIZE) {
|
||||
/* zero (remainder of) page */
|
||||
int s = rc < 0 ? 0 : rc;
|
||||
zero_user_segment(page, s, PAGE_CACHE_SIZE);
|
||||
}
|
||||
|
||||
if (add_to_page_cache_lru(page, mapping, page->index,
|
||||
GFP_NOFS)) {
|
||||
page_cache_release(page);
|
||||
dout("readpages %p add_to_page_cache failed %p\n",
|
||||
inode, page);
|
||||
continue;
|
||||
}
|
||||
dout("readpages %p adding %p idx %lu\n", inode, page,
|
||||
page->index);
|
||||
flush_dcache_page(page);
|
||||
SetPageUptodate(page);
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
dout("readpages %p file %p nr_pages %d max %d\n", inode, file, nr_pages,
|
||||
max);
|
||||
while (!list_empty(page_list)) {
|
||||
rc = start_read(inode, page_list, max);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
BUG_ON(rc == 0);
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
kfree(pages);
|
||||
dout("readpages %p file %p ret %d\n", inode, file, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -945,7 +945,7 @@ static int send_cap_msg(struct ceph_mds_session *session,
|
||||
seq, issue_seq, mseq, follows, size, max_size,
|
||||
xattr_version, xattrs_buf ? (int)xattrs_buf->vec.iov_len : 0);
|
||||
|
||||
msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, sizeof(*fc), GFP_NOFS);
|
||||
msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, sizeof(*fc), GFP_NOFS, false);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
+1
-45
@@ -9,7 +9,6 @@
|
||||
#include <linux/namei.h>
|
||||
#include <linux/writeback.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/pagevec.h>
|
||||
|
||||
#include "super.h"
|
||||
#include "mds_client.h"
|
||||
@@ -1363,49 +1362,6 @@ void ceph_queue_invalidate(struct inode *inode)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* invalidate any pages that are not dirty or under writeback. this
|
||||
* includes pages that are clean and mapped.
|
||||
*/
|
||||
static void ceph_invalidate_nondirty_pages(struct address_space *mapping)
|
||||
{
|
||||
struct pagevec pvec;
|
||||
pgoff_t next = 0;
|
||||
int i;
|
||||
|
||||
pagevec_init(&pvec, 0);
|
||||
while (pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
|
||||
for (i = 0; i < pagevec_count(&pvec); i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
pgoff_t index;
|
||||
int skip_page =
|
||||
(PageDirty(page) || PageWriteback(page));
|
||||
|
||||
if (!skip_page)
|
||||
skip_page = !trylock_page(page);
|
||||
|
||||
/*
|
||||
* We really shouldn't be looking at the ->index of an
|
||||
* unlocked page. But we're not allowed to lock these
|
||||
* pages. So we rely upon nobody altering the ->index
|
||||
* of this (pinned-by-us) page.
|
||||
*/
|
||||
index = page->index;
|
||||
if (index > next)
|
||||
next = index;
|
||||
next++;
|
||||
|
||||
if (skip_page)
|
||||
continue;
|
||||
|
||||
generic_error_remove_page(mapping, page);
|
||||
unlock_page(page);
|
||||
}
|
||||
pagevec_release(&pvec);
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidate inode pages in a worker thread. (This can't be done
|
||||
* in the message handler context.)
|
||||
@@ -1429,7 +1385,7 @@ static void ceph_invalidate_work(struct work_struct *work)
|
||||
orig_gen = ci->i_rdcache_gen;
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
ceph_invalidate_nondirty_pages(inode->i_mapping);
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
if (orig_gen == ci->i_rdcache_gen &&
|
||||
|
||||
+28
-6
@@ -42,17 +42,39 @@ static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
|
||||
struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
struct ceph_mds_request *req;
|
||||
struct ceph_ioctl_layout l;
|
||||
struct ceph_inode_info *ci = ceph_inode(file->f_dentry->d_inode);
|
||||
struct ceph_ioctl_layout nl;
|
||||
int err, i;
|
||||
|
||||
/* copy and validate */
|
||||
if (copy_from_user(&l, arg, sizeof(l)))
|
||||
return -EFAULT;
|
||||
|
||||
if ((l.object_size & ~PAGE_MASK) ||
|
||||
(l.stripe_unit & ~PAGE_MASK) ||
|
||||
!l.stripe_unit ||
|
||||
(l.object_size &&
|
||||
(unsigned)l.object_size % (unsigned)l.stripe_unit))
|
||||
/* validate changed params against current layout */
|
||||
err = ceph_do_getattr(file->f_dentry->d_inode, CEPH_STAT_CAP_LAYOUT);
|
||||
if (!err) {
|
||||
nl.stripe_unit = ceph_file_layout_su(ci->i_layout);
|
||||
nl.stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
|
||||
nl.object_size = ceph_file_layout_object_size(ci->i_layout);
|
||||
nl.data_pool = le32_to_cpu(ci->i_layout.fl_pg_pool);
|
||||
nl.preferred_osd =
|
||||
(s32)le32_to_cpu(ci->i_layout.fl_pg_preferred);
|
||||
} else
|
||||
return err;
|
||||
|
||||
if (l.stripe_count)
|
||||
nl.stripe_count = l.stripe_count;
|
||||
if (l.stripe_unit)
|
||||
nl.stripe_unit = l.stripe_unit;
|
||||
if (l.object_size)
|
||||
nl.object_size = l.object_size;
|
||||
if (l.data_pool)
|
||||
nl.data_pool = l.data_pool;
|
||||
if (l.preferred_osd)
|
||||
nl.preferred_osd = l.preferred_osd;
|
||||
|
||||
if ((nl.object_size & ~PAGE_MASK) ||
|
||||
(nl.stripe_unit & ~PAGE_MASK) ||
|
||||
((unsigned)nl.object_size % (unsigned)nl.stripe_unit))
|
||||
return -EINVAL;
|
||||
|
||||
/* make sure it's a valid data pool */
|
||||
|
||||
+54
-1
@@ -6,7 +6,31 @@
|
||||
|
||||
#define CEPH_IOCTL_MAGIC 0x97
|
||||
|
||||
/* just use u64 to align sanely on all archs */
|
||||
/*
|
||||
* CEPH_IOC_GET_LAYOUT - get file layout or dir layout policy
|
||||
* CEPH_IOC_SET_LAYOUT - set file layout
|
||||
* CEPH_IOC_SET_LAYOUT_POLICY - set dir layout policy
|
||||
*
|
||||
* The file layout specifies how file data is striped over objects in
|
||||
* the distributed object store, which object pool they belong to (if
|
||||
* it differs from the default), and an optional 'preferred osd' to
|
||||
* store them on.
|
||||
*
|
||||
* Files get a new layout based on the policy set on the containing
|
||||
* directory or one of its ancestors. The GET_LAYOUT ioctl will let
|
||||
* you examine the layout for a file or the policy on a directory.
|
||||
*
|
||||
* SET_LAYOUT will let you set a layout on a newly created file. This
|
||||
* only works immediately after the file is created and before any
|
||||
* data is written to it.
|
||||
*
|
||||
* SET_LAYOUT_POLICY will let you set a layout policy (default layout)
|
||||
* on a directory that will apply to any new files created in that
|
||||
* directory (or any child directory that doesn't specify a layout of
|
||||
* its own).
|
||||
*/
|
||||
|
||||
/* use u64 to align sanely on all archs */
|
||||
struct ceph_ioctl_layout {
|
||||
__u64 stripe_unit, stripe_count, object_size;
|
||||
__u64 data_pool;
|
||||
@@ -21,6 +45,8 @@ struct ceph_ioctl_layout {
|
||||
struct ceph_ioctl_layout)
|
||||
|
||||
/*
|
||||
* CEPH_IOC_GET_DATALOC - get location of file data in the cluster
|
||||
*
|
||||
* Extract identity, address of the OSD and object storing a given
|
||||
* file offset.
|
||||
*/
|
||||
@@ -39,7 +65,34 @@ struct ceph_ioctl_dataloc {
|
||||
#define CEPH_IOC_GET_DATALOC _IOWR(CEPH_IOCTL_MAGIC, 3, \
|
||||
struct ceph_ioctl_dataloc)
|
||||
|
||||
/*
|
||||
* CEPH_IOC_LAZYIO - relax consistency
|
||||
*
|
||||
* Normally Ceph switches to synchronous IO when multiple clients have
|
||||
* the file open (and or more for write). Reads and writes bypass the
|
||||
* page cache and go directly to the OSD. Setting this flag on a file
|
||||
* descriptor will allow buffered IO for this file in cases where the
|
||||
* application knows it won't interfere with other nodes (or doesn't
|
||||
* care).
|
||||
*/
|
||||
#define CEPH_IOC_LAZYIO _IO(CEPH_IOCTL_MAGIC, 4)
|
||||
|
||||
/*
|
||||
* CEPH_IOC_SYNCIO - force synchronous IO
|
||||
*
|
||||
* This ioctl sets a file flag that forces the synchronous IO that
|
||||
* bypasses the page cache, even if it is not necessary. This is
|
||||
* essentially the opposite behavior of IOC_LAZYIO. This forces the
|
||||
* same read/write path as a file opened by multiple clients when one
|
||||
* or more of those clients is opened for write.
|
||||
*
|
||||
* Note that this type of sync IO takes a different path than a file
|
||||
* opened with O_SYNC/D_SYNC (writes hit the page cache and are
|
||||
* immediately flushed on page boundaries). It is very similar to
|
||||
* O_DIRECT (writes bypass the page cache) excep that O_DIRECT writes
|
||||
* are not copied (user page must remain stable) and O_DIRECT writes
|
||||
* have alignment restrictions (on the buffer and file offset).
|
||||
*/
|
||||
#define CEPH_IOC_SYNCIO _IO(CEPH_IOCTL_MAGIC, 5)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -764,7 +764,8 @@ static struct ceph_msg *create_session_msg(u32 op, u64 seq)
|
||||
struct ceph_msg *msg;
|
||||
struct ceph_mds_session_head *h;
|
||||
|
||||
msg = ceph_msg_new(CEPH_MSG_CLIENT_SESSION, sizeof(*h), GFP_NOFS);
|
||||
msg = ceph_msg_new(CEPH_MSG_CLIENT_SESSION, sizeof(*h), GFP_NOFS,
|
||||
false);
|
||||
if (!msg) {
|
||||
pr_err("create_session_msg ENOMEM creating msg\n");
|
||||
return NULL;
|
||||
@@ -1240,7 +1241,7 @@ int ceph_add_cap_releases(struct ceph_mds_client *mdsc,
|
||||
while (session->s_num_cap_releases < session->s_nr_caps + extra) {
|
||||
spin_unlock(&session->s_cap_lock);
|
||||
msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPRELEASE, PAGE_CACHE_SIZE,
|
||||
GFP_NOFS);
|
||||
GFP_NOFS, false);
|
||||
if (!msg)
|
||||
goto out_unlocked;
|
||||
dout("add_cap_releases %p msg %p now %d\n", session, msg,
|
||||
@@ -1652,7 +1653,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
|
||||
if (req->r_old_dentry_drop)
|
||||
len += req->r_old_dentry->d_name.len;
|
||||
|
||||
msg = ceph_msg_new(CEPH_MSG_CLIENT_REQUEST, len, GFP_NOFS);
|
||||
msg = ceph_msg_new(CEPH_MSG_CLIENT_REQUEST, len, GFP_NOFS, false);
|
||||
if (!msg) {
|
||||
msg = ERR_PTR(-ENOMEM);
|
||||
goto out_free2;
|
||||
@@ -2518,7 +2519,7 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
|
||||
goto fail_nopagelist;
|
||||
ceph_pagelist_init(pagelist);
|
||||
|
||||
reply = ceph_msg_new(CEPH_MSG_CLIENT_RECONNECT, 0, GFP_NOFS);
|
||||
reply = ceph_msg_new(CEPH_MSG_CLIENT_RECONNECT, 0, GFP_NOFS, false);
|
||||
if (!reply)
|
||||
goto fail_nomsg;
|
||||
|
||||
@@ -2831,7 +2832,7 @@ void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
|
||||
dnamelen = dentry->d_name.len;
|
||||
len += dnamelen;
|
||||
|
||||
msg = ceph_msg_new(CEPH_MSG_CLIENT_LEASE, len, GFP_NOFS);
|
||||
msg = ceph_msg_new(CEPH_MSG_CLIENT_LEASE, len, GFP_NOFS, false);
|
||||
if (!msg)
|
||||
return;
|
||||
lease = msg->front.iov_base;
|
||||
|
||||
+36
-25
@@ -114,6 +114,7 @@ static int ceph_sync_fs(struct super_block *sb, int wait)
|
||||
enum {
|
||||
Opt_wsize,
|
||||
Opt_rsize,
|
||||
Opt_rasize,
|
||||
Opt_caps_wanted_delay_min,
|
||||
Opt_caps_wanted_delay_max,
|
||||
Opt_cap_release_safety,
|
||||
@@ -136,6 +137,7 @@ enum {
|
||||
static match_table_t fsopt_tokens = {
|
||||
{Opt_wsize, "wsize=%d"},
|
||||
{Opt_rsize, "rsize=%d"},
|
||||
{Opt_rasize, "rasize=%d"},
|
||||
{Opt_caps_wanted_delay_min, "caps_wanted_delay_min=%d"},
|
||||
{Opt_caps_wanted_delay_max, "caps_wanted_delay_max=%d"},
|
||||
{Opt_cap_release_safety, "cap_release_safety=%d"},
|
||||
@@ -196,6 +198,9 @@ static int parse_fsopt_token(char *c, void *private)
|
||||
case Opt_rsize:
|
||||
fsopt->rsize = intval;
|
||||
break;
|
||||
case Opt_rasize:
|
||||
fsopt->rasize = intval;
|
||||
break;
|
||||
case Opt_caps_wanted_delay_min:
|
||||
fsopt->caps_wanted_delay_min = intval;
|
||||
break;
|
||||
@@ -289,28 +294,29 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt,
|
||||
|
||||
dout("parse_mount_options %p, dev_name '%s'\n", fsopt, dev_name);
|
||||
|
||||
fsopt->sb_flags = flags;
|
||||
fsopt->flags = CEPH_MOUNT_OPT_DEFAULT;
|
||||
fsopt->sb_flags = flags;
|
||||
fsopt->flags = CEPH_MOUNT_OPT_DEFAULT;
|
||||
|
||||
fsopt->rsize = CEPH_RSIZE_DEFAULT;
|
||||
fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
|
||||
fsopt->rsize = CEPH_RSIZE_DEFAULT;
|
||||
fsopt->rasize = CEPH_RASIZE_DEFAULT;
|
||||
fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
|
||||
fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
|
||||
fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
|
||||
fsopt->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT;
|
||||
fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT;
|
||||
fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
|
||||
fsopt->congestion_kb = default_congestion_kb();
|
||||
|
||||
/* ip1[:port1][,ip2[:port2]...]:/subdir/in/fs */
|
||||
err = -EINVAL;
|
||||
if (!dev_name)
|
||||
goto out;
|
||||
*path = strstr(dev_name, ":/");
|
||||
if (*path == NULL) {
|
||||
pr_err("device name is missing path (no :/ in %s)\n",
|
||||
dev_name);
|
||||
goto out;
|
||||
}
|
||||
fsopt->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT;
|
||||
fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT;
|
||||
fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
|
||||
fsopt->congestion_kb = default_congestion_kb();
|
||||
|
||||
/* ip1[:port1][,ip2[:port2]...]:/subdir/in/fs */
|
||||
err = -EINVAL;
|
||||
if (!dev_name)
|
||||
goto out;
|
||||
*path = strstr(dev_name, ":/");
|
||||
if (*path == NULL) {
|
||||
pr_err("device name is missing path (no :/ in %s)\n",
|
||||
dev_name);
|
||||
goto out;
|
||||
}
|
||||
dev_name_end = *path;
|
||||
dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name);
|
||||
|
||||
@@ -376,6 +382,8 @@ static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt)
|
||||
seq_printf(m, ",wsize=%d", fsopt->wsize);
|
||||
if (fsopt->rsize != CEPH_RSIZE_DEFAULT)
|
||||
seq_printf(m, ",rsize=%d", fsopt->rsize);
|
||||
if (fsopt->rasize != CEPH_RASIZE_DEFAULT)
|
||||
seq_printf(m, ",rasize=%d", fsopt->rsize);
|
||||
if (fsopt->congestion_kb != default_congestion_kb())
|
||||
seq_printf(m, ",write_congestion_kb=%d", fsopt->congestion_kb);
|
||||
if (fsopt->caps_wanted_delay_min != CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT)
|
||||
@@ -422,20 +430,23 @@ struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
|
||||
struct ceph_options *opt)
|
||||
{
|
||||
struct ceph_fs_client *fsc;
|
||||
const unsigned supported_features =
|
||||
CEPH_FEATURE_FLOCK |
|
||||
CEPH_FEATURE_DIRLAYOUTHASH;
|
||||
const unsigned required_features = 0;
|
||||
int err = -ENOMEM;
|
||||
|
||||
fsc = kzalloc(sizeof(*fsc), GFP_KERNEL);
|
||||
if (!fsc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
fsc->client = ceph_create_client(opt, fsc);
|
||||
fsc->client = ceph_create_client(opt, fsc, supported_features,
|
||||
required_features);
|
||||
if (IS_ERR(fsc->client)) {
|
||||
err = PTR_ERR(fsc->client);
|
||||
goto fail;
|
||||
}
|
||||
fsc->client->extra_mon_dispatch = extra_mon_dispatch;
|
||||
fsc->client->supported_features |= CEPH_FEATURE_FLOCK |
|
||||
CEPH_FEATURE_DIRLAYOUTHASH;
|
||||
fsc->client->monc.want_mdsmap = 1;
|
||||
|
||||
fsc->mount_options = fsopt;
|
||||
@@ -774,10 +785,10 @@ static int ceph_register_bdi(struct super_block *sb,
|
||||
{
|
||||
int err;
|
||||
|
||||
/* set ra_pages based on rsize mount option? */
|
||||
if (fsc->mount_options->rsize >= PAGE_CACHE_SIZE)
|
||||
/* set ra_pages based on rasize mount option? */
|
||||
if (fsc->mount_options->rasize >= PAGE_CACHE_SIZE)
|
||||
fsc->backing_dev_info.ra_pages =
|
||||
(fsc->mount_options->rsize + PAGE_CACHE_SIZE - 1)
|
||||
(fsc->mount_options->rasize + PAGE_CACHE_SIZE - 1)
|
||||
>> PAGE_SHIFT;
|
||||
else
|
||||
fsc->backing_dev_info.ra_pages =
|
||||
|
||||
+11
-8
@@ -36,7 +36,8 @@
|
||||
#define ceph_test_mount_opt(fsc, opt) \
|
||||
(!!((fsc)->mount_options->flags & CEPH_MOUNT_OPT_##opt))
|
||||
|
||||
#define CEPH_RSIZE_DEFAULT (512*1024) /* readahead */
|
||||
#define CEPH_RSIZE_DEFAULT 0 /* max read size */
|
||||
#define CEPH_RASIZE_DEFAULT (8192*1024) /* readahead */
|
||||
#define CEPH_MAX_READDIR_DEFAULT 1024
|
||||
#define CEPH_MAX_READDIR_BYTES_DEFAULT (512*1024)
|
||||
#define CEPH_SNAPDIRNAME_DEFAULT ".snap"
|
||||
@@ -45,8 +46,9 @@ struct ceph_mount_options {
|
||||
int flags;
|
||||
int sb_flags;
|
||||
|
||||
int wsize;
|
||||
int rsize; /* max readahead */
|
||||
int wsize; /* max write size */
|
||||
int rsize; /* max read size */
|
||||
int rasize; /* max readahead */
|
||||
int congestion_kb; /* max writeback in flight */
|
||||
int caps_wanted_delay_min, caps_wanted_delay_max;
|
||||
int cap_release_safety;
|
||||
@@ -344,9 +346,10 @@ static inline struct ceph_vino ceph_vino(struct inode *inode)
|
||||
* x86_64+ino32 64 32
|
||||
* x86_64 64 64
|
||||
*/
|
||||
static inline u32 ceph_ino_to_ino32(ino_t ino)
|
||||
static inline u32 ceph_ino_to_ino32(__u64 vino)
|
||||
{
|
||||
ino ^= ino >> (sizeof(ino) * 8 - 32);
|
||||
u32 ino = vino & 0xffffffff;
|
||||
ino ^= vino >> 32;
|
||||
if (!ino)
|
||||
ino = 1;
|
||||
return ino;
|
||||
@@ -357,11 +360,11 @@ static inline u32 ceph_ino_to_ino32(ino_t ino)
|
||||
*/
|
||||
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 = ceph_ino_to_ino32(ino);
|
||||
return ceph_ino_to_ino32(vino.ino);
|
||||
#else
|
||||
return (ino_t)vino.ino;
|
||||
#endif
|
||||
return ino;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user