#define __LINUX_CLASS_OBD_H
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
#include <linux/time.h>
#include <linux/obd.h>
#include <linux/obd_class.h>
#include <linux/list.h>
+
+#define obd_unlock_page(page) do { if (PageLocked(page)) { \
+ UnlockPage(page);\
+ } else {\
+ printk("file %s, line %d: expecting locked page\n",\
+ __FILE__, __LINE__); \
+ } \
+} while(0)
+
struct obdfs_pgrq {
- struct list_head rq_plist; /* linked list of req's */
- unsigned long rq_jiffies;
- struct page *rq_page; /* page to be written */
+ struct list_head rq_plist; /* linked list of req's */
+ unsigned long rq_jiffies;
+ struct page *rq_page; /* page to be written */
};
-struct list_head obdfs_super_list; /* list of all OBDFS superblocks */
+struct list_head obdfs_super_list; /* list of all OBDFS superblocks */
struct obdfs_sb_info {
- struct list_head osi_list; /* list of supers */
- struct obd_conn osi_conn;
- struct super_block *osi_super;
- struct obd_device *osi_obd;
- struct obd_ops *osi_ops;
- ino_t osi_rootino; /* number of root inode */
- int osi_minor; /* minor of /dev/obdX */
- struct list_head osi_inodes; /* list of dirty inodes */
- unsigned long osi_cache_count;
- struct semaphore osi_list_mutex;
+ struct list_head osi_list; /* list of supers */
+ struct obd_conn osi_conn;
+ struct super_block *osi_super;
+ struct obd_device *osi_obd;
+ struct obd_ops *osi_ops;
+ ino_t osi_rootino; /* number of root inode */
+ int osi_minor; /* minor of /dev/obdX */
+ struct list_head osi_inodes; /* list of dirty inodes */
+ unsigned long osi_cache_count;
+ struct semaphore osi_list_mutex;
};
struct obdfs_inode_info {
- int oi_flags;
- struct list_head oi_inodes;
- struct list_head oi_pages;
- char oi_inline[OBD_INLINESZ];
+ int oi_flags;
+ struct list_head oi_inodes;
+ struct list_head oi_pages;
+ char oi_inline[OBD_INLINESZ];
};
/* dir.c */
+#define EXT2_DIR_PAD 4
+#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
+ ~EXT2_DIR_ROUND)
+#define EXT2_NAME_LEN 255
+struct ext2_dir_entry_2 {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u8 name_len; /* Name length */
+ __u8 file_type;
+ char name[EXT2_NAME_LEN]; /* File name */
+};
int obdfs_check_dir_entry (const char * function, struct inode * dir,
- struct ext2_dir_entry_2 * de, struct page * page,
- unsigned long offset);
+ struct ext2_dir_entry_2 * de, struct page * page,
+ unsigned long offset);
extern struct file_operations obdfs_dir_operations;
extern struct inode_operations obdfs_dir_inode_operations;
int obdfs_flush_dirty_pages(unsigned long check_time);
/* namei.c */
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+ __u32 s_inodes_count; /* Inodes count */
+ __u32 s_blocks_count; /* Blocks count */
+ __u32 s_r_blocks_count; /* Reserved blocks count */
+ __u32 s_free_blocks_count; /* Free blocks count */
+ __u32 s_free_inodes_count; /* Free inodes count */
+ __u32 s_first_data_block; /* First Data Block */
+ __u32 s_log_block_size; /* Block size */
+ __s32 s_log_frag_size; /* Fragment size */
+ __u32 s_blocks_per_group; /* # Blocks per group */
+ __u32 s_frags_per_group; /* # Fragments per group */
+ __u32 s_inodes_per_group; /* # Inodes per group */
+ __u32 s_mtime; /* Mount time */
+ __u32 s_wtime; /* Write time */
+ __u16 s_mnt_count; /* Mount count */
+ __s16 s_max_mnt_count; /* Maximal mount count */
+ __u16 s_magic; /* Magic signature */
+ __u16 s_state; /* File system state */
+ __u16 s_errors; /* Behaviour when detecting errors */
+ __u16 s_minor_rev_level; /* minor revision level */
+ __u32 s_lastcheck; /* time of last check */
+ __u32 s_checkinterval; /* max. time between checks */
+ __u32 s_creator_os; /* OS */
+ __u32 s_rev_level; /* Revision level */
+ __u16 s_def_resuid; /* Default uid for reserved blocks */
+ __u16 s_def_resgid; /* Default gid for reserved blocks */
+ /*
+ * These fields are for EXT2_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the filesystem.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ __u32 s_first_ino; /* First non-reserved inode */
+ __u16 s_inode_size; /* size of inode structure */
+ __u16 s_block_group_nr; /* block group # of this superblock */
+ __u32 s_feature_compat; /* compatible feature set */
+ __u32 s_feature_incompat; /* incompatible feature set */
+ __u32 s_feature_ro_compat; /* readonly-compatible feature set */
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ __u32 s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT2_COMPAT_PREALLOC flag is on.
+ */
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ __u16 s_padding1;
+ __u32 s_reserved[204]; /* Padding to the end of the block */
+};
+
+#define EXT2_SB(sb) (&((sb)->u.ext2_sb))
+/*
+ * Maximal count of links to a file
+ */
+#define EXT2_LINK_MAX 32000
+/*
+ * Ext2 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+#define EXT2_FT_UNKNOWN 0
+#define EXT2_FT_REG_FILE 1
+#define EXT2_FT_DIR 2
+#define EXT2_FT_CHRDEV 3
+#define EXT2_FT_BLKDEV 4
+#define EXT2_FT_FIFO 5
+#define EXT2_FT_SOCK 6
+#define EXT2_FT_SYMLINK 7
+
+#define EXT2_FT_MAX 8
+
+#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
+#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
+
+
struct dentry *obdfs_lookup(struct inode * dir, struct dentry *dentry);
int obdfs_create (struct inode * dir, struct dentry * dentry, int mode);
int obdfs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
int obdfs_unlink(struct inode *dir, struct dentry *dentry);
int obdfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev);
int obdfs_symlink(struct inode *dir, struct dentry *dentry,
- const char *symname);
+ const char *symname);
int obdfs_link(struct dentry *old_dentry, struct inode *dir,
- struct dentry *dentry);
+ struct dentry *dentry);
int obdfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry);
+ struct inode *new_dir, struct dentry *new_dentry);
/* rw.c */
-int obdfs_do_writepage(struct inode *, struct page *, int sync);
+int obdfs_do_writepage(struct page *, int sync);
int obdfs_init_pgrqcache(void);
void obdfs_cleanup_pgrqcache(void);
inline void obdfs_pgrq_del(struct obdfs_pgrq *pgrq);
-int obdfs_readpage(struct dentry *dentry, struct page *page);
-int obdfs_writepage(struct dentry *dentry, struct page *page);
+int obdfs_readpage(struct file *file, struct page *page);
+int obdfs_writepage(struct page *page);
struct page *obdfs_getpage(struct inode *inode, unsigned long offset,
- int create, int locked);
+ int create, int locked);
int obdfs_write_one_page(struct file *file, struct page *page,
- unsigned long offset, unsigned long bytes,
- const char * buf);
+ unsigned long offset, unsigned long bytes,
+ const char * buf);
int obdfs_do_vec_wr(struct inode **inodes, obd_count num_io, obd_count num_oa,
- struct obdo **obdos, obd_count *oa_bufs,
- struct page **pages, char **bufs, obd_size *counts,
- obd_off *offsets, obd_flag *flags);
+ struct obdo **obdos, obd_count *oa_bufs,
+ struct page **pages, char **bufs, obd_size *counts,
+ obd_off *offsets, obd_flag *flags);
void obdfs_truncate(struct inode *inode);
/* super.c */
static inline struct obdfs_inode_info *obdfs_i2info(struct inode *inode)
{
- return (struct obdfs_inode_info *)&(inode->u.generic_ip);
+ return (struct obdfs_inode_info *)&(inode->u.generic_ip);
}
static inline struct obdfs_sb_info *obdfs_i2sbi(struct inode *inode)
{
- return (struct obdfs_sb_info *) &(inode->i_sb->u.generic_sbp);
+ return (struct obdfs_sb_info *) &(inode->i_sb->u.generic_sbp);
}
static inline struct list_head *obdfs_iplist(struct inode *inode)
{
- struct obdfs_inode_info *info = obdfs_i2info(inode);
+ struct obdfs_inode_info *info = obdfs_i2info(inode);
- return &info->oi_pages;
+ return &info->oi_pages;
}
static inline struct list_head *obdfs_islist(struct inode *inode)
{
- struct obdfs_inode_info *info = obdfs_i2info(inode);
+ struct obdfs_inode_info *info = obdfs_i2info(inode);
- return &info->oi_inodes;
+ return &info->oi_inodes;
}
static inline struct list_head *obdfs_slist(struct inode *inode)
{
- struct obdfs_sb_info *sbi = obdfs_i2sbi(inode);
+ struct obdfs_sb_info *sbi = obdfs_i2sbi(inode);
- return &sbi->osi_inodes;
+ return &sbi->osi_inodes;
}
-#define obd_down(mutex) { \
- /* CDEBUG(D_INFO, "get lock\n"); */ \
- obdfs_mutex_start = jiffies; \
- down(mutex); \
- if (jiffies - obdfs_mutex_start) \
- CDEBUG(D_CACHE, "waited on mutex %ld jiffies\n", \
- jiffies - obdfs_mutex_start); \
+#define obd_down(mutex) { \
+ /* CDEBUG(D_INFO, "get lock\n"); */ \
+ obdfs_mutex_start = jiffies; \
+ down(mutex); \
+ if (jiffies - obdfs_mutex_start) \
+ CDEBUG(D_CACHE, "waited on mutex %ld jiffies\n", \
+ jiffies - obdfs_mutex_start); \
}
-#define obd_up(mutex) { \
- up(mutex); \
- if (jiffies - obdfs_mutex_start > 1) \
- CDEBUG(D_CACHE, "held mutex for %ld jiffies\n", \
- jiffies - obdfs_mutex_start); \
- /* CDEBUG(D_INFO, "free lock\n"); */ \
+#define obd_up(mutex) { \
+ up(mutex); \
+ if (jiffies - obdfs_mutex_start > 1) \
+ CDEBUG(D_CACHE, "held mutex for %ld jiffies\n", \
+ jiffies - obdfs_mutex_start); \
+ /* CDEBUG(D_INFO, "free lock\n"); */ \
}
/* We track if a page has been added to the OBD page cache by stting a
* used for a while.
*/
#define PG_obdcache 29
-#define OBDAddCachePage(page) test_and_set_bit(PG_obdcache, &(page)->flags)
-#define OBDClearCachePage(page) clear_bit(PG_obdcache, &(page)->flags)
+#define OBDAddCachePage(page) test_and_set_bit(PG_obdcache, &(page)->flags)
+#define OBDClearCachePage(page) clear_bit(PG_obdcache, &(page)->flags)
static inline void obdfs_print_plist(struct inode *inode)
{
- struct list_head *page_list = obdfs_iplist(inode);
- struct list_head *tmp;
-
- CDEBUG(D_INFO, "inode %ld: page", inode->i_ino);
- /* obd_down(&obdfs_i2sbi(inode)->osi_list_mutex); */
- if (list_empty(page_list)) {
- CDEBUG(D_INFO, " list empty\n");
- obd_up(&obdfs_i2sbi(inode)->osi_list_mutex);
- return;
- }
-
- tmp = page_list;
- while ( (tmp = tmp->next) != page_list) {
- struct obdfs_pgrq *pgrq;
- pgrq = list_entry(tmp, struct obdfs_pgrq, rq_plist);
- CDEBUG(D_INFO, " %p", pgrq->rq_page);
- }
- CDEBUG(D_INFO, "\n");
- /* obd_up(&obdfs_i2sbi(inode)->osi_list_mutex); */
+ struct list_head *page_list = obdfs_iplist(inode);
+ struct list_head *tmp;
+
+ CDEBUG(D_INFO, "inode %ld: page", inode->i_ino);
+ /* obd_down(&obdfs_i2sbi(inode)->osi_list_mutex); */
+ if (list_empty(page_list)) {
+ CDEBUG(D_INFO, " list empty\n");
+ obd_up(&obdfs_i2sbi(inode)->osi_list_mutex);
+ return;
+ }
+
+ tmp = page_list;
+ while ( (tmp = tmp->next) != page_list) {
+ struct obdfs_pgrq *pgrq;
+ pgrq = list_entry(tmp, struct obdfs_pgrq, rq_plist);
+ CDEBUG(D_INFO, " %p", pgrq->rq_page);
+ }
+ CDEBUG(D_INFO, "\n");
+ /* obd_up(&obdfs_i2sbi(inode)->osi_list_mutex); */
}
static inline int obdfs_has_inline(struct inode *inode)
{
- return (obdfs_i2info(inode)->oi_flags & OBD_FL_INLINEDATA);
+ return (obdfs_i2info(inode)->oi_flags & OBD_FL_INLINEDATA);
}
static void inline obdfs_from_inode(struct obdo *oa, struct inode *inode)
{
- struct obdfs_inode_info *oinfo = obdfs_i2info(inode);
-
- CDEBUG(D_INFO, "src inode %ld, dst obdo %ld valid 0x%08x\n",
- inode->i_ino, (long)oa->o_id, oa->o_valid);
- obdo_from_inode(oa, inode);
- if (obdfs_has_inline(inode)) {
- CDEBUG(D_INODE, "copying inline data from inode to obdo\n");
- memcpy(oa->o_inline, oinfo->oi_inline, OBD_INLINESZ);
- oa->o_obdflags |= OBD_FL_INLINEDATA;
- oa->o_valid |= OBD_MD_FLINLINE;
- }
+ struct obdfs_inode_info *oinfo = obdfs_i2info(inode);
+
+ CDEBUG(D_INFO, "src inode %ld, dst obdo %ld valid 0x%08x\n",
+ inode->i_ino, (long)oa->o_id, oa->o_valid);
+ obdo_from_inode(oa, inode);
+ if (obdfs_has_inline(inode)) {
+ CDEBUG(D_INODE, "copying inline data from inode to obdo\n");
+ memcpy(oa->o_inline, oinfo->oi_inline, OBD_INLINESZ);
+ oa->o_obdflags |= OBD_FL_INLINEDATA;
+ oa->o_valid |= OBD_MD_FLINLINE;
+ }
} /* obdfs_from_inode */
static void inline obdfs_to_inode(struct inode *inode, struct obdo *oa)
{
- struct obdfs_inode_info *oinfo = obdfs_i2info(inode);
+ struct obdfs_inode_info *oinfo = obdfs_i2info(inode);
- CDEBUG(D_INFO, "src obdo %ld valid 0x%08x, dst inode %ld\n",
- (long)oa->o_id, oa->o_valid, inode->i_ino);
+ CDEBUG(D_INFO, "src obdo %ld valid 0x%08x, dst inode %ld\n",
+ (long)oa->o_id, oa->o_valid, inode->i_ino);
- obdo_to_inode(inode, oa);
+ obdo_to_inode(inode, oa);
- if (obdo_has_inline(oa)) {
- CDEBUG(D_INODE, "copying inline data from obdo to inode\n");
- memcpy(oinfo->oi_inline, oa->o_inline, OBD_INLINESZ);
- oinfo->oi_flags |= OBD_FL_INLINEDATA;
- }
+ if (obdo_has_inline(oa)) {
+ CDEBUG(D_INODE, "copying inline data from obdo to inode\n");
+ memcpy(oinfo->oi_inline, oa->o_inline, OBD_INLINESZ);
+ oinfo->oi_flags |= OBD_FL_INLINEDATA;
+ }
} /* obdfs_to_inode */
#define NOLOCK 0
dst->o_size = src->o_size;
dst->o_blocks = src->o_blocks;
dst->o_valid |= (OBD_MD_FLSIZE | OBD_MD_FLBLOCKS);
- UnlockPage(page);
+ obd_unlock_page(page);
__free_page(page);
EXIT;
# this may be different on other architectures
# we use 32-bit integers for all 64-bit quantities in this program
-# #define OBD_INLINESZ 60
-# #define OBD_OBDMDSZ 60
+# #define OBD_INLINESZ 60
+# #define OBD_OBDMDSZ 60
# /* Note: 64-bit types are 64-bit aligned in structure */
# struct obdo {
-# obd_id o_id;
-# obd_gr o_gr;
-# obd_time o_atime;
-# obd_time o_mtime;
-# obd_time o_ctime;
-# obd_size o_size;
-# obd_blocks o_blocks;
-# obd_blksize o_blksize;
-# obd_mode o_mode;
-# obd_uid o_uid;
-# obd_gid o_gid;
-# obd_flag o_flags;
-# obd_flag o_obdflags;
-# obd_count o_nlink;
-# obd_count o_generation;
-# obd_flag o_valid; /* hot fields in this obdo */
-# char o_inline[60];
-# char o_obdmd[60];
-# struct list_head o_list;
-# struct obd_ops *o_op;
+# obd_id o_id;
+# obd_gr o_gr;
+# obd_time o_atime;
+# obd_time o_mtime;
+# obd_time o_ctime;
+# obd_size o_size;
+# obd_blocks o_blocks;
+# obd_blksize o_blksize;
+# obd_mode o_mode;
+# obd_uid o_uid;
+# obd_gid o_gid;
+# obd_flag o_flags;
+# obd_flag o_obdflags;
+# obd_count o_nlink;
+# obd_count o_generation;
+# obd_flag o_valid; /* hot fields in this obdo */
+# char o_inline[60];
+# char o_obdmd[60];
+# struct list_head o_list;
+# struct obd_ops *o_op;
# };
sub obdo_pack {
$obdo->{gid},
$obdo->{flags},
$obdo->{obdflags},
- $obdo->{nlink},
- $obdo->{generation},
- $obdo->{valid},
+ $obdo->{nlink},
+ $obdo->{generation},
+ $obdo->{valid},
$obdo->{inline},
$obdo->{obdmd},
0, 0, # struct list_head
);
#
-# setup completion function
+# setup completion function
#
my @jcm_cmd_list = keys %commands;
sub readl {
if ( $file ) {
- my $str = <STDIN>;
- chop($str);
- return $str;
+ my $str = <STDIN>;
+ chop($str);
+ return $str;
} else {
return $term->readline(@_);
}
$term = new Term::ReadLine 'obdcontrol ';
$attribs = $term->Attribs;
$attribs->{attempted_completion_function} = \&completeme;
- $term->ornaments('md,me,,'); # bold face prompt
+ $term->ornaments('md,me,,'); # bold face prompt
# make sure stdout is not buffered
STDOUT->autoflush(1);
sub completeme {
my ($text, $line, $start, $end) = @_;
if (substr($line, 0, $start) =~ /^\s*$/) {
- $attribs->{completion_word} = \@jcm_cmd_list;
- return $term->completion_matches($text,
- $attribs->{'list_completion_function'});
+ $attribs->{completion_word} = \@jcm_cmd_list;
+ return $term->completion_matches($text,
+ $attribs->{'list_completion_function'});
}
}
my $name;
my @completions = completeme($given, $given, 0, length($given));
if ($#completions == 0) {
- $name = shift @completions;
+ $name = shift @completions;
}
return $name;
my $cmd;
if ( $file ) {
- $cmd = $word;
+ $cmd = $word;
} else {
- $cmd = find_command($word);
+ $cmd = find_command($word);
}
unless ($cmd) {
- printf STDERR "$word: No such command, or not unique.\n";
- return (-1);
+ printf STDERR "$word: No such command, or not unique.\n";
+ return (-1);
}
if ($cmd eq "help" || $cmd eq "exit" || $cmd eq "quit") {
- return (&{$commands{$cmd}->{func}}(@cmdline));
+ return (&{$commands{$cmd}->{func}}(@cmdline));
}
# Call the function.
my $device = shift;
if ($::client_id) {
- print "Disconnecting active session ($::client_id)...";
- Disconnect($::client_id);
+ print "Disconnecting active session ($::client_id)...";
+ Disconnect($::client_id);
}
if (! $device ) {
- $device = "/dev/obd0";
+ $device = "/dev/obd0";
}
$::device = $device;
# Open the device, as we need an FD for the ioctl
my $datalen = 0;
if ( ! $type ) {
- print "error: missing type\n";
+ print "error: missing type\n";
usage:
- print "usage: attach {obdext2 | obdsnap | obdscsi}\n";
- return;
+ print "usage: attach {obdext2 | obdsnap | obdscsi}\n";
+ return;
}
if ($type eq "obdscsi" ) {
- my $adapter = shift;
- my $bus = shift;
- my $tid = shift;
- my $lun = shift;
+ my $adapter = shift;
+ my $bus = shift;
+ my $tid = shift;
+ my $lun = shift;
- $data = pack("iiii", $adapter, $bus, $tid, $lun);
- $datalen = 4 * 4;
+ $data = pack("iiii", $adapter, $bus, $tid, $lun);
+ $datalen = 4 * 4;
} elsif ($type eq "obdsnap" ) {
- my $snapdev = shift;
- my $snapidx = shift;
- my $tableno = shift;
+ my $snapdev = shift;
+ my $snapidx = shift;
+ my $tableno = shift;
- $data = pack("iii", $snapdev, $snapidx, $tableno);
- $datalen = 3 * 4;
+ $data = pack("iii", $snapdev, $snapidx, $tableno);
+ $datalen = 3 * 4;
} elsif ($type eq "obdext2") {
- $data = pack("i", 4711); # bogus data
- $datalen = 0;
+ $data = pack("i", 4711); # bogus data
+ $datalen = 0;
} else {
- print "error: unknown attach type $type\n";
- goto usage;
+ print "error: unknown attach type $type\n";
+ goto usage;
}
my $len = length($type);
my $rc = ioctl(DEV_OBD, &OBD_IOC_ATTACH, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
my $rc = ioctl(DEV_OBD, &OBD_IOC_DETACH, $data);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
sub TestExt2Iterator {
if (!defined($::client_id)) {
- print "You must first ``connect''.\n";
- return;
+ print "You must first ``connect''.\n";
+ return;
}
my $err = 0;
my $rc = ioctl(DEV_OBD, &OBD_EXT2_RUNIT, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
sub SnapDelete {
if (!defined($::client_id)) {
- print "You must first ``connect''.\n";
- return;
+ print "You must first ``connect''.\n";
+ return;
}
my $err = 0;
my $rc = ioctl(DEV_OBD, &OBD_SNAP_DELETE, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
# don't do anything until connected
if (!defined($::client_id)) {
- print "You must first ``connect''.\n";
- return;
+ print "You must first ``connect''.\n";
+ return;
}
if ( ! $snaptable || ! defined $restoreto ) {
- print "Usage: snaprestore \"restore to slot\" \"snaptable\" \"tableno\"\n";
- return;
+ print "Usage: snaprestore \"restore to slot\" \"snaptable\" \"tableno\"\n";
+ return;
}
if ( ! -f $snaptable ) {
- print "Table $snaptable doesn't exist\n";
- return;
+ print "Table $snaptable doesn't exist\n";
+ return;
}
my $table = ReadSnapShotTable($snaptable);
$restoretime = FindSnapInTable($table, $restoreto);
if ( ! defined $table->{0} || ! defined $restoretime ) {
- PrintSnapShotTable($table);
- print "No current or $restoreto slot in this table\n";
- return;
+ PrintSnapShotTable($table);
+ print "No current or $restoreto slot in this table\n";
+ return;
}
my $currentindex = $table->{0};
if ( $table->{$restoretime} == $currentindex ) {
- print "You should not restore to the current snapshot\n";
- return;
+ print "You should not restore to the current snapshot\n";
+ return;
}
# swap the entries for 0 and $restoreto
my $rc = ioctl(DEV_OBD, &OBD_SNAP_RESTORE, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Snaprestore finished (success)\n";
- delete $table->{$restoretime} if defined $restoretime;
- # write it back
- WriteSnapShotTable($snaptable, $table);
-
- # set it in the kernel
- SnapSetTable($tableno, $snaptable);
- # PrintSnapShotTable($table);
+ print "Snaprestore finished (success)\n";
+ delete $table->{$restoretime} if defined $restoretime;
+ # write it back
+ WriteSnapShotTable($snaptable, $table);
+
+ # set it in the kernel
+ SnapSetTable($tableno, $snaptable);
+ # PrintSnapShotTable($table);
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
my $snapno =shift;
foreach my $restoretime ( keys %{$table} ) {
- if ( $table->{$restoretime} == $snapno) {
- print "Found key $restoretime for snapno $snapno\n";
- return $restoretime;
- }
+ if ( $table->{$restoretime} == $snapno) {
+ print "Found key $restoretime for snapno $snapno\n";
+ return $restoretime;
+ }
}
undef;
}
-
+
sub SnapPrint {
my $err = 0;
my $rc = ioctl(DEV_OBD, &OBD_SNAP_PRINTTABLE, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
my $datalen = 0;
if ( ! -f $file ) {
- print "No such file $file\n";
+ print "No such file $file\n";
}
$table = ReadSnapShotTable($file);
print "Snapcount $snapcount\n";
if ( ! defined $table->{0} ) {
- print "No current snapshot in table! First make one\n";
- return ;
+ print "No current snapshot in table! First make one\n";
+ return ;
}
$data = pack("ii", $snaptableno, $snapcount);
$datalen = 2 * 4;
foreach my $time (sort keys %{$table}) {
- # XXX we should change to pack LL instead of I for times
- $data .= pack("Ii", $time, $table->{$time});
- $datalen += 8;
+ # XXX we should change to pack LL instead of I for times
+ $data .= pack("Ii", $time, $table->{$time});
+ $datalen += 8;
}
my $len = length($type);
my $rc = ioctl(DEV_OBD, &OBD_SNAP_SETTABLE, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
my $file = &readl("enter file name: ");
if ( ! -f $file ) {
- `touch $file`;
+ `touch $file`;
}
my $table = ReadSnapShotTable($file);
my $time = &readl("enter time or 'now' or 'current': ");
my $oldtime = SnapFindTimeFromIdx($idx, $table);
if (defined $oldtime) {
- print "This already exists, first clean up\n";
- goto again;
+ print "This already exists, first clean up\n";
+ goto again;
}
if ( $time eq 'now' ) {
- $time = time;
+ $time = time;
} elsif ( $time eq 'current' ) {
- $time = 0;
+ $time = 0;
}
$table->{$time} = $idx;
goto again;
done:
my $ok = &readl("OK with new table? [Yn]: ");
unless ( $ok eq "n" ) {
- WriteSnapShotTable($file, $table);
+ WriteSnapShotTable($file, $table);
}
}
my $table = shift;
foreach my $time ( keys %{$table} ) {
- if ( $table->{$time} == $idx ) {
- return $time;
- }
+ if ( $table->{$time} == $idx ) {
+ return $time;
+ }
}
undef;
}
my $time;
foreach $time ( sort keys %{$table} ) {
- my $stime = localtime($time);
- if ( ! $time ) {
- $stime = "current";
- }
- printf "Time: %s -- Index %d\n", $stime, $table->{$time};
+ my $stime = localtime($time);
+ if ( ! $time ) {
+ $stime = "current";
+ }
+ printf "Time: %s -- Index %d\n", $stime, $table->{$time};
}
}
open FH, "<$file";
while ( <FH> ) {
- my ($time, $index) = split ;
- $table->{$time} = $index;
+ my ($time, $index) = split ;
+ $table->{$time} = $index;
}
close FH;
open FH, ">$file";
foreach my $time ( sort keys %{$table} ) {
- print FH "$time $table->{$time}\n";
+ print FH "$time $table->{$time}\n";
}
close FH;
}
my $rc = ioctl(DEV_OBD, &OBD_IOC_COPY, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
my $rc = ioctl(DEV_OBD, &OBD_IOC_MIGR, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
my $rc = ioctl(DEV_OBD, &OBD_IOC_FORMATOBD, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
my $rc = ioctl(DEV_OBD, &OBD_IOC_PARTITION, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
# by type here
if ($arg && !defined($::st = stat($arg))) {
- print "$dev is not a valid device\n";
- return;
+ print "$dev is not a valid device\n";
+ return;
}
if ( $arg ) {
- $dev = $::st->rdev() unless $dev;
- $data = pack("i", $dev);
- $datalen = 4;
+ $dev = $::st->rdev() unless $dev;
+ $data = pack("i", $dev);
+ $datalen = 4;
}
my $packed = pack("ip", $datalen, $data);
my $rc = ioctl(DEV_OBD, &OBD_IOC_SETUP, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
my $rc = ioctl(DEV_OBD, &OBD_IOC_CLEANUP, $err);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
- $::client_id = 0;
+ print "Finished (success)\n";
+ $::client_id = 0;
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
$id = unpack("I", $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- $::client_id = $id;
- print "Client ID : $id\n";
- print "Finished (success)\n";
+ $::client_id = $id;
+ print "Client ID : $id\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
my $id = shift;
if (!defined($id)) {
- $id = $::client_id;
+ $id = $::client_id;
}
if (!defined($id)) {
- print "syntax: disconnect [client ID]\n";
- print "When client ID is not given, the last valid client ID to be returned by a\n";
- print "connect command this session is used; there is no such ID.\n";
- return;
+ print "syntax: disconnect [client ID]\n";
+ print "When client ID is not given, the last valid client ID to be returned by a\n";
+ print "connect command this session is used; there is no such ID.\n";
+ return;
}
my $packed = pack("L", $id);
my $rc = ioctl(DEV_OBD, &OBD_IOC_DISCONNECT, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- $::client_id = undef;
- print "Finished (success)\n";
+ $::client_id = undef;
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
sub Create {
if (!defined($::client_id)) {
- print "You must first ``connect''.\n";
- return;
+ print "You must first ``connect''.\n";
+ return;
}
my $num = shift;
}
if (!defined($mode)) {
- $mode = 0100644; # create a file (rw-r--r--) if not specified
+ $mode = 0100644; # create a file (rw-r--r--) if not specified
}
if (scalar($num) < 1 || defined($quiet) && $quiet ne "quiet") {
- print "usage: create [<number of objects> [<mode> [quiet]]]\n";
- return;
+ print "usage: create [<number of objects> [<mode> [quiet]]]\n";
+ return;
}
my $i;
- my $id = 0; # can't currently request IDs
+ my $id = 0; # can't currently request IDs
print "Creating " . scalar($num) . " object";
if (scalar($num) > 1) {
- print "s";
+ print "s";
}
print "\n";
for ($i = 0; $i < scalar($num); $i++) {
- my $obdo;
- $obdo->{id} = $id;
- $obdo->{mode} = scalar($mode);
- $obdo->{valid} = &OBD_MD_FLMODE;
+ my $obdo;
+ $obdo->{id} = $id;
+ $obdo->{mode} = scalar($mode);
+ $obdo->{valid} = &OBD_MD_FLMODE;
- my $packed = pack("I", $::client_id) . obdo_pack($obdo);
- $rc = ioctl(DEV_OBD, &OBD_IOC_CREATE, $packed);
- if ($rc ne "0 but true") {
- last;
- } elsif (!defined($quiet)) {
- $obdo = obdo_unpack($packed, 4);
- print "Created object #$obdo->{id}.\n";
- }
+ my $packed = pack("I", $::client_id) . obdo_pack($obdo);
+ $rc = ioctl(DEV_OBD, &OBD_IOC_CREATE, $packed);
+ if ($rc ne "0 but true") {
+ last;
+ } elsif (!defined($quiet)) {
+ $obdo = obdo_unpack($packed, 4);
+ print "Created object #$obdo->{id}.\n";
+ }
}
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
my $rc = ioctl(DEV_OBD, &OBD_IOC_SYNC, $err);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
sub Destroy {
if (!defined($::client_id)) {
- print "You must first ``connect''.\n";
- return;
+ print "You must first ``connect''.\n";
+ return;
}
my $id = shift;
if (!defined($id) || scalar($id) < 1) {
- print "usage: destroy <object number>\n";
- return;
+ print "usage: destroy <object number>\n";
+ return;
}
print "Destroying object $id...\n";
my $rc = ioctl(DEV_OBD, &OBD_IOC_DESTROY, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
sub Getattr {
if (!defined($::client_id)) {
- print "You must first ``connect''.\n";
- return;
+ print "You must first ``connect''.\n";
+ return;
}
my $id = shift;
if (!defined($id) || scalar($id) < 1) {
- print "invalid arguments; type \"help getattr\" for a synopsis\n";
- return;
+ print "invalid arguments; type \"help getattr\" for a synopsis\n";
+ return;
}
# see Setattr
my $rc = ioctl(DEV_OBD, &OBD_IOC_GETATTR, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- $obdo = obdo_unpack($packed, 4);
- obdo_print($obdo);
+ $obdo = obdo_unpack($packed, 4);
+ obdo_print($obdo);
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
sub Setattr {
if (!defined($::client_id)) {
- print "You must first ``connect''.\n";
- return;
+ print "You must first ``connect''.\n";
+ return;
}
my $id = shift;
if (!defined($id) || scalar($id) < 1) {
- print "invalid arguments; type \"help setattr\" for a synopsis\n";
- return;
+ print "invalid arguments; type \"help setattr\" for a synopsis\n";
+ return;
}
# XXX we do not currently set all of the fields in the obdo
$obdo->{valid} = 0;
if (defined($obdo->{atime})) {
- $obdo->{valid} |= &OBD_MD_FLATIME;
+ $obdo->{valid} |= &OBD_MD_FLATIME;
}
if (defined($obdo->{mtime})) {
- $obdo->{valid} |= &OBD_MD_FLMTIME;
+ $obdo->{valid} |= &OBD_MD_FLMTIME;
}
if (defined($obdo->{ctime})) {
- $obdo->{valid} |= &OBD_MD_FLCTIME;
+ $obdo->{valid} |= &OBD_MD_FLCTIME;
}
if (defined($obdo->{size})) {
- $obdo->{valid} |= &OBD_MD_FLSIZE;
+ $obdo->{valid} |= &OBD_MD_FLSIZE;
}
if (defined($obdo->{mode})) {
- $obdo->{valid} |= &OBD_MD_FLMODE;
+ $obdo->{valid} |= &OBD_MD_FLMODE;
}
if (defined($obdo->{uid})) {
- $obdo->{valid} |= &OBD_MD_FLUID;
+ $obdo->{valid} |= &OBD_MD_FLUID;
}
if (defined($obdo->{gid})) {
- $obdo->{valid} |= &OBD_MD_FLGID;
+ $obdo->{valid} |= &OBD_MD_FLGID;
}
printf "valid is %x, mode is %o\n", $obdo->{valid}, $obdo->{mode};
my $rc = ioctl(DEV_OBD, &OBD_IOC_SETATTR, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
sub Read {
if (!defined($::client_id)) {
- print "You must first ``connect''.\n";
- return;
+ print "You must first ``connect''.\n";
+ return;
}
my $id = shift;
my $offset = shift;
if (!defined($id) || scalar($id) < 1 || !defined($count) ||
- $count < 1 || (defined($offset) && $offset < 0)) {
- print "invalid arguments; type \"help read\" for a synopsis\n";
- return;
+ $count < 1 || (defined($offset) && $offset < 0)) {
+ print "invalid arguments; type \"help read\" for a synopsis\n";
+ return;
}
if (!defined($offset)) {
- $offset = 0;
+ $offset = 0;
}
print("Reading $count bytes starting at byte $offset from object " .
- "$id...\n");
+ "$id...\n");
# "allocate" a large enough buffer
my $buf = sprintf("%${count}s", " ");
# the perl we're using doesn't support pack type Q, and offset is 64 bits
my $packed = pack("L", $::client_id) . obdo_pack($obdo) .
- pack("p LL LL", $buf, $count, $offset);
+ pack("p LL LL", $buf, $count, $offset);
my $rc = ioctl(DEV_OBD, &OBD_IOC_READ, $packed);
$retval = unpack("l", $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- if ($retval >= 0) {
- print substr($buf, 0, $retval);
- print "\nRead $retval of an attempted $count bytes.\n";
- print "Finished (success)\n";
- } else {
- print "Finished (error $retval)\n";
- }
+ if ($retval >= 0) {
+ print substr($buf, 0, $retval);
+ print "\nRead $retval of an attempted $count bytes.\n";
+ print "Finished (success)\n";
+ } else {
+ print "Finished (error $retval)\n";
+ }
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
sub Read2 {
if (!defined($::client_id)) {
- print "You must first ``connect''.\n";
- return;
+ print "You must first ``connect''.\n";
+ return;
}
my $id = shift;
my $offset = shift;
if (!defined($id) || scalar($id) < 1 || !defined($count) ||
- $count < 1 || (defined($offset) && $offset < 0)) {
- print "invalid arguments; type \"help read\" for a synopsis\n";
- return;
+ $count < 1 || (defined($offset) && $offset < 0)) {
+ print "invalid arguments; type \"help read\" for a synopsis\n";
+ return;
}
if (!defined($offset)) {
- $offset = 0;
+ $offset = 0;
}
print("Reading $count bytes starting at byte $offset from object " .
- "$id...\n");
+ "$id...\n");
# "allocate" a large enough buffer
my $buf = sprintf("%${count}s", " ");
# the perl we're using doesn't support pack type Q, and offset is 64 bits
my $packed = pack("L", $::client_id) . obdo_pack($obdo) .
- pack("p LL LL", $buf, $count, $offset);
+ pack("p LL LL", $buf, $count, $offset);
my $rc = ioctl(DEV_OBD, &OBD_IOC_READ2, $packed);
$retval = unpack("l", $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- if ($retval >= 0) {
- print substr($buf, 0, $retval);
- print "\nRead $retval of an attempted $count bytes.\n";
- print "Finished (success)\n";
- } else {
- print "Finished (error $retval)\n";
- }
+ if ($retval >= 0) {
+ print substr($buf, 0, $retval);
+ print "\nRead $retval of an attempted $count bytes.\n";
+ print "Finished (success)\n";
+ } else {
+ print "Finished (error $retval)\n";
+ }
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
sub Write {
if (!defined($::client_id)) {
- print "You must first ``connect''.\n";
- return;
+ print "You must first ``connect''.\n";
+ return;
}
my $id = shift;
my $count = length($text);
if (!defined($id) || scalar($id) < 1 || !defined($offset) ||
- scalar($offset) < 0) {
- print "invalid arguments; type \"help write\" for a synopsis\n";
- return;
+ scalar($offset) < 0) {
+ print "invalid arguments; type \"help write\" for a synopsis\n";
+ return;
}
if (!defined($text)) {
- $text = "";
- $count = 0;
+ $text = "";
+ $count = 0;
}
print("Writing $count bytes starting at byte $offset to object $id...\n");
# the perl we're using doesn't support pack type Q
my $packed = pack("L", $::client_id) . obdo_pack($obdo) .
- pack("p LL LL", $buf, $count, $offset);
+ pack("p LL LL", $text, $count, $offset);
my $rc = ioctl(DEV_OBD, &OBD_IOC_WRITE, $packed);
$retval = unpack("l", $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- if ($retval >= 0) {
- print "\nWrote $retval of an attempted $count bytes.\n";
- print "Finished (success)\n";
- } else {
- print "Finished (error $retval)\n";
- }
+ if ($retval >= 0) {
+ print "\nWrote $retval of an attempted $count bytes.\n";
+ print "Finished (success)\n";
+ } else {
+ print "Finished (error $retval)\n";
+ }
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
sub Punch {
if (!defined($::client_id)) {
- print "You must first ``connect''.\n";
- return;
+ print "You must first ``connect''.\n";
+ return;
}
my $id = shift;
my $count = shift;
if (!defined($id) || scalar($id) < 1 || !defined($start) ||
- scalar($start) < 0 || !defined($count) || scalar($count) < 0) {
- print "invalid arguments; type \"help punch\" for a synopsis\n";
- return;
+ scalar($start) < 0 || !defined($count) || scalar($count) < 0) {
+ print "invalid arguments; type \"help punch\" for a synopsis\n";
+ return;
}
print("Punching $count bytes starting at byte $start from object $id...\n");
# the perl we're using doesn't support pack type Q
my $packed = pack("L", $::client_id) . obdo_pack($obdo) .
- pack("p LL LL", $buf, $start, $count);
+ pack("p LL LL", $buf, $start, $count);
my $rc = ioctl(DEV_OBD, &OBD_IOC_PUNCH, $packed);
$retval = unpack("l", $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- if ($retval >= 0) {
- print "\nPunched $retval of an attempted $count bytes.\n";
- print "Finished (success)\n";
- } else {
- print "Finished (error $retval)\n";
- }
+ if ($retval >= 0) {
+ print "\nPunched $retval of an attempted $count bytes.\n";
+ print "Finished (success)\n";
+ } else {
+ print "Finished (error $retval)\n";
+ }
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
my $num = shift;
if (!defined($::client_id)) {
- print "You must first ``connect''.\n";
- return;
+ print "You must first ``connect''.\n";
+ return;
}
if (!defined($num) || scalar($num) < 1 || scalar($num) > 32) {
- $num = 32;
+ $num = 32;
}
print "Preallocating $num objects...\n";
my $rc = ioctl(DEV_OBD, &OBD_IOC_PREALLOCATE, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- my $alloc = unpack("x4L", $packed);
- my @ids = unpack("x8L32", $packed);
- my $i;
-
- print "Got $alloc objects: ";
- foreach $i (@ids) {
- print $i . " ";
- }
- print "\nFinished (success)\n";
+ my $alloc = unpack("x4L", $packed);
+ my @ids = unpack("x8L32", $packed);
+ my $i;
+
+ print "Got $alloc objects: ";
+ foreach $i (@ids) {
+ print $i . " ";
+ }
+ print "\nFinished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
my $rc = ioctl(DEV_OBD, &OBD_IOC_DEC_USE_COUNT, 0);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- print "Finished (success)\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
sub Statfs {
if (!defined($::client_id)) {
- print "You must first ``connect''.\n";
- return;
+ print "You must first ``connect''.\n";
+ return;
}
# struct statfs {
# };
my $packed = pack("LLLLLLLIILL6", $::client_id, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, 0, 0);
my $rc = ioctl(DEV_OBD, &OBD_IOC_STATFS, $packed);
if (!defined $rc) {
- print STDERR "ioctl failed: $!\n";
+ print STDERR "ioctl failed: $!\n";
} elsif ($rc eq "0 but true") {
- # skip both the conn_id and the fs_type in the buffer
- my ($bsize, $blocks, $bfree, $bavail, $files, $ffree) =
- unpack("x4x4LLLLLL", $packed);
- print("$bsize byte blocks: $blocks, " . ($blocks - $bfree) . " used, " .
- "$bfree free ($bavail available).\n");
- print "$files files, " . ($files - $ffree) . " used, $ffree free.\n";
- print "Finished (success)\n";
+ # skip both the conn_id and the fs_type in the buffer
+ my ($bsize, $blocks, $bfree, $bavail, $files, $ffree) =
+ unpack("x4x4LLLLLL", $packed);
+ print("$bsize byte blocks: $blocks, " . ($blocks - $bfree) . " used, " .
+ "$bfree free ($bavail available).\n");
+ print "$files files, " . ($files - $ffree) . " used, $ffree free.\n";
+ print "Finished (success)\n";
} else {
- print "ioctl returned error code $rc.\n";
+ print "ioctl returned error code $rc.\n";
}
}
my $cmd = shift;
if ( !$cmd || !$commands{$cmd} ) {
- print "Comands: ", join( ' ', @jcm_cmd_list), "\n";
+ print "Comands: ", join( ' ', @jcm_cmd_list), "\n";
} else {
- print "Usage: " . $commands{$cmd}->{doc} . "\n";
+ print "Usage: " . $commands{$cmd}->{doc} . "\n";
}
}
sub Quit {
if ($::client_id) {
- print "Disconnecting active session ($::client_id)...";
- Disconnect($::client_id);
+ print "Disconnecting active session ($::client_id)...";
+ Disconnect($::client_id);
}
exit;
}
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/obdfs.h>
static ssize_t obdfs_dir_read (struct file * filp, char * buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
- return -EISDIR;
+ return -EISDIR;
}
static int obdfs_readdir(struct file *, void *, filldir_t);
struct file_operations obdfs_dir_operations = {
- NULL, /* lseek - default */
- obdfs_dir_read, /* read */
- NULL, /* write - bad */
- obdfs_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL, /* fsync */
- NULL, /* fasync */
- NULL /* lock */
+ read: obdfs_dir_read,
+ readdir: obdfs_readdir
};
struct inode_operations obdfs_dir_inode_operations = {
- &obdfs_dir_operations, /* default directory file-ops */
- obdfs_create, /* create */
- obdfs_lookup, /* lookup */
- obdfs_link, /* link */
- obdfs_unlink, /* unlink */
- obdfs_symlink, /* symlink */
- obdfs_mkdir, /* mkdir */
- obdfs_rmdir, /* rmdir */
- obdfs_mknod, /* mknod */
- obdfs_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- obdfs_readpage, /* readpage */
- obdfs_writepage, /* writepage */
- obdfs_truncate, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
+ 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,
+ truncate: obdfs_truncate
};
int obdfs_check_dir_entry (const char * function, struct inode * dir,
- struct ext2_dir_entry_2 * de,
- struct page * page,
- unsigned long offset)
+ struct ext2_dir_entry_2 * de,
+ struct page * page,
+ unsigned long offset)
{
- const char * error_msg = NULL;
- return 1;
-
- ENTRY;
- if ( !de ) {
- error_msg = "null de passed";
- return 1;
- }
-
- if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(1))
- error_msg = "rec_len is smaller than minimal";
- else if (le16_to_cpu(de->rec_len) % 4 != 0)
- error_msg = "rec_len % 4 != 0";
- else if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(de->name_len))
- error_msg = "rec_len is too small for name_len";
- else if (dir && ((char *) de - (char *)page_address(page)) + le16_to_cpu(de->rec_len) >
- dir->i_sb->s_blocksize)
- error_msg = "directory entry across blocks";
+ const char * error_msg = NULL;
+ return 1;
+
+ ENTRY;
+ if ( !de ) {
+ error_msg = "null de passed";
+ return 1;
+ }
+
+ if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(1))
+ error_msg = "rec_len is smaller than minimal";
+ else if (le16_to_cpu(de->rec_len) % 4 != 0)
+ error_msg = "rec_len % 4 != 0";
+ else if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(de->name_len))
+ error_msg = "rec_len is too small for name_len";
+ else if (dir && ((char *) de - (char *)page_address(page)) + le16_to_cpu(de->rec_len) >
+ dir->i_sb->s_blocksize)
+ error_msg = "directory entry across blocks";
#if 0 /* this one doesn't yet work for OBDFS */
- else
+ else
if (dir && le32_to_cpu(de->inode) > le32_to_cpu(dir->i_sb->u.ext2_sb.s_es->s_inodes_count))
- error_msg = "inode out of bounds";
+ error_msg = "inode out of bounds";
#endif
- if (error_msg != NULL)
- ext2_error (dir->i_sb, function, "bad entry in directory #%lu: %s - "
- "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
- dir->i_ino, error_msg, offset,
- (unsigned long) le32_to_cpu(de->inode),
- le16_to_cpu(de->rec_len), de->name_len);
- EXIT;
- return error_msg == NULL ? 1 : 0;
+ if (error_msg != NULL)
+ ext2_error (dir->i_sb, function, "bad entry in directory #%lu: %s - "
+ "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
+ dir->i_ino, error_msg, offset,
+ (unsigned long) le32_to_cpu(de->inode),
+ le16_to_cpu(de->rec_len), de->name_len);
+ EXIT;
+ return error_msg == NULL ? 1 : 0;
}
static int obdfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- int error = 0;
- unsigned long offset;
- int stored;
- struct ext2_dir_entry_2 * de;
- struct super_block * sb;
- struct page *page;
- struct inode *inode = filp->f_dentry->d_inode;
-
- ENTRY;
-
- sb = inode->i_sb;
-
- stored = 0;
- offset = filp->f_pos & (PAGE_SIZE - 1);
-
- OIDEBUG(inode);
- while (!error && !stored && filp->f_pos < inode->i_size) {
- page = obdfs_getpage(inode, filp->f_pos, 0, LOCKED);
- /* PDEBUG(page, "readdir"); */
- if (!page) {
- ext2_error (sb, "ext2_readdir",
- "directory #%lu contains a hole at offset %lu",
- inode->i_ino, (unsigned long)filp->f_pos);
- filp->f_pos += PAGE_SIZE - offset;
- continue;
- }
+ int error = 0;
+ unsigned long offset;
+ int stored;
+ struct ext2_dir_entry_2 * de;
+ struct super_block * sb;
+ struct page *page;
+ struct inode *inode = filp->f_dentry->d_inode;
+
+ ENTRY;
+
+ sb = inode->i_sb;
+
+ stored = 0;
+ offset = filp->f_pos & (PAGE_SIZE - 1);
+
+ OIDEBUG(inode);
+ while (!error && !stored && filp->f_pos < inode->i_size) {
+ page = obdfs_getpage(inode, filp->f_pos, 0, LOCKED);
+ /* PDEBUG(page, "readdir"); */
+ if (!page) {
+ ext2_error (sb, "ext2_readdir",
+ "directory #%lu contains a hole at offset %lu",
+ inode->i_ino, (unsigned long)filp->f_pos);
+ filp->f_pos += PAGE_SIZE - offset;
+ continue;
+ }
#if 0
- /* XXX need to do read ahead and support stuff below */
+ /* XXX need to do read ahead and support stuff below */
revalidate:
- /* If the dir block has changed since the last call to
- * readdir(2), then we might be pointing to an invalid
- * dirent right now. Scan from the start of the block
- * to make sure. */
- if (filp->f_version != inode->i_version) {
- for (i = 0; i < sb->s_blocksize && i < offset; ) {
- de = (struct ext2_dir_entry_2 *)
- (bh->b_data + i);
- /* It's too expensive to do a full
- * dirent test each time round this
- * loop, but we do have to test at
- * least that it is non-zero. A
- * failure will be detected in the
- * dirent test below. */
- if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(1))
- break;
- i += le16_to_cpu(de->rec_len);
- }
- offset = i;
- filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
- | offset;
- filp->f_version = inode->i_version;
- }
-#endif
- while (!error && filp->f_pos < inode->i_size
- && offset < PAGE_SIZE) {
- de = (struct ext2_dir_entry_2 *) ((char *)page_address(page) + offset);
+ /* If the dir block has changed since the last call to
+ * readdir(2), then we might be pointing to an invalid
+ * dirent right now. Scan from the start of the block
+ * to make sure. */
+ if (filp->f_version != inode->i_version) {
+ for (i = 0; i < sb->s_blocksize && i < offset; ) {
+ de = (struct ext2_dir_entry_2 *)
+ (bh->b_data + i);
+ /* It's too expensive to do a full
+ * dirent test each time round this
+ * loop, but we do have to test at
+ * least that it is non-zero. A
+ * failure will be detected in the
+ * dirent test below. */
+ if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(1))
+ break;
+ i += le16_to_cpu(de->rec_len);
+ }
+ offset = i;
+ filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
+ | offset;
+ filp->f_version = inode->i_version;
+ }
+#endif
+ while (!error && filp->f_pos < inode->i_size
+ && offset < PAGE_SIZE) {
+ de = (struct ext2_dir_entry_2 *) ((char *)page_address(page) + offset);
#if 0
- if (!obdfs_check_dir_entry ("ext2_readdir", inode, de,
- bh, offset)) {
- /* On error, skip the f_pos to the
+ if (!obdfs_check_dir_entry ("ext2_readdir", inode, de,
+ bh, offset)) {
+ /* On error, skip the f_pos to the
next block. */
- filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1))
- + sb->s_blocksize;
- brelse (bh);
- return stored;
- }
+ filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1))
+ + sb->s_blocksize;
+ brelse (bh);
+ return stored;
+ }
#endif
- offset += le16_to_cpu(de->rec_len);
- if (le32_to_cpu(de->inode)) {
- /* We might block in the next section
- * if the data destination is
- * currently swapped out. So, use a
- * version stamp to detect whether or
- * not the directory has been modified
- * during the copy operation.
- */
- /* XXX
- unsigned long version = inode->i_version;
- */
- error = filldir(dirent, de->name,
- de->name_len,
- filp->f_pos, le32_to_cpu(de->inode));
- if (error)
- break;
+ offset += le16_to_cpu(de->rec_len);
+ if (le32_to_cpu(de->inode)) {
+ unsigned char d_type = DT_UNKNOWN;
+ /* We might block in the next section
+ * if the data destination is
+ * currently swapped out. So, use a
+ * version stamp to detect whether or
+ * not the directory has been modified
+ * during the copy operation.
+ */
+ /* XXX
+ unsigned long version = inode->i_version;
+ */
+ error = filldir
+ (dirent, de->name, de->name_len,
+ filp->f_pos, le32_to_cpu(de->inode),
+ d_type);
+ if (error)
+ break;
#if 0
- if (version != inode->i_version)
- goto revalidate;
+ if (version != inode->i_version)
+ goto revalidate;
#endif
- stored ++;
- }
- filp->f_pos += le16_to_cpu(de->rec_len);
- }
- offset = 0;
- UnlockPage(page);
- page_cache_release(page);
- }
- UPDATE_ATIME(inode);
- EXIT;
- return 0;
+ stored ++;
+ }
+ filp->f_pos += le16_to_cpu(de->rec_len);
+ }
+ offset = 0;
+ obd_unlock_page(page);
+ page_cache_release(page);
+ }
+ UPDATE_ATIME(inode);
+ EXIT;
+ return 0;
}
* ext2 fs regular file handling primitives
*
* 64-bit file support on 64-bit platforms by Jakub Jelinek
- * (jj@sunsite.ms.mff.cuni.cz)
+ * (jj@sunsite.ms.mff.cuni.cz)
*/
#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/stat.h>
static inline void remove_suid(struct inode *inode)
{
- unsigned int mode;
+ 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;
+ /* 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;
- mark_inode_dirty(inode);
- }
+ /* was any of the uid bits set? */
+ mode &= inode->i_mode;
+ if (mode && !capable(CAP_FSETID)) {
+ inode->i_mode &= ~mode;
+ mark_inode_dirty(inode);
+ }
}
/*
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, %d bytes, offset %ld\n",
- file->f_dentry->d_inode->i_ino, count, (long)*ppos);
+ ssize_t retval;
+ CDEBUG(D_INFO, "Writing inode %ld, %d bytes, offset %ld\n",
+ file->f_dentry->d_inode->i_ino, count, (long)*ppos);
- retval = generic_file_write(file, buf, count,
- ppos, obdfs_write_one_page);
- CDEBUG(D_INFO, "Wrote %d\n", retval);
- if (retval > 0) {
- struct inode *inode = file->f_dentry->d_inode;
- remove_suid(inode);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- mark_inode_dirty(inode);
- }
- EXIT;
- return retval;
+ retval = generic_file_write(file, buf, count, ppos);
+ CDEBUG(D_INFO, "Wrote %d\n", retval);
+ if (retval > 0) {
+ struct inode *inode = file->f_dentry->d_inode;
+ remove_suid(inode);
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ }
+ EXIT;
+ return retval;
}
struct file_operations obdfs_file_operations = {
- NULL, /* lseek - default */
- generic_file_read, /* read */
- obdfs_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll */
- NULL, /* ioctl */
- generic_file_mmap, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- NULL /* XXX add XXX */, /* fsync */
- NULL, /* fasync */
- NULL /* lock */
+ read: generic_file_read, /* read */
+ write: obdfs_file_write, /* write */
+ mmap: generic_file_mmap, /* mmap */
};
+extern int obdfs_notify_change(struct dentry *de, struct iattr *attr);
struct inode_operations obdfs_file_inode_operations = {
- &obdfs_file_operations, /* default directory file-ops */
- obdfs_create, /* create */
- obdfs_lookup, /* lookup */
- obdfs_link, /* link */
- obdfs_unlink, /* unlink */
- obdfs_symlink, /* symlink */
- obdfs_mkdir, /* mkdir */
- obdfs_rmdir, /* rmdir */
- obdfs_mknod, /* mknod */
- obdfs_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- obdfs_readpage, /* readpage */
- obdfs_writepage, /* writepage */
- obdfs_truncate, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
+ 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,
+ truncate: obdfs_truncate,
+ setattr: obdfs_notify_change
};
* 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
+ * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
*
* Changes for use in OBDFS
* Copyright (c) 1999, Seagate Technology Inc.
#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b))
+
+
/*
* NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
*
* `de != NULL' is guaranteed by caller.
*/
static inline int ext2_match (int len, const char * const name,
- struct ext2_dir_entry_2 * de)
+ struct ext2_dir_entry_2 * de)
{
- if (len != de->name_len)
- return 0;
- if (!de->inode)
- return 0;
- return !memcmp(name, de->name, len);
+ if (len != de->name_len)
+ return 0;
+ if (!de->inode)
+ return 0;
+ return !memcmp(name, de->name, len);
}
/*
- * obdfs_find_entry()
+ * obdfs_find_entry()
*
* finds an entry in the specified directory with the wanted name. It
* returns the cache buffer in which the entry was found, and the entry
* entry - you'll have to do that yourself if you want to.
*/
static struct page * obdfs_find_entry (struct inode * dir,
- const char * const name, int namelen,
- struct ext2_dir_entry_2 ** res_dir,
- int lock)
+ const char * const name, int namelen,
+ struct ext2_dir_entry_2 ** res_dir,
+ int lock)
{
- struct super_block * sb;
- unsigned long offset;
- struct page * page;
-
- ENTRY;
- CDEBUG(D_INFO, "find entry for %*s\n", namelen, name);
-
- *res_dir = NULL;
- sb = dir->i_sb;
-
- if (namelen > EXT2_NAME_LEN)
- return NULL;
-
- CDEBUG(D_INFO, "dirsize is %Ld\n", dir->i_size);
-
- page = 0;
- offset = 0;
- while ( offset < dir->i_size ) {
- struct ext2_dir_entry_2 * de;
- char * dlimit;
-
- page = obdfs_getpage(dir, offset, 0, lock);
-
- if ( !page ) {
- CDEBUG(D_INFO, "No page, offset %lx\n", offset);
- return NULL;
- }
-
- de = (struct ext2_dir_entry_2 *) page_address(page);
- dlimit = (char *)page_address(page) + PAGE_SIZE;
- while ((char *) de < dlimit) {
- /* this code is executed quadratically often */
- /* do minimal checking `by hand' */
- int de_len;
- /* CDEBUG(D_INFO, "Entry %p len %d, page at %#lx - %#lx , offset %lx\n",
- de, le16_to_cpu(de->rec_len), page_address(page),
- page_address(page) + PAGE_SIZE, offset); */
-
- if ((char *) de + namelen <= dlimit &&
- ext2_match (namelen, name, de)) {
- /* found a match -
- just to be sure, do a full check */
- if (!obdfs_check_dir_entry("ext2_find_entry",
- dir, de, page, offset))
- goto failure;
- *res_dir = de;
- EXIT;
- return page;
- }
- /* prevent looping on a bad block */
- de_len = le16_to_cpu(de->rec_len);
- if (de_len <= 0) {
- printk("Bad entry at %p len %d\n", de, de_len);
- goto failure;
- }
- offset += de_len;
- de = (struct ext2_dir_entry_2 *)
- ((char *) de + de_len);
- /* CDEBUG(D_INFO, "Next while %lx\n", offset); */
- }
- if ( lock )
- UnlockPage(page);
- page_cache_release(page);
- page = NULL;
- CDEBUG(D_INFO, "Next for %lx\n", offset);
- }
+ struct super_block * sb;
+ unsigned long offset;
+ struct page * page;
+
+ ENTRY;
+ CDEBUG(D_INFO, "find entry for %*s\n", namelen, name);
+
+ *res_dir = NULL;
+ sb = dir->i_sb;
+
+ if (namelen > EXT2_NAME_LEN)
+ return NULL;
+
+ CDEBUG(D_INFO, "dirsize is %Ld\n", dir->i_size);
+
+ page = 0;
+ offset = 0;
+ while ( offset < dir->i_size ) {
+ struct ext2_dir_entry_2 * de;
+ char * dlimit;
+
+ page = obdfs_getpage(dir, offset, 0, lock);
+
+ if ( !page ) {
+ CDEBUG(D_INFO, "No page, offset %lx\n", offset);
+ return NULL;
+ }
+
+ de = (struct ext2_dir_entry_2 *) page_address(page);
+ dlimit = (char *)page_address(page) + PAGE_SIZE;
+ while ((char *) de < dlimit) {
+ /* this code is executed quadratically often */
+ /* do minimal checking `by hand' */
+ int de_len;
+ /* CDEBUG(D_INFO, "Entry %p len %d, page at %#lx - %#lx , offset %lx\n",
+ de, le16_to_cpu(de->rec_len), page_address(page),
+ page_address(page) + PAGE_SIZE, offset); */
+
+ if ((char *) de + namelen <= dlimit &&
+ ext2_match (namelen, name, de)) {
+ /* found a match -
+ just to be sure, do a full check */
+ if (!obdfs_check_dir_entry("ext2_find_entry",
+ dir, de, page, offset))
+ goto failure;
+ *res_dir = de;
+ EXIT;
+ return page;
+ }
+ /* prevent looping on a bad block */
+ de_len = le16_to_cpu(de->rec_len);
+ if (de_len <= 0) {
+ printk("Bad entry at %p len %d\n", de, de_len);
+ goto failure;
+ }
+ offset += de_len;
+ de = (struct ext2_dir_entry_2 *)
+ ((char *) de + de_len);
+ /* CDEBUG(D_INFO, "Next while %lx\n", offset); */
+ }
+ obd_unlock_page(page);
+ page_cache_release(page);
+ page = NULL;
+ CDEBUG(D_INFO, "Next for %lx\n", offset);
+ }
failure:
- CDEBUG(D_INFO, "Negative case, page %p, offset %ld\n", page, offset);
- if (page) {
- if (lock)
- UnlockPage(page);
- page_cache_release(page);
- }
- EXIT;
- return NULL;
+ CDEBUG(D_INFO, "Negative case, page %p, offset %ld\n", page, offset);
+ if (page) {
+ obd_unlock_page(page);
+ page_cache_release(page);
+ }
+ EXIT;
+ return NULL;
} /* obdfs_find_entry */
struct dentry *obdfs_lookup(struct inode *dir, struct dentry *dentry)
{
- struct inode * inode;
- struct ext2_dir_entry_2 * de;
- struct page *page;
- ENTRY;
-
- if (dentry->d_name.len > EXT2_NAME_LEN)
- return ERR_PTR(-ENAMETOOLONG);
-
- page = obdfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len,
- &de, LOCKED);
- inode = NULL;
- if ( !page )
- CDEBUG(D_INFO, "No page - negative entry.\n");
- if ( page && !de ) {
- CDEBUG(D_INODE, "Danger: PAGE but de.\n");
- return ERR_PTR(-ENOENT);
- }
- if (page) {
- unsigned long ino = le32_to_cpu(de->inode);
- UnlockPage(page);
- page_cache_release(page);
- inode = iget(dir->i_sb, ino);
-
- if (!inode) {
- CDEBUG(D_INODE, "No inode.\n");
- EXIT;
- return ERR_PTR(-EACCES);
- }
- }
- d_add(dentry, inode);
- EXIT;
- return NULL;
+ struct inode * inode;
+ struct ext2_dir_entry_2 * de;
+ struct page *page;
+ ENTRY;
+
+ if (dentry->d_name.len > EXT2_NAME_LEN)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ page = obdfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len,
+ &de, LOCKED);
+ inode = NULL;
+ if ( !page )
+ CDEBUG(D_INFO, "No page - negative entry.\n");
+ if ( page && !de ) {
+ CDEBUG(D_INODE, "Danger: PAGE but de.\n");
+ return ERR_PTR(-ENOENT);
+ }
+ if (page) {
+ unsigned long ino = le32_to_cpu(de->inode);
+ page_cache_release(page);
+ obd_unlock_page(page);
+ inode = iget(dir->i_sb, ino);
+
+ if (!inode) {
+ CDEBUG(D_INODE, "No inode.\n");
+ EXIT;
+ return ERR_PTR(-EACCES);
+ }
+ }
+ d_add(dentry, inode);
+ EXIT;
+ return NULL;
} /* obdfs_lookup */
/*
- * obdfs_add_entry()
+ * obdfs_add_entry()
*
* adds a file entry to the specified directory, using the same
* semantics as ext2_find_entry(). It returns NULL if it failed.
* on the inode protects this page as well.
*/
static struct page *obdfs_add_entry (struct inode * dir,
- const char * name, int namelen,
- struct ext2_dir_entry_2 ** res_dir,
- int *err)
+ const char * name, int namelen,
+ struct ext2_dir_entry_2 ** res_dir,
+ int *err)
{
- unsigned long offset;
- unsigned short rec_len;
- struct page *page;
- struct ext2_dir_entry_2 * de, * de1;
- struct super_block * sb;
-
- ENTRY;
- *err = -EINVAL;
- *res_dir = NULL;
- if (!dir || !dir->i_nlink) {
- CDEBUG(D_INODE, "bad directory\n");
- EXIT;
- return NULL;
- }
- sb = dir->i_sb;
-
- if (!namelen) {
- CDEBUG(D_INODE, "bad directory\n");
- EXIT;
- return NULL;
- }
- /*
- * Is this a busy deleted directory? Can't create new files if so
- */
- if (dir->i_size == 0)
- {
- OIDEBUG(dir);
- *err = -ENOENT;
- EXIT;
- return NULL;
- }
- page = obdfs_getpage(dir, 0, 0, LOCKED);
- if (!page) {
- EXIT;
- return NULL;
- }
- rec_len = EXT2_DIR_REC_LEN(namelen);
- /* CDEBUG(D_INFO, "reclen: %d\n", rec_len); */
- /* PDEBUG(page, "starting search"); */
- offset = 0;
- de = (struct ext2_dir_entry_2 *) page_address(page);
- *err = -ENOSPC;
- while (1) {
- /* CDEBUG(D_INFO,
- "Entry at %p, (page at %#lx - %#lx), offset %ld\n",
- de, page_address(page), page_address(page) + PAGE_SIZE,
- offset); */
- if ((char *)de >= PAGE_SIZE + (char *)page_address(page)) {
- UnlockPage(page);
- page_cache_release(page);
- page = obdfs_getpage(dir, offset, 1, LOCKED);
- if (!page) {
- EXIT;
- return NULL;
- }
- /* PDEBUG(page, "new directory page"); */
- if (dir->i_size <= offset) {
- if (dir->i_size == 0) {
- *err = -ENOENT;
- EXIT;
- return NULL;
- }
-
- CDEBUG(D_INFO, "creating next block\n");
-
- de = (struct ext2_dir_entry_2 *) page_address(page);
- de->inode = 0;
- de->rec_len = cpu_to_le16(PAGE_SIZE);
- dir->i_size = offset + PAGE_SIZE;
- dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
- mark_inode_dirty(dir);
- } else {
-
- CDEBUG(D_INFO, "skipping to next block\n");
-
- de = (struct ext2_dir_entry_2 *) page_address(page);
- }
- }
- if (!obdfs_check_dir_entry ("ext2_add_entry", dir, de, page,
- offset)) {
- *err = -ENOENT;
- UnlockPage(page);
- page_cache_release(page);
- EXIT;
- return NULL;
- }
- CDEBUG(D_INFO, "\n");
- if (ext2_match (namelen, name, de)) {
- *err = -EEXIST;
- UnlockPage(page);
- page_cache_release(page);
- EXIT;
- return NULL;
- }
- /* CDEBUG(D_INFO, "Testing for enough space at de %p\n", de);*/
- if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) ||
- (le16_to_cpu(de->rec_len) >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
- offset += le16_to_cpu(de->rec_len);
- /* CDEBUG(D_INFO,
- "Found enough space de %p, offset %#lx\n",
- de, offset); */
- if (le32_to_cpu(de->inode)) {
- /*CDEBUG(D_INFO, "Insert new in %p\n", de);*/
- de1 = (struct ext2_dir_entry_2 *) ((char *) de +
- EXT2_DIR_REC_LEN(de->name_len));
- /*CDEBUG(D_INFO, "-- de1 at %p\n", de1);*/
- de1->rec_len = cpu_to_le16(le16_to_cpu(de->rec_len) -
- EXT2_DIR_REC_LEN(de->name_len));
- de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
- de = de1;
- }
- /* CDEBUG(D_INFO,
- "Reclen adjusted; copy %d bytes to %p, "
- "page at %#lx EOP at %#lx\n",
- namelen, de->name, page_address(page),
- page_address(page) + PAGE_SIZE); */
- de->inode = 0;
- de->name_len = namelen;
- de->file_type = 0;
- memcpy (de->name, name, namelen);
- /*
- * XXX shouldn't update any times until successful
- * completion of syscall, but too many callers depend
- * on this.
- *
- * XXX similarly, too many callers depend on
- * ext2_new_inode() setting the times, but error
- * recovery deletes the inode, so the worst that can
- * happen is that the times are slightly out of date
- * and/or different from the directory change time.
- */
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
- dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
- mark_inode_dirty(dir);
- dir->i_version = ++event;
- *res_dir = de;
- *err = 0;
- /* PDEBUG(page, "add_entry"); */
- /* XXX unlock page here */
- EXIT;
- return page;
- }
- offset += le16_to_cpu(de->rec_len);
- de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
- }
-
- UnlockPage(page);
- page_cache_release(page);
- /* PDEBUG(page, "add_entry"); */
- EXIT;
- return NULL;
+ unsigned long offset;
+ unsigned short rec_len;
+ struct page *page;
+ struct ext2_dir_entry_2 * de, * de1;
+ struct super_block * sb;
+
+ ENTRY;
+ *err = -EINVAL;
+ *res_dir = NULL;
+ if (!dir || !dir->i_nlink) {
+ CDEBUG(D_INODE, "bad directory\n");
+ EXIT;
+ return NULL;
+ }
+ sb = dir->i_sb;
+
+ if (!namelen) {
+ CDEBUG(D_INODE, "bad directory\n");
+ EXIT;
+ return NULL;
+ }
+ /*
+ * Is this a busy deleted directory? Can't create new files if so
+ */
+ if (dir->i_size == 0)
+ {
+ OIDEBUG(dir);
+ *err = -ENOENT;
+ EXIT;
+ return NULL;
+ }
+ page = obdfs_getpage(dir, 0, 0, LOCKED);
+ if (!page) {
+ EXIT;
+ return NULL;
+ }
+ rec_len = EXT2_DIR_REC_LEN(namelen);
+ /* CDEBUG(D_INFO, "reclen: %d\n", rec_len); */
+ /* PDEBUG(page, "starting search"); */
+ offset = 0;
+ de = (struct ext2_dir_entry_2 *) page_address(page);
+ *err = -ENOSPC;
+ while (1) {
+ /* CDEBUG(D_INFO,
+ "Entry at %p, (page at %#lx - %#lx), offset %ld\n",
+ de, page_address(page), page_address(page) + PAGE_SIZE,
+ offset); */
+ if ((char *)de >= PAGE_SIZE + (char *)page_address(page)) {
+ obd_unlock_page(page);
+ page_cache_release(page);
+ page = obdfs_getpage(dir, offset, 1, LOCKED);
+ if (!page) {
+ EXIT;
+ return NULL;
+ }
+ /* PDEBUG(page, "new directory page"); */
+ if (dir->i_size <= offset) {
+ if (dir->i_size == 0) {
+ *err = -ENOENT;
+ EXIT;
+ return NULL;
+ }
+
+ CDEBUG(D_INFO, "creating next block\n");
+
+ de = (struct ext2_dir_entry_2 *) page_address(page);
+ de->inode = 0;
+ de->rec_len = cpu_to_le16(PAGE_SIZE);
+ dir->i_size = offset + PAGE_SIZE;
+ dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
+ mark_inode_dirty(dir);
+ } else {
+
+ CDEBUG(D_INFO, "skipping to next block\n");
+
+ de = (struct ext2_dir_entry_2 *) page_address(page);
+ }
+ }
+ if (!obdfs_check_dir_entry ("ext2_add_entry", dir, de, page,
+ offset)) {
+ *err = -ENOENT;
+ obd_unlock_page(page);
+ page_cache_release(page);
+ EXIT;
+ return NULL;
+ }
+ CDEBUG(D_INFO, "\n");
+ if (ext2_match (namelen, name, de)) {
+ *err = -EEXIST;
+ obd_unlock_page(page);
+ page_cache_release(page);
+ EXIT;
+ return NULL;
+ }
+ /* CDEBUG(D_INFO, "Testing for enough space at de %p\n", de);*/
+ if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) ||
+ (le16_to_cpu(de->rec_len) >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
+ offset += le16_to_cpu(de->rec_len);
+ /* CDEBUG(D_INFO,
+ "Found enough space de %p, offset %#lx\n",
+ de, offset); */
+ if (le32_to_cpu(de->inode)) {
+ /*CDEBUG(D_INFO, "Insert new in %p\n", de);*/
+ de1 = (struct ext2_dir_entry_2 *) ((char *) de +
+ EXT2_DIR_REC_LEN(de->name_len));
+ /*CDEBUG(D_INFO, "-- de1 at %p\n", de1);*/
+ de1->rec_len = cpu_to_le16(le16_to_cpu(de->rec_len) -
+ EXT2_DIR_REC_LEN(de->name_len));
+ de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
+ de = de1;
+ }
+ /* CDEBUG(D_INFO,
+ "Reclen adjusted; copy %d bytes to %p, "
+ "page at %#lx EOP at %#lx\n",
+ namelen, de->name, page_address(page),
+ page_address(page) + PAGE_SIZE); */
+ de->inode = 0;
+ de->name_len = namelen;
+ de->file_type = 0;
+ memcpy (de->name, name, namelen);
+ /*
+ * XXX shouldn't update any times until successful
+ * completion of syscall, but too many callers depend
+ * on this.
+ *
+ * XXX similarly, too many callers depend on
+ * ext2_new_inode() setting the times, but error
+ * recovery deletes the inode, so the worst that can
+ * happen is that the times are slightly out of date
+ * and/or different from the directory change time.
+ */
+ dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
+ mark_inode_dirty(dir);
+ dir->i_version = ++event;
+ *res_dir = de;
+ *err = 0;
+ PDEBUG(page, "add_entry");
+ /* XXX unlock page here */
+ EXIT;
+ return page;
+ }
+ offset += le16_to_cpu(de->rec_len);
+ de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+ }
+
+ obd_unlock_page(page);
+ page_cache_release(page);
+ /* PDEBUG(page, "add_entry"); */
+ EXIT;
+ return NULL;
} /* obdfs_add_entry */
/*
* previous entry
*/
static int obdfs_delete_entry (struct ext2_dir_entry_2 * dir,
- struct page * page)
+ struct page * page)
{
- struct ext2_dir_entry_2 * de, * pde;
- int i;
-
- i = 0;
- pde = NULL;
- de = (struct ext2_dir_entry_2 *) page_address(page);
- while (i < PAGE_SIZE) {
- if (!obdfs_check_dir_entry ("ext2_delete_entry", NULL,
- de, page, i))
- return -EIO;
- if (de == dir) {
- if (pde)
- pde->rec_len =
- cpu_to_le16(le16_to_cpu(pde->rec_len) +
- le16_to_cpu(dir->rec_len));
- else
- dir->inode = 0;
- return 0;
- }
- i += le16_to_cpu(de->rec_len);
- pde = de;
- de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
- }
- return -ENOENT;
+ struct ext2_dir_entry_2 * de, * pde;
+ int i;
+
+ i = 0;
+ pde = NULL;
+ de = (struct ext2_dir_entry_2 *) page_address(page);
+ while (i < PAGE_SIZE) {
+ if (!obdfs_check_dir_entry ("ext2_delete_entry", NULL,
+ de, page, i))
+ return -EIO;
+ if (de == dir) {
+ if (pde)
+ pde->rec_len =
+ cpu_to_le16(le16_to_cpu(pde->rec_len) +
+ le16_to_cpu(dir->rec_len));
+ else
+ dir->inode = 0;
+ return 0;
+ }
+ i += le16_to_cpu(de->rec_len);
+ pde = de;
+ de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+ }
+ return -ENOENT;
} /* obdfs_delete_entry */
static inline void ext2_set_de_type(struct super_block *sb,
- struct ext2_dir_entry_2 *de,
- umode_t mode) {
- /* XXX fix this to check for obdfs feature, not ext2 feature */
- if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
- return;
- if (S_ISREG(mode))
- de->file_type = EXT2_FT_REG_FILE;
- else if (S_ISDIR(mode))
- de->file_type = EXT2_FT_DIR;
- else if (S_ISLNK(mode))
- de->file_type = EXT2_FT_SYMLINK;
- else if (S_ISSOCK(mode))
- de->file_type = EXT2_FT_SOCK;
- else if (S_ISFIFO(mode))
- de->file_type = EXT2_FT_FIFO;
- else if (S_ISCHR(mode))
- de->file_type = EXT2_FT_CHRDEV;
- else if (S_ISBLK(mode))
- de->file_type = EXT2_FT_BLKDEV;
+ struct ext2_dir_entry_2 *de,
+ umode_t mode) {
+ return;
+ /* XXX fix this to check for obdfs feature, not ext2 feature */
+ if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
+ return;
+ if (S_ISREG(mode))
+ de->file_type = EXT2_FT_REG_FILE;
+ else if (S_ISDIR(mode))
+ de->file_type = EXT2_FT_DIR;
+ else if (S_ISLNK(mode))
+ de->file_type = EXT2_FT_SYMLINK;
+ else if (S_ISSOCK(mode))
+ de->file_type = EXT2_FT_SOCK;
+ else if (S_ISFIFO(mode))
+ de->file_type = EXT2_FT_FIFO;
+ else if (S_ISCHR(mode))
+ de->file_type = EXT2_FT_CHRDEV;
+ else if (S_ISBLK(mode))
+ de->file_type = EXT2_FT_BLKDEV;
}
#if 0
static void show_dentry(struct list_head * dlist, int subdirs)
{
- struct list_head *tmp = dlist;
-
- while ((tmp = tmp->next) != dlist) {
- struct dentry * dentry;
- const char * unhashed = "";
-
- if ( subdirs )
- dentry = list_entry(tmp, struct dentry, d_child);
- else
- dentry = list_entry(tmp, struct dentry, d_alias);
-
- if (list_empty(&dentry->d_hash))
- unhashed = "(unhashed)";
-
- if ( dentry->d_inode )
- printk("show_dentry: %s/%s, d_count=%d%s (ino %ld, dev %d, ct %d)\n",
- dentry->d_parent->d_name.name,
- dentry->d_name.name, dentry->d_count,
- unhashed, dentry->d_inode->i_ino,
- dentry->d_inode->i_dev,
- dentry->d_inode->i_count);
- else
- printk("show_dentry: %s/%s, d_count=%d%s \n",
- dentry->d_parent->d_name.name,
- dentry->d_name.name, dentry->d_count,
- unhashed);
- }
+ struct list_head *tmp = dlist;
+
+ while ((tmp = tmp->next) != dlist) {
+ struct dentry * dentry;
+ const char * unhashed = "";
+
+ if ( subdirs )
+ dentry = list_entry(tmp, struct dentry, d_child);
+ else
+ dentry = list_entry(tmp, struct dentry, d_alias);
+
+ if (list_empty(&dentry->d_hash))
+ unhashed = "(unhashed)";
+
+ if ( dentry->d_inode )
+ printk("show_dentry: %s/%s, d_count=%d%s (ino %ld, dev %d, ct %d)\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name, dentry->d_count,
+ unhashed, dentry->d_inode->i_ino,
+ dentry->d_inode->i_dev,
+ dentry->d_inode->i_count);
+ else
+ printk("show_dentry: %s/%s, d_count=%d%s \n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name, dentry->d_count,
+ unhashed);
+ }
} /* show_dentry */
#endif
static struct inode *obdfs_new_inode(struct inode *dir, int mode)
{
- struct obdo *oa;
- struct inode *inode;
- int err;
-
- ENTRY;
- if (IOPS(dir, create) == NULL) {
- printk(KERN_ERR __FUNCTION__ ": no create method!\n");
- EXIT;
- return ERR_PTR(-EIO);
- }
- 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_FLMODE;
-
- err = IOPS(dir, create)(IID(dir), oa);
-
- if ( err ) {
- CDEBUG(D_INODE, "fatal: creating new inode (err %d)\n", err);
- obdo_free(oa);
- EXIT;
- return ERR_PTR(err);
- }
-
- inode = iget(dir->i_sb, (ino_t)oa->o_id);
-
- if (!inode) {
- CDEBUG(D_INODE, "fatal: get new inode %ld\n", (long)oa->o_id);
- IOPS(dir, destroy)(IID(dir), oa);
- obdo_free(oa);
- EXIT;
- return ERR_PTR(-EIO);
- }
-
- if (!list_empty(&inode->i_dentry)) {
- CDEBUG(D_INODE, "New inode (%ld) has aliases!\n", inode->i_ino);
- IOPS(dir, destroy)(IID(dir), oa);
- obdo_free(oa);
- iput(inode);
- EXIT;
- return ERR_PTR(-EIO);
- }
- obdo_free(oa);
-
- EXIT;
- return inode;
+ struct obdo *oa;
+ struct inode *inode;
+ int err;
+
+ ENTRY;
+ if (IOPS(dir, create) == NULL) {
+ printk(KERN_ERR __FUNCTION__ ": no create method!\n");
+ EXIT;
+ return ERR_PTR(-EIO);
+ }
+ 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_FLMODE;
+
+ err = IOPS(dir, create)(IID(dir), oa);
+
+ if ( err ) {
+ CDEBUG(D_INODE, "fatal: creating new inode (err %d)\n", err);
+ obdo_free(oa);
+ EXIT;
+ return ERR_PTR(err);
+ }
+
+ inode = iget(dir->i_sb, (ino_t)oa->o_id);
+
+ if (!inode) {
+ CDEBUG(D_INODE, "fatal: get new inode %ld\n", (long)oa->o_id);
+ IOPS(dir, destroy)(IID(dir), oa);
+ obdo_free(oa);
+ EXIT;
+ return ERR_PTR(-EIO);
+ }
+
+ if (!list_empty(&inode->i_dentry)) {
+ CDEBUG(D_INODE, "New inode (%ld) has aliases!\n", inode->i_ino);
+ IOPS(dir, destroy)(IID(dir), oa);
+ obdo_free(oa);
+ iput(inode);
+ EXIT;
+ return ERR_PTR(-EIO);
+ }
+ obdo_free(oa);
+
+ EXIT;
+ return inode;
} /* obdfs_new_inode */
*/
int obdfs_create (struct inode * dir, struct dentry * dentry, int mode)
{
- struct inode * inode;
- struct page *page;
- struct ext2_dir_entry_2 * de;
- int err = -EIO;
+ struct inode * inode;
+ struct page *page;
+ struct ext2_dir_entry_2 * de;
+ int err = -EIO;
ENTRY;
- inode = obdfs_new_inode(dir, mode);
- if ( IS_ERR(inode) ) {
- EXIT;
- return PTR_ERR(inode);
- }
-
- inode->i_op = &obdfs_file_inode_operations;
- mark_inode_dirty(inode);
- page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!page) {
- inode->i_nlink--;
- mark_inode_dirty(inode);
- iput (inode);
- EXIT;
- return err;
- }
- de->inode = cpu_to_le32(inode->i_ino);
- ext2_set_de_type(dir->i_sb, de, S_IFREG);
- dir->i_version = ++event;
-
- err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
- UnlockPage(page);
-
- page_cache_release(page);
- d_instantiate(dentry, inode);
- EXIT;
- return err;
+ inode = obdfs_new_inode(dir, mode);
+ if ( IS_ERR(inode) ) {
+ EXIT;
+ return PTR_ERR(inode);
+ }
+
+ inode->i_op = &obdfs_file_inode_operations;
+ mark_inode_dirty(inode);
+ page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page) {
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ iput (inode);
+ EXIT;
+ return err;
+ }
+ de->inode = cpu_to_le32(inode->i_ino);
+ ext2_set_de_type(dir->i_sb, de, S_IFREG);
+ dir->i_version = ++event;
+
+ err = obdfs_do_writepage(page, IS_SYNC(dir));
+ obd_unlock_page(page);
+ page_cache_release(page);
+ d_instantiate(dentry, inode);
+ EXIT;
+ return err;
} /* obdfs_create */
int obdfs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
- struct inode * inode;
- struct page *page;
- struct ext2_dir_entry_2 * de;
- struct obdfs_inode_info *oinfo;
- int err;
+ struct inode * inode;
+ struct page *page;
+ struct ext2_dir_entry_2 * de;
+ struct obdfs_inode_info *oinfo;
+ int err;
ENTRY;
- inode = obdfs_new_inode(dir, mode);
- if ( IS_ERR(inode) ) {
- EXIT;
- return PTR_ERR(inode);
- }
-
- inode->i_uid = current->fsuid;
- init_special_inode(inode, mode, rdev);
- oinfo = obdfs_i2info(inode);
- ((obd_count *)oinfo->oi_inline)[0] = rdev;
- oinfo->oi_flags |= OBD_FL_INLINEDATA;
-
- page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!page)
- goto out_no_entry;
- de->inode = cpu_to_le32(inode->i_ino);
- dir->i_version = ++event;
- ext2_set_de_type(dir->i_sb, de, inode->i_mode);
- mark_inode_dirty(inode);
-
- err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
- UnlockPage(page);
-
- d_instantiate(dentry, inode);
- page_cache_release(page);
- err = 0;
+ inode = obdfs_new_inode(dir, mode);
+ if ( IS_ERR(inode) ) {
+ EXIT;
+ return PTR_ERR(inode);
+ }
+
+ inode->i_uid = current->fsuid;
+ init_special_inode(inode, mode, rdev);
+ oinfo = obdfs_i2info(inode);
+ ((obd_count *)oinfo->oi_inline)[0] = rdev;
+ oinfo->oi_flags |= OBD_FL_INLINEDATA;
+
+ page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page)
+ goto out_no_entry;
+ de->inode = cpu_to_le32(inode->i_ino);
+ dir->i_version = ++event;
+ ext2_set_de_type(dir->i_sb, de, inode->i_mode);
+ mark_inode_dirty(inode);
+
+ err = obdfs_do_writepage(page, IS_SYNC(dir));
+ obd_unlock_page(page);
+
+ d_instantiate(dentry, inode);
+ page_cache_release(page);
+ err = 0;
out:
- return err;
+ return err;
out_no_entry:
- inode->i_nlink--;
- mark_inode_dirty(inode);
- iput(inode);
- goto out;
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ iput(inode);
+ goto out;
} /* obdfs_mknod */
int obdfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
- struct inode * inode;
- struct page *page, *inode_page;
- struct ext2_dir_entry_2 * de;
- int err;
-
- ENTRY;
-
- err = -EMLINK;
- if (dir->i_nlink >= EXT2_LINK_MAX)
- goto out;
-
- mode |= S_IFDIR;
- if (dir->i_mode & S_ISGID)
- mode |= S_ISGID;
-
- inode = obdfs_new_inode(dir, mode);
- if ( IS_ERR(inode) ) {
- EXIT;
- return PTR_ERR(inode);
- }
-
- inode->i_op = &obdfs_dir_inode_operations;
- inode->i_blocks = 0;
- inode_page = obdfs_getpage(inode, 0, 1, LOCKED);
- if (!inode_page) {
- inode->i_nlink--; /* is this nlink == 0? */
- mark_inode_dirty(inode);
- iput (inode);
- return -EIO;
- }
- de = (struct ext2_dir_entry_2 *) page_address(inode_page);
-
- /* create . and .. */
- de->inode = cpu_to_le32(inode->i_ino);
- de->name_len = 1;
- de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
- strcpy (de->name, ".");
- ext2_set_de_type(dir->i_sb, de, S_IFDIR);
- de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
- de->inode = cpu_to_le32(dir->i_ino);
- de->rec_len = cpu_to_le16(PAGE_SIZE - EXT2_DIR_REC_LEN(1));
- de->name_len = 2;
- strcpy (de->name, "..");
- ext2_set_de_type(dir->i_sb, de, S_IFDIR);
- inode->i_nlink = 2;
-
- err = obdfs_do_writepage(inode, inode_page, IS_SYNC(inode));
- inode->i_blocks = PAGE_SIZE/inode->i_sb->s_blocksize;
- inode->i_size = PAGE_SIZE;
- UnlockPage(inode_page);
- page_cache_release(inode_page);
- mark_inode_dirty(inode);
- if (err) {
- EXIT;
- goto out_no_entry;
- }
-
- /* now deal with the parent */
- page = obdfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!page) {
- EXIT;
- goto out_no_entry;
- }
-
- de->inode = cpu_to_le32(inode->i_ino);
- ext2_set_de_type(dir->i_sb, de, S_IFDIR);
- dir->i_version = ++event;
-
- dir->i_nlink++;
- dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
- mark_inode_dirty(dir);
- err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
-
- UnlockPage(page);
-
- page_cache_release(page);
- d_instantiate(dentry, inode);
- EXIT;
+ struct inode * inode;
+ struct page *page, *inode_page;
+ struct ext2_dir_entry_2 * de;
+ int err;
+
+ ENTRY;
+
+ err = -EMLINK;
+ if (dir->i_nlink >= EXT2_LINK_MAX)
+ goto out;
+
+ mode |= S_IFDIR;
+ if (dir->i_mode & S_ISGID)
+ mode |= S_ISGID;
+
+ inode = obdfs_new_inode(dir, mode);
+ if ( IS_ERR(inode) ) {
+ EXIT;
+ return PTR_ERR(inode);
+ }
+
+ inode->i_op = &obdfs_dir_inode_operations;
+ inode->i_blocks = 0;
+ inode_page = obdfs_getpage(inode, 0, 1, LOCKED);
+ if (!inode_page) {
+ inode->i_nlink--; /* is this nlink == 0? */
+ mark_inode_dirty(inode);
+ iput (inode);
+ return -EIO;
+ }
+ de = (struct ext2_dir_entry_2 *) page_address(inode_page);
+
+ /* create . and .. */
+ de->inode = cpu_to_le32(inode->i_ino);
+ de->name_len = 1;
+ de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
+ strcpy (de->name, ".");
+ ext2_set_de_type(dir->i_sb, de, S_IFDIR);
+ de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+ de->inode = cpu_to_le32(dir->i_ino);
+ de->rec_len = cpu_to_le16(PAGE_SIZE - EXT2_DIR_REC_LEN(1));
+ de->name_len = 2;
+ strcpy (de->name, "..");
+ ext2_set_de_type(dir->i_sb, de, S_IFDIR);
+ inode->i_nlink = 2;
+
+ err = obdfs_do_writepage(inode_page, IS_SYNC(inode));
+ inode->i_blocks = PAGE_SIZE/inode->i_sb->s_blocksize;
+ inode->i_size = PAGE_SIZE;
+ obd_unlock_page(inode_page);
+ page_cache_release(inode_page);
+ mark_inode_dirty(inode);
+ if (err) {
+ EXIT;
+ goto out_no_entry;
+ }
+
+ /* now deal with the parent */
+ page = obdfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page) {
+ EXIT;
+ goto out_no_entry;
+ }
+
+ de->inode = cpu_to_le32(inode->i_ino);
+ ext2_set_de_type(dir->i_sb, de, S_IFDIR);
+ dir->i_version = ++event;
+
+ dir->i_nlink++;
+ dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
+ mark_inode_dirty(dir);
+ err = obdfs_do_writepage(page, IS_SYNC(dir));
+
+ obd_unlock_page(page);
+
+ page_cache_release(page);
+ d_instantiate(dentry, inode);
+ EXIT;
out:
- return err;
+ return err;
out_no_entry:
- inode->i_nlink = 0;
- mark_inode_dirty(inode);
- iput (inode);
- goto out;
+ inode->i_nlink = 0;
+ mark_inode_dirty(inode);
+ iput (inode);
+ goto out;
} /* obdfs_mkdir */
*/
static int empty_dir (struct inode * inode)
{
- unsigned long offset;
- struct page *page;
- struct ext2_dir_entry_2 * de, * de1;
- struct super_block * sb;
-
- sb = inode->i_sb;
- if (inode->i_size < EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) ||
- !(page = obdfs_getpage (inode, 0, 0, LOCKED))) {
- ext2_warning (inode->i_sb, "empty_dir",
- "bad directory (dir #%lu) - no data block",
- inode->i_ino);
- return 1;
- }
- de = (struct ext2_dir_entry_2 *) page_address(page);
- de1 = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
- if (le32_to_cpu(de->inode) != inode->i_ino || !le32_to_cpu(de1->inode) ||
- strcmp (".", de->name) || strcmp ("..", de1->name)) {
- ext2_warning (inode->i_sb, "empty_dir",
- "bad directory (dir #%lu) - no `.' or `..'",
- inode->i_ino);
- page_cache_release(page);
- return 1;
- }
- offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
- de = (struct ext2_dir_entry_2 *) ((char *) de1 + le16_to_cpu(de1->rec_len));
- while (offset < inode->i_size ) {
- if (!page || (void *) de >= (void *) (page_address(page) + PAGE_SIZE)) {
- if (page) {
- UnlockPage(page);
- page_cache_release(page);
- }
- page = obdfs_getpage(inode, offset, 0, LOCKED);
- if (!page) {
+ unsigned long offset;
+ struct page *page;
+ struct ext2_dir_entry_2 * de, * de1;
+ struct super_block * sb;
+
+ sb = inode->i_sb;
+ if (inode->i_size < EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) ||
+ !(page = obdfs_getpage (inode, 0, 0, LOCKED))) {
+ ext2_warning (inode->i_sb, "empty_dir",
+ "bad directory (dir #%lu) - no data block",
+ inode->i_ino);
+ return 1;
+ }
+ de = (struct ext2_dir_entry_2 *) page_address(page);
+ de1 = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+ if (le32_to_cpu(de->inode) != inode->i_ino || !le32_to_cpu(de1->inode) ||
+ strcmp (".", de->name) || strcmp ("..", de1->name)) {
+ ext2_warning (inode->i_sb, "empty_dir",
+ "bad directory (dir #%lu) - no `.' or `..'",
+ inode->i_ino);
+ page_cache_release(page);
+ return 1;
+ }
+ offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
+ de = (struct ext2_dir_entry_2 *) ((char *) de1 + le16_to_cpu(de1->rec_len));
+ while (offset < inode->i_size ) {
+ if (!page || (void *) de >= (void *) (page_address(page) + PAGE_SIZE)) {
+ if (page) {
+ obd_unlock_page(page);
+ page_cache_release(page);
+ }
+ page = obdfs_getpage(inode, offset, 0, LOCKED);
+ if (!page) {
#if 0
- ext2_error (sb, "empty_dir",
- "directory #%lu contains a hole at offset %lu",
- inode->i_ino, offset);
+ ext2_error (sb, "empty_dir",
+ "directory #%lu contains a hole at offset %lu",
+ inode->i_ino, offset);
#endif
- offset += sb->s_blocksize;
- continue;
- }
- de = (struct ext2_dir_entry_2 *) page_address(page);
- }
- if (!obdfs_check_dir_entry ("empty_dir", inode, de, page,
- offset)) {
- UnlockPage(page);
- page_cache_release(page);
- return 1;
- }
- if (le32_to_cpu(de->inode)) {
- UnlockPage(page);
- page_cache_release(page);
- return 0;
- }
- offset += le16_to_cpu(de->rec_len);
- de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
- }
- UnlockPage(page);
- page_cache_release(page);
- return 1;
+ offset += sb->s_blocksize;
+ continue;
+ }
+ de = (struct ext2_dir_entry_2 *) page_address(page);
+ }
+ if (!obdfs_check_dir_entry ("empty_dir", inode, de, page,
+ offset)) {
+ obd_unlock_page(page);
+ page_cache_release(page);
+ return 1;
+ }
+ if (le32_to_cpu(de->inode)) {
+ obd_unlock_page(page);
+ page_cache_release(page);
+ return 0;
+ }
+ offset += le16_to_cpu(de->rec_len);
+ de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+ }
+ obd_unlock_page(page);
+ page_cache_release(page);
+ return 1;
} /* empty_dir */
int obdfs_rmdir (struct inode * dir, struct dentry *dentry)
{
- int retval;
- struct inode * inode;
- struct page *page;
- struct ext2_dir_entry_2 * de;
-
- ENTRY;
-
- retval = -ENOENT;
- page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, LOCKED);
- if (!page)
- goto end_rmdir;
-
- inode = dentry->d_inode;
- DQUOT_INIT(inode);
-
- retval = -EIO;
- if (le32_to_cpu(de->inode) != inode->i_ino)
- goto end_rmdir;
-
- retval = -ENOTEMPTY;
- if (!empty_dir (inode))
- goto end_rmdir;
-
- retval = obdfs_delete_entry (de, page);
- dir->i_version = ++event;
- if (retval)
- goto end_rmdir;
- retval = obdfs_do_writepage(dir, page, IS_SYNC(dir));
- /* XXX handle err? */
- UnlockPage(page);
-
- if (inode->i_nlink != 2)
- ext2_warning (inode->i_sb, "ext2_rmdir",
- "empty directory has nlink!=2 (%d)",
- inode->i_nlink);
- inode->i_version = ++event;
- inode->i_nlink = 0;
- inode->i_size = 0;
- mark_inode_dirty(inode);
- dir->i_nlink--;
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
- mark_inode_dirty(dir);
- d_delete(dentry);
+ int retval;
+ struct inode * inode;
+ struct page *page;
+ struct ext2_dir_entry_2 * de;
+
+ ENTRY;
+
+ retval = -ENOENT;
+ page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, LOCKED);
+ if (!page)
+ goto end_rmdir;
+
+ inode = dentry->d_inode;
+ DQUOT_INIT(inode);
+
+ retval = -EIO;
+ if (le32_to_cpu(de->inode) != inode->i_ino)
+ goto end_rmdir;
+
+ retval = -ENOTEMPTY;
+ if (!empty_dir (inode))
+ goto end_rmdir;
+
+ retval = obdfs_delete_entry (de, page);
+ dir->i_version = ++event;
+ if (retval)
+ goto end_rmdir;
+ retval = obdfs_do_writepage(page, IS_SYNC(dir));
+ /* XXX handle err? */
+ obd_unlock_page(page);
+
+ if (inode->i_nlink != 2)
+ ext2_warning (inode->i_sb, "ext2_rmdir",
+ "empty directory has nlink!=2 (%d)",
+ inode->i_nlink);
+ inode->i_version = ++event;
+ inode->i_nlink = 0;
+ inode->i_size = 0;
+ mark_inode_dirty(inode);
+ dir->i_nlink--;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
+ mark_inode_dirty(dir);
+ d_delete(dentry);
end_rmdir:
- if ( page )
- page_cache_release(page);
- EXIT;
- return retval;
+ if ( page )
+ page_cache_release(page);
+ EXIT;
+ return retval;
} /* obdfs_rmdir */
int obdfs_unlink(struct inode * dir, struct dentry *dentry)
{
- int retval;
- struct inode * inode;
- struct page *page;
- struct ext2_dir_entry_2 * de;
+ int retval;
+ struct inode * inode;
+ struct page *page;
+ struct ext2_dir_entry_2 * de;
ENTRY;
- retval = -ENOENT;
- page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, LOCKED);
- if (!page)
- goto end_unlink;
-
- inode = dentry->d_inode;
- DQUOT_INIT(inode);
-
- retval = -EIO;
- if (le32_to_cpu(de->inode) != inode->i_ino)
- goto end_unlink;
-
- if (!inode->i_nlink) {
- ext2_warning (inode->i_sb, "ext2_unlink",
- "Deleting nonexistent file (%lu), %d",
- inode->i_ino, inode->i_nlink);
- inode->i_nlink = 1;
- }
- retval = obdfs_delete_entry (de, page);
- if (retval)
- goto end_unlink;
- dir->i_version = ++event;
- retval = obdfs_do_writepage(dir, page, IS_SYNC(dir));
- /* XXX handle err? */
- UnlockPage(page);
-
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
- mark_inode_dirty(dir);
- inode->i_nlink--;
- mark_inode_dirty(inode);
- inode->i_ctime = dir->i_ctime;
- d_delete(dentry); /* This also frees the inode */
+ retval = -ENOENT;
+ page = obdfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, LOCKED);
+ if (!page)
+ goto end_unlink;
+
+ inode = dentry->d_inode;
+ DQUOT_INIT(inode);
+
+ retval = -EIO;
+ if (le32_to_cpu(de->inode) != inode->i_ino)
+ goto end_unlink;
+
+ if (!inode->i_nlink) {
+ ext2_warning (inode->i_sb, "ext2_unlink",
+ "Deleting nonexistent file (%lu), %d",
+ inode->i_ino, inode->i_nlink);
+ inode->i_nlink = 1;
+ }
+ retval = obdfs_delete_entry (de, page);
+ if (retval)
+ goto end_unlink;
+ dir->i_version = ++event;
+ retval = obdfs_do_writepage(page, IS_SYNC(dir));
+ /* XXX handle err? */
+ obd_unlock_page(page);
+
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
+ mark_inode_dirty(dir);
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ inode->i_ctime = dir->i_ctime;
+ d_delete(dentry); /* This also frees the inode */
end_unlink:
- if (page)
- page_cache_release(page);
- EXIT;
- return retval;
+ if (page)
+ page_cache_release(page);
+ EXIT;
+ return retval;
} /* obdfs_unlink */
int obdfs_symlink (struct inode * dir, struct dentry *dentry,
- const char * symname)
+ const char * symname)
{
- struct inode * inode;
- struct ext2_dir_entry_2 * de;
- struct obdfs_inode_info *oinfo;
- struct page* page = NULL, * name_page = NULL;
- char * link;
- int l, err;
+ struct inode * inode;
+ struct ext2_dir_entry_2 * de;
+ struct obdfs_inode_info *oinfo;
+ struct page* page = NULL, * name_page = NULL;
+ char * link;
+ int l, err;
ENTRY;
- err = -ENAMETOOLONG;
- l = strlen(symname)+1;
- if (l > PAGE_SIZE) {
- EXIT;
- goto out;
- }
-
- inode = obdfs_new_inode(dir, S_IFLNK);
- if ( IS_ERR(inode) ) {
- EXIT;
- goto out;
- }
-
- inode->i_mode = S_IFLNK | S_IRWXUGO;
- oinfo = obdfs_i2info(inode);
-
- if (l >= sizeof(oinfo->oi_inline)) {
- CDEBUG(D_INFO, "l=%d, normal symlink\n", l);
- inode->i_op = &obdfs_symlink_inode_operations;
-
- name_page = obdfs_getpage(inode, 0, 1, LOCKED);
- if (!name_page) {
- EXIT;
- err = -ENOMEM;
- goto out_no_entry;
- }
- link = (char *)page_address(name_page);
- } else {
- CDEBUG(D_INFO, "l=%d, fast symlink\n", l);
- inode->i_op = &obdfs_fast_symlink_inode_operations;
- link = oinfo->oi_inline;
- oinfo->oi_flags |= OBD_FL_INLINEDATA;
- }
- memcpy(link, symname, l);
- if (name_page) {
- err = obdfs_do_writepage(inode, name_page, IS_SYNC(inode));
- /* PDEBUG(name_page, "symlink"); */
- UnlockPage(name_page);
- page_cache_release(name_page);
- if (err) {
- EXIT;
- goto out_no_entry;
- }
- }
- inode->i_size = l-1;
- mark_inode_dirty(inode);
-
- page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len,
- &de, &err);
- if (!page)
- goto out_no_entry;
- de->inode = cpu_to_le32(inode->i_ino);
- ext2_set_de_type(dir->i_sb, de, S_IFLNK);
- dir->i_version = ++event;
- err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
- UnlockPage(page);
-
- d_instantiate(dentry, inode);
+ err = -ENAMETOOLONG;
+ l = strlen(symname)+1;
+ if (l > PAGE_SIZE) {
+ EXIT;
+ goto out;
+ }
+
+ inode = obdfs_new_inode(dir, S_IFLNK);
+ if ( IS_ERR(inode) ) {
+ EXIT;
+ goto out;
+ }
+
+ inode->i_mode = S_IFLNK | S_IRWXUGO;
+ oinfo = obdfs_i2info(inode);
+
+ if (l >= sizeof(oinfo->oi_inline)) {
+ CDEBUG(D_INFO, "l=%d, normal symlink\n", l);
+ inode->i_op = &obdfs_symlink_inode_operations;
+
+ name_page = obdfs_getpage(inode, 0, 1, LOCKED);
+ if (!name_page) {
+ EXIT;
+ err = -ENOMEM;
+ goto out_no_entry;
+ }
+ link = (char *)page_address(name_page);
+ } else {
+ CDEBUG(D_INFO, "l=%d, fast symlink\n", l);
+ inode->i_op = &obdfs_fast_symlink_inode_operations;
+ link = oinfo->oi_inline;
+ oinfo->oi_flags |= OBD_FL_INLINEDATA;
+ }
+ memcpy(link, symname, l);
+ if (name_page) {
+ err = obdfs_do_writepage(name_page, IS_SYNC(inode));
+ /* PDEBUG(name_page, "symlink"); */
+ obd_unlock_page(name_page);
+ page_cache_release(name_page);
+ if (err) {
+ EXIT;
+ goto out_no_entry;
+ }
+ }
+ inode->i_size = l-1;
+ mark_inode_dirty(inode);
+
+ page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len,
+ &de, &err);
+ if (!page)
+ goto out_no_entry;
+ de->inode = cpu_to_le32(inode->i_ino);
+ ext2_set_de_type(dir->i_sb, de, S_IFLNK);
+ dir->i_version = ++event;
+ err = obdfs_do_writepage(page, IS_SYNC(dir));
+ obd_unlock_page(page);
+
+ d_instantiate(dentry, inode);
out:
- EXIT;
- return err;
+ EXIT;
+ return err;
out_no_entry:
- inode->i_nlink--;
- mark_inode_dirty(inode);
- iput (inode);
- goto out;
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ iput (inode);
+ goto out;
} /* obdfs_symlink */
int obdfs_link (struct dentry * old_dentry,
- struct inode * dir, struct dentry *dentry)
+ struct inode * dir, struct dentry *dentry)
{
- struct inode *inode = old_dentry->d_inode;
- struct ext2_dir_entry_2 * de;
- struct page *page;
- int err;
+ struct inode *inode = old_dentry->d_inode;
+ struct ext2_dir_entry_2 * de;
+ struct page *page;
+ int err;
ENTRY;
- if (S_ISDIR(inode->i_mode))
- return -EPERM;
+ if (S_ISDIR(inode->i_mode))
+ return -EPERM;
- if (inode->i_nlink >= EXT2_LINK_MAX)
- return -EMLINK;
+ if (inode->i_nlink >= EXT2_LINK_MAX)
+ return -EMLINK;
- page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!page)
- return err;
+ page = obdfs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!page)
+ return err;
- de->inode = cpu_to_le32(inode->i_ino);
- ext2_set_de_type(dir->i_sb, de, inode->i_mode);
- dir->i_version = ++event;
+ de->inode = cpu_to_le32(inode->i_ino);
+ ext2_set_de_type(dir->i_sb, de, inode->i_mode);
+ dir->i_version = ++event;
- err = obdfs_do_writepage(dir, page, IS_SYNC(dir));
- UnlockPage(page);
+ err = obdfs_do_writepage(page, IS_SYNC(dir));
+ obd_unlock_page(page);
- page_cache_release(page);
- inode->i_nlink++;
- inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(inode);
- inode->i_count++;
- d_instantiate(dentry, inode);
- return err;
+ page_cache_release(page);
+ inode->i_nlink++;
+ inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ atomic_inc(&inode->i_count);
+ d_instantiate(dentry, inode);
+ return err;
} /* obdfs_link */
#define PARENT_INO(buffer) \
- ((struct ext2_dir_entry_2 *) ((char *) buffer + \
- le16_to_cpu(((struct ext2_dir_entry_2 *) buffer)->rec_len)))->inode
+ ((struct ext2_dir_entry_2 *) ((char *) buffer + \
+ le16_to_cpu(((struct ext2_dir_entry_2 *) buffer)->rec_len)))->inode
/*
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
int obdfs_rename (struct inode * old_dir, struct dentry *old_dentry,
- struct inode * new_dir, struct dentry *new_dentry)
+ struct inode * new_dir, struct dentry *new_dentry)
{
- struct inode * old_inode, * new_inode;
- struct page * old_page, * new_page, * dir_page;
- struct ext2_dir_entry_2 * old_de, * new_de;
- int retval;
+ struct inode * old_inode, * new_inode;
+ struct page * old_page, * new_page, * dir_page;
+ struct ext2_dir_entry_2 * old_de, * new_de;
+ int retval;
ENTRY;
- new_page = dir_page = NULL;
-
- /* does the old entry exist? - if not get out */
- old_page = obdfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de, NOLOCK);
- /* PDEBUG(old_page, "rename - old page"); */
- /*
- * Check for inode number is _not_ due to possible IO errors.
- * We might rmdir the source, keep it as pwd of some process
- * and merrily kill the link to whatever was created under the
- * same name. Goodbye sticky bit ;-<
- */
- old_inode = old_dentry->d_inode;
- retval = -ENOENT;
- if (!old_page || le32_to_cpu(old_de->inode) != old_inode->i_ino) {
- EXIT;
- goto end_rename;
- }
-
- /* find new inode */
- new_inode = new_dentry->d_inode;
- new_page = obdfs_find_entry (new_dir, new_dentry->d_name.name,
- new_dentry->d_name.len, &new_de, NOLOCK);
- /* PDEBUG(new_page, "rename - new page "); */
- if (new_page) {
- if (!new_inode) {
- page_cache_release(new_page);
- new_page = NULL;
- } else {
- DQUOT_INIT(new_inode);
- }
- }
- /* in this case we to check more ... */
- if (S_ISDIR(old_inode->i_mode)) {
- /* can only rename into empty new directory */
- if (new_inode) {
- retval = -ENOTEMPTY;
- if (!empty_dir (new_inode)) {
- EXIT;
- goto end_rename;
- }
- }
- retval = -EIO;
- dir_page = obdfs_getpage (old_inode, 0, 0, LOCKED);
- /* PDEBUG(dir_page, "rename dir page"); */
-
- if (!dir_page) {
- EXIT;
- goto end_rename;
- }
- if (le32_to_cpu(PARENT_INO(page_address(dir_page))) !=
- old_dir->i_ino) {
- EXIT;
- goto end_rename;
- }
- retval = -EMLINK;
- if (!new_inode && new_dir!=old_dir &&
- new_dir->i_nlink >= EXT2_LINK_MAX) {
- EXIT;
- goto end_rename;
- }
- }
- /* create the target dir entry */
- if (!new_page) {
- new_page = obdfs_add_entry (new_dir, new_dentry->d_name.name,
- new_dentry->d_name.len, &new_de,
- &retval);
- /* PDEBUG(new_page, "rename new page"); */
- if (!new_page) {
- EXIT;
- goto end_rename;
- }
- }
- new_dir->i_version = ++event;
-
- /*
- * remove the old entry
- */
- new_de->inode = le32_to_cpu(old_inode->i_ino);
- if (EXT2_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
- EXT2_FEATURE_INCOMPAT_FILETYPE))
- new_de->file_type = old_de->file_type;
-
- obdfs_delete_entry (old_de, old_page);
-
- old_dir->i_version = ++event;
- if (new_inode) {
- new_inode->i_nlink--;
- new_inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(new_inode);
- }
- old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
- old_dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
- mark_inode_dirty(old_dir);
- if (dir_page) {
- PARENT_INO(page_address(dir_page)) =le32_to_cpu(new_dir->i_ino);
- retval = obdfs_do_writepage(old_inode, dir_page,
- IS_SYNC(old_inode));
- /* XXX handle err - not sure if this is correct */
- if (retval) {
- EXIT;
- goto end_rename;
- }
- old_dir->i_nlink--;
- mark_inode_dirty(old_dir);
- if (new_inode) {
- new_inode->i_nlink--;
- mark_inode_dirty(new_inode);
- } else {
- new_dir->i_nlink++;
- new_dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
- mark_inode_dirty(new_dir);
- }
- }
- if ( old_page != new_page ) {
- unsigned long index = old_page->index;
- /* lock the old_page and release unlocked copy */
- CDEBUG(D_INFO, "old_page at %p\n", old_page);
- page_cache_release(old_page);
- old_page = obdfs_getpage(old_dir, index << PAGE_SHIFT, 0,
- LOCKED);
- CDEBUG(D_INFO, "old_page at %p\n", old_page);
- retval = obdfs_do_writepage(old_dir, old_page,IS_SYNC(old_dir));
- /* XXX handle err - not sure if this is correct */
- if (retval) {
- EXIT;
- goto end_rename;
- }
- }
-
- retval = obdfs_do_writepage(new_dir, new_page, IS_SYNC(new_dir));
+ new_page = dir_page = NULL;
+
+ /* does the old entry exist? - if not get out */
+ old_page = obdfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de, NOLOCK);
+ /* PDEBUG(old_page, "rename - old page"); */
+ /*
+ * Check for inode number is _not_ due to possible IO errors.
+ * We might rmdir the source, keep it as pwd of some process
+ * and merrily kill the link to whatever was created under the
+ * same name. Goodbye sticky bit ;-<
+ */
+ old_inode = old_dentry->d_inode;
+ retval = -ENOENT;
+ if (!old_page || le32_to_cpu(old_de->inode) != old_inode->i_ino) {
+ EXIT;
+ goto end_rename;
+ }
+
+ /* find new inode */
+ new_inode = new_dentry->d_inode;
+ new_page = obdfs_find_entry (new_dir, new_dentry->d_name.name,
+ new_dentry->d_name.len, &new_de, NOLOCK);
+ /* PDEBUG(new_page, "rename - new page "); */
+ if (new_page) {
+ if (!new_inode) {
+ page_cache_release(new_page);
+ new_page = NULL;
+ } else {
+ DQUOT_INIT(new_inode);
+ }
+ }
+ /* in this case we to check more ... */
+ if (S_ISDIR(old_inode->i_mode)) {
+ /* can only rename into empty new directory */
+ if (new_inode) {
+ retval = -ENOTEMPTY;
+ if (!empty_dir (new_inode)) {
+ EXIT;
+ goto end_rename;
+ }
+ }
+ retval = -EIO;
+ dir_page = obdfs_getpage (old_inode, 0, 0, LOCKED);
+ /* PDEBUG(dir_page, "rename dir page"); */
+
+ if (!dir_page) {
+ EXIT;
+ goto end_rename;
+ }
+ if (le32_to_cpu(PARENT_INO(page_address(dir_page))) !=
+ old_dir->i_ino) {
+ EXIT;
+ goto end_rename;
+ }
+ retval = -EMLINK;
+ if (!new_inode && new_dir!=old_dir &&
+ new_dir->i_nlink >= EXT2_LINK_MAX) {
+ EXIT;
+ goto end_rename;
+ }
+ }
+ /* create the target dir entry */
+ if (!new_page) {
+ new_page = obdfs_add_entry (new_dir, new_dentry->d_name.name,
+ new_dentry->d_name.len, &new_de,
+ &retval);
+ /* PDEBUG(new_page, "rename new page"); */
+ if (!new_page) {
+ EXIT;
+ goto end_rename;
+ }
+ }
+ new_dir->i_version = ++event;
+
+ /*
+ * remove the old entry
+ */
+ new_de->inode = le32_to_cpu(old_inode->i_ino);
+ if (EXT2_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ new_de->file_type = old_de->file_type;
+
+ obdfs_delete_entry (old_de, old_page);
+
+ old_dir->i_version = ++event;
+ if (new_inode) {
+ new_inode->i_nlink--;
+ new_inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(new_inode);
+ }
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ old_dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
+ mark_inode_dirty(old_dir);
+ if (dir_page) {
+ PARENT_INO(page_address(dir_page)) =le32_to_cpu(new_dir->i_ino);
+ retval = obdfs_do_writepage(dir_page, IS_SYNC(old_inode));
+ /* XXX handle err - not sure if this is correct */
+ if (retval) {
+ EXIT;
+ goto end_rename;
+ }
+ old_dir->i_nlink--;
+ mark_inode_dirty(old_dir);
+ if (new_inode) {
+ new_inode->i_nlink--;
+ mark_inode_dirty(new_inode);
+ } else {
+ new_dir->i_nlink++;
+ new_dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
+ mark_inode_dirty(new_dir);
+ }
+ }
+ if ( old_page != new_page ) {
+ unsigned long index = old_page->index;
+ /* lock the old_page and release unlocked copy */
+ CDEBUG(D_INFO, "old_page at %p\n", old_page);
+ page_cache_release(old_page);
+ old_page = obdfs_getpage(old_dir, index << PAGE_SHIFT, 0,
+ LOCKED);
+ CDEBUG(D_INFO, "old_page at %p\n", old_page);
+ retval = obdfs_do_writepage(old_page,IS_SYNC(old_dir));
+ /* XXX handle err - not sure if this is correct */
+ if (retval) {
+ EXIT;
+ goto end_rename;
+ }
+ }
+
+ retval = obdfs_do_writepage(new_page, IS_SYNC(new_dir));
end_rename:
- if (old_page && PageLocked(old_page) )
- UnlockPage(old_page);
- if (old_page)
- page_cache_release(old_page);
- if (new_page && PageLocked(new_page) )
- UnlockPage(new_page);
- if (new_page)
- page_cache_release(new_page);
- if (dir_page && PageLocked(dir_page) )
- UnlockPage(dir_page);
- if (dir_page)
- page_cache_release(dir_page);
-
- return retval;
+ if (old_page && PageLocked(old_page) )
+ obd_unlock_page(old_page);
+ if (old_page)
+ page_cache_release(old_page);
+ if (new_page && PageLocked(new_page) )
+ obd_unlock_page(new_page);
+ if (new_page)
+ page_cache_release(new_page);
+ if (dir_page && PageLocked(dir_page) )
+ obd_unlock_page(dir_page);
+ if (dir_page)
+ page_cache_release(dir_page);
+
+ return retval;
} /* obdfs_rename */
/* SYNCHRONOUS I/O for an inode */
static int obdfs_brw(int rw, struct inode *inode, struct page *page, int create)
{
- obd_count num_obdo = 1;
- obd_count bufs_per_obdo = 1;
- struct obdo *oa;
- char *buf = (char *)page_address(page);
- 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;
- if (IOPS(inode, brw) == NULL) {
- printk(KERN_ERR __FUNCTION__ ": no brw method!\n");
- EXIT;
- return -EIO;
- }
-
- oa = obdo_fromid(IID(inode), inode->i_ino, OBD_MD_FLNOTOBD);
- if ( IS_ERR(oa) ) {
- EXIT;
- return PTR_ERR(oa);
- }
- obdfs_from_inode(oa, inode);
-
- err = IOPS(inode, brw)(rw, IID(inode), num_obdo, &oa, &bufs_per_obdo,
- &buf, &count, &offset, &flags);
-
- if ( !err )
- obdfs_to_inode(inode, oa); /* copy o_blocks to i_blocks */
-
- obdo_free(oa);
-
- EXIT;
- return err;
+ obd_count num_obdo = 1;
+ obd_count bufs_per_obdo = 1;
+ struct obdo *oa;
+ char *buf = (char *)page_address(page);
+ 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;
+ if (IOPS(inode, brw) == NULL) {
+ printk(KERN_ERR __FUNCTION__ ": no brw method!\n");
+ EXIT;
+ return -EIO;
+ }
+
+ oa = obdo_fromid(IID(inode), inode->i_ino, OBD_MD_FLNOTOBD);
+ if ( IS_ERR(oa) ) {
+ EXIT;
+ return PTR_ERR(oa);
+ }
+ obdfs_from_inode(oa, inode);
+
+ err = IOPS(inode, brw)(rw, IID(inode), num_obdo, &oa, &bufs_per_obdo,
+ &buf, &count, &offset, &flags);
+
+ 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_readpage(struct dentry *dentry, struct page *page)
+int obdfs_readpage(struct file *file, struct page *page)
{
- struct inode *inode = dentry->d_inode;
- int rc;
-
- ENTRY;
- /* PDEBUG(page, "READ"); */
- rc = obdfs_brw(READ, inode, page, 0);
- if ( !rc ) {
- SetPageUptodate(page);
- UnlockPage(page);
- }
- /* PDEBUG(page, "READ"); */
- EXIT;
- return rc;
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ int rc;
+
+ ENTRY;
+ /* PDEBUG(page, "READ"); */
+ rc = obdfs_brw(READ, inode, page, 0);
+ if ( !rc ) {
+ SetPageUptodate(page);
+ obd_unlock_page(page);
+ }
+ /* PDEBUG(page, "READ"); */
+ EXIT;
+ return rc;
} /* obdfs_readpage */
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;
+ 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);
+ --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))
- printk(KERN_INFO __FUNCTION__
- ": unable to free all of cache\n");
- obdfs_pgrq_cachep = NULL;
- } else
- printk(KERN_INFO __FUNCTION__ ": called with NULL pointer\n");
-
- EXIT;
+ 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))
+ printk(KERN_INFO __FUNCTION__
+ ": unable to free all of cache\n");
+ obdfs_pgrq_cachep = NULL;
+ } else
+ printk(KERN_INFO __FUNCTION__ ": 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)
+ 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;
+ 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)
+ 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;
- if (IOPS(inodes[0], brw) == NULL) {
- printk(KERN_ERR __FUNCTION__ ": no brw method!\n");
- EXIT;
- return -EIO;
- }
-
- 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 = IOPS(inodes[0], brw)(WRITE, IID(inodes[0]), num_obdos, obdos,
- oa_bufs, bufs, counts, offsets, flags);
-
- CDEBUG(D_INFO, "BRW done\n");
- /* release the pages from the page cache */
- while ( num_io > 0 ) {
- --num_io;
- CDEBUG(D_INFO, "calling put_page for %p, index %ld\n",
- pages[num_io], pages[num_io]->index);
- /* PDEBUG(pages[num_io], "do_vec_wr"); */
- put_page(pages[num_io]);
- /* PDEBUG(pages[num_io], "do_vec_wr"); */
- }
- CDEBUG(D_INFO, "put_page done\n");
-
- while ( num_obdos > 0) {
- --num_obdos;
- CDEBUG(D_INFO, "free obdo %ld\n",(long)obdos[num_obdos]->o_id);
- /* copy o_blocks to i_blocks */
- obdfs_to_inode(inodes[num_obdos], obdos[num_obdos]);
- obdo_free(obdos[num_obdos]);
- }
- CDEBUG(D_INFO, "obdo_free done\n");
- EXIT;
- return err;
+ int err;
+
+ ENTRY;
+ if (IOPS(inodes[0], brw) == NULL) {
+ printk(KERN_ERR __FUNCTION__ ": no brw method!\n");
+ EXIT;
+ return -EIO;
+ }
+
+ 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 = IOPS(inodes[0], brw)(WRITE, IID(inodes[0]), num_obdos, obdos,
+ oa_bufs, bufs, counts, offsets, flags);
+
+ CDEBUG(D_INFO, "BRW done\n");
+ /* release the pages from the page cache */
+ while ( num_io > 0 ) {
+ --num_io;
+ CDEBUG(D_INFO, "calling put_page for %p, index %ld\n",
+ pages[num_io], pages[num_io]->index);
+ /* PDEBUG(pages[num_io], "do_vec_wr"); */
+ put_page(pages[num_io]);
+ /* PDEBUG(pages[num_io], "do_vec_wr"); */
+ }
+ CDEBUG(D_INFO, "put_page done\n");
+
+ while ( num_obdos > 0) {
+ --num_obdos;
+ CDEBUG(D_INFO, "free obdo %ld\n",(long)obdos[num_obdos]->o_id);
+ /* copy o_blocks to i_blocks */
+ obdfs_to_inode(inodes[num_obdos], obdos[num_obdos]);
+ obdo_free(obdos[num_obdos]);
+ }
+ CDEBUG(D_INFO, "obdo_free done\n");
+ EXIT;
+ return err;
}
*/
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++;
-
- /* 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)) ) {
- 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;
+ 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++;
+
+ /* 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 */
/* select between SYNC and ASYNC I/O methods */
-int obdfs_do_writepage(struct inode *inode, struct page *page, int sync)
+int obdfs_do_writepage(struct page *page, int sync)
{
- int err;
-
- ENTRY;
- /* PDEBUG(page, "WRITEPAGE"); */
- if ( sync )
- err = obdfs_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);
- /* PDEBUG(page,"WRITEPAGE"); */
- EXIT;
- return err;
+ struct inode *inode = page->mapping->host;
+ int err;
+
+ ENTRY;
+ /* PDEBUG(page, "WRITEPAGE"); */
+ if ( sync )
+ err = obdfs_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);
+ /* PDEBUG(page,"WRITEPAGE"); */
+ EXIT;
+ return err;
} /* obdfs_do_writepage */
/* returns the page unlocked, but with a reference */
-int obdfs_writepage(struct dentry *dentry, struct page *page)
+int obdfs_writepage(struct page *page)
{
- return obdfs_do_writepage(dentry->d_inode, page, 0);
+ return obdfs_do_writepage(page, 0);
}
+
/*
* This does the "real" work of the write. The generic routine has
* allocated the page, locked it, done all the page alignment stuff
* 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)
+ 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(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(file->f_dentry, page);
- unlock_kernel();
-
- return (err < 0 ? err : bytes);
+ 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(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 */
/*
* modeled on NFS code.
*/
struct page *obdfs_getpage(struct inode *inode, unsigned long offset,
- int create, int locked)
+ 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) {
- printk(KERN_WARNING " grab_cache_page says no dice ...\n");
- EXIT;
- return NULL;
- }
-
- /* PDEBUG(page, "GETPAGE: got page - before reading\n"); */
- /* now check if the data in the page is up to date */
- if ( Page_Uptodate(page)) {
- if (!locked)
- UnlockPage(page);
- EXIT;
- return page;
- }
+ 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) {
+ printk(KERN_WARNING " grab_cache_page says no dice ...\n");
+ EXIT;
+ return NULL;
+ }
+
+ /* PDEBUG(page, "GETPAGE: got page - before reading\n"); */
+ /* now check if the data in the page is up to date */
+ if ( Page_Uptodate(page)) {
+ if (!locked) {
+ if (PageLocked(page))
+ obd_unlock_page(page);
+ } else {
+ printk("file %s, line %d: expecting locked page\n",
+ __FILE__, __LINE__);
+ }
+ EXIT;
+ return page;
+ }
#ifdef EXT2_OBD_DEBUG
- if ((obd_debug_level & D_INFO) && obdfs_find_page_index(inode, index)) {
- CDEBUG(D_INFO, "OVERWRITE: found dirty page %p, index %ld\n",
- page, page->index);
- }
+ if ((obd_debug_level & D_INFO) && obdfs_find_page_index(inode, index)) {
+ CDEBUG(D_INFO, "OVERWRITE: found dirty page %p, index %ld\n",
+ page, page->index);
+ }
#endif
- err = obdfs_brw(READ, inode, page, create);
-
- if ( err ) {
- SetPageError(page);
- UnlockPage(page);
- EXIT;
- return page;
- }
-
- if ( !locked )
- UnlockPage(page);
- SetPageUptodate(page);
- /* PDEBUG(page,"GETPAGE - after reading"); */
- EXIT;
- return page;
+ err = obdfs_brw(READ, inode, page, create);
+
+ if ( err ) {
+ SetPageError(page);
+ obd_unlock_page(page);
+ EXIT;
+ return page;
+ }
+
+ if ( !locked )
+ obd_unlock_page(page);
+ SetPageUptodate(page);
+ /* PDEBUG(page,"GETPAGE - after reading"); */
+ EXIT;
+ return page;
} /* obdfs_getpage */
void obdfs_truncate(struct inode *inode)
{
- struct obdo *oa;
- int err;
- ENTRY;
-
- obdfs_dequeue_pages(inode);
-
- if (IOPS(inode, punch) == NULL) {
- printk(KERN_ERR __FUNCTION__ ": no punch method!\n");
- EXIT;
- return;
- }
- oa = obdo_alloc();
- if ( !oa ) {
- /* XXX This would give an inconsistent FS, so deal with it as
- * best we can for now - an obdo on the stack is not pretty.
- */
- struct obdo obdo;
-
- printk(__FUNCTION__ ": obdo_alloc failed - using stack!\n");
-
- obdo.o_valid = OBD_MD_FLNOTOBD;
- obdfs_from_inode(&obdo, inode);
-
- err = IOPS(inode, punch)(IID(inode), &obdo, obdo.o_size, 0);
- } 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, oa->o_size);
- err = IOPS(inode, punch)(IID(inode), oa, oa->o_size, 0);
-
- obdo_free(oa);
- }
-
- if (err) {
- printk(__FUNCTION__ ": obd_truncate fails (%d)\n", err);
- EXIT;
- return;
- }
- EXIT;
+ struct obdo *oa;
+ int err;
+ ENTRY;
+
+ obdfs_dequeue_pages(inode);
+
+ if (IOPS(inode, punch) == NULL) {
+ printk(KERN_ERR __FUNCTION__ ": no punch method!\n");
+ EXIT;
+ return;
+ }
+ oa = obdo_alloc();
+ if ( !oa ) {
+ /* XXX This would give an inconsistent FS, so deal with it as
+ * best we can for now - an obdo on the stack is not pretty.
+ */
+ struct obdo obdo;
+
+ printk(__FUNCTION__ ": obdo_alloc failed - using stack!\n");
+
+ obdo.o_valid = OBD_MD_FLNOTOBD;
+ obdfs_from_inode(&obdo, inode);
+
+ err = IOPS(inode, punch)(IID(inode), &obdo, obdo.o_size, 0);
+ } 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, oa->o_size);
+ err = IOPS(inode, punch)(IID(inode), oa, oa->o_size, 0);
+
+ obdo_free(oa);
+ }
+
+ if (err) {
+ printk(__FUNCTION__ ": obd_truncate fails (%d)\n", err);
+ EXIT;
+ return;
+ }
+ EXIT;
} /* obdfs_truncate */
* 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.
*
*/
#include <linux/obdfs.h>
struct list_head obdfs_super_list;
+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, char *, strlen(value) + 1);
- if ( !retval ) {
- printk(KERN_ALERT __FUNCTION__ ": out of memory!\n");
- return NULL;
- }
-
- memcpy(retval, value, strlen(value)+1);
- CDEBUG(D_PSDEV, "Assigned option: %s, value %s\n", opt, retval);
- return retval;
+ 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, char *, strlen(value) + 1);
+ if ( !retval ) {
+ printk(KERN_ALERT __FUNCTION__ ": out of memory!\n");
+ return NULL;
+ }
+
+ memcpy(retval, value, strlen(value)+1);
+ CDEBUG(D_PSDEV, "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;
-
- }
+ 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 int obdfs_getdev(char *devpath, int *dev)
{
- struct dentry *dentry;
- kdev_t devno;
-
- dentry = lookup_dentry(devpath, NULL, 0);
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
-
- if (!S_ISCHR(dentry->d_inode->i_mode))
- return -ENODEV;
-
- devno = dentry->d_inode->i_rdev;
- if ( MAJOR(devno) != OBD_PSDEV_MAJOR )
- return -ENODEV;
-
- if ( MINOR(devno) >= MAX_OBD_DEVICES )
- return -ENODEV;
-
- *dev = devno;
- return 0;
+ struct dentry *dentry;
+ kdev_t devno;
+ struct nameidata nd;
+ int error = 0;
+
+ ENTRY;
+ if (path_init(devpath, LOOKUP_POSITIVE, &nd))
+ error = path_walk(devpath, &nd);
+ if (error)
+ return error;
+
+ dentry = nd.dentry;
+ if (!S_ISCHR(dentry->d_inode->i_mode))
+ return -ENODEV;
+
+ devno = dentry->d_inode->i_rdev;
+ if ( MAJOR(devno) != OBD_PSDEV_MAJOR )
+ return -ENODEV;
+
+ if ( MINOR(devno) >= MAX_OBD_DEVICES )
+ return -ENODEV;
+
+ *dev = devno;
+ return 0;
}
static struct super_block * obdfs_read_super(struct super_block *sb,
- void *data, int silent)
+ 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 devno;
- int err;
- unsigned long blocksize;
- unsigned long blocksize_bits;
- unsigned long root_ino;
- int scratch;
-
-
- ENTRY;
+ struct obdfs_sb_info *sbi = (struct obdfs_sb_info *)(&sb->u.generic_sbp);
+ struct obd_device *obddev;
+ char *device = NULL;
+ char *version = NULL;
+ int devno;
+ int err;
+ unsigned long blocksize;
+ unsigned long blocksize_bits;
+ unsigned long root_ino;
+ int scratch;
+
+
+ ENTRY;
MOD_INC_USE_COUNT;
-
- memset(sbi, 0, sizeof(*sbi));
-
- obdfs_options(data, &device, &version);
- if ( !device ) {
- printk(__FUNCTION__ ": no device\n");
- EXIT;
- goto ERR;
- }
-
- if ( (err = obdfs_getdev(device, &devno)) ) {
- printk("Cannot get devno of %s, error %d\n", device, err);
- EXIT;
- goto ERR;;
- }
-
- if ( MAJOR(devno) != OBD_PSDEV_MAJOR ) {
- printk(__FUNCTION__ ": wrong major number %d!\n", MAJOR(devno));
- EXIT;
- goto ERR;
- }
-
- if ( MINOR(devno) >= MAX_OBD_DEVICES ) {
- printk(__FUNCTION__ ": minor of %s too high (%d)\n",
- device, MINOR(devno));
- EXIT;
- goto ERR;
- }
-
- obddev = &obd_dev[MINOR(devno)];
-
- if ( ! (obddev->obd_flags & OBD_ATTACHED) ||
- ! (obddev->obd_flags & OBD_SET_UP) ){
- printk("device %s not attached or not set up (%d)\n",
- device, MINOR(devno));
- EXIT;
- goto ERR;;
- }
-
- sbi->osi_obd = obddev;
- sbi->osi_ops = sbi->osi_obd->obd_type->typ_ops;
-
- sbi->osi_conn.oc_dev = obddev;
+
+ memset(sbi, 0, sizeof(*sbi));
+
+ CDEBUG(D_INFO, "\n");
+ obdfs_options(data, &device, &version);
+ if ( !device ) {
+ printk(__FUNCTION__ ": no device\n");
+ EXIT;
+ goto ERR;
+ }
+
+ CDEBUG(D_INFO, "\n");
+ if ( (err = obdfs_getdev(device, &devno)) ) {
+ printk("Cannot get devno of %s, error %d\n", device, err);
+ EXIT;
+ goto ERR;;
+ }
+
+ CDEBUG(D_INFO, "\n");
+ if ( MAJOR(devno) != OBD_PSDEV_MAJOR ) {
+ printk(__FUNCTION__ ": wrong major number %d!\n", MAJOR(devno));
+ EXIT;
+ goto ERR;
+ }
+
+ CDEBUG(D_INFO, "\n");
+ if ( MINOR(devno) >= MAX_OBD_DEVICES ) {
+ printk(__FUNCTION__ ": minor of %s too high (%d)\n",
+ device, MINOR(devno));
+ EXIT;
+ goto ERR;
+ }
+
+ CDEBUG(D_INFO, "\n");
+ obddev = &obd_dev[MINOR(devno)];
+
+ CDEBUG(D_INFO, "\n");
+ if ( ! (obddev->obd_flags & OBD_ATTACHED) ||
+ ! (obddev->obd_flags & OBD_SET_UP) ){
+ printk("device %s not attached or not set up (%d)\n",
+ device, MINOR(devno));
+ EXIT;
+ goto ERR;;
+ }
+
+ CDEBUG(D_INFO, "\n");
+ sbi->osi_obd = obddev;
+ sbi->osi_ops = sbi->osi_obd->obd_type->typ_ops;
+
+ sbi->osi_conn.oc_dev = obddev;
err = sbi->osi_ops->o_connect(&sbi->osi_conn);
- if ( err ) {
- printk("OBDFS: cannot connect to %s\n", device);
- EXIT;
- goto ERR;
- }
-
- /* list of dirty inodes, and a mutex to hold while modifying it */
- INIT_LIST_HEAD(&sbi->osi_inodes);
- sema_init(&sbi->osi_list_mutex, 1);
-
- sbi->osi_super = sb;
-
- err = sbi->osi_ops->o_get_info(&sbi->osi_conn, strlen("blocksize"),
- "blocksize", &scratch,
- (void *)&blocksize);
- if ( err ) {
- printk("getinfo call to drive failed (blocksize)\n");
- EXIT;
- goto ERR;
- }
-
- err = sbi->osi_ops->o_get_info(&sbi->osi_conn, strlen("blocksize_bits"),
- "blocksize_bits", &scratch,
- (void *)&blocksize_bits);
- if ( err ) {
- printk("getinfo call to drive failed (blocksize_bits)\n");
- EXIT;
- goto ERR;
- }
-
- err = sbi->osi_ops->o_get_info(&sbi->osi_conn, strlen("root_ino"),
- "root_ino", &scratch, (void *)&root_ino);
- if ( err ) {
- printk("getinfo call to drive failed (root_ino)\n");
- EXIT;
- goto ERR;
- }
-
- lock_super(sb);
-
+ if ( err ) {
+ printk("OBDFS: cannot connect to %s\n", device);
+ EXIT;
+ goto ERR;
+ }
+
+ CDEBUG(D_INFO, "\n");
+ /* list of dirty inodes, and a mutex to hold while modifying it */
+ INIT_LIST_HEAD(&sbi->osi_inodes);
+ sema_init(&sbi->osi_list_mutex, 1);
+
+ CDEBUG(D_INFO, "\n");
+ sbi->osi_super = sb;
+
+ CDEBUG(D_INFO, "\n");
+ err = sbi->osi_ops->o_get_info(&sbi->osi_conn, strlen("blocksize"),
+ "blocksize", &scratch,
+ (void *)&blocksize);
+ if ( err ) {
+ printk("getinfo call to drive failed (blocksize)\n");
+ EXIT;
+ goto ERR;
+ }
+
+ CDEBUG(D_INFO, "\n");
+ err = sbi->osi_ops->o_get_info(&sbi->osi_conn, strlen("blocksize_bits"),
+ "blocksize_bits", &scratch,
+ (void *)&blocksize_bits);
+ if ( err ) {
+ printk("getinfo call to drive failed (blocksize_bits)\n");
+ EXIT;
+ goto ERR;
+ }
+
+ CDEBUG(D_INFO, "\n");
+ err = sbi->osi_ops->o_get_info(&sbi->osi_conn, strlen("root_ino"),
+ "root_ino", &scratch, (void *)&root_ino);
+ if ( err ) {
+ printk("getinfo call to drive failed (root_ino)\n");
+ EXIT;
+ goto ERR;
+ }
+
+ CDEBUG(D_INFO, "\n");
sb->s_blocksize = blocksize;
sb->s_blocksize_bits = (unsigned char)blocksize_bits;
sb->s_magic = OBDFS_SUPER_MAGIC;
sb->s_op = &obdfs_super_operations;
- /* XXX how to get "sb->s_flags |= MS_RDONLY" here for snapshots? */
+ /* XXX how to get "sb->s_flags |= MS_RDONLY" here for snapshots? */
- /* make root inode */
- root = iget(sb, root_ino);
+ /* make root inode */
+ CDEBUG(D_INFO, "\n");
+ root = iget(sb, root_ino);
if (!root || is_bad_inode(root)) {
- printk("OBDFS: bad iget for root\n");
- sb->s_dev = 0;
- err = -ENOENT;
- unlock_super(sb);
- EXIT;
- goto ERR;
- }
-
- CDEBUG(D_INFO, "obdfs_read_super: sbdev %d, rootino: %ld, dev %s, "
- "minor: %d, blocksize: %ld, blocksize bits %ld\n",
- sb->s_dev, root->i_ino, device, MINOR(devno),
- blocksize, blocksize_bits);
- sb->s_root = d_alloc_root(root);
- list_add(&sbi->osi_list, &obdfs_super_list);
- unlock_super(sb);
- OBD_FREE(device, strlen(device) + 1);
- if (version)
- OBD_FREE(version, strlen(version) + 1);
- EXIT;
+ printk("OBDFS: bad iget for root\n");
+ sb->s_dev = 0;
+ err = -ENOENT;
+ EXIT;
+ goto ERR;
+ }
+
+ CDEBUG(D_INFO, "obdfs_read_super: sbdev %d, rootino: %ld, dev %s, "
+ "minor: %d, blocksize: %ld, blocksize bits %ld\n",
+ sb->s_dev, root->i_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 (sbi) {
- sbi->osi_super = NULL;
- }
+ MOD_DEC_USE_COUNT;
+ if (device)
+ OBD_FREE(device, strlen(device) + 1);
+ if (version)
+ OBD_FREE(version, strlen(version) + 1);
+ if (sbi) {
+ sbi->osi_super = NULL;
+ }
if (root) {
iput(root);
}
ENTRY;
sb->s_dev = 0;
-
- sbi = (struct obdfs_sb_info *) &sb->u.generic_sbp;
- obdfs_flush_reqs(&sbi->osi_inodes, ~0UL);
+
+ sbi = (struct obdfs_sb_info *) &sb->u.generic_sbp;
+ obdfs_flush_reqs(&sbi->osi_inodes, ~0UL);
- OPS(sb,disconnect)(ID(sb));
- list_del(&sbi->osi_list);
- memset(sbi, 0, sizeof(*sbi));
-
- printk(KERN_INFO "OBDFS: Bye bye.\n");
+ OPS(sb,disconnect)(ID(sb));
+ list_del(&sbi->osi_list);
+ memset(sbi, 0, sizeof(*sbi));
+
+ printk(KERN_INFO "OBDFS: Bye bye.\n");
MOD_DEC_USE_COUNT;
- EXIT;
+ EXIT;
} /* obdfs_put_super */
/* all filling in of inodes postponed until lookup */
static void obdfs_read_inode(struct inode *inode)
{
- struct obdo *oa;
-
- ENTRY;
- oa = obdo_fromid(IID(inode), inode->i_ino,
- OBD_MD_FLNOTOBD | OBD_MD_FLBLOCKS);
- if ( IS_ERR(oa) ) {
- printk(__FUNCTION__ ": obdo_fromid failed\n");
- EXIT;
- return /* PTR_ERR(oa) */;
- }
-
- ODEBUG(oa);
- 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 */
-
- obdo_free(oa);
- /* OIDEBUG(inode); */
-
- if (S_ISREG(inode->i_mode)) {
- inode->i_op = &obdfs_file_inode_operations;
- EXIT;
- } else if (S_ISDIR(inode->i_mode)) {
- inode->i_op = &obdfs_dir_inode_operations;
- EXIT;
- } else if (S_ISLNK(inode->i_mode)) {
- inode->i_op = inode->i_blocks
- ?&obdfs_symlink_inode_operations
- :&obdfs_fast_symlink_inode_operations;
- EXIT;
- } else {
- init_special_inode(inode, inode->i_mode,
- ((int *)obdfs_i2info(inode)->oi_inline)[0]);
- }
-
- return;
+ struct obdo *oa;
+
+ ENTRY;
+ oa = obdo_fromid(IID(inode), inode->i_ino,
+ OBD_MD_FLNOTOBD | OBD_MD_FLBLOCKS);
+ if ( IS_ERR(oa) ) {
+ printk(__FUNCTION__ ": obdo_fromid failed\n");
+ EXIT;
+ return /* PTR_ERR(oa) */;
+ }
+
+ ODEBUG(oa);
+ 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 */
+
+ obdo_free(oa);
+ /* 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;
+ 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]);
+ }
+
+ return;
} /* obdfs_read_inode */
-static void obdfs_write_inode(struct inode *inode)
+static void obdfs_write_inode(struct inode *inode, int wait)
{
- struct obdo *oa;
- int err;
-
- ENTRY;
- if (IOPS(inode, setattr) == NULL) {
- printk(KERN_ERR __FUNCTION__ ": no setattr method!\n");
- EXIT;
- return;
- }
- oa = obdo_alloc();
- if ( !oa ) {
- printk(__FUNCTION__ ": obdo_alloc failed\n");
- EXIT;
- return;
- }
-
- oa->o_valid = OBD_MD_FLNOTOBD;
- obdfs_from_inode(oa, inode);
- err = IOPS(inode, setattr)(IID(inode), oa);
-
- if ( err )
- printk(__FUNCTION__ ": obd_setattr fails (%d)\n", err);
-
- EXIT;
- obdo_free(oa);
+ struct obdo *oa;
+ int err;
+
+ ENTRY;
+ if (IOPS(inode, setattr) == NULL) {
+ printk(KERN_ERR __FUNCTION__ ": no setattr method!\n");
+ EXIT;
+ return;
+ }
+ oa = obdo_alloc();
+ if ( !oa ) {
+ printk(__FUNCTION__ ": obdo_alloc failed\n");
+ EXIT;
+ return;
+ }
+
+ oa->o_valid = OBD_MD_FLNOTOBD;
+ obdfs_from_inode(oa, inode);
+ err = IOPS(inode, setattr)(IID(inode), oa);
+
+ if ( err )
+ printk(__FUNCTION__ ": obd_setattr fails (%d)\n", err);
+
+ EXIT;
+ obdo_free(oa);
} /* obdfs_write_inode */
*/
static void obdfs_put_inode(struct inode *inode)
{
- ENTRY;
- if (inode->i_nlink) {
- EXIT;
- return;
- }
-
- obdfs_dequeue_pages(inode);
- EXIT;
+ ENTRY;
+ if (inode->i_nlink) {
+ EXIT;
+ return;
+ }
+
+ obdfs_dequeue_pages(inode);
+ EXIT;
} /* obdfs_put_inode */
static void obdfs_delete_inode(struct inode *inode)
{
- struct obdo *oa;
- int err;
+ struct obdo *oa;
+ int err;
ENTRY;
- if (IOPS(inode, destroy) == NULL) {
- printk(KERN_ERR __FUNCTION__ ": no destroy method!\n");
- EXIT;
- return;
- }
-
- oa = obdo_alloc();
- if ( !oa ) {
- printk(__FUNCTION__ ": obdo_alloc failed\n");
- EXIT;
- return;
- }
- oa->o_valid = OBD_MD_FLNOTOBD;
- obdfs_from_inode(oa, inode);
-
- ODEBUG(oa);
- err = IOPS(inode, destroy)(IID(inode), oa);
- obdo_free(oa);
-
- if (err) {
- printk(__FUNCTION__ ": obd_destroy fails (%d)\n", err);
- EXIT;
- return;
- }
-
- EXIT;
+ if (IOPS(inode, destroy) == NULL) {
+ printk(KERN_ERR __FUNCTION__ ": no destroy method!\n");
+ EXIT;
+ return;
+ }
+
+ oa = obdo_alloc();
+ if ( !oa ) {
+ printk(__FUNCTION__ ": obdo_alloc failed\n");
+ EXIT;
+ return;
+ }
+ oa->o_valid = OBD_MD_FLNOTOBD;
+ obdfs_from_inode(oa, inode);
+
+ ODEBUG(oa);
+ err = IOPS(inode, destroy)(IID(inode), oa);
+ obdo_free(oa);
+
+ if (err) {
+ printk(__FUNCTION__ ": obd_destroy fails (%d)\n", err);
+ EXIT;
+ return;
+ }
+
+ EXIT;
} /* obdfs_delete_inode */
-static int obdfs_notify_change(struct dentry *de, struct iattr *attr)
+int obdfs_notify_change(struct dentry *de, struct iattr *attr)
{
- struct inode *inode = de->d_inode;
- struct obdo *oa;
- int err;
-
- ENTRY;
- if (IOPS(inode, setattr) == NULL) {
- printk(KERN_ERR __FUNCTION__ ": no setattr method!\n");
- EXIT;
- return -EIO;
- }
- oa = obdo_alloc();
- if ( !oa ) {
- printk(__FUNCTION__ ": obdo_alloc failed\n");
- return -ENOMEM;
- }
-
- oa->o_id = inode->i_ino;
- obdo_from_iattr(oa, attr);
+ struct inode *inode = de->d_inode;
+ struct obdo *oa;
+ int err;
+
+ ENTRY;
+ if (IOPS(inode, setattr) == NULL) {
+ printk(KERN_ERR __FUNCTION__ ": no setattr method!\n");
+ EXIT;
+ return -EIO;
+ }
+ oa = obdo_alloc();
+ if ( !oa ) {
+ printk(__FUNCTION__ ": obdo_alloc failed\n");
+ return -ENOMEM;
+ }
+
+ oa->o_id = inode->i_ino;
+ obdo_from_iattr(oa, attr);
err = IOPS(inode, setattr)(IID(inode), oa);
- if ( err )
- printk(__FUNCTION__ ": obd_setattr fails (%d)\n", err);
+ if ( err )
+ printk(__FUNCTION__ ": obd_setattr fails (%d)\n", err);
- EXIT;
- obdo_free(oa);
+ EXIT;
+ obdo_free(oa);
return err;
} /* obdfs_notify_change */
-static int obdfs_statfs(struct super_block *sb, struct statfs *buf,
- int bufsize)
+static int obdfs_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
- int err;
+ struct statfs tmp;
+ int bufsize = sizeof(*buf);
+ int err;
- ENTRY;
+ ENTRY;
- err = OPS(sb,statfs)(ID(sb), &tmp);
- if ( err ) {
- printk(__FUNCTION__ ": obd_statfs fails (%d)\n", err);
- return err;
- }
- copy_to_user(buf, &tmp, (bufsize<sizeof(tmp)) ? bufsize : sizeof(tmp));
+ err = OPS(sb,statfs)(ID(sb), &tmp);
+ if ( err ) {
+ printk(__FUNCTION__ ": obd_statfs fails (%d)\n", err);
+ return err;
+ }
+ copy_to_user(buf, &tmp, (bufsize<sizeof(tmp)) ? bufsize : sizeof(tmp));
- EXIT;
+ EXIT;
- return err;
+ return err;
}
/* exported operations */
struct super_operations obdfs_super_operations =
{
- obdfs_read_inode, /* read_inode */
- obdfs_write_inode, /* write_inode */
- obdfs_put_inode, /* put_inode */
- obdfs_delete_inode, /* delete_inode */
- obdfs_notify_change, /* notify_change */
- obdfs_put_super, /* put_super */
- NULL, /* write_super */
- obdfs_statfs, /* statfs */
- NULL /* remount_fs */
+ read_inode: obdfs_read_inode,
+ write_inode: obdfs_write_inode,
+ 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 = {
int init_obdfs(void)
{
- int err;
+ int err;
- printk(KERN_INFO "OBDFS v0.1, braam@stelias.com\n");
+ printk(KERN_INFO "OBDFS v0.1, braam@stelias.com\n");
- obdfs_sysctl_init();
+ obdfs_sysctl_init();
- INIT_LIST_HEAD(&obdfs_super_list);
- err = obdfs_init_pgrqcache();
- if (err)
- return err;
+ INIT_LIST_HEAD(&obdfs_super_list);
+ err = obdfs_init_pgrqcache();
+ if (err)
+ return err;
- obdfs_flushd_init();
- return register_filesystem(&obdfs_fs_type);
+ obdfs_flushd_init();
+ return register_filesystem(&obdfs_fs_type);
}
+struct address_space_operations obdfs_aops = {
+ readpage: obdfs_readpage,
+ writepage: obdfs_writepage,
+ sync_page: block_sync_page,
+ prepare_write: NULL,
+ commit_write: generic_commit_write,
+ bmap: NULL
+};
+
#ifdef MODULE
int init_module(void)
{
- return init_obdfs();
+ 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;
+ 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
*/
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
#include <linux/mm.h>
#include <linux/stat.h>
#include <linux/locks.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);
+ char *s = obdfs_i2info(dentry->d_inode)->oi_inline;
+ return vfs_readlink(dentry, buffer, buflen, s);
}
-static struct dentry *obdfs_fast_follow_link(struct dentry *dentry, struct dentry *base, unsigned flags)
+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(dentry, base, flags, s);
+ char *s = obdfs_i2info(dentry->d_inode)->oi_inline;
+ return vfs_follow_link(nd, s);
}
struct inode_operations obdfs_fast_symlink_inode_operations = {
- readlink: obdfs_fast_readlink,
- follow_link: obdfs_fast_follow_link,
+ readlink: obdfs_fast_readlink,
+ follow_link: obdfs_fast_follow_link,
};
static int obdfs_readlink(struct dentry *dentry, char *buffer, int buflen)
{
- struct page *page = NULL;
- int res;
+ struct page *page = NULL;
+ int res;
- ENTRY;
- OIDEBUG(dentry->d_inode);
- page = obdfs_getpage(dentry->d_inode, 0, 0, 0);
- /* PDEBUG(page, "readlink"); */
- if (!page) {
- EXIT;
- return 0;
- }
- res = vfs_readlink(dentry, buffer, buflen, (char *)page_address(page));
- page_cache_release(page);
- EXIT;
- return res;
+ ENTRY;
+ OIDEBUG(dentry->d_inode);
+ page = obdfs_getpage(dentry->d_inode, 0, 0, 0);
+ /* PDEBUG(page, "readlink"); */
+ 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 struct dentry * obdfs_follow_link(struct dentry * dentry,
- struct dentry *base,
- unsigned int follow)
+static int obdfs_follow_link(struct dentry * dentry,
+ struct nameidata *nd)
{
- struct page *page = NULL;
- struct dentry *res;
+ struct page *page = NULL;
+ int res;
- ENTRY;
- OIDEBUG(dentry->d_inode);
- page = obdfs_getpage(dentry->d_inode, 0, 0, 0);
- /* PDEBUG(page, "follow_link"); */
- if (!page) {
- dput(base);
- EXIT;
- return ERR_PTR(-EIO);
- }
- res = vfs_follow_link(dentry, base, follow, (char *)page_address(page));
- page_cache_release(page);
- EXIT;
- return res;
+ ENTRY;
+ OIDEBUG(dentry->d_inode);
+ page = obdfs_getpage(dentry->d_inode, 0, 0, 0);
+ /* PDEBUG(page, "follow_link"); */
+ 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 = {