+++ /dev/null
-# Copyright (C) 2001 Cluster File Systems, Inc.
-#
-# This code is issued under the GNU General Public License.
-# See the file COPYING in this distribution
-
-DEFS=
-
-MODULE = obdfs
-modulefs_DATA = obdfs.o
-EXTRA_PROGRAMS = obdfs
-obdfs_SOURCES = rw.c file.c dir.c sysctl.c super.c namei.c symlink.c
-
-include $(top_srcdir)/Rules
+++ /dev/null
-OBDFS - v 0.001
-
-This version can mount, list and set the attributes of the root
-directory.
-
-1. configure the obd to use /dev/obd with a scratch file system
-
-2. make
-
-3. insmod obdfs
-
-4. mount -t obdfs -o device=/dev/obd0 /dev/obd0 /mnt/obd
-
-To verify: type mount (output:
-/dev/obd on /mnt/obd type obdfs (rw))
-
-5. ls -ld /mnt/obd
-
-6. chmod 711 /mnt/obd, ls -ld /mnt/obd
-
-7. chown disk /mnt/obd, ls -ld /mnt/obd
-
+++ /dev/null
-/*
- * linux/fs/ext2/dir.c
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- * from
- *
- * linux/fs/minix/dir.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * ext2 directory handling functions
- *
- * Big-endian to little-endian byte-swapping/bitmaps by
- * David S. Miller (davem@caip.rutgers.edu), 1995
- *
- * All code that works with directory layout had been switched to pagecache
- * and moved here. AV
- */
-
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/pagemap.h>
-
-#define DEBUG_SUBSYSTEM S_OBDFS
-
-#include <linux/obd_support.h>
-#include <linux/locks.h>
-
-typedef struct ext2_dir_entry_2 ext2_dirent;
-
-#define PageChecked(page) test_bit(PG_checked, &(page)->flags)
-#define SetPageChecked(page) set_bit(PG_checked, &(page)->flags)
-
-int waitfor_one_page(struct page *page)
-{
- int error = 0;
- struct buffer_head *bh, *head = page->buffers;
-
- bh = head;
- do {
- wait_on_buffer(bh);
- if (buffer_req(bh) && !buffer_uptodate(bh))
- error = -EIO;
- } while ((bh = bh->b_this_page) != head);
- return error;
-}
-
-/*
- * ext2 uses block-sized chunks. Arguably, sector-sized ones would be
- * more robust, but we have what we have
- */
-static inline unsigned ext2_chunk_size(struct inode *inode)
-{
- //return inode->i_sb->s_blocksize;
- return PAGE_SIZE;
-}
-
-static inline void ext2_put_page(struct page *page)
-{
- kunmap(page);
- page_cache_release(page);
-}
-
-static inline unsigned long dir_pages(struct inode *inode)
-{
- return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
-}
-
-static int ext2_commit_chunk(struct page *page, unsigned from, unsigned to)
-{
- struct inode *dir = page->mapping->host;
- int err = 0;
- dir->i_version = ++event;
- page->mapping->a_ops->commit_write(NULL, page, from, to);
- if (IS_SYNC(dir))
- err = waitfor_one_page(page);
- return err;
-}
-
-static void ext2_check_page(struct page *page)
-{
- struct inode *dir = page->mapping->host;
- unsigned chunk_size = ext2_chunk_size(dir);
- char *kaddr = page_address(page);
- // u32 max_inumber = le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count);
- unsigned offs, rec_len;
- unsigned limit = PAGE_CACHE_SIZE;
- ext2_dirent *p;
- char *error;
-
- if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) {
- limit = dir->i_size & ~PAGE_CACHE_MASK;
- if (limit & (chunk_size - 1))
- goto Ebadsize;
- for (offs = limit; offs<PAGE_CACHE_SIZE; offs += chunk_size) {
- ext2_dirent *p = (ext2_dirent*)(kaddr + offs);
- p->rec_len = cpu_to_le16(chunk_size);
- }
- if (!limit)
- goto out;
- }
- for (offs = 0; offs <= limit - EXT2_DIR_REC_LEN(1); offs += rec_len) {
- p = (ext2_dirent *)(kaddr + offs);
- rec_len = le16_to_cpu(p->rec_len);
-
- if (rec_len < EXT2_DIR_REC_LEN(1))
- goto Eshort;
- if (rec_len & 3)
- goto Ealign;
- if (rec_len < EXT2_DIR_REC_LEN(p->name_len))
- goto Enamelen;
- if (((offs + rec_len - 1) ^ offs) & ~(chunk_size-1))
- goto Espan;
- // if (le32_to_cpu(p->inode) > max_inumber)
- //goto Einumber;
- }
- if (offs != limit)
- goto Eend;
-out:
- SetPageChecked(page);
- return;
-
- /* Too bad, we had an error */
-
-Ebadsize:
- CERROR("ext2_check_page"
- "size of directory #%lu is not a multiple of chunk size",
- dir->i_ino
- );
- goto fail;
-Eshort:
- error = "rec_len is smaller than minimal";
- goto bad_entry;
-Ealign:
- error = "unaligned directory entry";
- goto bad_entry;
-Enamelen:
- error = "rec_len is too small for name_len";
- goto bad_entry;
-Espan:
- error = "directory entry across blocks";
- goto bad_entry;
- //Einumber:
- // error = "inode out of bounds";
-bad_entry:
- CERROR("ext2_check_page" "bad entry in directory #%lu: %s - "
- "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
- dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
- (unsigned long) le32_to_cpu(p->inode),
- rec_len, p->name_len);
- goto fail;
-Eend:
- p = (ext2_dirent *)(kaddr + offs);
- CERROR("ext2_check_page"
- "entry in directory #%lu spans the page boundary"
- "offset=%lu, inode=%lu",
- dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
- (unsigned long) le32_to_cpu(p->inode));
-fail:
- SetPageChecked(page);
- SetPageError(page);
-}
-
-static struct page * ext2_get_page(struct inode *dir, unsigned long n)
-{
- struct address_space *mapping = dir->i_mapping;
- struct page *page = read_cache_page(mapping, n,
- (filler_t*)mapping->a_ops->readpage, NULL);
- if (!IS_ERR(page)) {
- wait_on_page(page);
- kmap(page);
- if (!Page_Uptodate(page))
- goto fail;
- if (!PageChecked(page))
- ext2_check_page(page);
- if (PageError(page))
- goto fail;
- }
- return page;
-
-fail:
- ext2_put_page(page);
- return ERR_PTR(-EIO);
-}
-
-/*
- * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
- *
- * len <= EXT2_NAME_LEN and de != NULL are guaranteed by caller.
- */
-static inline int ext2_match (int len, const char * const name,
- struct ext2_dir_entry_2 * de)
-{
- if (len != de->name_len)
- return 0;
- if (!de->inode)
- return 0;
- return !memcmp(name, de->name, len);
-}
-
-/*
- * p is at least 6 bytes before the end of page
- */
-static inline ext2_dirent *ext2_next_entry(ext2_dirent *p)
-{
- return (ext2_dirent *)((char*)p + le16_to_cpu(p->rec_len));
-}
-
-static inline unsigned
-ext2_validate_entry(char *base, unsigned offset, unsigned mask)
-{
- ext2_dirent *de = (ext2_dirent*)(base + offset);
- ext2_dirent *p = (ext2_dirent*)(base + (offset&mask));
- while ((char*)p < (char*)de)
- p = ext2_next_entry(p);
- return (char *)p - base;
-}
-
-static unsigned char ext2_filetype_table[EXT2_FT_MAX] = {
- [EXT2_FT_UNKNOWN] DT_UNKNOWN,
- [EXT2_FT_REG_FILE] DT_REG,
- [EXT2_FT_DIR] DT_DIR,
- [EXT2_FT_CHRDEV] DT_CHR,
- [EXT2_FT_BLKDEV] DT_BLK,
- [EXT2_FT_FIFO] DT_FIFO,
- [EXT2_FT_SOCK] DT_SOCK,
- [EXT2_FT_SYMLINK] DT_LNK,
-};
-
-static unsigned int obdfs_dt2fmt[DT_WHT + 1] = {
- [EXT2_FT_UNKNOWN] 0,
- [EXT2_FT_REG_FILE] S_IFREG,
- [EXT2_FT_DIR] S_IFDIR,
- [EXT2_FT_CHRDEV] S_IFCHR,
- [EXT2_FT_BLKDEV] S_IFBLK,
- [EXT2_FT_FIFO] S_IFIFO,
- [EXT2_FT_SOCK] S_IFSOCK,
- [EXT2_FT_SYMLINK] S_IFLNK
-};
-
-#define S_SHIFT 12
-static unsigned char ext2_type_by_mode[S_IFMT >> S_SHIFT] = {
- [S_IFREG >> S_SHIFT] EXT2_FT_REG_FILE,
- [S_IFDIR >> S_SHIFT] EXT2_FT_DIR,
- [S_IFCHR >> S_SHIFT] EXT2_FT_CHRDEV,
- [S_IFBLK >> S_SHIFT] EXT2_FT_BLKDEV,
- [S_IFIFO >> S_SHIFT] EXT2_FT_FIFO,
- [S_IFSOCK >> S_SHIFT] EXT2_FT_SOCK,
- [S_IFLNK >> S_SHIFT] EXT2_FT_SYMLINK,
-};
-
-static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode)
-{
- mode_t mode = inode->i_mode;
- de->file_type = ext2_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
-}
-
-int
-new_obdfs_readdir (struct file * filp, void * dirent, filldir_t filldir)
-{
- loff_t pos = filp->f_pos;
- struct inode *inode = filp->f_dentry->d_inode;
- // XXX struct super_block *sb = inode->i_sb;
- unsigned offset = pos & ~PAGE_CACHE_MASK;
- unsigned long n = pos >> PAGE_CACHE_SHIFT;
- unsigned long npages = dir_pages(inode);
- unsigned chunk_mask = ~(ext2_chunk_size(inode)-1);
- unsigned char *types = NULL;
- int need_revalidate = (filp->f_version != inode->i_version);
-
- if (pos > inode->i_size - EXT2_DIR_REC_LEN(1))
- goto done;
-
- types = ext2_filetype_table;
-
- for ( ; n < npages; n++, offset = 0) {
- char *kaddr, *limit;
- ext2_dirent *de;
- struct page *page = ext2_get_page(inode, n);
-
- if (IS_ERR(page))
- continue;
- kaddr = page_address(page);
- if (need_revalidate) {
- offset = ext2_validate_entry(kaddr, offset, chunk_mask);
- need_revalidate = 0;
- }
- de = (ext2_dirent *)(kaddr+offset);
- limit = kaddr + PAGE_CACHE_SIZE - EXT2_DIR_REC_LEN(1);
- for ( ;(char*)de <= limit; de = ext2_next_entry(de))
- if (de->inode) {
- int over;
- unsigned char d_type = DT_UNKNOWN;
-
- if (types && de->file_type < EXT2_FT_MAX)
- d_type = types[de->file_type];
-
- offset = (char *)de - kaddr;
- over = filldir(dirent, de->name, de->name_len,
- (n<<PAGE_CACHE_SHIFT) | offset,
- le32_to_cpu(de->inode), d_type);
- if (over) {
- ext2_put_page(page);
- goto done;
- }
- }
- ext2_put_page(page);
- }
-
-done:
- filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
- filp->f_version = inode->i_version;
- UPDATE_ATIME(inode);
- return 0;
-}
-
-/*
- * ext2_find_entry()
- *
- * finds an entry in the specified directory with the wanted name. It
- * returns the page in which the entry was found, and the entry itself
- * (as a parameter - res_dir). Page is returned mapped and unlocked.
- * Entry is guaranteed to be valid.
- */
-struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
- struct dentry *dentry, struct page ** res_page)
-{
- const char *name = dentry->d_name.name;
- int namelen = dentry->d_name.len;
- unsigned reclen = EXT2_DIR_REC_LEN(namelen);
- unsigned long start, n;
- unsigned long npages = dir_pages(dir);
- struct page *page = NULL;
- ext2_dirent * de;
-
- /* OFFSET_CACHE */
- *res_page = NULL;
-
- // start = dir->u.ext2_i.i_dir_start_lookup;
- start = 0;
- if (start >= npages)
- start = 0;
- n = start;
- do {
- char *kaddr;
- page = ext2_get_page(dir, n);
- if (!IS_ERR(page)) {
- kaddr = page_address(page);
- de = (ext2_dirent *) kaddr;
- kaddr += PAGE_CACHE_SIZE - reclen;
- while ((char *) de <= kaddr) {
- if (ext2_match (namelen, name, de))
- goto found;
- de = ext2_next_entry(de);
- }
- ext2_put_page(page);
- }
- if (++n >= npages)
- n = 0;
- } while (n != start);
- return NULL;
-
-found:
- *res_page = page;
- // dir->u.ext2_i.i_dir_start_lookup = n;
- return de;
-}
-
-struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p)
-{
- struct page *page = ext2_get_page(dir, 0);
- ext2_dirent *de = NULL;
-
- if (!IS_ERR(page)) {
- de = ext2_next_entry((ext2_dirent *) page_address(page));
- *p = page;
- }
- return de;
-}
-
-ino_t obdfs_inode_by_name(struct inode * dir, struct dentry *dentry, int *type)
-{
- ino_t res = 0;
- struct ext2_dir_entry_2 * de;
- struct page *page;
-
- de = ext2_find_entry (dir, dentry, &page);
- if (de) {
- res = le32_to_cpu(de->inode);
- *type = obdfs_dt2fmt[de->file_type];
- kunmap(page);
- page_cache_release(page);
- }
- return res;
-}
-
-/* Releases the page */
-void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
- struct page *page, struct inode *inode)
-{
- unsigned from = (char *) de - (char *) page_address(page);
- unsigned to = from + le16_to_cpu(de->rec_len);
- int err;
-
- lock_page(page);
- err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
- if (err)
- LBUG();
- de->inode = cpu_to_le32(inode->i_ino);
- ext2_set_de_type (de, inode);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
- err = ext2_commit_chunk(page, from, to);
- UnlockPage(page);
- ext2_put_page(page);
-}
-
-/*
- * Parent is locked.
- */
-int ext2_add_link (struct dentry *dentry, struct inode *inode)
-{
- struct inode *dir = dentry->d_parent->d_inode;
- const char *name = dentry->d_name.name;
- int namelen = dentry->d_name.len;
- unsigned reclen = EXT2_DIR_REC_LEN(namelen);
- unsigned short rec_len, name_len;
- struct page *page = NULL;
- ext2_dirent * de;
- unsigned long npages = dir_pages(dir);
- unsigned long n;
- char *kaddr;
- unsigned from, to;
- int err;
-
- /* We take care of directory expansion in the same loop */
- for (n = 0; n <= npages; n++) {
- page = ext2_get_page(dir, n);
- err = PTR_ERR(page);
- if (IS_ERR(page))
- goto out;
- kaddr = page_address(page);
- de = (ext2_dirent *)kaddr;
- kaddr += PAGE_CACHE_SIZE - reclen;
- while ((char *)de <= kaddr) {
- err = -EEXIST;
- if (ext2_match (namelen, name, de))
- goto out_page;
- name_len = EXT2_DIR_REC_LEN(de->name_len);
- rec_len = le16_to_cpu(de->rec_len);
- if ( n==npages && rec_len == 0) {
- CERROR("Fatal dir behaviour\n");
- goto out_page;
- }
- if (!de->inode && rec_len >= reclen)
- goto got_it;
- if (rec_len >= name_len + reclen)
- goto got_it;
- de = (ext2_dirent *) ((char *) de + rec_len);
- }
- ext2_put_page(page);
- }
- LBUG();
- return -EINVAL;
-
-got_it:
- from = (char*)de - (char*)page_address(page);
- to = from + rec_len;
- lock_page(page);
- err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
- if (err)
- goto out_unlock;
- if (de->inode) {
- ext2_dirent *de1 = (ext2_dirent *) ((char *) de + name_len);
- de1->rec_len = cpu_to_le16(rec_len - name_len);
- de->rec_len = cpu_to_le16(name_len);
- de = de1;
- }
- de->name_len = namelen;
- memcpy (de->name, name, namelen);
- de->inode = cpu_to_le32(inode->i_ino);
- ext2_set_de_type (de, inode);
- CDEBUG(D_INODE, "type set to %o\n", de->file_type);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
- err = ext2_commit_chunk(page, from, to);
-
- // change_inode happens with the commit_chunk
- // obdfs_change_inode(dir);
- /* OFFSET_CACHE */
-out_unlock:
- UnlockPage(page);
-out_page:
- ext2_put_page(page);
-out:
- return err;
-}
-
-/*
- * ext2_delete_entry deletes a directory entry by merging it with the
- * previous entry. Page is up-to-date. Releases the page.
- */
-int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
-{
- struct address_space *mapping = page->mapping;
- struct inode *inode = mapping->host;
- char *kaddr = page_address(page);
- unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1);
- unsigned to = ((char*)dir - kaddr) + le16_to_cpu(dir->rec_len);
- ext2_dirent * pde = NULL;
- ext2_dirent * de = (ext2_dirent *) (kaddr + from);
- int err;
-
- while ((char*)de < (char*)dir) {
- pde = de;
- de = ext2_next_entry(de);
- }
- if (pde)
- from = (char*)pde - (char*)page_address(page);
- lock_page(page);
- err = mapping->a_ops->prepare_write(NULL, page, from, to);
- if (err)
- LBUG();
- if (pde)
- pde->rec_len = cpu_to_le16(to-from);
- dir->inode = 0;
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- err = ext2_commit_chunk(page, from, to);
- UnlockPage(page);
- ext2_put_page(page);
- return err;
-}
-
-/*
- * Set the first fragment of directory.
- */
-int ext2_make_empty(struct inode *inode, struct inode *parent)
-{
- struct address_space *mapping = inode->i_mapping;
- struct page *page = grab_cache_page(mapping, 0);
- unsigned chunk_size = ext2_chunk_size(inode);
- struct ext2_dir_entry_2 * de;
- char *base;
- int err;
- ENTRY;
-
- if (!page)
- return -ENOMEM;
- err = mapping->a_ops->prepare_write(NULL, page, 0, chunk_size);
- if (err)
- goto fail;
-
- base = page_address(page);
-
- de = (struct ext2_dir_entry_2 *) base;
- de->name_len = 1;
- de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(1));
- memcpy (de->name, ".\0\0", 4);
- de->inode = cpu_to_le32(inode->i_ino);
- ext2_set_de_type (de, inode);
-
- de = (struct ext2_dir_entry_2 *) (base + EXT2_DIR_REC_LEN(1));
- de->name_len = 2;
- de->rec_len = cpu_to_le16(chunk_size - EXT2_DIR_REC_LEN(1));
- de->inode = cpu_to_le32(parent->i_ino);
- memcpy (de->name, "..\0", 4);
- ext2_set_de_type (de, inode);
-
- err = ext2_commit_chunk(page, 0, chunk_size);
-fail:
- UnlockPage(page);
- page_cache_release(page);
- ENTRY;
- return err;
-}
-
-/*
- * routine to check that the specified directory is empty (for rmdir)
- */
-int ext2_empty_dir (struct inode * inode)
-{
- struct page *page = NULL;
- unsigned long i, npages = dir_pages(inode);
-
- for (i = 0; i < npages; i++) {
- char *kaddr;
- ext2_dirent * de;
- page = ext2_get_page(inode, i);
-
- if (IS_ERR(page))
- continue;
-
- kaddr = page_address(page);
- de = (ext2_dirent *)kaddr;
- kaddr += PAGE_CACHE_SIZE-EXT2_DIR_REC_LEN(1);
-
- while ((char *)de <= kaddr) {
- if (de->inode != 0) {
- /* check for . and .. */
- if (de->name[0] != '.')
- goto not_empty;
- if (de->name_len > 2)
- goto not_empty;
- if (de->name_len < 2) {
- if (de->inode !=
- cpu_to_le32(inode->i_ino))
- goto not_empty;
- } else if (de->name[1] != '.')
- goto not_empty;
- }
- de = ext2_next_entry(de);
- }
- ext2_put_page(page);
- }
- return 1;
-
-not_empty:
- ext2_put_page(page);
- return 0;
-}
-
-struct file_operations obdfs_dir_operations = {
- read: generic_read_dir,
- readdir: new_obdfs_readdir
-};
+++ /dev/null
-/*
- * linux/fs/ext2/file.c
- *
- * This code is issued under the GNU General Public License.
- * See the file COPYING in this distribution
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- * from
- *
- * linux/fs/minix/file.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * ext2 fs regular file handling primitives
- *
- * 64-bit file support on 64-bit platforms by Jakub Jelinek
- * (jj@sunsite.ms.mff.cuni.cz)
- */
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/locks.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
-
-#define DEBUG_SUBSYSTEM S_OBDFS
-
-#include <linux/obd_support.h>
-#include <linux/obdfs.h>
-
-extern int obdfs_setattr(struct dentry *de, struct iattr *attr);
-void obdfs_change_inode(struct inode *inode);
-
-static inline void obdfs_remove_suid(struct inode *inode)
-{
- unsigned int mode;
-
- /* set S_IGID if S_IXGRP is set, and always set S_ISUID */
- mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID;
-
- /* was any of the uid bits set? */
- mode &= inode->i_mode;
- if (mode && !capable(CAP_FSETID)) {
- inode->i_mode &= ~mode;
- // XXX careful here - we cannot change the size
- //obdfs_change_inode(inode);
- }
-}
-
-/*
- * Write to a file (through the page cache).
- */
-static ssize_t
-obdfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-{
- ssize_t retval;
- CDEBUG(D_INFO, "Writing inode %ld, %ld bytes, offset %Ld\n",
- file->f_dentry->d_inode->i_ino, (long)count, *ppos);
-
- retval = generic_file_write(file, buf, count, ppos);
- CDEBUG(D_INFO, "Wrote %ld\n", (long)retval);
-
- /* update mtime/ctime/atime here, NOT size */
- if (retval > 0) {
- struct iattr attr;
- attr.ia_valid = ATTR_MTIME | ATTR_CTIME | ATTR_ATIME;
- attr.ia_mtime = attr.ia_ctime = attr.ia_atime =
- CURRENT_TIME;
- obdfs_setattr(file->f_dentry, &attr);
- }
- EXIT;
- return retval;
-}
-
-
-/* XXX this does not need to do anything for data, it _does_ need to
- call setattr */
-int obdfs_fsync(struct file *file, struct dentry *dentry, int data)
-{
- return 0;
-}
-
-struct file_operations obdfs_file_operations = {
- read: generic_file_read,
- write: obdfs_file_write,
- mmap: generic_file_mmap,
- fsync: NULL
-};
-
-
-struct inode_operations obdfs_file_inode_operations = {
- truncate: obdfs_truncate,
- setattr: obdfs_setattr
-};
-
+++ /dev/null
-/*
- * OBDFS Super operations - also used for Lustre file system
- *
- *
- * This code is issued under the GNU General Public License.
- * See the file COPYING in this distribution
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- * Copryright (C) 1999 Stelias Computing Inc. <braam@stelias.com>
- * Copryright (C) 1999 Seagate Technology Inc.
- *
- */
-#define __NO_VERSION__
-#include <linux/fs.h>
-#include <linux/locks.h>
-#include <linux/swap.h>
-
-#include <linux/obd_support.h>
-#include <linux/obd_class.h>
-#include <linux/obdfs.h>
-
-
-/* XXX temporary until the real function is available from kernel
- * XXX set this to memory size in pages for max page cache size
- */
-#define nr_free_buffer_pages() 32768
-
-/* Defines for page buf daemon */
-struct pupd_prm {
- int nfract; /* Percentage of buffer cache dirty to
- activate bdflush */
- int ndirty; /* Maximum number of dirty blocks to write out per
- wake-cycle */
- int nrefill; /* Number of clean buffers to try to obtain
- each time we call refill */
- int nref_dirt; /* Dirty buffer threshold for activating bdflush
- when trying to refill buffers. */
- int interval; /* jiffies delay between pupdate flushes */
- int age_buffer; /* Time for normal buffer to age before we flush it */
- int age_super; /* Time for superblock to age before we flush it */
-};
-
-
-static struct pupdated {
- int active;
- wait_queue_head_t waitq;
- struct timer_list timer;
- struct pupd_prm parms;
-} pupdated = {
- active: -1,
- parms: {40, 1024, 64, 256, 1*HZ, 30*HZ, 5*HZ }
-};
-
-
-/* Called with the superblock list lock held */
-static int obdfs_enqueue_pages(struct inode *inode, struct obdo **obdo,
- int nr_slots, struct page **pages, char **bufs,
- obd_size *counts, obd_off *offsets,
- obd_flag *flag, unsigned long check_time)
-{
- struct list_head *page_list = obdfs_iplist(inode);
- struct list_head *tmp;
- int num = 0;
-
- ENTRY;
-
- tmp = page_list;
- /* Traverse list in reverse order, so we do FIFO, not LIFO order */
- while ( (tmp = tmp->prev) != page_list && num < nr_slots ) {
- struct obdfs_pgrq *req;
- struct page *page;
-
- req = list_entry(tmp, struct obdfs_pgrq, rq_plist);
- page = req->rq_page;
-
-
- if (req->rq_jiffies > check_time)
- break; /* pages are in chronological order */
-
- /* Only allocate the obdo if we will actually do I/O here */
- if ( !*obdo ) {
- OIDEBUG(inode);
- *obdo = obdo_fromid(IID(inode), inode->i_ino,
- OBD_MD_FLNOTOBD);
- if ( IS_ERR(*obdo) ) {
- int err = PTR_ERR(*obdo);
- *obdo = NULL;
-
- EXIT;
- return err;
- }
-
- /* FIXME revisit fromid & from_inode */
- obdfs_from_inode(*obdo, inode);
- *flag = OBD_BRW_CREATE;
- }
-
- /* Remove request from list before write to avoid conflict.
- * Note that obdfs_pgrq_del() also deletes the request.
- */
- obdfs_pgrq_del(req);
- if ( !page ) {
- CDEBUG(D_CACHE, "no page \n");
- continue;
- }
-
- bufs[num] = (char *)page_address(page);
- pages[num] = page;
- counts[num] = PAGE_SIZE;
- offsets[num] = ((obd_off)page->index) << PAGE_SHIFT;
- CDEBUG(D_INFO, "ENQ inode %ld, page %p addr %p to vector\n",
- inode->i_ino, page, (char *)page_address(page));
- num++;
- }
-
- if (!list_empty(page_list))
- CDEBUG(D_INFO, "inode %ld list not empty\n", inode->i_ino);
- CDEBUG(D_INFO, "added %d page(s) to vector\n", num);
-
- EXIT;
- return num;
-} /* obdfs_enqueue_pages */
-
-/* Dequeue cached pages for a dying inode without writing them to disk. */
-void obdfs_dequeue_pages(struct inode *inode)
-{
- struct list_head *tmp;
-
- ENTRY;
- obd_down(&obdfs_i2sbi(inode)->osi_list_mutex);
- tmp = obdfs_islist(inode);
- if ( list_empty(tmp) ) {
- CDEBUG(D_INFO, "no dirty pages for inode %ld\n", inode->i_ino);
- obd_up(&obdfs_i2sbi(inode)->osi_list_mutex);
- EXIT;
- return;
- }
-
- /* take it out of the super list */
- list_del(tmp);
- INIT_LIST_HEAD(obdfs_islist(inode));
-
- tmp = obdfs_iplist(inode);
- while ( (tmp = tmp->prev) != obdfs_iplist(inode) ) {
- struct obdfs_pgrq *req;
- struct page *page;
-
- req = list_entry(tmp, struct obdfs_pgrq, rq_plist);
- page = req->rq_page;
- /* take it out of the list and free */
- obdfs_pgrq_del(req);
- /* now put the page away */
- put_page(page);
- }
-
- obd_up(&obdfs_i2sbi(inode)->osi_list_mutex);
-
- /* decrement inode reference for page cache */
- atomic_dec(&inode->i_count);
- EXIT;
-}
-
-/* This value is not arbitrarily chosen. KIO_STATIC_PAGES from linux/iobuf.h */
-#define MAX_IOVEC (KIO_STATIC_PAGES - 1)
-
-/* Remove writeback requests for the superblock */
-int obdfs_flush_reqs(struct list_head *inode_list, unsigned long check_time)
-{
- struct list_head *tmp;
- unsigned long max_io, total_io = 0;
- obd_count num_io;
- obd_count num_obdos;
- struct inode *inodes[MAX_IOVEC]; /* write data back to these */
- struct page *pages[MAX_IOVEC]; /* call put_page on these */
- struct obdo *obdos[MAX_IOVEC];
- char *bufs[MAX_IOVEC];
- obd_size counts[MAX_IOVEC];
- obd_off offsets[MAX_IOVEC];
- obd_flag flags[MAX_IOVEC];
- obd_count bufs_per_obdo[MAX_IOVEC];
- int err = 0;
- struct obdfs_sb_info *sbi;
-
- ENTRY;
- if (!inode_list) {
- CDEBUG(D_INODE, "no list\n");
- EXIT;
- return 0;
- }
-
- sbi = list_entry(inode_list, struct obdfs_sb_info, osi_inodes);
-
- obd_down(&sbi->osi_list_mutex);
- if ( list_empty(inode_list) ) {
- CDEBUG(D_INFO, "list empty\n");
- obd_up(&sbi->osi_list_mutex);
- EXIT;
- return 0;
- }
-
- /* If we are forcing a write, write out all dirty pages */
- max_io = check_time == ~0UL ? 1<<31 : pupdated.parms.ndirty;
- CDEBUG(D_INFO, "max_io = %lu\n", max_io);
-
- /* Add each inode's dirty pages to a write vector, and write it.
- * Traverse list in reverse order, so we do FIFO, not LIFO order
- */
- again:
- tmp = inode_list;
- num_io = 0;
- num_obdos = 0;
- while ( (tmp = tmp->prev) != inode_list && total_io < max_io) {
- struct obdfs_inode_info *ii;
- struct inode *inode;
- int res;
-
- ii = list_entry(tmp, struct obdfs_inode_info, oi_inodes);
- inode = list_entry(ii, struct inode, u);
- inodes[num_obdos] = inode;
- obdos[num_obdos] = NULL;
- CDEBUG(D_INFO, "checking inode %ld pages\n", inode->i_ino);
-
- /* Make sure we reference "inode" and not "inodes[num_obdos]",
- * as num_obdos will change after the loop is run.
- */
- if (!list_empty(obdfs_iplist(inode))) {
- res = obdfs_enqueue_pages(inode, &obdos[num_obdos],
- MAX_IOVEC - num_io,
- &pages[num_io], &bufs[num_io],
- &counts[num_io],
- &offsets[num_io],
- &flags[num_obdos],
- check_time);
- CDEBUG(D_INFO, "FLUSH inode %ld, pages flushed: %d\n",
- inode->i_ino, res);
- if ( res < 0 ) {
- CDEBUG(D_INODE,
- "fatal: unable to enqueue inode %ld (err %d)\n",
- inode->i_ino, res);
- /* XXX Move bad inode to end of list so we can
- * continue with flushing list. This is a
- * temporary measure to avoid machine lockups.
- * Maybe if we have -ENOENT, simply discard.
- */
- list_del(tmp);
- list_add(tmp, inode_list);
- err = res;
- EXIT;
- goto BREAK;
- }
- if (res == 0)
- continue;
-
- num_io += res;
- total_io += res;
- bufs_per_obdo[num_obdos] = res;
- num_obdos++;
-
- if ( num_io == MAX_IOVEC ) {
- obd_up(&sbi->osi_list_mutex);
- err = obdfs_do_vec_wr(inodes, num_io, num_obdos,
- obdos, bufs_per_obdo,
- pages, bufs, counts,
- offsets, flags);
- if ( err ) {
- CDEBUG(D_INODE,
- "fatal: do_vec_wr err=%d\n",
- err);
- EXIT;
- goto ERR;
- }
- obd_down(&sbi->osi_list_mutex);
- goto again;
- }
- }
- }
-
-BREAK:
- obd_up(&sbi->osi_list_mutex);
-
- /* flush any remaining I/Os */
- if ( num_io ) {
- err = obdfs_do_vec_wr(inodes, num_io, num_obdos, obdos,
- bufs_per_obdo, pages, bufs, counts,
- offsets, flags);
- if (err)
- CDEBUG(D_INODE, "fatal: unable to do vec_wr (err %d)\n", err);
- num_io = 0;
- num_obdos = 0;
- }
-
- /* Remove inode from superblock dirty list when no more pages.
- * Make sure we don't point at the current inode with tmp
- * when we re-init the list on the inode, or we will loop.
- */
- obd_down(&sbi->osi_list_mutex);
- tmp = inode_list;
- while ( (tmp = tmp->prev) != inode_list ) {
- struct obdfs_inode_info *ii;
- struct inode *inode;
-
- ii = list_entry(tmp, struct obdfs_inode_info, oi_inodes);
- inode = list_entry(ii, struct inode, u);
- CDEBUG(D_INFO, "checking inode %ld empty\n", inode->i_ino);
- if (list_empty(obdfs_iplist(inode))) {
- CDEBUG(D_INFO, "remove inode %ld from dirty list\n",
- inode->i_ino);
- tmp = tmp->next;
- list_del(obdfs_islist(inode));
- /* decrement inode reference for page cache */
- atomic_dec(&inode->i_count);
- INIT_LIST_HEAD(obdfs_islist(inode));
- }
- }
- obd_up(&sbi->osi_list_mutex);
-
- CDEBUG(D_INFO, "flushed %ld pages in total\n", total_io);
- EXIT;
-ERR:
- return err ? err : total_io;
-} /* obdfs_flush_reqs */
-
-
-/* Walk all of the superblocks and write out blocks which are too old.
- * Return the maximum number of blocks written for a single filesystem.
- */
-int obdfs_flush_dirty_pages(unsigned long check_time)
-{
- struct list_head *sl;
- int max = 0;
-
- /* ENTRY; */
- sl = &obdfs_super_list;
- while ( (sl = sl->prev) != &obdfs_super_list ) {
- struct obdfs_sb_info *sbi =
- list_entry(sl, struct obdfs_sb_info, osi_list);
- int ret;
-
- /* walk write requests here, use the sb, check the time */
- ret = obdfs_flush_reqs(&sbi->osi_inodes, check_time);
- /* XXX handle error? What to do with it? */
-
- max = ret > max ? ret : max;
- }
- if (max) { EXIT; }
- return max;
-} /* obdfs_flush_dirty_pages */
-
-
-static void pupdate_wakeup(unsigned long l)
-{
- wake_up(&pupdated.waitq);
-}
-
-
-static int pupdate(void *unused)
-{
- u_long flags;
- int interval = pupdated.parms.interval;
- long age = pupdated.parms.age_buffer;
- int wrote = 0;
-
- if (pupdated.active >= 0) {
- CDEBUG(D_CACHE, "attempted to run multiple pupdates\n");
- return 1;
- }
-
- init_timer(&pupdated.timer);
- init_waitqueue_head(&pupdated.waitq);
- pupdated.timer.function = pupdate_wakeup;
-
- exit_files(current);
- exit_mm(current);
- daemonize();
-
- current->session = 1;
- current->pgrp = 1;
- strcpy(current->comm, "pupdated");
-
- CDEBUG(D_CACHE, "pupdated activated...\n");
- pupdated.active = 1;
-
- spin_lock_irqsave(¤t->sigmask_lock, flags);
- flush_signals(current);
- sigfillset(¤t->blocked);
- recalc_sigpending(current);
- spin_unlock_irqrestore(¤t->sigmask_lock, flags);
-
- do {
- long dirty_limit;
-
- /* update interval */
- if (pupdated.active == 1 && interval) {
- mod_timer(&pupdated.timer, jiffies + interval);
- interruptible_sleep_on(&pupdated.waitq);
- }
- if (pupdated.active == 0) {
- del_timer(&pupdated.timer);
- /* If stopped, we flush one last time... */
- }
-
- /* asynchronous setattr etc for the future ...
- obdfs_flush_dirty_inodes(jiffies - pupdated.parms.age_super);
- */
- dirty_limit = nr_free_buffer_pages() * pupdated.parms.nfract / 100;
-
- if (obdfs_cache_count > dirty_limit) {
- interval = 0;
- if (wrote < pupdated.parms.ndirty)
- age >>= 1;
- if (wrote)
- CDEBUG(D_CACHE, "wrote %d, age %ld, interval %d\n",
- wrote, age, interval);
- } else {
- if (wrote < pupdated.parms.ndirty >> 1 &&
- obdfs_cache_count < dirty_limit / 2) {
- interval = pupdated.parms.interval;
- age = pupdated.parms.age_buffer;
- if (wrote)
- CDEBUG(D_INFO,
- "wrote %d, age %ld, interval %d\n",
- wrote, age, interval);
- } else if (obdfs_cache_count > dirty_limit / 2) {
- interval >>= 1;
- if (wrote < pupdated.parms.ndirty)
- age >>= 1;
- if (wrote)
- CDEBUG(D_CACHE,
- "wrote %d, age %ld, interval %d\n",
- wrote, age, interval);
- }
- }
-
- wrote = obdfs_flush_dirty_pages(jiffies - age);
- if (wrote) {
- CDEBUG(D_CACHE,
- "dirty_limit %ld, cache_count %ld, wrote %d\n",
- dirty_limit, obdfs_cache_count, wrote);
- run_task_queue(&tq_disk);
- }
- } while (pupdated.active == 1);
-
- CDEBUG(D_CACHE, "pupdated stopped...\n");
- pupdated.active = -1;
- wake_up(&pupdated.waitq);
- return 0;
-}
-
-
-int obdfs_flushd_init(void)
-{
- /*
- kernel_thread(bdflush, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
- */
- kernel_thread(pupdate, NULL, 0);
- CDEBUG(D_PSDEV, "flushd inited\n");
- return 0;
-}
-
-int obdfs_flushd_cleanup(void)
-{
- ENTRY;
-
- /* Shut down pupdated. */
- if (pupdated.active > 0) {
- CDEBUG(D_CACHE, "inform pupdated\n");
- pupdated.active = 0;
- wake_up(&pupdated.waitq);
-
- CDEBUG(D_CACHE, "wait for pupdated\n");
- while (pupdated.active == 0) {
- interruptible_sleep_on(&pupdated.waitq);
- }
- CDEBUG(D_CACHE, "done waiting for pupdated\n");
- }
-
- EXIT;
- return 0;
-}
+++ /dev/null
-/*
- * linux/fs/obdfs/namei.c
- *
- * This code is issued under the GNU General Public License.
- * See the file COPYING in this distribution
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- * from
- *
- * linux/fs/ext2/namei.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * Big-endian to little-endian byte-swapping/bitmaps by
- * David S. Miller (davem@caip.rutgers.edu), 1995
- * Directory entry file type support and forward compatibility hooks
- * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
- *
- * Changes for use in OBDFS
- * Copyright (c) 1999, Seagate Technology Inc.
- * Copyright (C) 2001, Cluster File Systems, Inc.
- * Rewritten based on recent ext2 page cache use.
- *
- */
-
-#include <linux/fs.h>
-#include <linux/locks.h>
-#include <linux/quotaops.h>
-
-#define DEBUG_SUBSYSTEM S_OBDFS
-
-#include <linux/obdfs.h>
-#include <linux/lustre_lite.h>
-extern struct address_space_operations obdfs_aops;
-
-/* from super.c */
-extern void obdfs_change_inode(struct inode *inode);
-extern int obdfs_setattr(struct dentry *de, struct iattr *attr);
-
-/* from dir.c */
-extern int ext2_add_link (struct dentry *dentry, struct inode *inode);
-obd_id obdfs_inode_by_name(struct inode * dir, struct dentry *dentry, int *typ);
-int ext2_make_empty(struct inode *inode, struct inode *parent);
-struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
- struct dentry *dentry, struct page ** res_page);
-int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page );
-int ext2_empty_dir (struct inode * inode);
-struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p);
-void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
- struct page *page, struct inode *inode);
-
-/*
- * Couple of helper functions - make the code slightly cleaner.
- */
-static inline void ext2_inc_count(struct inode *inode)
-{
- inode->i_nlink++;
- obdfs_change_inode(inode);
-}
-
-/* postpone the disk update until the inode really goes away */
-static inline void ext2_dec_count(struct inode *inode)
-{
- inode->i_nlink--;
- if (inode->i_nlink > 0)
- obdfs_change_inode(inode);
-}
-
-static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
-{
- int err;
- err = ext2_add_link(dentry, inode);
- if (!err) {
- d_instantiate(dentry, inode);
- return 0;
- }
- ext2_dec_count(inode);
- iput(inode);
- return err;
-}
-
-/* methods */
-static struct dentry *obdfs_lookup(struct inode * dir, struct dentry *dentry)
-{
- struct obdo *oa;
- struct inode * inode = NULL;
- int type;
- obd_id ino;
-
- ENTRY;
- if (dentry->d_name.len > EXT2_NAME_LEN)
- return ERR_PTR(-ENAMETOOLONG);
-
- ino = obdfs_inode_by_name(dir, dentry, &type);
- if (!ino)
- goto negative;
-
- oa = obdo_fromid(IID(dir), ino, type,
- (__u32)(OBD_MD_FLNOTOBD | OBD_MD_FLBLOCKS));
- if ( IS_ERR(oa) ) {
- CERROR("obdo_fromid failed\n");
- EXIT;
- return ERR_PTR(-EACCES);
- }
-
- inode = iget4(dir->i_sb, (ino_t)ino, NULL, oa);
- obdo_free(oa);
-
- if (!inode)
- return ERR_PTR(-EACCES);
-
- negative:
- d_add(dentry, inode);
- return NULL;
-}
-
-
-/*
- * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
- *
- * `len <= EXT2_NAME_LEN' is guaranteed by caller.
- * `de != NULL' is guaranteed by caller.
- */
-static inline int ext2_match (int len, const char * const name,
- struct ext2_dir_entry_2 * de)
-{
- if (len != de->name_len)
- return 0;
- if (!de->inode)
- return 0;
- return !memcmp(name, de->name, len);
-}
-
-static struct inode *obdfs_new_inode(struct inode *dir, int mode)
-{
- struct obdo *oa;
- struct inode *inode;
- int err;
-
- ENTRY;
- oa = obdo_alloc();
- if (!oa) {
- EXIT;
- return ERR_PTR(-ENOMEM);
- }
-
- /* Send a hint to the create method on the type of file to create */
- oa->o_mode = mode;
- oa->o_valid = OBD_MD_FLTYPE | OBD_MD_FLMODE;
- CDEBUG(D_INODE, "\n");
- err = obd_create(IID(dir), oa, NULL);
- CDEBUG(D_INODE, "\n");
-
- if ( err ) {
- CERROR("new_inode - fatal: err %d\n", err);
- obdo_free(oa);
- EXIT;
- return ERR_PTR(err);
- }
- CDEBUG(D_INODE, "obdo mode %o\n", oa->o_mode);
-
- inode = iget4(dir->i_sb, (ino_t)oa->o_id, NULL, oa);
- CDEBUG(D_INODE, "\n");
-
- if (!inode) {
- CERROR("new_inode -fatal: %ld\n", (long)oa->o_id);
- obd_destroy(IID(dir), oa, NULL);
- obdo_free(oa);
- EXIT;
- return ERR_PTR(-EIO);
- }
- obdo_free(oa);
-
- if (!list_empty(&inode->i_dentry)) {
- CERROR("new_inode -fatal: aliases %ld, ct %d lnk %d\n",
- (long)oa->o_id,
- atomic_read(&inode->i_count),
- inode->i_nlink);
- obd_destroy(IID(dir), oa, NULL);
- iput(inode);
- EXIT;
- return ERR_PTR(-EIO);
- }
-
- EXIT;
- return inode;
-} /* obdfs_new_inode */
-
-
-/*
- * By the time this is called, we already have created
- * the directory cache entry for the new file, but it
- * is so far negative - it has no inode.
- *
- * If the create succeeds, we fill in the inode information
- * with d_instantiate().
- */
-static int obdfs_create (struct inode * dir, struct dentry * dentry, int mode)
-{
- struct inode * inode = obdfs_new_inode (dir, mode);
- int err = PTR_ERR(inode);
- if (!IS_ERR(inode)) {
- inode->i_op = &obdfs_file_inode_operations;
- inode->i_fop = &obdfs_file_operations;
- inode->i_mapping->a_ops = &obdfs_aops;
- err = ext2_add_nondir(dentry, inode);
- }
- return err;
-} /* obdfs_create */
-
-
-static int obdfs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
-{
- struct inode * inode = obdfs_new_inode (dir, mode);
- int err = PTR_ERR(inode);
- if (!IS_ERR(inode)) {
- init_special_inode(inode, mode, rdev);
- obdfs_change_inode(inode);
- err = ext2_add_nondir(dentry, inode);
- }
- return err;
-}
-
-static int obdfs_symlink (struct inode * dir, struct dentry * dentry,
- const char * symname)
-{
- struct super_block * sb = dir->i_sb;
- int err = -ENAMETOOLONG;
- unsigned l = strlen(symname)+1;
- struct inode * inode;
- struct obdfs_inode_info *oinfo;
-
- if (l > sb->s_blocksize)
- goto out;
-
- inode = obdfs_new_inode (dir, S_IFLNK | S_IRWXUGO);
- err = PTR_ERR(inode);
- if (IS_ERR(inode))
- goto out;
-
- oinfo = obdfs_i2info(inode);
- if (l >= sizeof(oinfo->oi_inline)) {
- /* slow symlink */
- inode->i_op = &page_symlink_inode_operations;
- inode->i_mapping->a_ops = &obdfs_aops;
- err = block_symlink(inode, symname, l);
- if (err)
- goto out_fail;
- } else {
- /* fast symlink */
- inode->i_op = &obdfs_fast_symlink_inode_operations;
- memcpy(oinfo->oi_inline, symname, l);
- inode->i_size = l-1;
- }
- obdfs_change_inode(inode);
-
- err = ext2_add_nondir(dentry, inode);
-out:
- return err;
-
-out_fail:
- ext2_dec_count(inode);
- iput (inode);
- goto out;
-}
-
-
-
-static int obdfs_link (struct dentry * old_dentry, struct inode * dir,
- struct dentry *dentry)
-{
- struct inode *inode = old_dentry->d_inode;
-
- if (S_ISDIR(inode->i_mode))
- return -EPERM;
-
- if (inode->i_nlink >= EXT2_LINK_MAX)
- return -EMLINK;
-
- inode->i_ctime = CURRENT_TIME;
- ext2_inc_count(inode);
- atomic_inc(&inode->i_count);
-
- return ext2_add_nondir(dentry, inode);
-}
-
-
-static int obdfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
-{
- struct inode * inode;
- int err = -EMLINK;
- ENTRY;
-
- if (dir->i_nlink >= EXT2_LINK_MAX)
- goto out;
-
- ext2_inc_count(dir);
-
- inode = obdfs_new_inode (dir, S_IFDIR | mode);
- err = PTR_ERR(inode);
- if (IS_ERR(inode))
- goto out_dir;
-
- inode->i_op = &obdfs_dir_inode_operations;
- inode->i_fop = &obdfs_dir_operations;
- inode->i_mapping->a_ops = &obdfs_aops;
-
- ext2_inc_count(inode);
-
- err = ext2_make_empty(inode, dir);
- if (err)
- goto out_fail;
-
- err = ext2_add_link(dentry, inode);
- if (err)
- goto out_fail;
-
- d_instantiate(dentry, inode);
-out:
- EXIT;
- return err;
-
-out_fail:
- ext2_dec_count(inode);
- ext2_dec_count(inode);
- iput(inode);
- EXIT;
-out_dir:
- ext2_dec_count(dir);
- EXIT;
- goto out;
-}
-
-static int obdfs_unlink(struct inode * dir, struct dentry *dentry)
-{
- struct inode * inode = dentry->d_inode;
- struct ext2_dir_entry_2 * de;
- struct page * page;
- int err = -ENOENT;
-
- de = ext2_find_entry (dir, dentry, &page);
- if (!de)
- goto out;
-
- err = ext2_delete_entry (de, page);
- if (err)
- goto out;
-
- inode->i_ctime = dir->i_ctime;
- ext2_dec_count(inode);
- err = 0;
-out:
- return err;
-}
-
-
-static int obdfs_rmdir (struct inode * dir, struct dentry *dentry)
-{
- struct inode * inode = dentry->d_inode;
- int err = -ENOTEMPTY;
-
- if (ext2_empty_dir(inode)) {
- err = obdfs_unlink(dir, dentry);
- if (!err) {
- inode->i_size = 0;
- ext2_dec_count(inode);
- ext2_dec_count(dir);
- }
- }
- return err;
-}
-
-static int obdfs_rename (struct inode * old_dir, struct dentry * old_dentry,
- struct inode * new_dir, struct dentry * new_dentry )
-{
- struct inode * old_inode = old_dentry->d_inode;
- struct inode * new_inode = new_dentry->d_inode;
- struct page * dir_page = NULL;
- struct ext2_dir_entry_2 * dir_de = NULL;
- struct page * old_page;
- struct ext2_dir_entry_2 * old_de;
- int err = -ENOENT;
-
- old_de = ext2_find_entry (old_dir, old_dentry, &old_page);
- if (!old_de)
- goto out;
-
- if (S_ISDIR(old_inode->i_mode)) {
- err = -EIO;
- dir_de = ext2_dotdot(old_inode, &dir_page);
- if (!dir_de)
- goto out_old;
- }
-
- if (new_inode) {
- struct page *new_page;
- struct ext2_dir_entry_2 *new_de;
-
- err = -ENOTEMPTY;
- if (dir_de && !ext2_empty_dir (new_inode))
- goto out_dir;
-
- err = -ENOENT;
- new_de = ext2_find_entry (new_dir, new_dentry, &new_page);
- if (!new_de)
- goto out_dir;
- ext2_inc_count(old_inode);
- ext2_set_link(new_dir, new_de, new_page, old_inode);
- new_inode->i_ctime = CURRENT_TIME;
- if (dir_de)
- new_inode->i_nlink--;
- ext2_dec_count(new_inode);
- } else {
- if (dir_de) {
- err = -EMLINK;
- if (new_dir->i_nlink >= EXT2_LINK_MAX)
- goto out_dir;
- }
- ext2_inc_count(old_inode);
- err = ext2_add_link(new_dentry, old_inode);
- if (err) {
- ext2_dec_count(old_inode);
- goto out_dir;
- }
- if (dir_de)
- ext2_inc_count(new_dir);
- }
-
- ext2_delete_entry (old_de, old_page);
- ext2_dec_count(old_inode);
-
- if (dir_de) {
- ext2_set_link(old_inode, dir_de, dir_page, new_dir);
- ext2_dec_count(old_dir);
- }
- return 0;
-
-
-out_dir:
- if (dir_de) {
- kunmap(dir_page);
- page_cache_release(dir_page);
- }
-out_old:
- kunmap(old_page);
- page_cache_release(old_page);
-out:
- return err;
-}
-
-struct inode_operations obdfs_dir_inode_operations = {
- create: obdfs_create,
- lookup: obdfs_lookup,
- link: obdfs_link,
- unlink: obdfs_unlink,
- symlink: obdfs_symlink,
- mkdir: obdfs_mkdir,
- rmdir: obdfs_rmdir,
- mknod: obdfs_mknod,
- rename: obdfs_rename,
- setattr: obdfs_setattr
-};
+++ /dev/null
-/*
- * OBDFS Super operations
- *
- * This code is issued under the GNU General Public License.
- * See the file COPYING in this distribution
- *
- * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de>
- * Copryright (C) 1999 Stelias Computing Inc,
- * (author Peter J. Braam <braam@stelias.com>)
- * Copryright (C) 1999 Seagate Technology Inc.
-*/
-
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/locks.h>
-#include <linux/unistd.h>
-#include <linux/version.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
-#include <linux/vmalloc.h>
-#include <asm/segment.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
-
-#define DEBUG_SUBSYSTEM S_OBDFS
-
-#include <linux/obd_support.h>
-#include <linux/obd_ext2.h>
-#include <linux/obdfs.h>
-
-void obdfs_change_inode(struct inode *inode);
-
-static int cache_writes = 0;
-
-
-/* page cache support stuff */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
-/*
- * Add a page to the dirty page list.
- */
-void __set_page_dirty(struct page *page)
-{
- struct address_space *mapping;
- spinlock_t *pg_lock;
-
- pg_lock = PAGECACHE_LOCK(page);
- spin_lock(pg_lock);
-
- mapping = page->mapping;
- spin_lock(&mapping->page_lock);
-
- list_del(&page->list);
- list_add(&page->list, &mapping->dirty_pages);
-
- spin_unlock(&mapping->page_lock);
- spin_unlock(pg_lock);
-
- if (mapping->host)
- mark_inode_dirty_pages(mapping->host);
-}
-/*
- * Remove page from dirty list
- */
-void __set_page_clean(struct page *page)
-{
- struct address_space *mapping = page->mapping;
- struct inode *inode;
-
- if (!mapping)
- return;
-
- list_del(&page->list);
- list_add(&page->list, &mapping->clean_pages);
-
- inode = mapping->host;
- if (list_empty(&mapping->dirty_pages)) {
- CDEBUG(D_INODE, "inode clean\n");
- inode->i_state &= ~I_DIRTY_PAGES;
- }
- EXIT;
-}
-
-#else
-/*
- * Add a page to the dirty page list.
- */
-void set_page_dirty(struct page *page)
-{
- if (!test_and_set_bit(PG_dirty, &page->flags)) {
- struct address_space *mapping = page->mapping;
-
- if (mapping) {
- spin_lock(&pagecache_lock);
- list_del(&page->list);
- list_add(&page->list, &mapping->dirty_pages);
- spin_unlock(&pagecache_lock);
-
- if (mapping->host)
- mark_inode_dirty_pages(mapping->host);
- }
- }
-}
-/*
- * Remove page from dirty list
- */
-void __set_page_clean(struct page *page)
-{
- struct address_space *mapping = page->mapping;
- struct inode *inode;
-
- if (!mapping)
- return;
-
- spin_lock(&pagecache_lock);
- list_del(&page->list);
- list_add(&page->list, &mapping->clean_pages);
-
- inode = mapping->host;
- if (list_empty(&mapping->dirty_pages)) {
- CDEBUG(D_INODE, "inode clean\n");
- inode->i_state &= ~I_DIRTY_PAGES;
- }
- spin_unlock(&pagecache_lock);
- EXIT;
-}
-
-#endif
-
-
-inline void set_page_clean(struct page *page)
-{
- if (PageDirty(page)) {
- ClearPageDirty(page);
- __set_page_clean(page);
- }
-}
-
-/* SYNCHRONOUS I/O to object storage for an inode -- object attr will be updated too */
-static int obdfs_brw(int rw, struct inode *inode2,
- struct page *page, int create)
-{
- struct inode *inode = page->mapping->host;
- struct ll_inode_info *lii = ll_i2info(inode);
- obd_size count = PAGE_SIZE;
- obd_off offset = ((obd_off)page->index) << PAGE_SHIFT;
- obd_flag flags = create ? OBD_BRW_CREATE : 0;
- int err;
-
- ENTRY;
-
- CHECK_MOUNT_EPOCH(inode);
- CHECK_MOUNT_EPOCH(inode2);
-
- err = obd_brw(rw == WRITE ? OBD_BRW_WRITE : OBD_BRW_READ, IID(inode),
- md, 1, &page, &count, &offset,
- &flags, NULL);
- //if ( !err )
- // obdfs_to_inode(inode, oa); /* copy o_blocks to i_blocks */
-
- obdo_free(oa);
- EXIT;
- return err;
-} /* obdfs_brw */
-
-/* SYNCHRONOUS I/O to object storage for an inode -- object attr will be updated too */
-static int obdfs_commit_page(struct page *page, int create, int from, int to)
-{
- struct inode *inode = page->mapping->host;
- obd_count num_obdo = 1;
- obd_count bufs_per_obdo = 1;
- struct obdo *oa;
- obd_size count = to;
- obd_off offset = (((obd_off)page->index) << PAGE_SHIFT);
- obd_flag flags = create ? OBD_BRW_CREATE : 0;
- int err;
-
- ENTRY;
-
- CDEBUG(D_INODE, "commit_page writing (at %d) to %d, count %Ld\n",
- from, to, (unsigned long long)count);
-
- err = obd_brw(OBD_BRW_WRITE, IID(inode), md, 1,
- &page, &count, &offset, &flags, NULL);
- if ( !err ) {
- SetPageUptodate(page);
- set_page_clean(page);
- }
-
- //if ( !err )
- // obdfs_to_inode(inode, oa); /* copy o_blocks to i_blocks */
-
- obdo_free(oa);
- EXIT;
- return err;
-} /* obdfs_brw */
-
-/* returns the page unlocked, but with a reference */
-int obdfs_writepage(struct page *page)
-{
- int rc;
- struct inode *inode = page->mapping->host;
- ENTRY;
- CERROR("---> writepage called ino %ld!\n", inode->i_ino);
- LBUG();
- rc = obdfs_brw(OBD_BRW_WRITE, inode, page, 1);
- if ( !rc ) {
- set_page_clean(page);
- } else {
- CDEBUG(D_INODE, "--> GRR %d\n", rc);
- }
- EXIT;
- return rc;
-}
-
-
-void write_inode_pages(struct inode *inode)
-{
- struct list_head *tmp = &inode->i_mapping->dirty_pages;
-
- while ( (tmp = tmp->next) != &inode->i_mapping->dirty_pages) {
- struct page *page;
- page = list_entry(tmp, struct page, list);
- obdfs_writepage(page);
- }
-}
-
-
-/* returns the page unlocked, but with a reference */
-int obdfs_readpage(struct file *file, struct page *page)
-{
- struct inode *inode = page->mapping->host;
- int rc;
-
- ENTRY;
-
- if ( ((inode->i_size + PAGE_CACHE_SIZE -1)>>PAGE_SHIFT)
- <= page->index) {
- memset(kmap(page), 0, PAGE_CACHE_SIZE);
- kunmap(page);
- goto readpage_out;
- }
-
- if (Page_Uptodate(page)) {
- EXIT;
- goto readpage_out;
- }
-
- rc = obdfs_brw(OBD_BRW_READ, inode, page, 0);
- if ( rc ) {
- EXIT;
- return rc;
- }
-
- readpage_out:
- SetPageUptodate(page);
- UnlockPage(page);
- EXIT;
- return 0;
-} /* obdfs_readpage */
-
-int obdfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
-{
- struct inode *inode = page->mapping->host;
- obd_off offset = ((obd_off)page->index) << PAGE_SHIFT;
- int rc = 0;
- ENTRY;
-
- kmap(page);
- if (Page_Uptodate(page)) {
- EXIT;
- goto prepare_done;
- }
-
- if ( (from <= offset) && (to >= offset + PAGE_SIZE) ) {
- EXIT;
- return 0;
- }
-
- rc = obdfs_brw(OBD_BRW_READ, inode, page, 0);
- if (!rc)
- SetPageUptodate(page);
-
- prepare_done:
- set_page_dirty(page);
- //SetPageDirty(page);
- EXIT;
- return rc;
-}
-
-
-#if 0
-
-
-
-static kmem_cache_t *obdfs_pgrq_cachep = NULL;
-
-int obdfs_init_pgrqcache(void)
-{
- ENTRY;
- if (obdfs_pgrq_cachep == NULL) {
- CDEBUG(D_CACHE, "allocating obdfs_pgrq_cache\n");
- obdfs_pgrq_cachep = kmem_cache_create("obdfs_pgrq",
- sizeof(struct obdfs_pgrq),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
- if (obdfs_pgrq_cachep == NULL) {
- EXIT;
- return -ENOMEM;
- } else {
- CDEBUG(D_CACHE, "allocated cache at %p\n",
- obdfs_pgrq_cachep);
- }
- } else {
- CDEBUG(D_CACHE, "using existing cache at %p\n",
- obdfs_pgrq_cachep);
- }
- EXIT;
- return 0;
-} /* obdfs_init_wreqcache */
-
-inline void obdfs_pgrq_del(struct obdfs_pgrq *pgrq)
-{
- --obdfs_cache_count;
- CDEBUG(D_INFO, "deleting page %p from list [count %ld]\n",
- pgrq->rq_page, obdfs_cache_count);
- list_del(&pgrq->rq_plist);
- OBDClearCachePage(pgrq->rq_page);
- kmem_cache_free(obdfs_pgrq_cachep, pgrq);
-}
-
-void obdfs_cleanup_pgrqcache(void)
-{
- ENTRY;
- if (obdfs_pgrq_cachep != NULL) {
- CDEBUG(D_CACHE, "destroying obdfs_pgrqcache at %p, count %ld\n",
- obdfs_pgrq_cachep, obdfs_cache_count);
- if (kmem_cache_destroy(obdfs_pgrq_cachep))
- CERROR("unable to free all of cache\n");
- obdfs_pgrq_cachep = NULL;
- } else
- CERROR("called with NULL pointer\n");
-
- EXIT;
-} /* obdfs_cleanup_wreqcache */
-
-
-/* called with the list lock held */
-static struct page *obdfs_find_page_index(struct inode *inode,
- unsigned long index)
-{
- struct list_head *page_list = obdfs_iplist(inode);
- struct list_head *tmp;
- struct page *page;
-
- ENTRY;
-
- CDEBUG(D_INFO, "looking for inode %ld pageindex %ld\n",
- inode->i_ino, index);
- OIDEBUG(inode);
-
- if (list_empty(page_list)) {
- EXIT;
- return NULL;
- }
- tmp = page_list;
- while ( (tmp = tmp->next) != page_list ) {
- struct obdfs_pgrq *pgrq;
-
- pgrq = list_entry(tmp, struct obdfs_pgrq, rq_plist);
- page = pgrq->rq_page;
- if (index == page->index) {
- CDEBUG(D_INFO,
- "INDEX SEARCH found page %p, index %ld\n",
- page, index);
- EXIT;
- return page;
- }
- }
-
- EXIT;
- return NULL;
-} /* obdfs_find_page_index */
-
-
-/* call and free pages from Linux page cache: called with io lock on inodes */
-int obdfs_do_vec_wr(struct inode **inodes, obd_count num_io,
- obd_count num_obdos, struct obdo **obdos,
- obd_count *oa_bufs, struct page **pages, char **bufs,
- obd_size *counts, obd_off *offsets, obd_flag *flags)
-{
- int err;
-
- ENTRY;
- CDEBUG(D_INFO, "writing %d page(s), %d obdo(s) in vector\n",
- num_io, num_obdos);
- if (obd_debug_level & D_INFO) { /* DEBUGGING */
- int i;
- printk("OBDOS: ");
- for (i = 0; i < num_obdos; i++)
- printk("%ld:0x%p ", (long)obdos[i]->o_id, obdos[i]);
-
- printk("\nPAGES: ");
- for (i = 0; i < num_io; i++)
- printk("0x%p ", pages[i]);
- printk("\n");
- }
-
- err = obd_brw(OBD_BRW_WRITE, IID(inodes[0]), num_obdos, obdos,
- oa_bufs, pages, counts, offsets, flags);
-
- CDEBUG(D_INFO, "BRW done\n");
- /* release the pages from the page cache */
- while (num_io-- > 0) {
- CDEBUG(D_INFO, "calling put_page for %p, index %ld\n",
- pages[num_io], pages[num_io]->index);
- put_page(pages[num_io]);
- }
- CDEBUG(D_INFO, "put_page done\n");
-
- while (num_obdos-- > 0) {
- CDEBUG(D_INFO, "free obdo %ld\n",(long)obdos[num_obdos]->o_id);
- /* copy o_blocks to i_blocks */
- obdfs_set_size (inodes[num_obdos], obdos[num_obdos]->o_size);
- //obdfs_to_inode(inodes[num_obdos], obdos[num_obdos]);
- obdo_free(obdos[num_obdos]);
- }
- CDEBUG(D_INFO, "obdo_free done\n");
- EXIT;
- return err;
-}
-
-
-/*
- * Add a page to the write request cache list for later writing.
- * ASYNCHRONOUS write method.
- */
-static int obdfs_add_page_to_cache(struct inode *inode, struct page *page)
-{
- int err = 0;
- ENTRY;
-
- /* The PG_obdcache bit is cleared by obdfs_pgrq_del() BEFORE the page
- * is written, so at worst we will write the page out twice.
- *
- * If the page has the PG_obdcache bit set, then the inode MUST be
- * on the superblock dirty list so we don't need to check this.
- * Dirty inodes are removed from the superblock list ONLY when they
- * don't have any more cached pages. It is possible to have an inode
- * with no dirty pages on the superblock list, but not possible to
- * have an inode with dirty pages NOT on the superblock dirty list.
- */
- if (!OBDAddCachePage(page)) {
- struct obdfs_pgrq *pgrq;
- pgrq = kmem_cache_alloc(obdfs_pgrq_cachep, SLAB_KERNEL);
- if (!pgrq) {
- OBDClearCachePage(page);
- EXIT;
- return -ENOMEM;
- }
- /* not really necessary since we set all pgrq fields here
- memset(pgrq, 0, sizeof(*pgrq));
- */
-
- pgrq->rq_page = page;
- pgrq->rq_jiffies = jiffies;
- get_page(pgrq->rq_page);
-
- obd_down(&obdfs_i2sbi(inode)->osi_list_mutex);
- list_add(&pgrq->rq_plist, obdfs_iplist(inode));
- obdfs_cache_count++;
- //CERROR("-- count %d\n", obdfs_cache_count);
-
- /* If inode isn't already on superblock inodes list, add it.
- *
- * We increment the reference count on the inode to keep it
- * from being freed from memory. This _should_ be an iget()
- * with an iput() in both flush_reqs() and put_inode(), but
- * since put_inode() is called from iput() we can't call iput()
- * again there. Instead we just increment/decrement i_count,
- * which is mostly what iget/iput do for an inode in memory.
- */
- if ( list_empty(obdfs_islist(inode)) ) {
- atomic_inc(&inode->i_count);
- CDEBUG(D_INFO,
- "adding inode %ld to superblock list %p\n",
- inode->i_ino, obdfs_slist(inode));
- list_add(obdfs_islist(inode), obdfs_slist(inode));
- }
- obd_up(&obdfs_i2sbi(inode)->osi_list_mutex);
-
- }
-
- /* XXX For testing purposes, we can write out the page here.
- err = obdfs_flush_reqs(obdfs_slist(inode), ~0UL);
- */
-
- EXIT;
- return err;
-} /* obdfs_add_page_to_cache */
-
-void rebalance(void)
-{
- if (obdfs_cache_count > 60000) {
- CERROR("-- count %ld\n", obdfs_cache_count);
- //obdfs_flush_dirty_pages(~0UL);
- CERROR("-- count %ld\n", obdfs_cache_count);
- }
-}
-
-
-
-/* select between SYNC and ASYNC I/O methods */
-int obdfs_do_writepage(struct page *page, int sync)
-{
- struct inode *inode = page->mapping->host;
- int err;
-
- ENTRY;
- if ( sync )
- err = obdfs_brw(OBD_BRW_WRITE, inode, page, 1);
- else {
- err = obdfs_add_page_to_cache(inode, page);
- CDEBUG(D_INFO, "DO_WR ino: %ld, page %p, err %d, uptodate %d\n",
- inode->i_ino, page, err, Page_Uptodate(page));
- }
-
- if ( !err ) {
- SetPageUptodate(page);
- set_page_clean(page);
- }
- EXIT;
- return err;
-} /* obdfs_do_writepage */
-
-
-
-
-#endif
-
-int obdfs_commit_write(struct file *file, struct page *page, unsigned from, unsigned to)
-{
- struct inode *inode = page->mapping->host;
- int rc = 0;
- loff_t len = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
- ENTRY;
- CDEBUG(D_INODE, "commit write ino %ld (end at %Ld) from %d to %d ,ind %ld\n",
- inode->i_ino, len, from, to, page->index);
-
-
- if (cache_writes == 0) {
- rc = obdfs_commit_page(page, 1, from, to);
- }
-
- if (len > inode->i_size) {
- obdfs_set_size(inode, len);
- }
-
- kunmap(page);
- EXIT;
- return rc;
-}
-
-
-/*
- * This does the "real" work of the write. The generic routine has
- * allocated the page, locked it, done all the page alignment stuff
- * calculations etc. Now we should just copy the data from user
- * space and write it back to the real medium..
- *
- * If the writer ends up delaying the write, the writer needs to
- * increment the page use counts until he is done with the page.
- *
- * Return value is the number of bytes written.
- */
-int obdfs_write_one_page(struct file *file, struct page *page,
- unsigned long offset, unsigned long bytes,
- const char * buf)
-{
- struct inode *inode = file->f_dentry->d_inode;
- int err;
-
- ENTRY;
- /* We check for complete page writes here, as we then don't have to
- * get the page before writing over everything anyways.
- */
- if (!Page_Uptodate(page) && (offset != 0 || bytes != PAGE_SIZE)) {
- err = obdfs_brw(OBD_BRW_READ, inode, page, 0);
- if ( err )
- return err;
- SetPageUptodate(page);
- }
-
- if (copy_from_user((u8*)page_address(page) + offset, buf, bytes))
- return -EFAULT;
-
- lock_kernel();
- err = obdfs_writepage(page);
- unlock_kernel();
-
- return (err < 0 ? err : bytes);
-} /* obdfs_write_one_page */
-
-/*
- * return an up to date page:
- * - if locked is true then is returned locked
- * - if create is true the corresponding disk blocks are created
- * - page is held, i.e. caller must release the page
- *
- * modeled on NFS code.
- */
-struct page *obdfs_getpage(struct inode *inode, unsigned long offset,
- int create, int locked)
-{
- struct page * page;
- int index;
- int err;
-
- ENTRY;
-
- offset = offset & PAGE_CACHE_MASK;
- CDEBUG(D_INFO, "ino: %ld, offset %ld, create %d, locked %d\n",
- inode->i_ino, offset, create, locked);
- index = offset >> PAGE_CACHE_SHIFT;
-
- page = grab_cache_page(&inode->i_data, index);
-
- /* Yuck, no page */
- if (! page) {
- CERROR("grab_cache_page says no dice ...\n");
- EXIT;
- return NULL;
- }
-
- /* now check if the data in the page is up to date */
- if ( Page_Uptodate(page)) {
- if (!locked) {
- if (PageLocked(page))
- UnlockPage(page);
- } else {
- CERROR("expecting locked page\n");
- }
- EXIT;
- return page;
- }
-
- err = obdfs_brw(OBD_BRW_READ, inode, page, create);
-
- if ( err ) {
- SetPageError(page);
- UnlockPage(page);
- EXIT;
- return page;
- }
-
- if ( !locked )
- UnlockPage(page);
- SetPageUptodate(page);
- EXIT;
- return page;
-} /* obdfs_getpage */
-
-
-void obdfs_truncate(struct inode *inode)
-{
- struct obdo *oa;
- int err;
- ENTRY;
-
- //obdfs_dequeue_pages(inode);
- oa = obdo_alloc();
- if ( !oa ) {
- err = -ENOMEM;
- CERROR("obdo_alloc failed!\n");
- } else {
- oa->o_valid = OBD_MD_FLNOTOBD;
- obdfs_from_inode(oa, inode);
-
- CDEBUG(D_INFO, "calling punch for %ld (%Lu bytes at 0)\n",
- (long)oa->o_id, (unsigned long long)oa->o_size);
- err = obd_punch(IID(inode), oa, oa->o_size, 0);
-
- obdo_free(oa);
- }
-
- if (err) {
- CERROR("obd_truncate fails (%d)\n", err);
- EXIT;
- return;
- }
- EXIT;
-} /* obdfs_truncate */
-
-struct address_space_operations obdfs_aops = {
- readpage: obdfs_readpage,
- writepage: obdfs_writepage,
- sync_page: block_sync_page,
- prepare_write: obdfs_prepare_write,
- commit_write: obdfs_commit_write,
- bmap: NULL
-};
+++ /dev/null
-
-/*
- * OBDFS Super operations
- *
- * This code is issued under the GNU General Public License.
- * See the file COPYING in this distribution
- *
- * Copryright (C) 1996 Peter J. Braam <braam@stelias.com>
- * Copryright (C) 1999 Stelias Computing Inc. <braam@stelias.com>
- * Copryright (C) 1999 Seagate Technology Inc.
- * Copryright (C) 2001 Mountain View Data, Inc.
- * Copryright (C) 2002 Cluster File Systems, Inc.
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/locks.h>
-#include <linux/unistd.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
-#include <linux/vmalloc.h>
-#include <asm/segment.h>
-
-#define DEBUG_SUBSYSTEM S_OBDFS
-
-#include <linux/obd_support.h>
-#include <linux/obd_class.h>
-#include <linux/obdfs.h>
-
-struct list_head obdfs_super_list;
-extern struct address_space_operations obdfs_aops;
-struct super_operations obdfs_super_operations;
-long obdfs_cache_count = 0;
-long obdfs_mutex_start = 0;
-
-static char *obdfs_read_opt(const char *opt, char *data)
-{
- char *value;
- char *retval;
-
- CDEBUG(D_INFO, "option: %s, data %s\n", opt, data);
- if ( strncmp(opt, data, strlen(opt)) )
- return NULL;
-
- if ( (value = strchr(data, '=')) == NULL )
- return NULL;
-
- value++;
- OBD_ALLOC(retval, strlen(value) + 1);
- if ( !retval ) {
- CERROR("out of memory!\n");
- return NULL;
- }
-
- memcpy(retval, value, strlen(value)+1);
- CDEBUG(D_SUPER, "Assigned option: %s, value %s\n", opt, retval);
- return retval;
-}
-
-static void obdfs_options(char *options, char **dev, char **vers)
-{
- char *this_char;
-
- if (!options)
- return;
-
- for (this_char = strtok (options, ",");
- this_char != NULL;
- this_char = strtok (NULL, ",")) {
- CDEBUG(D_INFO, "this_char %s\n", this_char);
- if ( (!*dev && (*dev = obdfs_read_opt("device", this_char)))||
- (!*vers && (*vers = obdfs_read_opt("version", this_char))) )
- continue;
-
- }
-}
-
-static struct super_block * obdfs_read_super(struct super_block *sb,
- void *data, int silent)
-{
- struct inode *root = 0;
- struct obdfs_sb_info *sbi = (struct obdfs_sb_info *)(&sb->u.generic_sbp);
- struct obd_device *obddev;
- char *device = NULL;
- char *version = NULL;
- int connected = 0;
- int devno;
- int err;
- unsigned long blocksize;
- unsigned long blocksize_bits;
- obd_id root_ino;
- int scratch;
- struct obdo *oa;
-
- ENTRY;
- MOD_INC_USE_COUNT;
-
- memset(sbi, 0, sizeof(*sbi));
-
- CDEBUG(D_INFO, "\n");
- obdfs_options(data, &device, &version);
- if (!device) {
- CERROR("no device\n");
- EXIT;
- goto ERR;
- }
-
- devno = simple_strtoul(device, NULL, 0);
- CDEBUG(D_INFO, "\n");
- if (devno >= MAX_OBD_DEVICES) {
- CERROR("device of %s too high (%d)\n", device, devno);
- EXIT;
- goto ERR;
- }
-
- CDEBUG(D_INFO, "\n");
-
- obddev = &obd_dev[devno];
- sbi->osi_obd = obddev;
-
- err = obd_connect(&sbi->osi_conn, obddev);
- if (err) {
- CERROR("OBDFS: cannot connect to %s\n", device);
- EXIT;
- goto ERR;
- }
-
- connected = 1;
- CDEBUG(D_INFO, "\n");
- /* list of dirty inodes, and a mutex to hold while modifying it */
- INIT_LIST_HEAD(&sbi->osi_inodes);
- init_MUTEX (&sbi->osi_list_mutex);
-
- CDEBUG(D_INFO, "\n");
- sbi->osi_super = sb;
-
- CDEBUG(D_INFO, "\n");
- err = obd_get_info(&sbi->osi_conn, strlen("blocksize"),
- "blocksize", &scratch,
- (void *)&blocksize);
- if (err) {
- CERROR("getinfo call to drive failed (blocksize)\n");
- EXIT;
- goto ERR;
- }
-
- CDEBUG(D_INFO, "\n");
- err = obd_get_info(&sbi->osi_conn, strlen("blocksize_bits"),
- "blocksize_bits", &scratch,
- (void *)&blocksize_bits);
- if (err) {
- CERROR("getinfo call to drive failed (blocksize_bits)\n");
- EXIT;
- goto ERR;
- }
-
- CDEBUG(D_INFO, "\n");
- err = obd_get_info(&sbi->osi_conn, strlen("root_ino"),
- "root_ino", &scratch, (void *)&root_ino);
- if (err) {
- CERROR("getinfo call to drive failed (root_ino)\n");
- EXIT;
- goto ERR;
- }
-
- CDEBUG(D_INFO, "\n");
- sb->s_maxbytes = 1LL << 36;
- CERROR("Max bytes: %Lx\n", sb->s_maxbytes);
- sb->s_blocksize = PAGE_SIZE;
- sb->s_blocksize_bits = (unsigned char)PAGE_SHIFT;
- sb->s_magic = OBDFS_SUPER_MAGIC;
- sb->s_op = &obdfs_super_operations;
-
- /* XXX how to get "sb->s_flags |= MS_RDONLY" here for snapshots? */
-
- /* make root inode */
- CDEBUG(D_INFO, "\n");
- oa = obdo_fromid(&sbi->osi_conn, root_ino, S_IFDIR,
- (__u32)(OBD_MD_FLNOTOBD | OBD_MD_FLBLOCKS));
- CDEBUG(D_INFO, "mode %o\n", oa->o_mode);
- if (IS_ERR(oa)) {
- CERROR("obdo_fromid failed\n");
- iput(root);
- EXIT;
- goto ERR;
- }
- CDEBUG(D_INFO, "\n");
- root = iget4(sb, (ino_t)root_ino, NULL, oa);
- obdo_free(oa);
- CDEBUG(D_INFO, "\n");
- if (!root) {
- CERROR("OBDFS: bad iget4 for root\n");
- sb->s_dev = 0;
- err = -ENOENT;
- EXIT;
- goto ERR;
- }
-
- CDEBUG(D_INFO, "sbdev %d, rootino: %Ld, dev %s, "
- "minor: %d, blocksize: %ld, blocksize bits %ld\n",
- sb->s_dev, (long long)root_ino, device, MINOR(devno),
- blocksize, blocksize_bits);
- sb->s_root = d_alloc_root(root);
- list_add(&sbi->osi_list, &obdfs_super_list);
- OBD_FREE(device, strlen(device) + 1);
- if (version)
- OBD_FREE(version, strlen(version) + 1);
- EXIT;
- return sb;
-
-ERR:
- MOD_DEC_USE_COUNT;
- if (device)
- OBD_FREE(device, strlen(device) + 1);
- if (version)
- OBD_FREE(version, strlen(version) + 1);
- if (connected)
- obd_disconnect(&sbi->osi_conn);
-
- if (sbi) {
- sbi->osi_super = NULL;
- }
- if (root) {
- iput(root);
- }
- sb->s_dev = 0;
- return NULL;
-} /* obdfs_read_super */
-
-
-static void obdfs_put_super(struct super_block *sb)
-{
- struct obdfs_sb_info *sbi;
-
- ENTRY;
- sb->s_dev = 0;
-
- sbi = (struct obdfs_sb_info *) &sb->u.generic_sbp;
- //obdfs_flush_reqs(&sbi->osi_inodes, ~0UL);
-
- obd_disconnect(ID(sb));
- list_del(&sbi->osi_list);
-
- CERROR("OBDFS: Bye bye.\n");
-
- MOD_DEC_USE_COUNT;
- EXIT;
-} /* obdfs_put_super */
-
-
-void obdfs_do_change_inode(struct inode *inode, int valid)
-{
- struct obdo *oa;
- int err;
-
- ENTRY;
- oa = obdo_alloc();
- if ( !oa ) {
- CERROR("obdo_alloc failed\n");
- EXIT;
- return;
- }
-
- oa->o_valid = OBD_MD_FLNOTOBD & (valid | OBD_MD_FLID);
- obdfs_from_inode(oa, inode);
- oa->o_mode = inode->i_mode;
- err = obd_setattr(IID(inode), oa);
-
- if ( err )
- CERROR("obd_setattr fails (%d)\n", err);
-
- EXIT;
- obdo_free(oa);
-} /* obdfs_write_inode */
-
-void obdfs_change_inode(struct inode *inode, int mask)
-{
- return obdfs_do_change_inode(inode, OBD_MD_FLNLINK);
-}
-
-
-extern void write_inode_pages(struct inode *);
-/* This routine is called from iput() (for each unlink on the inode).
- * We can't put this call into delete_inode() since that is called only
- * when i_count == 0, and we need to keep a reference on the inode while
- * it is in the page cache, which means i_count > 0. Catch 22.
- */
-static void obdfs_put_inode(struct inode *inode)
-{
- ENTRY;
- if (inode->i_nlink && (atomic_read(&inode->i_count) == 1)) {
- write_inode_pages(inode);
- EXIT;
- return;
- }
-
- //obdfs_dequeue_pages(inode);
- EXIT;
-} /* obdfs_put_inode */
-
-
-static void obdfs_delete_inode(struct inode *inode)
-{
- obdfs_do_change_inode(inode, ~0);
- clear_inode(inode);
-}
-#if 0
-{
- struct obdo *oa;
- int err;
-
- ENTRY;
- oa = obdo_alloc();
- if ( !oa ) {
- CERROR("obdo_alloc failed\n");
- EXIT;
- return;
- }
- oa->o_valid = OBD_MD_FLNOTOBD;
- obdfs_from_inode(oa, inode);
-
- /* XXX how do we know that this inode is now clean? */
- CERROR("delete_inode ------> link %d\n", inode->i_nlink);
- ODEBUG(oa);
- err = obd_destroy(IID(inode), oa);
- obdo_free(oa);
- clear_inode(inode);
- if (err) {
- CERROR("obd_destroy fails (%d)\n", err);
- EXIT;
- return;
- }
-
- EXIT;
-} /* obdfs_delete_inode */
-#endif
-
-
-static int obdfs_attr2inode(struct inode * inode, struct iattr * attr)
-{
- unsigned int ia_valid = attr->ia_valid;
- int error = 0;
-
- if (ia_valid & ATTR_SIZE) {
- error = vmtruncate(inode, attr->ia_size);
- if (error)
- goto out;
- }
-
- if (ia_valid & ATTR_UID)
- inode->i_uid = attr->ia_uid;
- if (ia_valid & ATTR_GID)
- inode->i_gid = attr->ia_gid;
- if (ia_valid & ATTR_ATIME)
- inode->i_atime = attr->ia_atime;
- if (ia_valid & ATTR_MTIME)
- inode->i_mtime = attr->ia_mtime;
- if (ia_valid & ATTR_CTIME)
- inode->i_ctime = attr->ia_ctime;
- if (ia_valid & ATTR_MODE) {
- inode->i_mode = attr->ia_mode;
- if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
- inode->i_mode &= ~S_ISGID;
- }
-out:
- return error;
-}
-
-int obdfs_setattr(struct dentry *de, struct iattr *attr)
-{
- struct inode *inode = de->d_inode;
- struct obdo *oa;
- int err;
-
- ENTRY;
- oa = obdo_alloc();
- if ( !oa ) {
- CERROR("obdo_alloc failed\n");
- return -ENOMEM;
- }
-
- obdfs_attr2inode(inode, attr);
- oa->o_id = inode->i_ino;
- oa->o_mode = inode->i_mode;
- obdo_from_iattr(oa, attr);
- err = obd_setattr(IID(inode), oa);
-
- if ( err )
- CERROR("obd_setattr fails (%d)\n", err);
-
- EXIT;
- obdo_free(oa);
- return err;
-} /* obdfs_setattr */
-
-
-
-static int obdfs_statfs(struct super_block *sb, struct statfs *sfs)
-{
- int rc;
-
- ENTRY;
-
- rc = obd_statfs(ID(sb), sfs);
- if (rc)
- CERROR("obd_statfs fails: rc = %d\n", rc);
- else
- CDEBUG(D_SUPER, "statfs returns avail %ld\n", sfs->f_bavail);
-
- RETURN(rc);
-}
-
-static inline void obdfs_read_inode2(struct inode *inode, void *opaque)
-{
- struct obdo *oa = opaque;
-
- ENTRY;
- obdfs_to_inode(inode, oa);
-
- INIT_LIST_HEAD(obdfs_iplist(inode)); /* list of dirty pages on inode */
- INIT_LIST_HEAD(obdfs_islist(inode)); /* list of inodes in superblock */
-
- /* OIDEBUG(inode); */
-
- if (S_ISREG(inode->i_mode)) {
- inode->i_op = &obdfs_file_inode_operations;
- inode->i_fop = &obdfs_file_operations;
- inode->i_mapping->a_ops = &obdfs_aops;
- EXIT;
- } else if (S_ISDIR(inode->i_mode)) {
- inode->i_op = &obdfs_dir_inode_operations;
- inode->i_fop = &obdfs_dir_operations;
- inode->i_mapping->a_ops = &obdfs_aops;
- EXIT;
- } else if (S_ISLNK(inode->i_mode)) {
- if (inode->i_blocks) {
- inode->i_op = &obdfs_symlink_inode_operations;
- inode->i_mapping->a_ops = &obdfs_aops;
- }else {
- inode->i_op = &obdfs_fast_symlink_inode_operations;
- }
- EXIT;
- } else {
- init_special_inode(inode, inode->i_mode,
- ((int *)obdfs_i2info(inode)->oi_inline)[0]);
- }
-
- EXIT;
- return;
-}
-
-/* exported operations */
-struct super_operations obdfs_super_operations =
-{
- read_inode2: obdfs_read_inode2,
- put_inode: obdfs_put_inode,
- delete_inode: obdfs_delete_inode,
- put_super: obdfs_put_super,
- statfs: obdfs_statfs
-};
-
-
-struct file_system_type obdfs_fs_type = {
- "obdfs", 0, obdfs_read_super, NULL
-};
-
-int init_obdfs(void)
-{
- //int err;
-
- printk(KERN_INFO "OBDFS v0.1, info@clusterfs.com\n");
-
- obdfs_sysctl_init();
-
- INIT_LIST_HEAD(&obdfs_super_list);
- //err = obdfs_init_pgrqcache();
- //if (err)
- //return err;
-
- //obdfs_flushd_init();
- return register_filesystem(&obdfs_fs_type);
-}
-
-
-
-
-#ifdef MODULE
-int init_module(void)
-{
- return init_obdfs();
-}
-
-void cleanup_module(void)
-{
- ENTRY;
-
- //obdfs_flushd_cleanup();
- obdfs_sysctl_clean();
- //obdfs_cleanup_pgrqcache();
- unregister_filesystem(&obdfs_fs_type);
- CDEBUG(D_MALLOC, "OBDFS mem used %ld\n", obd_memory);
- EXIT;
-}
-
-#endif
+++ /dev/null
-/*
- * linux/fs/ext2/symlink.c
- *
- * This code is issued under the GNU General Public License.
- * See the file COPYING in this distribution
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- * from
- *
- * linux/fs/minix/symlink.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * ext2 symlink handling code
- *
- * Modified for OBDFS.
- * Re-written Oct 2001.
- *
- * Copyright (C) 2001 Cluster File Systems, Inc. (author: braam@clusterfs.com)
- */
-
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/stat.h>
-#include <linux/locks.h>
-
-#define DEBUG_SUBSYSTEM S_OBDFS
-
-#include <linux/obd_support.h> /* for ENTRY and EXIT only */
-#include <linux/obdfs.h>
-
-static int obdfs_fast_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
- char *s = obdfs_i2info(dentry->d_inode)->oi_inline;
- return vfs_readlink(dentry, buffer, buflen, s);
-}
-
-static int obdfs_fast_follow_link(struct dentry *dentry, struct nameidata *nd)
-{
- char *s = obdfs_i2info(dentry->d_inode)->oi_inline;
- return vfs_follow_link(nd, s);
-}
-
-extern int obdfs_setattr(struct dentry *de, struct iattr *attr);
-struct inode_operations obdfs_fast_symlink_inode_operations = {
- readlink: obdfs_fast_readlink,
- follow_link: obdfs_fast_follow_link,
- setattr: obdfs_setattr
-};
-
-static int obdfs_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
- struct page *page = NULL;
- int res;
-
- ENTRY;
- page = obdfs_getpage(dentry->d_inode, 0, 0, 0);
- if (!page) {
- EXIT;
- return 0;
- }
- res = vfs_readlink(dentry, buffer, buflen, (char *)page_address(page));
- page_cache_release(page);
- EXIT;
- return res;
-} /* obdfs_readlink */
-
-static int obdfs_follow_link(struct dentry * dentry,
- struct nameidata *nd)
-{
- struct page *page = NULL;
- int res;
-
- ENTRY;
- page = obdfs_getpage(dentry->d_inode, 0, 0, 0);
- if (!page) {
- dput(nd->dentry);
- EXIT;
- return -EIO;
- }
- res = vfs_follow_link(nd, (char *)page_address(page));
- page_cache_release(page);
- EXIT;
- return res;
-}
-
-struct inode_operations obdfs_symlink_inode_operations = {
- readlink: obdfs_readlink,
- follow_link: obdfs_follow_link,
- setattr: obdfs_setattr
-};
+++ /dev/null
-/*
- * Copyright (C) 2001 Cluster File Systems, Inc.
- *
- * This code is issued under the GNU General Public License.
- * See the file COPYING in this distribution
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/sysctl.h>
-#include <linux/swapctl.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/ctype.h>
-#include <asm/bitops.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-#include <linux/utsname.h>
-
-
-struct ctl_table_header *obdfs_table_header = NULL;
-
-int obdfs_debug_level = 0;
-int obdfs_print_entry = 1;
-
-
-#define OBDFS_SYSCTL 1
-
-#define OBDFS_DEBUG 1 /* control debugging */
-#define OBDFS_ENTRY 2 /* control enter/leave pattern */
-#define OBDFS_TIMEOUT 3 /* timeout on upcalls to become intrble */
-#define OBDFS_HARD 4 /* mount type "hard" or "soft" */
-#define OBDFS_VARS 5
-#define OBDFS_INDEX 6
-#define OBDFS_RESET 7
-
-#define OBDFS_VARS_SLOT 2
-
-static ctl_table obdfs_table[] = {
- {OBDFS_DEBUG, "debug", &obdfs_debug_level, sizeof(int), 0644, NULL, &proc_dointvec},
- {OBDFS_ENTRY, "trace", &obdfs_print_entry, sizeof(int), 0644, NULL, &proc_dointvec},
- { 0 }
-};
-
-static ctl_table top_table[] = {
- {OBDFS_SYSCTL, "obdfs", NULL, 0, 0555, obdfs_table},
- {0}
-};
-
-void obdfs_sysctl_init (void)
-{
-
-#ifdef CONFIG_SYSCTL
- if ( !obdfs_table_header )
- obdfs_table_header = register_sysctl_table(top_table, 0);
-#endif
-}
-
-void obdfs_sysctl_clean (void)
-{
-#ifdef CONFIG_SYSCTL
- if ( obdfs_table_header )
- unregister_sysctl_table(obdfs_table_header);
- obdfs_table_header = NULL;
-#endif
-}