diff options
Diffstat (limited to 'fs/ocfs2/export.c')
| -rw-r--r-- | fs/ocfs2/export.c | 243 |
1 files changed, 133 insertions, 110 deletions
diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c index 5810160d92a..29651167190 100644 --- a/fs/ocfs2/export.c +++ b/fs/ocfs2/export.c @@ -26,17 +26,20 @@ #include <linux/fs.h> #include <linux/types.h> -#define MLOG_MASK_PREFIX ML_EXPORT #include <cluster/masklog.h> #include "ocfs2.h" +#include "alloc.h" #include "dir.h" #include "dlmglue.h" +#include "dcache.h" #include "export.h" #include "inode.h" #include "buffer_head_io.h" +#include "suballoc.h" +#include "ocfs2_trace.h" struct ocfs2_inode_handle { @@ -44,41 +47,98 @@ struct ocfs2_inode_handle u32 ih_generation; }; -static struct dentry *ocfs2_get_dentry(struct super_block *sb, void *vobjp) +static struct dentry *ocfs2_get_dentry(struct super_block *sb, + struct ocfs2_inode_handle *handle) { - struct ocfs2_inode_handle *handle = vobjp; struct inode *inode; + struct ocfs2_super *osb = OCFS2_SB(sb); + u64 blkno = handle->ih_blkno; + int status, set; struct dentry *result; - mlog_entry("(0x%p, 0x%p)\n", sb, handle); + trace_ocfs2_get_dentry_begin(sb, handle, (unsigned long long)blkno); - if (handle->ih_blkno == 0) { - mlog_errno(-ESTALE); - return ERR_PTR(-ESTALE); + if (blkno == 0) { + result = ERR_PTR(-ESTALE); + goto bail; + } + + inode = ocfs2_ilookup(sb, blkno); + /* + * If the inode exists in memory, we only need to check it's + * generation number + */ + if (inode) + goto check_gen; + + /* + * This will synchronize us against ocfs2_delete_inode() on + * all nodes + */ + status = ocfs2_nfs_sync_lock(osb, 1); + if (status < 0) { + mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status); + goto check_err; + } + + status = ocfs2_test_inode_bit(osb, blkno, &set); + trace_ocfs2_get_dentry_test_bit(status, set); + if (status < 0) { + if (status == -EINVAL) { + /* + * The blkno NFS gave us doesn't even show up + * as an inode, we return -ESTALE to be + * nice + */ + status = -ESTALE; + } else + mlog(ML_ERROR, "test inode bit failed %d\n", status); + goto unlock_nfs_sync; + } + + /* If the inode allocator bit is clear, this inode must be stale */ + if (!set) { + status = -ESTALE; + goto unlock_nfs_sync; } - inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno); + inode = ocfs2_iget(osb, blkno, 0, 0); + +unlock_nfs_sync: + ocfs2_nfs_sync_unlock(osb, 1); + +check_err: + if (status < 0) { + if (status == -ESTALE) { + trace_ocfs2_get_dentry_stale((unsigned long long)blkno, + handle->ih_generation); + } + result = ERR_PTR(status); + goto bail; + } if (IS_ERR(inode)) { mlog_errno(PTR_ERR(inode)); - return (void *)inode; + result = (void *)inode; + goto bail; } +check_gen: if (handle->ih_generation != inode->i_generation) { iput(inode); - mlog_errno(-ESTALE); - return ERR_PTR(-ESTALE); + trace_ocfs2_get_dentry_generation((unsigned long long)blkno, + handle->ih_generation, + inode->i_generation); + result = ERR_PTR(-ESTALE); + goto bail; } - result = d_alloc_anon(inode); + result = d_obtain_alias(inode); + if (IS_ERR(result)) + mlog_errno(PTR_ERR(result)); - if (!result) { - iput(inode); - mlog_errno(-ENOMEM); - return ERR_PTR(-ENOMEM); - } - - mlog_exit_ptr(result); +bail: + trace_ocfs2_get_dentry_end(result); return result; } @@ -87,18 +147,12 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) int status; u64 blkno; struct dentry *parent; - struct inode *inode; struct inode *dir = child->d_inode; - struct buffer_head *dirent_bh = NULL; - struct ocfs2_dir_entry *dirent; - mlog_entry("(0x%p, '%.*s')\n", child, - child->d_name.len, child->d_name.name); + trace_ocfs2_get_parent(child, child->d_name.len, child->d_name.name, + (unsigned long long)OCFS2_I(dir)->ip_blkno); - mlog(0, "find parent of directory %"MLFu64"\n", - OCFS2_I(dir)->ip_blkno); - - status = ocfs2_meta_lock(dir, NULL, NULL, 0); + status = ocfs2_inode_lock(dir, NULL, 0); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -106,74 +160,60 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) goto bail; } - status = ocfs2_find_files_on_disk("..", 2, &blkno, dir, &dirent_bh, - &dirent); + status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno); if (status < 0) { parent = ERR_PTR(-ENOENT); goto bail_unlock; } - inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno); - if (IS_ERR(inode)) { - mlog(ML_ERROR, "Unable to create inode %"MLFu64"\n", blkno); - parent = ERR_PTR(-EACCES); - goto bail_unlock; - } - - parent = d_alloc_anon(inode); - if (!parent) { - iput(inode); - parent = ERR_PTR(-ENOMEM); - } + parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0)); bail_unlock: - ocfs2_meta_unlock(dir, 0); - - if (dirent_bh) - brelse(dirent_bh); + ocfs2_inode_unlock(dir, 0); bail: - mlog_exit_ptr(parent); + trace_ocfs2_get_parent_end(parent); return parent; } -static int ocfs2_encode_fh(struct dentry *dentry, __be32 *fh, int *max_len, - int connectable) +static int ocfs2_encode_fh(struct inode *inode, u32 *fh_in, int *max_len, + struct inode *parent) { - struct inode *inode = dentry->d_inode; int len = *max_len; int type = 1; u64 blkno; u32 generation; - - mlog_entry("(0x%p, '%.*s', 0x%p, %d, %d)\n", dentry, - dentry->d_name.len, dentry->d_name.name, - fh, len, connectable); - - if (len < 3 || (connectable && len < 6)) { - mlog(ML_ERROR, "fh buffer is too small for encoding\n"); - type = 255; + __le32 *fh = (__force __le32 *) fh_in; + +#ifdef TRACE_HOOKS_ARE_NOT_BRAINDEAD_IN_YOUR_OPINION +#error "You go ahead and fix that mess, then. Somehow" + trace_ocfs2_encode_fh_begin(dentry, dentry->d_name.len, + dentry->d_name.name, + fh, len, connectable); +#endif + + if (parent && (len < 6)) { + *max_len = 6; + type = FILEID_INVALID; + goto bail; + } else if (len < 3) { + *max_len = 3; + type = FILEID_INVALID; goto bail; } blkno = OCFS2_I(inode)->ip_blkno; generation = inode->i_generation; - mlog(0, "Encoding fh: blkno: %"MLFu64", generation: %u\n", - blkno, generation); + trace_ocfs2_encode_fh_self((unsigned long long)blkno, generation); len = 3; fh[0] = cpu_to_le32((u32)(blkno >> 32)); fh[1] = cpu_to_le32((u32)(blkno & 0xffffffff)); fh[2] = cpu_to_le32(generation); - if (connectable && !S_ISDIR(inode->i_mode)) { - struct inode *parent; - - spin_lock(&dentry->d_lock); - - parent = dentry->d_parent->d_inode; + if (parent) { blkno = OCFS2_I(parent)->ip_blkno; generation = parent->i_generation; @@ -181,68 +221,51 @@ static int ocfs2_encode_fh(struct dentry *dentry, __be32 *fh, int *max_len, fh[4] = cpu_to_le32((u32)(blkno & 0xffffffff)); fh[5] = cpu_to_le32(generation); - spin_unlock(&dentry->d_lock); - len = 6; type = 2; - mlog(0, "Encoding parent: blkno: %"MLFu64", generation: %u\n", - blkno, generation); + trace_ocfs2_encode_fh_parent((unsigned long long)blkno, + generation); } - + *max_len = len; bail: - mlog_exit(type); + trace_ocfs2_encode_fh_type(type); return type; } -static struct dentry *ocfs2_decode_fh(struct super_block *sb, __be32 *fh, - int fh_len, int fileid_type, - int (*acceptable)(void *context, - struct dentry *de), - void *context) +static struct dentry *ocfs2_fh_to_dentry(struct super_block *sb, + struct fid *fid, int fh_len, int fh_type) { - struct ocfs2_inode_handle handle, parent; - struct dentry *ret = NULL; - - mlog_entry("(0x%p, 0x%p, %d, %d, 0x%p, 0x%p)\n", - sb, fh, fh_len, fileid_type, acceptable, context); - - if (fh_len < 3 || fileid_type > 2) - goto bail; - - if (fileid_type == 2) { - if (fh_len < 6) - goto bail; + struct ocfs2_inode_handle handle; - parent.ih_blkno = (u64)le32_to_cpu(fh[3]) << 32; - parent.ih_blkno |= (u64)le32_to_cpu(fh[4]); - parent.ih_generation = le32_to_cpu(fh[5]); + if (fh_len < 3 || fh_type > 2) + return NULL; - mlog(0, "Decoding parent: blkno: %"MLFu64", generation: %u\n", - parent.ih_blkno, parent.ih_generation); - } - - handle.ih_blkno = (u64)le32_to_cpu(fh[0]) << 32; - handle.ih_blkno |= (u64)le32_to_cpu(fh[1]); - handle.ih_generation = le32_to_cpu(fh[2]); + handle.ih_blkno = (u64)le32_to_cpu(fid->raw[0]) << 32; + handle.ih_blkno |= (u64)le32_to_cpu(fid->raw[1]); + handle.ih_generation = le32_to_cpu(fid->raw[2]); + return ocfs2_get_dentry(sb, &handle); +} - mlog(0, "Encoding fh: blkno: %"MLFu64", generation: %u\n", - handle.ih_blkno, handle.ih_generation); +static struct dentry *ocfs2_fh_to_parent(struct super_block *sb, + struct fid *fid, int fh_len, int fh_type) +{ + struct ocfs2_inode_handle parent; - ret = ocfs2_export_ops.find_exported_dentry(sb, &handle, &parent, - acceptable, context); + if (fh_type != 2 || fh_len < 6) + return NULL; -bail: - mlog_exit_ptr(ret); - return ret; + parent.ih_blkno = (u64)le32_to_cpu(fid->raw[3]) << 32; + parent.ih_blkno |= (u64)le32_to_cpu(fid->raw[4]); + parent.ih_generation = le32_to_cpu(fid->raw[5]); + return ocfs2_get_dentry(sb, &parent); } -struct export_operations ocfs2_export_ops = { - .decode_fh = ocfs2_decode_fh, +const struct export_operations ocfs2_export_ops = { .encode_fh = ocfs2_encode_fh, - + .fh_to_dentry = ocfs2_fh_to_dentry, + .fh_to_parent = ocfs2_fh_to_parent, .get_parent = ocfs2_get_parent, - .get_dentry = ocfs2_get_dentry, }; |
