debug_buf = vmalloc(bufsize + DEBUG_OVERFLOW);
if (debug_buf == NULL)
return -ENOMEM;
- memset(debug_buf, 0, debug_size);
+ memset(debug_buf, 0, bufsize + DEBUG_OVERFLOW);
debug_wrapped = 0;
//printk(KERN_INFO "Portals: allocated %lu byte debug buffer at %p.\n",
- clear page cache after eviction (2766)
- don't copy lvb into (possibly NULL) reply on error (2983)
- don't deref dentry after dput, don't free lvb on error (2922)
+ - use the kms to determine writeback rpc length (2947)
+ - update client's i_blocks count via lvb messages (2543)
+ - handle intent open/close of special files properly (1557)
+ - mount MDS with errors=remount-ro, like obdfilter (2009)
* miscellania
- allow default OST striping configuration per directory (1414)
struct list_head lli_pending_write_llaps;
struct list_head lli_close_item;
+
+ struct file_operations *ll_save_ifop;
+ struct file_operations *ll_save_ffop;
+ struct file_operations *ll_save_wfop;
+ struct file_operations *ll_save_wrfop;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
struct inode lli_vfs_inode;
#endif
__u64 loi_kms; /* known minimum size */
__u64 loi_rss; /* recently seen size */
__u64 loi_mtime; /* recently seen mtime */
+ __u64 loi_blocks; /* recently seen blocks */
};
static inline void loi_init(struct lov_oinfo *loi)
int (*ap_make_ready)(void *data, int cmd);
int (*ap_refresh_count)(void *data, int cmd);
void (*ap_fill_obdo)(void *data, int cmd, struct obdo *oa);
- void (*ap_completion)(void *data, int cmd, int rc);
+ void (*ap_completion)(void *data, int cmd, struct obdo *oa, int rc);
};
/* the `oig' is passed down from a caller of obd rw methods. the callee
}
/* called for each page in a completed rpc.*/
-static void llu_ap_completion(void *data, int cmd, int rc)
+static void llu_ap_completion(void *data, int cmd, struct obdo *oa, int rc)
{
struct ll_async_page *llap;
struct page *page;
EXTRA_PROGRAMS = llite
COMMON_SRC = dcache.c dir.c file.c llite_close.c llite_lib.c llite_nfs.c rw.c \
- lproc_llite.c namei.c symlink.c llite_internal.h
+ lproc_llite.c namei.c special.c symlink.c llite_internal.h
if LINUX25
llite_SOURCES = $(COMMON_SRC) rw26.c super25.c
obj-y += llite.o
llite-objs := llite_lib.o dcache.o super.o rw.o \
super25.o file.o dir.o symlink.o namei.o lproc_llite.o \
- rw26.o llite_nfs.o llite_close.o
+ rw26.o llite_nfs.o llite_close.o special.o
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
#include <linux/lustre_compat25.h>
#endif
-
#include "llite_internal.h"
-static int ll_mdc_close(struct obd_export *mdc_exp, struct inode *inode,
+int ll_mdc_close(struct obd_export *mdc_exp, struct inode *inode,
struct file *file)
{
struct ll_file_data *fd = file->private_data;
RETURN(rc);
}
-static int ll_local_open(struct file *file, struct lookup_intent *it)
+int ll_local_open(struct file *file, struct lookup_intent *it)
{
struct ptlrpc_request *req = it->d.lustre.it_data;
struct ll_inode_info *lli = ll_i2info(file->f_dentry->d_inode);
}
__u64 lov_merge_size(struct lov_stripe_md *lsm, int kms);
+__u64 lov_merge_blocks(struct lov_stripe_md *lsm);
__u64 lov_merge_mtime(struct lov_stripe_md *lsm, __u64 current_time);
/* NB: lov_merge_size will prefer locally cached writes if they extend the
}
lvb->lvb_size = lov_merge_size(lli->lli_smd, 0);
+ inode->i_blocks = lov_merge_blocks(lli->lli_smd);
//inode->i_mtime = lov_merge_mtime(lli->lli_smd, inode->i_mtime);
- CDEBUG(D_DLMTRACE, "glimpse: size: "LPU64"\n", lvb->lvb_size);
+ CDEBUG(D_DLMTRACE, "glimpse: size: "LPU64", blocks: "LPU64"\n",
+ lvb->lvb_size, lvb->lvb_blocks);
obd_cancel(sbi->ll_osc_exp, lli->lli_smd, LCK_PR, &lockh);
#endif
};
-struct inode_operations ll_special_inode_operations = {
- setattr_raw: ll_setattr_raw,
- setattr: ll_setattr,
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
- getattr_it: ll_getattr,
-#else
- revalidate_it: ll_inode_revalidate_it,
-#endif
-};
int ll_prepare_write(struct file *, struct page *, unsigned from, unsigned to);
int ll_commit_write(struct file *, struct page *, unsigned from, unsigned to);
void ll_inode_fill_obdo(struct inode *inode, int cmd, struct obdo *oa);
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#define ll_ap_completion ll_ap_completion_24
-void ll_ap_completion_24(void *data, int cmd, int rc);
-#else
-#define ll_ap_completion ll_ap_completion_26
-void ll_ap_completion_26(void *data, int cmd, int rc);
-#endif
+void ll_ap_completion(void *data, int cmd, struct obdo *oa, int rc);
void ll_removepage(struct page *page);
int ll_sync_page(struct page *page);
int ll_readpage(struct file *file, struct page *page);
/* llite/file.c */
extern struct file_operations ll_file_operations;
extern struct inode_operations ll_file_inode_operations;
-extern struct inode_operations ll_special_inode_operations;
extern int ll_inode_revalidate_it(struct dentry *, struct lookup_intent *);
int ll_extent_lock(struct ll_file_data *, struct inode *,
struct lov_stripe_md *, int mode, ldlm_policy_data_t *,
int ll_file_release(struct inode *inode, struct file *file);
int ll_lsm_getattr(struct obd_export *, struct lov_stripe_md *, struct obdo *);
int ll_glimpse_size(struct inode *inode, struct ost_lvb *lvb);
+int ll_local_open(struct file *file, struct lookup_intent *it);
+int ll_mdc_close(struct obd_export *mdc_exp, struct inode *inode,
+ struct file *file);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
int ll_getattr(struct vfsmount *mnt, struct dentry *de,
struct lookup_intent *it, struct kstat *stat);
struct dentry *ll_fh_to_dentry(struct super_block *sb, __u32 *data, int len,
int fhtype, int parent);
int ll_dentry_to_fh(struct dentry *, __u32 *datap, int *lenp, int need_parent);
+
+/* llite/special.c */
+extern struct inode_operations ll_special_inode_operations;
+extern struct file_operations ll_special_chr_inode_fops;
+extern struct file_operations ll_special_chr_file_fops;
+extern struct file_operations ll_special_blk_inode_fops;
+extern struct file_operations ll_special_fifo_inode_fops;
+extern struct file_operations ll_special_fifo_file_fops;
+extern struct file_operations ll_special_sock_inode_fops;
+
/* llite/symlink.c */
extern struct inode_operations ll_fast_symlink_inode_operations;
} else {
inode->i_op = &ll_special_inode_operations;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+#warning "need to fix this for 2.6 also"
init_special_inode(inode, inode->i_mode,
kdev_t_to_nr(inode->i_rdev));
#else
init_special_inode(inode, inode->i_mode, inode->i_rdev);
+
+ lli->ll_save_ifop = inode->i_fop;
+ if (S_ISCHR(inode->i_mode))
+ inode->i_fop = &ll_special_chr_inode_fops;
+ else if (S_ISBLK(inode->i_mode))
+ inode->i_fop = &ll_special_blk_inode_fops;
+ else if (S_ISFIFO(inode->i_mode))
+ inode->i_fop = &ll_special_fifo_inode_fops;
+ else if (S_ISSOCK(inode->i_mode))
+ inode->i_fop = &ll_special_sock_inode_fops;
+ CWARN("saved %p, replaced with %p\n", lli->ll_save_ifop,
+ inode->i_fop);
+ if (lli->ll_save_ifop->owner)
+ CWARN("%p has owner %p\n", lli->ll_save_ifop,
+ lli->ll_save_ifop->owner);
#endif
EXIT;
}
return rc;
}
-int ll_write_count(struct page *page)
-{
- struct inode *inode = page->mapping->host;
-
- /* catch race with truncate */
- if (((loff_t)page->index << PAGE_SHIFT) >= inode->i_size)
- return 0;
-
- /* catch sub-page write at end of file */
- if (((loff_t)page->index << PAGE_SHIFT) + PAGE_SIZE > inode->i_size)
- return inode->i_size % PAGE_SIZE;
-
- return PAGE_SIZE;
-}
-
struct ll_async_page *llap_from_cookie(void *cookie)
{
struct ll_async_page *llap = cookie;
RETURN(0);
}
+/* We have two reasons for giving llite the opportunity to change the
+ * write length of a given queued page as it builds the RPC containing
+ * the page:
+ *
+ * 1) Further extending writes may have landed in the page cache
+ * since a partial write first queued this page requiring us
+ * to write more from the page cache.
+ * 2) We might have raced with truncate and want to avoid performing
+ * write RPCs that are just going to be thrown away by the
+ * truncate's punch on the storage targets.
+ *
+ * The kms serves these purposes as it is set at both truncate and extending
+ * writes.
+ */
static int ll_ap_refresh_count(void *data, int cmd)
{
struct ll_async_page *llap;
+ struct lov_stripe_md *lsm;
+ struct page *page;
+ __u64 kms;
ENTRY;
/* readpage queues with _COUNT_STABLE, shouldn't get here. */
if (IS_ERR(llap))
RETURN(PTR_ERR(llap));
- return ll_write_count(llap->llap_page);
+ page = llap->llap_page;
+ lsm = ll_i2info(page->mapping->host)->lli_smd;
+ kms = lov_merge_size(lsm, 1);
+
+ /* catch race with truncate */
+ if (((__u64)page->index << PAGE_SHIFT) >= kms)
+ return 0;
+
+ /* catch sub-page write at end of file */
+ if (((__u64)page->index << PAGE_SHIFT) + PAGE_SIZE > kms)
+ return kms % PAGE_SIZE;
+
+ return PAGE_SIZE;
}
void ll_inode_fill_obdo(struct inode *inode, int cmd, struct obdo *oa)
RETURN(rc);
}
+/* called for each page in a completed rpc.*/
+void ll_ap_completion(void *data, int cmd, struct obdo *oa, int rc)
+{
+ struct ll_async_page *llap;
+ struct page *page;
+ ENTRY;
+
+ llap = llap_from_cookie(data);
+ if (IS_ERR(llap)) {
+ EXIT;
+ return;
+ }
+
+ page = llap->llap_page;
+ LASSERT(PageLocked(page));
+
+ LL_CDEBUG_PAGE(D_PAGE, page, "completing cmd %d with %d\n", cmd, rc);
+
+ if (rc == 0) {
+ if (cmd == OBD_BRW_READ) {
+ if (!llap->llap_defer_uptodate)
+ SetPageUptodate(page);
+ } else {
+ llap->llap_write_queued = 0;
+ }
+ ClearPageError(page);
+ } else {
+ if (cmd == OBD_BRW_READ)
+ llap->llap_defer_uptodate = 0;
+ SetPageError(page);
+ }
+
+
+ unlock_page(page);
+
+ if (0 && cmd == OBD_BRW_WRITE) {
+ llap_write_complete(page->mapping->host, llap);
+ ll_try_done_writing(page->mapping->host);
+ }
+
+ page_cache_release(page);
+ EXIT;
+}
+
/* the kernel calls us here when a page is unhashed from the page cache.
* the page will be locked and the kernel is holding a spinlock, so
* we need to be careful. we're just tearing down our book-keeping
#include "llite_internal.h"
#include <linux/lustre_compat25.h>
-/* called for each page in a completed rpc.*/
-void ll_ap_completion_24(void *data, int cmd, int rc)
-{
- struct ll_async_page *llap;
- struct page *page;
- ENTRY;
-
- llap = llap_from_cookie(data);
- if (IS_ERR(llap)) {
- EXIT;
- return;
- }
-
- page = llap->llap_page;
- LASSERT(PageLocked(page));
-
- LL_CDEBUG_PAGE(D_PAGE, page, "completing cmd %d with %d\n", cmd, rc);
-
- if (rc == 0) {
- if (cmd == OBD_BRW_READ) {
- if (!llap->llap_defer_uptodate)
- SetPageUptodate(page);
- } else {
- llap->llap_write_queued = 0;
- }
- ClearPageError(page);
- } else {
- if (cmd == OBD_BRW_READ)
- llap->llap_defer_uptodate = 0;
- SetPageError(page);
- }
-
-
- unlock_page(page);
-
- if (0 && cmd == OBD_BRW_WRITE) {
- llap_write_complete(page->mapping->host, llap);
- ll_try_done_writing(page->mapping->host);
- }
-
- page_cache_release(page);
- EXIT;
-}
-
static int ll_writepage_24(struct page *page)
{
struct inode *inode = page->mapping->host;
#include "llite_internal.h"
#include <linux/lustre_compat25.h>
-/* called for each page in a completed rpc.*/
-void ll_ap_completion_26(void *data, int cmd, int rc)
-{
- struct ll_async_page *llap;
- struct page *page;
-
- llap = llap_from_cookie(data);
- if (IS_ERR(llap)) {
- EXIT;
- return;
- }
-
- page = llap->llap_page;
- LASSERT(PageLocked(page));
-
- if (rc == 0) {
- if (cmd == OBD_BRW_READ) {
- if (!llap->llap_defer_uptodate)
- SetPageUptodate(page);
- } else {
- llap->llap_write_queued = 0;
- }
- } else {
- SetPageError(page);
- }
-
- LL_CDEBUG_PAGE(D_PAGE, page, "io complete, unlocking\n");
-
- unlock_page(page);
-
- if (0 && cmd == OBD_BRW_WRITE) {
- llap_write_complete(page->mapping->host, llap);
- ll_try_done_writing(page->mapping->host);
- }
-
- page_cache_release(page);
-}
-
static int ll_writepage_26(struct page *page, struct writeback_control *wbc)
{
struct inode *inode = page->mapping->host;
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Special file handling for Lustre.
+ *
+ * Copyright (c) 2002, 2003 Cluster File Systems, Inc.
+ * Author: Wang Di <wangdi@clusterfs.com>
+ * Author: Andreas Dilger <adilger@clusterfs.com>
+ *
+ * This file is part of Lustre, http://www.lustre.org.
+ *
+ * Lustre is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * Lustre is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Lustre; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define DEBUG_SUBSYSTEM S_LLITE
+#include <linux/lustre_dlm.h>
+#include <linux/lustre_lite.h>
+#include <linux/pagemap.h>
+#include <linux/file.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#include <linux/lustre_compat25.h>
+#endif
+#include <asm/poll.h>
+#include "llite_internal.h"
+
+#define INODE_OPS 1
+#define FILE_OPS 2
+
+static struct file_operations **get_save_fops(struct file* filp, int mode)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct ll_inode_info *lli = ll_i2info(inode);
+
+ if (mode == INODE_OPS) {
+ return &(lli->ll_save_ifop);
+ } else if (mode == FILE_OPS) {
+ if (S_ISFIFO(inode->i_mode)) {
+ switch (filp->f_mode) {
+ case 1: /*O_RDONLY*/
+ return &(lli->ll_save_ffop);
+ case 2: /*O_WRONLY*/
+ return &(lli->ll_save_wfop);
+ case 3: /* O_RDWR */
+ return &(lli->ll_save_wrfop);
+ default:
+ return NULL;
+ }
+ }
+ return &(lli->ll_save_ffop);
+ } else {
+ CERROR("invalid special file ops %d\n", mode);
+ LBUG();
+ }
+}
+
+static void save_fops(struct file *filp, struct inode *inode,
+ struct file_operations *sfops)
+{
+ if (sfops != filp->f_op) {
+ struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+
+ *pfop = filp->f_op;
+ if (S_ISCHR(inode->i_mode))
+ filp->f_op = &ll_special_chr_file_fops;
+ else if (S_ISFIFO(inode->i_mode))
+ filp->f_op = &ll_special_fifo_file_fops;
+
+ CWARN("saved %p, replaced with %p\n", *pfop, filp->f_op);
+ if ((*pfop)->owner)
+ CWARN("%p has owner %p\n", *pfop,(*pfop)->owner);
+ }
+}
+
+static ssize_t ll_special_file_read(struct file *filp, char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+ int rc = -EINVAL;
+
+ if (pfop && *pfop && (*pfop)->read)
+ rc = (*pfop)->read(filp, buf, count, ppos);
+
+ RETURN(rc);
+}
+
+static ssize_t ll_special_file_write(struct file *filp, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+ int rc = -EINVAL;
+
+ if (pfop && *pfop && (*pfop)->write)
+ rc = (*pfop)->write(filp, buf, count, ppos);
+
+ RETURN(rc);
+}
+
+static int ll_special_file_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+ int rc = -ENOTTY;
+
+ if (pfop && *pfop && (*pfop)->ioctl) {
+ struct file_operations *sfops = filp->f_op;
+
+ rc = (*pfop)->ioctl(inode, filp, cmd, arg);
+ save_fops(filp, inode, sfops);
+ }
+ RETURN(rc);
+}
+
+static loff_t ll_special_file_seek(struct file *filp, loff_t offset, int origin)
+{
+ struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+ int rc = 0;
+
+ if (pfop && *pfop && (*pfop)->llseek)
+ rc = (*pfop)->llseek(filp, offset, origin);
+ else
+ rc = default_llseek(filp, offset, origin);
+
+ RETURN(rc);
+}
+
+
+#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
+
+static unsigned int ll_special_file_poll(struct file *filp,
+ struct poll_table_struct *poll_table)
+{
+ struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+ int rc = DEFAULT_POLLMASK;
+
+ if (pfop && *pfop && (*pfop)->poll)
+ rc = (*pfop)->poll(filp, poll_table);
+
+ RETURN(rc);
+}
+
+static int ll_special_file_open(struct inode *inode, struct file *filp)
+{
+ struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+ int rc = -EINVAL;
+
+ if (pfop && *pfop && (*pfop)->open)
+ rc = (*pfop)->open(inode, filp);
+
+ RETURN(rc);
+}
+
+static ssize_t ll_special_read(struct file *filp, char *buf, size_t count,
+ loff_t *ppos)
+{
+ struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
+ int rc = -EINVAL;
+
+ if (pfop && *pfop && (*pfop)->read)
+ rc = (*pfop)->read(filp, buf, count, ppos);
+
+ RETURN(rc);
+}
+
+static ssize_t ll_special_write(struct file *filp, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
+ int rc = -EINVAL;
+
+ if (pfop && *pfop && (*pfop)->write)
+ rc = (*pfop)->write(filp, buf, count, ppos);
+
+ RETURN(rc);
+}
+
+static int ll_special_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
+ int rc = -ENOTTY;
+
+ if (pfop && *pfop && (*pfop)->ioctl) {
+ struct file_operations *sfops = filp->f_op;
+
+ rc = (*pfop)->ioctl(inode, filp, cmd, arg);
+ /* sometimes, file_operations will be changed in ioctl */
+ save_fops(filp, inode, sfops);
+ }
+
+ RETURN(rc);
+}
+
+static int ll_special_mmap(struct file * filp, struct vm_area_struct * vma)
+{
+ struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
+ int rc = -ENODEV;
+
+ if (pfop && *pfop && (*pfop)->mmap)
+ rc = (*pfop)->mmap(filp, vma);
+
+ RETURN(rc);
+}
+
+static loff_t ll_special_seek(struct file *filp, loff_t offset, int origin)
+{
+ struct file_operations** pfop = get_save_fops (filp, INODE_OPS);
+ int rc = 0;
+
+ if (pfop && *pfop && (*pfop)->llseek)
+ rc = (*pfop)->llseek(filp, offset, origin);
+ else
+ rc = default_llseek(filp, offset, origin);
+
+ RETURN(rc);
+}
+
+static int ll_special_fsync(struct file *filp, struct dentry *dentry, int data)
+{
+ struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
+ int rc = -EINVAL;
+
+ if (pfop && *pfop && (*pfop)->fsync)
+ rc = (*pfop)->fsync(filp, dentry, data);
+
+ RETURN(rc);
+}
+
+static int ll_special_file_fasync(int fd, struct file *filp, int on)
+{
+ struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+ int rc = -EINVAL;
+
+ if (pfop && *pfop && (*pfop)->fasync)
+ rc = (*pfop)->fasync(fd, filp, on);
+
+ RETURN(rc);
+}
+
+static int ll_special_release_internal(struct inode *inode, struct file *filp,
+ int mode)
+{
+ struct file_operations **pfop = get_save_fops(filp, mode);
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ int rc = 0, err;
+ ENTRY;
+
+ if (pfop && *pfop) {
+ if ((*pfop)->release)
+ rc = (*pfop)->release(inode, filp);
+ /* FIXME fops_put */
+ }
+
+ lprocfs_counter_incr(sbi->ll_stats, LPROC_LL_RELEASE);
+
+ err = ll_mdc_close(sbi->ll_mdc_exp, inode, filp);
+ if (err && rc == 0)
+ rc = err;
+
+ RETURN(rc);
+}
+
+static int ll_special_open(struct inode *inode, struct file *filp)
+{
+ struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
+ struct file_operations *sfops = filp->f_op;
+ struct ptlrpc_request *req;
+ struct lookup_intent *it;
+ int rc = -EINVAL, err;
+ ENTRY;
+
+ if (pfop && *pfop) {
+ /* FIXME fops_get */
+ if ((*pfop)->open) {
+ rc = (*pfop)->open(inode, filp);
+
+ /* sometimes file_operations will be changed in open */
+ save_fops(filp, inode, sfops);
+ }
+ }
+
+ lprocfs_counter_incr(ll_i2sbi(inode)->ll_stats, LPROC_LL_OPEN);
+
+ it = filp->f_it;
+
+ err = ll_local_open(filp, it);
+ if (rc != 0) {
+ CERROR("error opening special file: rc %d", rc);
+ ll_mdc_close(ll_i2sbi(inode)->ll_mdc_exp, inode, filp);
+ } else if (err) {
+ if (pfop && *pfop && (*pfop)->release)
+ (*pfop)->release(inode, filp);
+ /* FIXME fops_put */
+ rc = err;
+ }
+
+ req = it->d.lustre.it_data;
+ if (req)
+ ptlrpc_req_finished(req);
+
+ RETURN(rc);
+}
+
+static int ll_special_release(struct inode *inode, struct file *filp)
+{
+ return ll_special_release_internal(inode, filp, INODE_OPS);
+}
+
+static int ll_special_file_release(struct inode *inode, struct file *filp)
+{
+ return ll_special_release_internal(inode, filp, FILE_OPS);
+}
+
+struct inode_operations ll_special_inode_operations = {
+ setattr_raw: ll_setattr_raw,
+ setattr: ll_setattr,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+ getattr_it: ll_getattr,
+#else
+ revalidate_it: ll_inode_revalidate_it,
+#endif
+};
+
+struct file_operations ll_special_chr_inode_fops = {
+ owner: THIS_MODULE,
+ open: ll_special_open,
+};
+
+struct file_operations ll_special_blk_inode_fops = {
+ owner: THIS_MODULE,
+ read: ll_special_read,
+ write: ll_special_write,
+ ioctl: ll_special_ioctl,
+ open: ll_special_open,
+ release: ll_special_release,
+ mmap: ll_special_mmap,
+ llseek: ll_special_seek,
+ fsync: ll_special_fsync,
+};
+
+struct file_operations ll_special_fifo_inode_fops = {
+ owner: THIS_MODULE,
+ open: ll_special_open,
+};
+
+struct file_operations ll_special_sock_inode_fops = {
+ owner: THIS_MODULE,
+ open: ll_special_open
+};
+
+struct file_operations ll_special_chr_file_fops = {
+ owner: THIS_MODULE,
+ llseek: ll_special_file_seek,
+ read: ll_special_file_read,
+ write: ll_special_file_write,
+ poll: ll_special_file_poll,
+ ioctl: ll_special_file_ioctl,
+ open: ll_special_file_open,
+ release: ll_special_file_release,
+ fasync: ll_special_file_fasync,
+};
+
+struct file_operations ll_special_fifo_file_fops = {
+ owner: THIS_MODULE,
+ llseek: ll_special_file_seek,
+ read: ll_special_file_read,
+ write: ll_special_file_write,
+ poll: ll_special_file_poll,
+ ioctl: ll_special_file_ioctl,
+ open: ll_special_file_open,
+ release: ll_special_file_release,
+};
/* XXX woah, shouldn't we be altering more here? size? */
oa->o_id = lap->lap_loi_id;
}
-static void lov_ap_completion(void *data, int cmd, int rc)
+
+static void lov_ap_completion(void *data, int cmd, struct obdo *oa, int rc)
{
struct lov_async_page *lap = lap_from_cookie(data);
if (IS_ERR(lap))
/* in a raid1 regime this would down a count of many ios
* in flight, onl calling the caller_ops completion when all
* the raid1 ios are complete */
- lap->lap_caller_ops->ap_completion(lap->lap_caller_data, cmd, rc);
+ lap->lap_caller_ops->ap_completion(lap->lap_caller_data, cmd, oa, rc);
}
static struct obd_async_page_ops lov_async_page_ops = {
submd->lsm_oinfo->loi_kms_valid = loi->loi_kms_valid;
submd->lsm_oinfo->loi_rss = loi->loi_rss;
submd->lsm_oinfo->loi_kms = loi->loi_kms;
+ submd->lsm_oinfo->loi_blocks = loi->loi_blocks;
loi->loi_mtime = submd->lsm_oinfo->loi_mtime;
/* XXX submd is not fully initialized here */
*flags = save_flags;
LASSERT(lock != NULL);
loi->loi_rss = tmp;
+ loi->loi_blocks = submd->lsm_oinfo->loi_blocks;
/* Extend KMS up to the end of this lock and no further
* A lock on [x,y] means a KMS of up to y + 1 bytes! */
if (tmp > lock->l_policy_data.l_extent.end)
save_flags & LDLM_FL_HAS_INTENT) {
memset(lov_lockhp, 0, sizeof(*lov_lockhp));
loi->loi_rss = submd->lsm_oinfo->loi_rss;
+ loi->loi_blocks = submd->lsm_oinfo->loi_blocks;
CDEBUG(D_INODE, "glimpsed, setting rss="LPU64"; leaving"
" kms="LPU64"\n", loi->loi_rss, loi->loi_kms);
} else {
}
EXPORT_SYMBOL(lov_merge_size);
+/* Merge blocks */
+__u64 lov_merge_blocks(struct lov_stripe_md *lsm)
+{
+ struct lov_oinfo *loi;
+ __u64 blocks = 0;
+ int i;
+
+ for (i = 0, loi = lsm->lsm_oinfo; i < lsm->lsm_stripe_count;
+ i++, loi++) {
+ blocks += loi->loi_blocks;
+ }
+ return blocks;
+}
+EXPORT_SYMBOL(lov_merge_blocks);
+
__u64 lov_merge_mtime(struct lov_stripe_md *lsm, __u64 current_time)
{
struct lov_oinfo *loi;
RETURN(-ENOMEM);
memset((void *)page, 0, PAGE_SIZE);
- sprintf((char *)page, "iopen_nopriv");
+ sprintf((char *)page, "iopen_nopriv,errors=remount-ro");
mnt = do_kern_mount(lcfg->lcfg_inlbuf2, 0,
lcfg->lcfg_inlbuf1, (void *)page);
memcpy(oa, &eap->eap_eas->eas_oa, sizeof(*oa));
}
-static void ec_ap_completion(void *data, int cmd, int rc)
+
+static void ec_ap_completion(void *data, int cmd, struct obdo *oa, int rc)
{
struct echo_async_page *eap = eap_from_cookie(data);
struct echo_async_state *eas;
res_lvb = res->lr_lvb_data;
LASSERT(res_lvb != NULL);
reply_lvb->lvb_size = res_lvb->lvb_size;
+ reply_lvb->lvb_blocks = res_lvb->lvb_blocks;
up(&res->lr_lvb_sem);
list_for_each(tmp, &res->lr_granted) {
down(&res->lr_lvb_sem);
reply_lvb->lvb_size = res_lvb->lvb_size;
+ reply_lvb->lvb_blocks = res_lvb->lvb_blocks;
up(&res->lr_lvb_sem);
LDLM_LOCK_PUT(l);
lvb->lvb_size = dentry->d_inode->i_size;
lvb->lvb_mtime = LTIME_S(dentry->d_inode->i_mtime);
+ lvb->lvb_blocks = dentry->d_inode->i_blocks;
f_dput(dentry);
-
- CDEBUG(D_DLMTRACE, "res: "LPU64" initial lvb size: "LPU64", mtime: "
- LPU64"\n", res->lr_name.name[0], lvb->lvb_size, lvb->lvb_mtime);
+ CDEBUG(D_DLMTRACE, "res: "LPU64" initial lvb size: "LPU64", "
+ "mtime: "LPU64", blocks: "LPU64"\n",
+ res->lr_name.name[0], lvb->lvb_size,
+ lvb->lvb_mtime, lvb->lvb_blocks);
out:
/* Don't free lvb data on lookup error */
lvb->lvb_mtime, new->lvb_mtime);
lvb->lvb_mtime = new->lvb_mtime;
}
+ if (new->lvb_blocks > lvb->lvb_blocks || !increase) {
+ CDEBUG(D_DLMTRACE, "res: "LPU64" updating lvb blocks: "
+ LPU64" -> "LPU64"\n", res->lr_name.name[0],
+ lvb->lvb_blocks, new->lvb_blocks);
+ lvb->lvb_blocks = new->lvb_blocks;
+ }
GOTO(out, rc = 0);
}
lvb->lvb_mtime, LTIME_S(dentry->d_inode->i_mtime));
lvb->lvb_mtime = LTIME_S(dentry->d_inode->i_mtime);
}
+ CDEBUG(D_DLMTRACE, "res: "LPU64" updating lvb blocks from disk: "
+ LPU64" -> %lu\n", res->lr_name.name[0],
+ lvb->lvb_blocks, dentry->d_inode->i_blocks);
+ lvb->lvb_blocks = dentry->d_inode->i_blocks;
+
f_dput(dentry);
out:
}
osc_update_grant(cli, body);
+ memcpy(oa, &body->oa, sizeof(*oa));
if (req->rq_reqmsg->opc == OST_WRITE) {
if (rc > 0) {
if (rc < requested_nob)
handle_short_read(rc, page_count, pga);
- memcpy(oa, &body->oa, sizeof(*oa));
-
#if CHECKSUM_BULK
if (oa->o_valid & OBD_MD_FLCKSUM) {
const struct ptlrpc_peer *peer =
/* this must be called holding the loi list lock to give coverage to exit_cache,
* async_flag maintenance, and oap_request */
-static void osc_complete_oap(struct client_obd *cli,
- struct osc_async_page *oap, int sent, int rc)
+static void osc_ap_completion(struct client_obd *cli, struct obdo *oa,
+ struct osc_async_page *oap, int sent, int rc)
{
osc_exit_cache(cli, oap, sent);
oap->oap_async_flags = 0;
oap->oap_request = NULL;
}
+ if (rc == 0 && oa != NULL)
+ oap->oap_loi->loi_blocks = oa->o_blocks;
+
if (oap->oap_oig) {
oig_complete_one(oap->oap_oig, &oap->oap_occ, rc);
oap->oap_oig = NULL;
}
oap->oap_caller_ops->ap_completion(oap->oap_caller_data, oap->oap_cmd,
- rc);
+ oa, rc);
}
static int brw_interpret_oap(struct ptlrpc_request *request,
spin_lock(&cli->cl_loi_list_lock);
- /* We need to decrement before osc_complete_oap->osc_wake_cache_waiters
+ /* We need to decrement before osc_ap_completion->osc_wake_cache_waiters
* is called so we know whether to go to sync BRWs or wait for more
* RPCs to complete */
cli->cl_brw_in_flight--;
//oap->oap_page, oap->oap_page->index, oap);
list_del_init(&oap->oap_rpc_item);
- osc_complete_oap(cli, oap, 1, rc);
+ osc_ap_completion(cli, aa->aa_oa, oap, 1, rc);
}
osc_wake_cache_waiters(cli);
if (oap->oap_count <= 0) {
CDEBUG(D_CACHE, "oap %p count %d, completing\n", oap,
oap->oap_count);
- osc_complete_oap(cli, oap, 0, oap->oap_count);
+ osc_ap_completion(cli, aa->aa_oa, oap, 0, oap->oap_count);
continue;
}
* were between the pending list and the rpc */
if (oap->oap_interrupted) {
CDEBUG(D_INODE, "oap %p interrupted\n", oap);
- osc_complete_oap(cli, oap, 0, oap->oap_count);
+ osc_ap_completion(cli, aa->aa_oa, oap, 0,
+ oap->oap_count);
continue;
}
&lvb, sizeof(lvb), lustre_swab_ost_lvb, lockh);
if ((*flags & LDLM_FL_HAS_INTENT && rc == ELDLM_LOCK_ABORTED) || !rc) {
- CDEBUG(D_INODE, "received kms == "LPU64"\n", lvb.lvb_size);
+ CDEBUG(D_INODE, "received kms == "LPU64", blocks == "LPU64"\n",
+ lvb.lvb_size, lvb.lvb_blocks);
lsm->lsm_oinfo->loi_rss = lvb.lvb_size;
+ lsm->lsm_oinfo->loi_blocks = lvb.lvb_blocks;
}
RETURN(rc);
debug_buf = vmalloc(bufsize + DEBUG_OVERFLOW);
if (debug_buf == NULL)
return -ENOMEM;
- memset(debug_buf, 0, debug_size);
+ memset(debug_buf, 0, bufsize + DEBUG_OVERFLOW);
debug_wrapped = 0;
//printk(KERN_INFO "Portals: allocated %lu byte debug buffer at %p.\n",
mv $TMP/debug $TMP/debug-busy.`date +%s`
exit 255
fi
-LEAK_LUSTRE=`dmesg | tail -40 | grep "obd mem.*leaked"`
+LEAK_LUSTRE=`dmesg | tail -30 | grep "obd mem.*leaked"`
LEAK_PORTALS=`dmesg | tail -20 | grep "Portals memory leaked"`
if [ "$LEAK_LUSTRE" -o "$LEAK_PORTALS" ]; then
echo "$LEAK_LUSTRE" 1>&2
mv $TMP/debug $TMP/debug-leak.`date +%s`
exit 254
fi
+lsmod | grep portals && echo "modules still loaded" && exit 1
exit $rc
run_test 18b "eviction and reconnect clears page cache (2766)"
test_19a() { # bug 2983 - ldlm_handle_enqueue cleanup
- mkdir -p $DIR/d19
- multiop $DIR/d19/f19a O_wc &
+ mkdir -p $DIR/$tdir
+ multiop $DIR/$tdir/${tfile} O_wc &
MULTI_PID=$!
usleep 500
cancel_lru_locks OSC
#define OBD_FAIL_LDLM_ENQUEUE_EXTENT_ERR 0x308
do_facet ost sysctl -w lustre.fail_loc=0x80000308
+ set -vx
kill -USR1 $MULTI_PID
- wait $MULTI_PID && error "multiop didn't fail enqueue" || true
+ wait $MULTI_PID
+ rc=$?
+ [ $rc -eq 0 ] && error "multiop didn't fail enqueue: rc $rc" || true
+ set +vx
}
-run_test 19a "ldlm_handle_enqueue error (should return error) ==="
+run_test 19a "ldlm_handle_enqueue error (should return error)"
test_19b() { # bug 2986 - ldlm_handle_enqueue error during open
- mkdir $DIR/d19
- touch $DIR/d19/f19b
+ mkdir $DIR/$tdir
+ touch $DIR/$tdir/${tfile}
cancel_lru_locks OSC
#define OBD_FAIL_LDLM_ENQUEUE_EXTENT_ERR 0x308
do_facet ost sysctl -w lustre.fail_loc=0x80000308
- dd if=/etc/hosts of=$DIR/d19/f19b && error "didn't fail enqueue" || true
+ dd if=/etc/hosts of=$DIR/$tdir/$tfile && \
+ error "didn't fail open enqueue" || true
}
-run_test 19b "ldlm_handle_enqueue error (should return error) ==="
+run_test 19b "ldlm_handle_enqueue error (should return error)"
$CLEANUP
[ -z "`echo $DIR | grep $MOUNT`" ] && echo "$DIR not in $MOUNT" && exit 99
LOVNAME=`cat /proc/fs/lustre/llite/fs0/lov/common_name`
-STRIPECOUNT=`cat /proc/fs/lustre/lov/$LOVNAME/numobd`
+OSTCOUNT=`cat /proc/fs/lustre/lov/$LOVNAME/numobd`
+STRIPECOUNT=`cat /proc/fs/lustre/lov/$LOVNAME/stripecount`
+STRIPESIZE=`cat /proc/fs/lustre/lov/$LOVNAME/stripesize`
[ -f $DIR/d52a/foo ] && chattr -a $DIR/d52a/foo
[ -f $DIR/d52b/foo ] && chattr -i $DIR/d52b/foo
run_test 27a "one stripe file =================================="
test_27c() {
- [ "$STRIPECOUNT" -lt "2" ] && echo "skipping 2-stripe test" && return
+ [ "$OSTCOUNT" -lt "2" ] && echo "skipping 2-stripe test" && return
if [ ! -d $DIR/d27 ]; then
mkdir $DIR/d27
fi
if [ ! -d $DIR/d27 ]; then
mkdir $DIR/d27
fi
- $LSTRIPE $DIR/d27/f27j 65536 $STRIPECOUNT 1 && error || true
+ $LSTRIPE $DIR/d27/f27j 65536 $OSTCOUNT 1 && error || true
}
run_test 27j "lstripe with bad stripe offset (should return error)"
# ensure that all stripes have some grant before we test client-side cache
setup_test42() {
[ "$SETUP_TEST42" ] && return
- for i in `seq -f $DIR/f42-%g 1 $STRIPECOUNT`; do
+ for i in `seq -f $DIR/f42-%g 1 $OSTCOUNT`; do
dd if=/dev/zero of=$i bs=4k count=1
rm $i
done
run_test 43c "md5sum of copy into lustre========================"
test_44() {
- [ "$STRIPECOUNT" -lt "2" ] && echo "skipping 2-stripe test" && return
+ [ "$OSTCOUNT" -lt "2" ] && echo "skipping 2-stripe test" && return
dd if=/dev/zero of=$DIR/f1 bs=4k count=1 seek=127
dd if=$DIR/f1 bs=4k count=1
}
}
run_test 53 "verify that MDS and OSTs agree on pre-creation ===="
-test_54() {
+test_54a() {
$SOCKETSERVER $DIR/socket &
sleep 1
$SOCKETCLIENT $DIR/socket || error
$MUNLINK $DIR/socket
}
-run_test 54 "unix damain socket test ==========================="
+run_test 54a "unix damain socket test =========================="
+
+test_54b() {
+ f="$DIR/f54b"
+ mknod $f c 1 3
+ chmod 0666 $f
+ dd if=/dev/zero of=$f bs=`page_size` count=1
+}
+run_test 54b "char device works in lustre ======================"
+
+test_54c() {
+ tfile="$DIR/f54c"
+ tdir="$DIR/d54c"
+ loopdev="$DIR/loop54c"
+
+ for i in `seq 3 7`; do
+ rm -f $loopdev
+ mknod $loopdev b 7 $i
+ losetup $loopdev > /dev/null 2>&1 || break
+ done
+ echo "make a loop file system with $tfile on $loopdev ($i)..."
+ dd if=/dev/zero of=$tfile bs=`page_size` seek=1024 count=1 > /dev/null
+ losetup $loopdev $tfile || error "can't set up $loopdev for $tfile"
+ mkfs.ext2 $loopdev || error "mke2fs on $loopdev"
+ mkdir -p $tdir
+ mount -t ext2 $loopdev $tdir || error "error mounting $loopdev on $tdir"
+ dd if=/dev/zero of=$tdir/tmp bs=`page_size` count=30 || error "dd write"
+ df $tdir
+ dd if=$tdir/tmp of=/dev/zero bs=`page_size` count=30 || error "dd read"
+ umount $tdir
+ losetup -d $loopdev
+ rm $loopdev
+}
+run_test 54c "block device works in lustre ====================="
+
+test_54d() {
+ f="$DIR/f54d"
+ string="aaaaaa"
+ mknod $f p
+ [ "$string" = `echo $string > $f | cat $f` ] || error
+}
+run_test 54d "fifo device works in lustre ======================"
test_55() {
rm -rf $DIR/d55
rm -rf $DIR/d55/*
umount $DIR/d55 || error
}
-run_test 55 "check iopen_connect_dentry()======================="
+run_test 55 "check iopen_connect_dentry() ======================"
test_56() {
rm -rf $DIR/d56
$LFIND --obd wrong_uuid $DIR/d56 2>&1 | grep -q "unknown obduuid" || \
error "lfs find --obd wrong_uuid should return error information"
- [ "$STRIPECOUNT" -lt 2 ] && \
+ [ "$OSTCOUNT" -lt 2 ] && \
echo "skipping other lfs find --obd test" && return
FILENUM=`$LFIND --recursive $DIR/d56 | sed -n '/^[ ]*1[ ]/p' | wc -l`
OBDUUID=`$LFIND --recursive $DIR/d56 | sed -n '/^[ ]*1:/p' | awk '{print $2}'`
LFS=${LFS:-lfs}
LVERIFY=${LVERIFY:-ll_dirstripe_verify}
- stripecount=`cat /proc/fs/lustre/lov/*/stripecount | head -1`
- if [ $stripecount -eq 0 ]; then
- stripecount=1
- fi
- stripesize=`cat /proc/fs/lustre/lov/*/stripesize | head -1`
- ostcount=`cat /proc/fs/lustre/lov/*/numobd | head -1`
-
- echo -n "case 1: dir has no stripe info..."
+ echo "dir has no stripe info"
mkdir $DIR/d65
touch $DIR/d65/f1
$LVERIFY $DIR/d65 $DIR/d65/f1 || error
- echo "pass"
- echo -n "case 2: setstripe $(($stripesize * 2)) 0 1 ..."
- $LFS setstripe $DIR/d65 $(($stripesize * 2)) 0 1 || error
+ echo "setstripe $(($STRIPESIZE * 2)) 0 1"
+ $LFS setstripe $DIR/d65 $(($STRIPESIZE * 2)) 0 1 || error
touch $DIR/d65/f2
$LVERIFY $DIR/d65 $DIR/d65/f2 || error
- echo "pass"
if [ $ostcount -gt 1 ]; then
- echo -n "case 3: setstripe $(($stripesize * 4)) 1 $(($ostcount - 1)) ..."
- $LFS setstripe $DIR/d65 $(($stripesize * 4)) 1 \
- $(($ostcount - 1)) || error
+ echo "setstripe $(($STRIPESIZE * 4)) 1 $(($OSTCOUNT - 1))"
+ $LFS setstripe $DIR/d65 $(($STRIPESIZE * 4)) 1 \
+ $(($OSTCOUNT - 1)) || error
touch $DIR/d65/f3
$LVERIFY $DIR/d65 $DIR/d65/f3 || error
- echo "pass"
fi
- echo -n "case 4: setstripe $stripesize -1 $(($stripecount - 1)) ..."
- $LFS setstripe $DIR/d65 $stripesize -1 $(($stripecount - 1)) || error
+ [ $STRIPECOUNT -eq 0 ] && sc=1 || sc=$(($STRIPECOUNT - 1))
+
+ echo "setstripe $STRIPESIZE -1 $sc"
+ $LFS setstripe $DIR/d65 $STRIPESIZE -1 $sc || error
touch $DIR/d65/f4 $DIR/d65/f5
$LVERIFY $DIR/d65 $DIR/d65/f4 $DIR/d65/f5 || error
- echo "pass"
- echo -n "case 5: setstripe 0 -1 0 (default) ..."
+ echo "setstripe 0 -1 0 (default)"
$LFS setstripe $DIR/d65 0 -1 0 || error
touch $DIR/d65/f6
$LVERIFY $DIR/d65 $DIR/d65/f6 || error
- echo "pass"
}
run_test 65 "Verify that the files are created using parent dir's stripe info"
+# bug 2543 - update blocks count on client
+test_66() {
+ COUNT=${COUNT:-8}
+ dd if=/dev/zero of=$DIR/f66 bs=1k count=$COUNT
+ sync
+ BLOCKS=`ls -s $DIR/f66 | awk '{ print $1 }'`
+ [ $BLOCKS -ge $COUNT ] || error "$DIR/f66 blocks $BLOCKS < $COUNT"
+}
+run_test 66 "update inode blocks count on client ==============="
+
# on the LLNL clusters, runas will still pick up root's $TMP settings,
# which will not be writable for the runas user, and then you get a CVS
# error message with a corrupt path string (CVS bug) and panic.
export LTESTDIR=${LTESTDIR:-$LUSTRE/../ltest}
[ -d /r ] && export ROOT=/r
+ export TMP=${TMP:-$ROOT/tmp}
export PATH=:$PATH:$LUSTRE/utils:$LUSTRE/tests
export LLMOUNT=${LLMOUNT:-"llmount"}