summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorDavid S. Miller <davem@nuts.ninka.net>2002-10-15 07:41:35 -0700
committerDavid S. Miller <davem@nuts.ninka.net>2002-10-15 07:41:35 -0700
commit8fbfe7cd5594010a23cb4e81786d1fb8015ffdee (patch)
treeb5be190f22984395209823ec3cac1c76fc93f67f /fs
parente22f7f5fd43205bfd20ea3a7bb4e689cb3f3d278 (diff)
parent5a7728c6d3eb83df9d120944cca4cf476dd326a1 (diff)
Merge nuts.ninka.net:/home/davem/src/BK/network-2.5
into nuts.ninka.net:/home/davem/src/BK/net-2.5
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.help15
-rw-r--r--fs/Config.in11
-rw-r--r--fs/Makefile5
-rw-r--r--fs/afs/Makefile36
-rw-r--r--fs/afs/cache-layout.h224
-rw-r--r--fs/afs/callback.c168
-rw-r--r--fs/afs/cell.c452
-rw-r--r--fs/afs/cell.h63
-rw-r--r--fs/afs/cmservice.c639
-rw-r--r--fs/afs/cmservice.h27
-rw-r--r--fs/afs/dir.c642
-rw-r--r--fs/afs/errors.h34
-rw-r--r--fs/afs/file.c143
-rw-r--r--fs/afs/fsclient.c816
-rw-r--r--fs/afs/fsclient.h53
-rw-r--r--fs/afs/inode.c418
-rw-r--r--fs/afs/internal.h127
-rw-r--r--fs/afs/kafsasyncd.c260
-rw-r--r--fs/afs/kafsasyncd.h49
-rw-r--r--fs/afs/kafstimod.c211
-rw-r--r--fs/afs/kafstimod.h45
-rw-r--r--fs/afs/main.c193
-rw-r--r--fs/afs/misc.c39
-rw-r--r--fs/afs/mntpt.c112
-rw-r--r--fs/afs/mount.h23
-rw-r--r--fs/afs/proc.c739
-rw-r--r--fs/afs/server.c489
-rw-r--r--fs/afs/server.h97
-rw-r--r--fs/afs/super.c595
-rw-r--r--fs/afs/super.h43
-rw-r--r--fs/afs/transport.h21
-rw-r--r--fs/afs/types.h152
-rw-r--r--fs/afs/vlclient.c662
-rw-r--r--fs/afs/vlclient.h95
-rw-r--r--fs/afs/vlocation.c824
-rw-r--r--fs/afs/vnode.c316
-rw-r--r--fs/afs/vnode.h88
-rw-r--r--fs/afs/volume.c430
-rw-r--r--fs/afs/volume.h92
-rw-r--r--fs/block_dev.c119
-rw-r--r--fs/buffer.c7
-rw-r--r--fs/dcache.c1
-rw-r--r--fs/dcookies.c323
-rw-r--r--fs/jfs/jfs_dtree.c6
-rw-r--r--fs/jfs/jfs_mount.c4
-rw-r--r--fs/nfs/Makefile1
-rw-r--r--fs/nfs/file.c6
-rw-r--r--fs/nfs/inode.c578
-rw-r--r--fs/nfs/nfs2xdr.c29
-rw-r--r--fs/nfs/nfs3proc.c40
-rw-r--r--fs/nfs/nfs3xdr.c18
-rw-r--r--fs/nfs/nfs4proc.c1577
-rw-r--r--fs/nfs/nfs4renewd.c110
-rw-r--r--fs/nfs/nfs4state.c81
-rw-r--r--fs/nfs/nfs4xdr.c1777
-rw-r--r--fs/nfs/proc.c53
-rw-r--r--fs/partitions/check.c454
-rw-r--r--fs/proc/proc_misc.c1
-rw-r--r--fs/xfs/linux/xfs_aops.c242
-rw-r--r--fs/xfs/linux/xfs_fs_subr.c2
-rw-r--r--fs/xfs/linux/xfs_globals.c9
-rw-r--r--fs/xfs/linux/xfs_globals.h1
-rw-r--r--fs/xfs/linux/xfs_ioctl.c10
-rw-r--r--fs/xfs/linux/xfs_iops.c64
-rw-r--r--fs/xfs/linux/xfs_iops.h1
-rw-r--r--fs/xfs/linux/xfs_linux.h4
-rw-r--r--fs/xfs/linux/xfs_lrw.c285
-rw-r--r--fs/xfs/linux/xfs_lrw.h8
-rw-r--r--fs/xfs/linux/xfs_super.c195
-rw-r--r--fs/xfs/linux/xfs_super.h10
-rw-r--r--fs/xfs/linux/xfs_sysctl.c61
-rw-r--r--fs/xfs/linux/xfs_sysctl.h15
-rw-r--r--fs/xfs/linux/xfs_vfs.h10
-rw-r--r--fs/xfs/linux/xfs_vnode.c46
-rw-r--r--fs/xfs/linux/xfs_vnode.h27
-rw-r--r--fs/xfs/pagebuf/page_buf.c27
-rw-r--r--fs/xfs/pagebuf/page_buf.h45
-rw-r--r--fs/xfs/pagebuf/page_buf_locking.c81
-rw-r--r--fs/xfs/support/debug.c39
-rw-r--r--fs/xfs/support/move.c4
-rw-r--r--fs/xfs/support/move.h5
-rw-r--r--fs/xfs/support/uuid.c4
-rw-r--r--fs/xfs/xfs_alloc.c22
-rw-r--r--fs/xfs/xfs_alloc_btree.c36
-rw-r--r--fs/xfs/xfs_arch.h4
-rw-r--r--fs/xfs/xfs_attr.c6
-rw-r--r--fs/xfs/xfs_attr_fetch.c2
-rw-r--r--fs/xfs/xfs_attr_leaf.c92
-rw-r--r--fs/xfs/xfs_bmap.c98
-rw-r--r--fs/xfs/xfs_bmap_btree.c321
-rw-r--r--fs/xfs/xfs_bmap_btree.h55
-rw-r--r--fs/xfs/xfs_btree.c6
-rw-r--r--fs/xfs/xfs_buf_item.c2
-rw-r--r--fs/xfs/xfs_clnt.h9
-rw-r--r--fs/xfs/xfs_da_btree.c40
-rw-r--r--fs/xfs/xfs_dir.c10
-rw-r--r--fs/xfs/xfs_dir2.c6
-rw-r--r--fs/xfs/xfs_dir2_block.c14
-rw-r--r--fs/xfs/xfs_dir2_data.c2
-rw-r--r--fs/xfs/xfs_dir2_leaf.c30
-rw-r--r--fs/xfs/xfs_dir2_node.c24
-rw-r--r--fs/xfs/xfs_dir2_sf.c32
-rw-r--r--fs/xfs/xfs_dir2_sf.h2
-rw-r--r--fs/xfs/xfs_dir2_trace.c4
-rw-r--r--fs/xfs/xfs_dir_leaf.c74
-rw-r--r--fs/xfs/xfs_dir_sf.h2
-rw-r--r--fs/xfs/xfs_dquot.c14
-rw-r--r--fs/xfs/xfs_error.c16
-rw-r--r--fs/xfs/xfs_fs.h12
-rw-r--r--fs/xfs/xfs_fsops.c16
-rw-r--r--fs/xfs/xfs_ialloc.c4
-rw-r--r--fs/xfs/xfs_ialloc_btree.c36
-rw-r--r--fs/xfs/xfs_iget.c69
-rw-r--r--fs/xfs/xfs_inode.c143
-rw-r--r--fs/xfs/xfs_inode.h24
-rw-r--r--fs/xfs/xfs_inode_item.c42
-rw-r--r--fs/xfs/xfs_inode_item.h5
-rw-r--r--fs/xfs/xfs_itable.c2
-rw-r--r--fs/xfs/xfs_log.c66
-rw-r--r--fs/xfs/xfs_log_recover.c66
-rw-r--r--fs/xfs/xfs_mount.c106
-rw-r--r--fs/xfs/xfs_mount.h15
-rw-r--r--fs/xfs/xfs_qm.c37
-rw-r--r--fs/xfs/xfs_qm_syscalls.c6
-rw-r--r--fs/xfs/xfs_quota_priv.h2
-rw-r--r--fs/xfs/xfs_rtalloc.c4
-rw-r--r--fs/xfs/xfs_rw.c4
-rw-r--r--fs/xfs/xfs_rw.h2
-rw-r--r--fs/xfs/xfs_trans.c1
-rw-r--r--fs/xfs/xfs_trans.h5
-rw-r--r--fs/xfs/xfs_trans_buf.c4
-rw-r--r--fs/xfs/xfs_trans_inode.c14
-rw-r--r--fs/xfs/xfs_types.h32
-rw-r--r--fs/xfs/xfs_utils.c4
-rw-r--r--fs/xfs/xfs_utils.h2
-rw-r--r--fs/xfs/xfs_vfsops.c209
-rw-r--r--fs/xfs/xfs_vnodeops.c27
-rw-r--r--fs/xfs/xfsidbg.c315
138 files changed, 15819 insertions, 2206 deletions
diff --git a/fs/Config.help b/fs/Config.help
index 44622847c4df..76ffd7584add 100644
--- a/fs/Config.help
+++ b/fs/Config.help
@@ -535,6 +535,13 @@ CONFIG_NFS_DIRECTIO
causes open() to return EINVAL if a file residing in NFS is
opened with the O_DIRECT flag.
+CONFIG_NFS_V4
+ Say Y here if you want your NFS client to be able to speak the newer
+ version 4 of the NFS protocol. This feature is experimental, and
+ should only be used if you are interested in helping to test NFSv4.
+
+ If unsure, say N.
+
CONFIG_ROOT_NFS
If you want your Linux box to mount its whole root file system (the
one containing the directory /) from some other computer over the
@@ -1137,3 +1144,11 @@ CONFIG_XFS_RT
If unsure, say N.
+CONFIG_AFS_FS
+ If you say Y here, you will get an experimental Andrew File System
+ driver. It currently only supports unsecured read-only AFS access.
+
+ See Documentation/filesystems/afs.txt for more intormation.
+
+ If unsure, say N.
+
diff --git a/fs/Config.in b/fs/Config.in
index e6eb844338ec..0464a17a8dbd 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -117,6 +117,7 @@ if [ "$CONFIG_NET" = "y" ]; then
dep_tristate 'InterMezzo file system support (replicating fs) (EXPERIMENTAL)' CONFIG_INTERMEZZO_FS $CONFIG_INET $CONFIG_EXPERIMENTAL
dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET
dep_mbool ' Provide NFSv3 client support' CONFIG_NFS_V3 $CONFIG_NFS_FS
+ dep_mbool ' Provide NFSv4 client support (EXPERIMENTAL)' CONFIG_NFS_V4 $CONFIG_NFS_FS $CONFIG_EXPERIMENTAL
dep_bool ' Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP
dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET
@@ -157,6 +158,16 @@ if [ "$CONFIG_NET" = "y" ]; then
# for fs/nls/Config.in
define_bool CONFIG_NCPFS_NLS n
fi
+
+ dep_tristate 'Andrew File System support (AFS) (Experimental)' CONFIG_AFS_FS $CONFIG_INET $CONFIG_EXPERIMENTAL
+ if [ "$CONFIG_AFS_FS" = "y" ]; then
+ define_tristate CONFIG_RXRPC y
+ else
+ if [ "$CONFIG_AFS_FS" = "m" ]; then
+ define_tristate CONFIG_RXRPC m
+ fi
+ fi
+
endmenu
else
diff --git a/fs/Makefile b/fs/Makefile
index d902bdd8bda3..c28d57ab55a9 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -6,7 +6,7 @@
#
export-objs := open.o dcache.o buffer.o bio.o inode.o dquot.o mpage.o aio.o \
- fcntl.o read_write.o
+ fcntl.o read_write.o dcookies.o
obj-y := open.o read_write.o devices.o file_table.o buffer.o \
bio.o super.o block_dev.o char_dev.o stat.o exec.o pipe.o \
@@ -40,6 +40,8 @@ obj-y += partitions/
obj-y += driverfs/
obj-y += devpts/
+obj-$(CONFIG_PROFILING) += dcookies.o
+
# Do not add any filesystems before this line
obj-$(CONFIG_EXT3_FS) += ext3/ # Before ext2 so root fs can be ext3
obj-$(CONFIG_JBD) += jbd/
@@ -84,5 +86,6 @@ obj-$(CONFIG_REISERFS_FS) += reiserfs/
obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/
obj-$(CONFIG_JFS_FS) += jfs/
obj-$(CONFIG_XFS_FS) += xfs/
+obj-$(CONFIG_AFS_FS) += afs/
include $(TOPDIR)/Rules.make
diff --git a/fs/afs/Makefile b/fs/afs/Makefile
new file mode 100644
index 000000000000..753cf8c5b4eb
--- /dev/null
+++ b/fs/afs/Makefile
@@ -0,0 +1,36 @@
+#
+# Makefile for Red Hat Linux AFS client.
+#
+
+kafs-objs := \
+ callback.o \
+ cell.o \
+ cmservice.o \
+ dir.o \
+ file.o \
+ fsclient.o \
+ inode.o \
+ kafsasyncd.o \
+ kafstimod.o \
+ main.o \
+ misc.o \
+ mntpt.o \
+ proc.o \
+ server.o \
+ super.o \
+ vlclient.o \
+ vlocation.o \
+ vnode.o \
+ volume.o
+
+# cache.o
+
+obj-m := kafs.o
+
+# superfluous for 2.5, but needed for 2.4..
+ifeq "$(VERSION).$(PATCHLEVEL)" "2.4"
+kafs.o: $(kafs-objs)
+ $(LD) -r -o kafs.o $(kafs-objs)
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/fs/afs/cache-layout.h b/fs/afs/cache-layout.h
new file mode 100644
index 000000000000..e71afd719a3f
--- /dev/null
+++ b/fs/afs/cache-layout.h
@@ -0,0 +1,224 @@
+/* cache-layout.h: AFS cache layout
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * The cache is stored on a block device and is laid out as:
+ *
+ * 0 +------------------------------------------------
+ * |
+ * | SuperBlock
+ * |
+ * 1 +------------------------------------------------
+ * |
+ * | file-meta-data File: Data block #0
+ * | - file-meta-data file (volix #0 file #0) : Meta-data block
+ * | - contains direct pointers to first 64 file data blocks
+ * | - Cached cell catalogue file (volix #0 file #1) file: Meta-data block
+ * | - Cached volume location catalogue file (volix #0 file #2): Meta-data block
+ * | - Vnode catalogue hash bucket #n file: Meta-data block
+ * |
+ * 2 +------------------------------------------------
+ * |
+ * | Bitmap Block Allocation Bitmap
+ * | - 1 bit per block in the bitmap block
+ * | - bit 0 of dword 0 refers to the bitmap block 0
+ * | - set if the bitmap block is full
+ * | - 32768 bits per block, requiring 4 blocks for a 16Tb cache
+ * | - bitmap bitmap blocks are cleared initially
+ * | - not present if <4 bitmap blocks
+ * |
+ * +------------------------------------------------
+ * |
+ * | File Block Allocation Bitmap
+ * | - 1 bit per block in the cache
+ * | - bit 0 of dword 0 refers to the first block of the data cache
+ * | - set if block is allocated
+ * | - 32768 bits per block, requiring 131072 blocks for a 16Tb cache
+ * | - bitmap blocks are cleared lazily (sb->bix_bitmap_unready)
+ * |
+ * +------------------------------------------------
+ * |
+ * | Data Cache
+ * |
+ * End +------------------------------------------------
+ *
+ * Blocks are indexed by an unsigned 32-bit word, meaning that the cache can hold up to 2^32 pages,
+ * or 16Tb in total.
+ *
+ * Credentials will be cached in memory, since they are subject to change without notice, and are
+ * difficult to derive manually, being constructed from the following information:
+ * - per vnode user ID and mode mask
+ * - parent directory ACL
+ * - directory ACL (dirs only)
+ * - group lists from ptserver
+ */
+
+#ifndef _LINUX_AFS_CACHE_LAYOUT_H
+#define _LINUX_AFS_CACHE_LAYOUT_H
+
+#include "types.h"
+
+typedef u32 afsc_blockix_t;
+typedef u32 afsc_cellix_t;
+
+/* Cached volume index
+ * - afsc_volix_t/4 is the index into the volume cache
+ * - afsc_volix_t%4 is 0 for R/W, 1 for R/O and 2 for Bak (3 is not used)
+ * - afsc_volix_t==0-3 refers to a "virtual" volume that stores meta-data about the cache
+ */
+typedef struct {
+ u32 index;
+} afsc_volix_t;
+
+#define AFSC_VNCAT_HASH_NBUCKETS 128
+
+/* special meta file IDs (all cell 0 vol 0) */
+enum afsc_meta_fids {
+ AFSC_META_FID_METADATA = 0,
+ AFSC_META_FID_CELL_CATALOGUE = 1,
+ AFSC_META_FID_VLDB_CATALOGUE = 2,
+ AFSC_META_FID_VNODE_CATALOGUE0 = 3,
+ AFSC_META_FID__COUNT = AFSC_VNCAT_HASH_NBUCKETS + 3
+};
+
+/*****************************************************************************/
+/*
+ * cache superblock block layout
+ * - the blockdev is prepared for initialisation by 'echo "kafsuninit" >/dev/hdaXX' before mounting
+ * - when initialised, the magic number is changed to "kafs-cache"
+ */
+struct afsc_super_block
+{
+ char magic[10]; /* magic number */
+#define AFSC_SUPER_MAGIC "kafs-cache"
+#define AFSC_SUPER_MAGIC_NEEDS_INIT "kafsuninit"
+#define AFSC_SUPER_MAGIC_SIZE 10
+
+ unsigned short endian; /* 0x1234 stored CPU-normal order */
+#define AFSC_SUPER_ENDIAN 0x1234
+
+ unsigned version; /* format version */
+#define AFSC_SUPER_VERSION 1
+
+ /* layout */
+ unsigned bsize; /* cache block size */
+ afsc_blockix_t bix_bitmap_fullmap; /* block ix of bitmap full bitmap */
+ afsc_blockix_t bix_bitmap; /* block ix of alloc bitmap */
+ afsc_blockix_t bix_bitmap_unready; /* block ix of unready area of bitmap */
+ afsc_blockix_t bix_cache; /* block ix of data cache */
+ afsc_blockix_t bix_end; /* block ix of end of cache */
+};
+
+/*****************************************************************************/
+/*
+ * vnode (inode) metadata cache record
+ * - padded out to 512 bytes and stored eight to a page
+ * - only the data version is necessary
+ * - disconnected operation is not supported
+ * - afs_iget() contacts the server to get the meta-data _anyway_ when an inode is first brought
+ * into memory
+ * - at least 64 direct block pointers will be available (a directory is max 256Kb)
+ * - any block pointer which is 0 indicates an uncached page
+ */
+struct afsc_vnode_meta
+{
+ /* file ID */
+ afsc_volix_t volume_ix; /* volume catalogue index */
+ unsigned vnode; /* vnode number */
+ unsigned unique; /* FID unique */
+ unsigned size; /* size of file */
+ time_t mtime; /* last modification time */
+
+ /* file status */
+ afs_dataversion_t version; /* current data version */
+
+ /* file contents */
+ afsc_blockix_t dbl_indirect; /* double indirect block index */
+ afsc_blockix_t indirect; /* single indirect block 0 index */
+ afsc_blockix_t direct[0]; /* direct block index (#AFSC_VNODE_META_DIRECT) */
+};
+
+#define AFSC_VNODE_META_RECSIZE 512 /* record size */
+
+#define AFSC_VNODE_META_DIRECT \
+ ((AFSC_VNODE_META_RECSIZE-sizeof(struct afsc_vnode_meta))/sizeof(afsc_blockix_t))
+
+#define AFSC_VNODE_META_PER_PAGE (PAGE_SIZE / AFSC_VNODE_META_RECSIZE)
+
+/*****************************************************************************/
+/*
+ * entry in the cached cell catalogue
+ */
+struct afsc_cell_record
+{
+ char name[64]; /* cell name (padded with NULs) */
+ struct in_addr servers[16]; /* cached cell servers */
+};
+
+/*****************************************************************************/
+/*
+ * entry in the cached volume location catalogue
+ * - indexed by afsc_volix_t/4
+ */
+struct afsc_vldb_record
+{
+ char name[64]; /* volume name (padded with NULs) */
+ afs_volid_t vid[3]; /* volume IDs for R/W, R/O and Bak volumes */
+ unsigned char vidmask; /* voltype mask for vid[] */
+ unsigned char _pad[1];
+ unsigned short nservers; /* number of entries used in servers[] */
+ struct in_addr servers[8]; /* fileserver addresses */
+ unsigned char srvtmask[8]; /* voltype masks for servers[] */
+#define AFSC_VOL_STM_RW 0x01 /* server holds a R/W version of the volume */
+#define AFSC_VOL_STM_RO 0x02 /* server holds a R/O version of the volume */
+#define AFSC_VOL_STM_BAK 0x04 /* server holds a backup version of the volume */
+
+ afsc_cellix_t cell_ix; /* cell catalogue index (MAX_UINT if unused) */
+ time_t ctime; /* time at which cached */
+};
+
+/*****************************************************************************/
+/*
+ * vnode catalogue entry
+ * - must be 2^x size so that do_generic_file_read doesn't present them split across pages
+ */
+struct afsc_vnode_catalogue
+{
+ afsc_volix_t volume_ix; /* volume catalogue index */
+ afs_vnodeid_t vnode; /* vnode ID */
+ u32 meta_ix; /* metadata file index */
+ u32 atime; /* last time entry accessed */
+} __attribute__((packed));
+
+#define AFSC_VNODE_CATALOGUE_PER_BLOCK ((size_t)(PAGE_SIZE/sizeof(struct afsc_vnode_catalogue)))
+
+/*****************************************************************************/
+/*
+ * vnode data "page directory" block
+ * - first 1024 pages don't map through here
+ * - PAGE_SIZE in size
+ */
+struct afsc_indirect_block
+{
+ afsc_blockix_t pt_bix[1024]; /* "page table" block indices */
+};
+
+/*****************************************************************************/
+/*
+ * vnode data "page table" block
+ * - PAGE_SIZE in size
+ */
+struct afsc_dbl_indirect_block
+{
+ afsc_blockix_t page_bix[1024]; /* "page" block indices */
+};
+
+
+#endif /* _LINUX_AFS_CACHE_LAYOUT_H */
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
new file mode 100644
index 000000000000..8d030bd67aa0
--- /dev/null
+++ b/fs/afs/callback.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
+ *
+ * This software may be freely redistributed under the terms of the
+ * GNU General Public License.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors: David Woodhouse <dwmw2@cambridge.redhat.com>
+ * David Howells <dhowells@redhat.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include "server.h"
+#include "vnode.h"
+#include "internal.h"
+
+/*****************************************************************************/
+/*
+ * allow the fileserver to request callback state (re-)initialisation
+ */
+int SRXAFSCM_InitCallBackState(afs_server_t *server)
+{
+ struct list_head callbacks;
+
+ _enter("%p",server);
+
+ INIT_LIST_HEAD(&callbacks);
+
+ /* transfer the callback list from the server to a temp holding area */
+ spin_lock(&server->cb_lock);
+
+ list_add(&callbacks,&server->cb_promises);
+ list_del_init(&server->cb_promises);
+
+ /* munch our way through the list, grabbing the inode, dropping all the locks and regetting
+ * them in the right order
+ */
+ while (!list_empty(&callbacks)) {
+ struct inode *inode;
+ afs_vnode_t *vnode;
+
+ vnode = list_entry(callbacks.next,afs_vnode_t,cb_link);
+ list_del_init(&vnode->cb_link);
+
+ /* try and grab the inode - may fail */
+ inode = igrab(AFS_VNODE_TO_I(vnode));
+ if (inode) {
+ int release = 0;
+
+ spin_unlock(&server->cb_lock);
+ spin_lock(&vnode->lock);
+
+ if (vnode->cb_server==server) {
+ vnode->cb_server = NULL;
+ afs_kafstimod_del_timer(&vnode->cb_timeout);
+ spin_lock(&afs_cb_hash_lock);
+ list_del_init(&vnode->cb_hash_link);
+ spin_unlock(&afs_cb_hash_lock);
+ release = 1;
+ }
+
+ spin_unlock(&vnode->lock);
+
+ iput(inode);
+ if (release) afs_put_server(server);
+
+ spin_lock(&server->cb_lock);
+ }
+ }
+
+ spin_unlock(&server->cb_lock);
+
+ _leave(" = 0");
+ return 0;
+} /* end SRXAFSCM_InitCallBackState() */
+
+/*****************************************************************************/
+/*
+ * allow the fileserver to break callback promises
+ */
+int SRXAFSCM_CallBack(afs_server_t *server, size_t count, afs_callback_t callbacks[])
+{
+ struct list_head *_p;
+
+ _enter("%p,%u,",server,count);
+
+ for (; count>0; callbacks++, count--) {
+ struct inode *inode = NULL;
+ afs_vnode_t *vnode = NULL;
+ int valid = 0;
+
+ _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }",
+ callbacks->fid.vid,
+ callbacks->fid.vnode,
+ callbacks->fid.unique,
+ callbacks->version,
+ callbacks->expiry,
+ callbacks->type
+ );
+
+ /* find the inode for this fid */
+ spin_lock(&afs_cb_hash_lock);
+
+ list_for_each(_p,&afs_cb_hash(server,&callbacks->fid)) {
+ vnode = list_entry(_p,afs_vnode_t,cb_hash_link);
+
+ if (memcmp(&vnode->fid,&callbacks->fid,sizeof(afs_fid_t))!=0)
+ continue;
+
+ /* right vnode, but is it same server? */
+ if (vnode->cb_server!=server)
+ break; /* no */
+
+ /* try and nail the inode down */
+ inode = igrab(AFS_VNODE_TO_I(vnode));
+ break;
+ }
+
+ spin_unlock(&afs_cb_hash_lock);
+
+ if (inode) {
+ /* we've found the record for this vnode */
+ spin_lock(&vnode->lock);
+ if (vnode->cb_server==server) {
+ /* the callback _is_ on the calling server */
+ vnode->cb_server = NULL;
+ valid = 1;
+
+ afs_kafstimod_del_timer(&vnode->cb_timeout);
+ vnode->flags |= AFS_VNODE_CHANGED;
+
+ spin_lock(&server->cb_lock);
+ list_del_init(&vnode->cb_link);
+ spin_unlock(&server->cb_lock);
+
+ spin_lock(&afs_cb_hash_lock);
+ list_del_init(&vnode->cb_hash_link);
+ spin_unlock(&afs_cb_hash_lock);
+ }
+ spin_unlock(&vnode->lock);
+
+ if (valid) {
+ invalidate_inode_pages(inode->i_mapping);
+ afs_put_server(server);
+ }
+ iput(inode);
+ }
+ }
+
+ _leave(" = 0");
+ return 0;
+} /* end SRXAFSCM_CallBack() */
+
+/*****************************************************************************/
+/*
+ * allow the fileserver to see if the cache manager is still alive
+ */
+int SRXAFSCM_Probe(afs_server_t *server)
+{
+ _debug("SRXAFSCM_Probe(%p)\n",server);
+ return 0;
+} /* end SRXAFSCM_Probe() */
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
new file mode 100644
index 000000000000..f7f00a2bec9e
--- /dev/null
+++ b/fs/afs/cell.c
@@ -0,0 +1,452 @@
+/* cell.c: AFS cell and server record management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <rxrpc/peer.h>
+#include <rxrpc/connection.h>
+#include "volume.h"
+#include "cell.h"
+#include "server.h"
+#include "transport.h"
+#include "vlclient.h"
+#include "kafstimod.h"
+#include "super.h"
+#include "internal.h"
+
+DECLARE_RWSEM(afs_proc_cells_sem);
+LIST_HEAD(afs_proc_cells);
+
+static struct list_head afs_cells = LIST_HEAD_INIT(afs_cells);
+static rwlock_t afs_cells_lock = RW_LOCK_UNLOCKED;
+static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
+static afs_cell_t *afs_cell_root;
+
+static char *rootcell;
+
+MODULE_PARM(rootcell,"s");
+MODULE_PARM_DESC(rootcell,"root AFS cell name and VL server IP addr list");
+
+/*****************************************************************************/
+/*
+ * create a cell record
+ * - "name" is the name of the cell
+ * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
+ */
+int afs_cell_create(const char *name, char *vllist, afs_cell_t **_cell)
+{
+ afs_cell_t *cell;
+ char *next;
+ int ret;
+
+ _enter("%s",name);
+
+ if (!name) BUG(); /* TODO: want to look up "this cell" in the cache */
+
+ down_write(&afs_cells_sem);
+
+ /* allocate and initialise a cell record */
+ cell = kmalloc(sizeof(afs_cell_t) + strlen(name) + 1,GFP_KERNEL);
+ if (!cell) {
+ _leave(" = -ENOMEM");
+ return -ENOMEM;
+ }
+
+ memset(cell,0,sizeof(afs_cell_t));
+ atomic_set(&cell->usage,0);
+
+ INIT_LIST_HEAD(&cell->link);
+ INIT_LIST_HEAD(&cell->caches);
+
+ rwlock_init(&cell->sv_lock);
+ INIT_LIST_HEAD(&cell->sv_list);
+ INIT_LIST_HEAD(&cell->sv_graveyard);
+ spin_lock_init(&cell->sv_gylock);
+
+ init_rwsem(&cell->vl_sem);
+ INIT_LIST_HEAD(&cell->vl_list);
+ INIT_LIST_HEAD(&cell->vl_graveyard);
+ spin_lock_init(&cell->vl_gylock);
+
+ strcpy(cell->name,name);
+
+ /* fill in the VL server list from the rest of the string */
+ ret = -EINVAL;
+ do {
+ unsigned a, b, c, d;
+
+ next = strchr(vllist,':');
+ if (next) *next++ = 0;
+
+ if (sscanf(vllist,"%u.%u.%u.%u",&a,&b,&c,&d)!=4)
+ goto badaddr;
+
+ if (a>255 || b>255 || c>255 || d>255)
+ goto badaddr;
+
+ cell->vl_addrs[cell->vl_naddrs++].s_addr =
+ htonl((a<<24)|(b<<16)|(c<<8)|d);
+
+ if (cell->vl_naddrs>=16)
+ break;
+
+ } while(vllist=next, vllist);
+
+ /* add a proc dir for this cell */
+ ret = afs_proc_cell_setup(cell);
+ if (ret<0)
+ goto error;
+
+ /* add to the cell lists */
+ write_lock(&afs_cells_lock);
+ list_add_tail(&cell->link,&afs_cells);
+ write_unlock(&afs_cells_lock);
+
+ down_write(&afs_proc_cells_sem);
+ list_add_tail(&cell->proc_link,&afs_proc_cells);
+ up_write(&afs_proc_cells_sem);
+
+ *_cell = cell;
+ up_write(&afs_cells_sem);
+
+ _leave(" = 0 (%p)",cell);
+ return 0;
+
+ badaddr:
+ printk("kAFS: bad VL server IP address: '%s'\n",vllist);
+ error:
+ up_write(&afs_cells_sem);
+ kfree(afs_cell_root);
+ return ret;
+} /* end afs_cell_create() */
+
+/*****************************************************************************/
+/*
+ * initialise the cell database from module parameters
+ */
+int afs_cell_init(void)
+{
+ char *cp;
+ int ret;
+
+ _enter("");
+
+ if (!rootcell) {
+ printk("kAFS: no root cell specified\n");
+ return -EINVAL;
+ }
+
+ cp = strchr(rootcell,':');
+ if (!cp) {
+ printk("kAFS: no VL server IP addresses specified\n");
+ return -EINVAL;
+ }
+
+ /* allocate a cell record for the root cell */
+ *cp++ = 0;
+ ret = afs_cell_create(rootcell,cp,&afs_cell_root);
+ if (ret==0)
+ afs_get_cell(afs_cell_root);
+
+ _leave(" = %d",ret);
+ return ret;
+
+} /* end afs_cell_init() */
+
+/*****************************************************************************/
+/*
+ * lookup a cell record
+ */
+int afs_cell_lookup(const char *name, afs_cell_t **_cell)
+{
+ struct list_head *_p;
+ afs_cell_t *cell;
+
+ _enter("\"%s\",",name?name:"*thiscell*");
+
+ cell = afs_cell_root;
+
+ if (name) {
+ /* if the cell was named, look for it in the cell record list */
+ cell = NULL;
+ read_lock(&afs_cells_lock);
+
+ list_for_each(_p,&afs_cells) {
+ cell = list_entry(_p,afs_cell_t,link);
+ if (strcmp(cell->name,name)==0)
+ break;
+ cell = NULL;
+ }
+
+ read_unlock(&afs_cells_lock);
+ }
+
+ if (cell)
+ afs_get_cell(cell);
+
+ *_cell = cell;
+ _leave(" = %d (%p)",cell?0:-ENOENT,cell);
+ return cell ? 0 : -ENOENT;
+
+} /* end afs_cell_lookup() */
+
+/*****************************************************************************/
+/*
+ * try and get a cell record
+ */
+afs_cell_t *afs_get_cell_maybe(afs_cell_t **_cell)
+{
+ afs_cell_t *cell;
+
+ write_lock(&afs_cells_lock);
+
+ cell = *_cell;
+ if (cell && !list_empty(&cell->link))
+ atomic_inc(&cell->usage);
+ else
+ cell = NULL;
+
+ write_unlock(&afs_cells_lock);
+
+ return cell;
+} /* end afs_get_cell_maybe() */
+
+/*****************************************************************************/
+/*
+ * destroy a cell record
+ */
+void afs_put_cell(afs_cell_t *cell)
+{
+ _enter("%p{%d,%s}",cell,atomic_read(&cell->usage),cell->name);
+
+ /* sanity check */
+ if (atomic_read(&cell->usage)<=0)
+ BUG();
+
+ /* to prevent a race, the decrement and the dequeue must be effectively atomic */
+ write_lock(&afs_cells_lock);
+
+ if (likely(!atomic_dec_and_test(&cell->usage))) {
+ write_unlock(&afs_cells_lock);
+ _leave("");
+ return;
+ }
+
+ write_unlock(&afs_cells_lock);
+
+ if (!list_empty(&cell->sv_list)) BUG();
+ if (!list_empty(&cell->sv_graveyard)) BUG();
+ if (!list_empty(&cell->vl_list)) BUG();
+ if (!list_empty(&cell->vl_graveyard)) BUG();
+
+ _leave(" [unused]");
+} /* end afs_put_cell() */
+
+/*****************************************************************************/
+/*
+ * destroy a cell record
+ */
+static void afs_cell_destroy(afs_cell_t *cell)
+{
+ _enter("%p{%d,%s}",cell,atomic_read(&cell->usage),cell->name);
+
+ /* to prevent a race, the decrement and the dequeue must be effectively atomic */
+ write_lock(&afs_cells_lock);
+
+ /* sanity check */
+ if (atomic_read(&cell->usage)!=0)
+ BUG();
+
+ list_del_init(&cell->link);
+
+ write_unlock(&afs_cells_lock);
+
+ down_write(&afs_cells_sem);
+
+ afs_proc_cell_remove(cell);
+
+ down_write(&afs_proc_cells_sem);
+ list_del_init(&cell->proc_link);
+ up_write(&afs_proc_cells_sem);
+
+ up_write(&afs_cells_sem);
+
+ if (!list_empty(&cell->sv_list)) BUG();
+ if (!list_empty(&cell->sv_graveyard)) BUG();
+ if (!list_empty(&cell->vl_list)) BUG();
+ if (!list_empty(&cell->vl_graveyard)) BUG();
+
+ /* finish cleaning up the cell */
+ kfree(cell);
+
+ _leave(" [destroyed]");
+} /* end afs_cell_destroy() */
+
+/*****************************************************************************/
+/*
+ * lookup the server record corresponding to an Rx RPC peer
+ */
+int afs_server_find_by_peer(const struct rxrpc_peer *peer, afs_server_t **_server)
+{
+ struct list_head *_pc, *_ps;
+ afs_server_t *server;
+ afs_cell_t *cell;
+
+ _enter("%p{a=%08x},",peer,ntohl(peer->addr.s_addr));
+
+ /* search the cell list */
+ read_lock(&afs_cells_lock);
+
+ list_for_each(_pc,&afs_cells) {
+ cell = list_entry(_pc,afs_cell_t,link);
+
+ _debug("? cell %s",cell->name);
+
+ write_lock(&cell->sv_lock);
+
+ /* check the active list */
+ list_for_each(_ps,&cell->sv_list) {
+ server = list_entry(_ps,afs_server_t,link);
+
+ _debug("?? server %08x",ntohl(server->addr.s_addr));
+
+ if (memcmp(&server->addr,&peer->addr,sizeof(struct in_addr))==0)
+ goto found_server;
+ }
+
+ /* check the inactive list */
+ spin_lock(&cell->sv_gylock);
+ list_for_each(_ps,&cell->sv_graveyard) {
+ server = list_entry(_ps,afs_server_t,link);
+
+ _debug("?? dead server %08x",ntohl(server->addr.s_addr));
+
+ if (memcmp(&server->addr,&peer->addr,sizeof(struct in_addr))==0)
+ goto found_dead_server;
+ }
+ spin_unlock(&cell->sv_gylock);
+
+ write_unlock(&cell->sv_lock);
+ }
+ read_unlock(&afs_cells_lock);
+
+ _leave(" = -ENOENT");
+ return -ENOENT;
+
+ /* we found it in the graveyard - resurrect it */
+ found_dead_server:
+ list_del(&server->link);
+ list_add_tail(&server->link,&cell->sv_list);
+ afs_get_server(server);
+ afs_kafstimod_del_timer(&server->timeout);
+ spin_unlock(&cell->sv_gylock);
+ goto success;
+
+ /* we found it - increment its ref count and return it */
+ found_server:
+ afs_get_server(server);
+
+ success:
+ write_unlock(&cell->sv_lock);
+ read_unlock(&afs_cells_lock);
+
+ *_server = server;
+ _leave(" = 0 (s=%p c=%p)",server,cell);
+ return 0;
+
+} /* end afs_server_find_by_peer() */
+
+/*****************************************************************************/
+/*
+ * purge in-memory cell database on module unload
+ * - the timeout daemon is stopped before calling this
+ */
+void afs_cell_purge(void)
+{
+ afs_vlocation_t *vlocation;
+ afs_cell_t *cell;
+
+ _enter("");
+
+ if (afs_cell_root)
+ afs_put_cell(afs_cell_root);
+
+ while (!list_empty(&afs_cells)) {
+ cell = NULL;
+
+ /* remove the next cell from the front of the list */
+ write_lock(&afs_cells_lock);
+
+ if (!list_empty(&afs_cells)) {
+ cell = list_entry(afs_cells.next,afs_cell_t,link);
+ list_del_init(&cell->link);
+ }
+
+ write_unlock(&afs_cells_lock);
+
+ if (cell) {
+ _debug("PURGING CELL %s (%d)",cell->name,atomic_read(&cell->usage));
+
+ if (!list_empty(&cell->sv_list)) BUG();
+ if (!list_empty(&cell->vl_list)) BUG();
+
+ /* purge the cell's VL graveyard list */
+ _debug(" - clearing VL graveyard");
+
+ spin_lock(&cell->vl_gylock);
+
+ while (!list_empty(&cell->vl_graveyard)) {
+ vlocation = list_entry(cell->vl_graveyard.next,
+ afs_vlocation_t,link);
+ list_del_init(&vlocation->link);
+
+ afs_kafstimod_del_timer(&vlocation->timeout);
+
+ spin_unlock(&cell->vl_gylock);
+
+ afs_vlocation_do_timeout(vlocation);
+ /* TODO: race if move to use krxtimod instead of kafstimod */
+
+ spin_lock(&cell->vl_gylock);
+ }
+
+ spin_unlock(&cell->vl_gylock);
+
+ /* purge the cell's server graveyard list */
+ _debug(" - clearing server graveyard");
+
+ spin_lock(&cell->sv_gylock);
+
+ while (!list_empty(&cell->sv_graveyard)) {
+ afs_server_t *server;
+
+ server = list_entry(cell->sv_graveyard.next,afs_server_t,link);
+ list_del_init(&server->link);
+
+ afs_kafstimod_del_timer(&server->timeout);
+
+ spin_unlock(&cell->sv_gylock);
+
+ afs_server_do_timeout(server);
+
+ spin_lock(&cell->sv_gylock);
+ }
+
+ spin_unlock(&cell->sv_gylock);
+
+ /* now the cell should be left with no references */
+ afs_cell_destroy(cell);
+ }
+ }
+
+ _leave("");
+} /* end afs_cell_purge() */
diff --git a/fs/afs/cell.h b/fs/afs/cell.h
new file mode 100644
index 000000000000..48eb9fa91f19
--- /dev/null
+++ b/fs/afs/cell.h
@@ -0,0 +1,63 @@
+/* cell.h: AFS cell record
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_CELL_H
+#define _LINUX_AFS_CELL_H
+
+#include "types.h"
+
+extern volatile int afs_cells_being_purged; /* T when cells are being purged by rmmod */
+
+/*****************************************************************************/
+/*
+ * AFS cell record
+ */
+struct afs_cell
+{
+ atomic_t usage;
+ struct list_head link; /* main cell list link */
+ struct list_head proc_link; /* /proc cell list link */
+ struct proc_dir_entry *proc_dir; /* /proc dir for this cell */
+ struct list_head caches; /* list of caches currently backing this cell */
+
+ /* server record management */
+ rwlock_t sv_lock; /* active server list lock */
+ struct list_head sv_list; /* active server list */
+ struct list_head sv_graveyard; /* inactive server list */
+ spinlock_t sv_gylock; /* inactive server list lock */
+
+ /* volume location record management */
+ struct rw_semaphore vl_sem; /* volume management serialisation semaphore */
+ struct list_head vl_list; /* cell's active VL record list */
+ struct list_head vl_graveyard; /* cell's inactive VL record list */
+ spinlock_t vl_gylock; /* graveyard lock */
+ unsigned short vl_naddrs; /* number of VL servers in addr list */
+ unsigned short vl_curr_svix; /* current server index */
+ struct in_addr vl_addrs[16]; /* cell VL server addresses */
+
+ char name[0]; /* cell name - must go last */
+};
+
+extern int afs_cell_init(void);
+
+extern int afs_cell_create(const char *name, char *vllist, afs_cell_t **_cell);
+
+extern int afs_cell_lookup(const char *name, afs_cell_t **_cell);
+
+#define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0)
+
+extern afs_cell_t *afs_get_cell_maybe(afs_cell_t **_cell);
+
+extern void afs_put_cell(afs_cell_t *cell);
+
+extern void afs_cell_purge(void);
+
+#endif /* _LINUX_AFS_CELL_H */
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
new file mode 100644
index 000000000000..b95c3625257a
--- /dev/null
+++ b/fs/afs/cmservice.c
@@ -0,0 +1,639 @@
+/* cmservice.c: AFS Cache Manager Service
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include "server.h"
+#include "cell.h"
+#include "transport.h"
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/call.h>
+#include "cmservice.h"
+#include "internal.h"
+
+static unsigned afscm_usage; /* AFS cache manager usage count */
+static struct rw_semaphore afscm_sem; /* AFS cache manager start/stop semaphore */
+
+static int afscm_new_call(struct rxrpc_call *call);
+static void afscm_attention(struct rxrpc_call *call);
+static void afscm_error(struct rxrpc_call *call);
+static void afscm_aemap(struct rxrpc_call *call);
+
+static void _SRXAFSCM_CallBack(struct rxrpc_call *call);
+static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call);
+static void _SRXAFSCM_Probe(struct rxrpc_call *call);
+
+typedef void (*_SRXAFSCM_xxxx_t)(struct rxrpc_call *call);
+
+static const struct rxrpc_operation AFSCM_ops[] = {
+ {
+ .id = 204,
+ .asize = RXRPC_APP_MARK_EOF,
+ .name = "CallBack",
+ .user = _SRXAFSCM_CallBack,
+ },
+ {
+ .id = 205,
+ .asize = RXRPC_APP_MARK_EOF,
+ .name = "InitCallBackState",
+ .user = _SRXAFSCM_InitCallBackState,
+ },
+ {
+ .id = 206,
+ .asize = RXRPC_APP_MARK_EOF,
+ .name = "Probe",
+ .user = _SRXAFSCM_Probe,
+ },
+#if 0
+ {
+ .id = 207,
+ .asize = RXRPC_APP_MARK_EOF,
+ .name = "GetLock",
+ .user = _SRXAFSCM_GetLock,
+ },
+ {
+ .id = 208,
+ .asize = RXRPC_APP_MARK_EOF,
+ .name = "GetCE",
+ .user = _SRXAFSCM_GetCE,
+ },
+ {
+ .id = 209,
+ .asize = RXRPC_APP_MARK_EOF,
+ .name = "GetXStatsVersion",
+ .user = _SRXAFSCM_GetXStatsVersion,
+ },
+ {
+ .id = 210,
+ .asize = RXRPC_APP_MARK_EOF,
+ .name = "GetXStats",
+ .user = _SRXAFSCM_GetXStats,
+ }
+#endif
+};
+
+static struct rxrpc_service AFSCM_service = {
+ .name = "AFS/CM",
+ .owner = THIS_MODULE,
+ .link = LIST_HEAD_INIT(AFSCM_service.link),
+ .new_call = afscm_new_call,
+ .service_id = 1,
+ .attn_func = afscm_attention,
+ .error_func = afscm_error,
+ .aemap_func = afscm_aemap,
+ .ops_begin = &AFSCM_ops[0],
+ .ops_end = &AFSCM_ops[sizeof(AFSCM_ops)/sizeof(AFSCM_ops[0])],
+};
+
+static DECLARE_COMPLETION(kafscmd_alive);
+static DECLARE_COMPLETION(kafscmd_dead);
+static DECLARE_WAIT_QUEUE_HEAD(kafscmd_sleepq);
+static LIST_HEAD(kafscmd_attention_list);
+static LIST_HEAD(afscm_calls);
+static spinlock_t afscm_calls_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t kafscmd_attention_lock = SPIN_LOCK_UNLOCKED;
+static int kafscmd_die;
+
+/*****************************************************************************/
+/*
+ * AFS Cache Manager kernel thread
+ */
+static int kafscmd(void *arg)
+{
+ DECLARE_WAITQUEUE(myself,current);
+
+ struct rxrpc_call *call;
+ _SRXAFSCM_xxxx_t func;
+ int die;
+
+ printk("kAFS: Started kafscmd %d\n",current->pid);
+ strcpy(current->comm,"kafscmd");
+
+ daemonize();
+
+ complete(&kafscmd_alive);
+
+ /* only certain signals are of interest */
+ spin_lock_irq(&current->sig->siglock);
+ siginitsetinv(&current->blocked,0);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3)
+ recalc_sigpending();
+#else
+ recalc_sigpending(current);
+#endif
+ spin_unlock_irq(&current->sig->siglock);
+
+ /* loop around looking for things to attend to */
+ do {
+ if (list_empty(&kafscmd_attention_list)) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&kafscmd_sleepq,&myself);
+
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!list_empty(&kafscmd_attention_list) ||
+ signal_pending(current) ||
+ kafscmd_die)
+ break;
+
+ schedule();
+ }
+
+ remove_wait_queue(&kafscmd_sleepq,&myself);
+ set_current_state(TASK_RUNNING);
+ }
+
+ die = kafscmd_die;
+
+ /* dequeue the next call requiring attention */
+ call = NULL;
+ spin_lock(&kafscmd_attention_lock);
+
+ if (!list_empty(&kafscmd_attention_list)) {
+ call = list_entry(kafscmd_attention_list.next,
+ struct rxrpc_call,
+ app_attn_link);
+ list_del_init(&call->app_attn_link);
+ die = 0;
+ }
+
+ spin_unlock(&kafscmd_attention_lock);
+
+ if (call) {
+ /* act upon it */
+ _debug("@@@ Begin Attend Call %p",call);
+
+ func = call->app_user;
+ if (func)
+ func(call);
+
+ rxrpc_put_call(call);
+
+ _debug("@@@ End Attend Call %p",call);
+ }
+
+ } while(!die);
+
+ /* and that's all */
+ complete_and_exit(&kafscmd_dead,0);
+
+} /* end kafscmd() */
+
+/*****************************************************************************/
+/*
+ * handle a call coming in to the cache manager
+ * - if I want to keep the call, I must increment its usage count
+ * - the return value will be negated and passed back in an abort packet if non-zero
+ * - serialised by virtue of there only being one krxiod
+ */
+static int afscm_new_call(struct rxrpc_call *call)
+{
+ _enter("%p{cid=%u u=%d}",call,ntohl(call->call_id),atomic_read(&call->usage));
+
+ rxrpc_get_call(call);
+
+ /* add to my current call list */
+ spin_lock(&afscm_calls_lock);
+ list_add(&call->app_link,&afscm_calls);
+ spin_unlock(&afscm_calls_lock);
+
+ _leave(" = 0");
+ return 0;
+
+} /* end afscm_new_call() */
+
+/*****************************************************************************/
+/*
+ * queue on the kafscmd queue for attention
+ */
+static void afscm_attention(struct rxrpc_call *call)
+{
+ _enter("%p{cid=%u u=%d}",call,ntohl(call->call_id),atomic_read(&call->usage));
+
+ spin_lock(&kafscmd_attention_lock);
+
+ if (list_empty(&call->app_attn_link)) {
+ list_add_tail(&call->app_attn_link,&kafscmd_attention_list);
+ rxrpc_get_call(call);
+ }
+
+ spin_unlock(&kafscmd_attention_lock);
+
+ wake_up(&kafscmd_sleepq);
+
+ _leave(" {u=%d}",atomic_read(&call->usage));
+} /* end afscm_attention() */
+
+/*****************************************************************************/
+/*
+ * handle my call being aborted
+ * - clean up, dequeue and put my ref to the call
+ */
+static void afscm_error(struct rxrpc_call *call)
+{
+ int removed;
+
+ _enter("%p{est=%s ac=%u er=%d}",
+ call,
+ rxrpc_call_error_states[call->app_err_state],
+ call->app_abort_code,
+ call->app_errno);
+
+ spin_lock(&kafscmd_attention_lock);
+
+ if (list_empty(&call->app_attn_link)) {
+ list_add_tail(&call->app_attn_link,&kafscmd_attention_list);
+ rxrpc_get_call(call);
+ }
+
+ spin_unlock(&kafscmd_attention_lock);
+
+ removed = 0;
+ spin_lock(&afscm_calls_lock);
+ if (!list_empty(&call->app_link)) {
+ list_del_init(&call->app_link);
+ removed = 1;
+ }
+ spin_unlock(&afscm_calls_lock);
+
+ if (removed)
+ rxrpc_put_call(call);
+
+ wake_up(&kafscmd_sleepq);
+
+ _leave("");
+} /* end afscm_error() */
+
+/*****************************************************************************/
+/*
+ * map afs abort codes to/from Linux error codes
+ * - called with call->lock held
+ */
+static void afscm_aemap(struct rxrpc_call *call)
+{
+ switch (call->app_err_state) {
+ case RXRPC_ESTATE_LOCAL_ABORT:
+ call->app_abort_code = -call->app_errno;
+ break;
+ case RXRPC_ESTATE_PEER_ABORT:
+ call->app_errno = -ECONNABORTED;
+ break;
+ default:
+ break;
+ }
+} /* end afscm_aemap() */
+
+/*****************************************************************************/
+/*
+ * start the cache manager service if not already started
+ */
+int afscm_start(void)
+{
+ int ret;
+
+ down_write(&afscm_sem);
+ if (!afscm_usage) {
+ ret = kernel_thread(kafscmd,NULL,0);
+ if (ret<0)
+ goto out;
+
+ wait_for_completion(&kafscmd_alive);
+
+ ret = rxrpc_add_service(afs_transport,&AFSCM_service);
+ if (ret<0)
+ goto kill;
+ }
+
+ afscm_usage++;
+ up_write(&afscm_sem);
+
+ return 0;
+
+ kill:
+ kafscmd_die = 1;
+ wake_up(&kafscmd_sleepq);
+ wait_for_completion(&kafscmd_dead);
+
+ out:
+ up_write(&afscm_sem);
+ return ret;
+
+} /* end afscm_start() */
+
+/*****************************************************************************/
+/*
+ * stop the cache manager service
+ */
+void afscm_stop(void)
+{
+ struct rxrpc_call *call;
+
+ down_write(&afscm_sem);
+
+ if (afscm_usage==0) BUG();
+ afscm_usage--;
+
+ if (afscm_usage==0) {
+ /* don't want more incoming calls */
+ rxrpc_del_service(afs_transport,&AFSCM_service);
+
+ /* abort any calls I've still got open (the afscm_error() will dequeue them) */
+ spin_lock(&afscm_calls_lock);
+ while (!list_empty(&afscm_calls)) {
+ call = list_entry(afscm_calls.next,struct rxrpc_call,app_link);
+ list_del_init(&call->app_link);
+ rxrpc_get_call(call);
+ spin_unlock(&afscm_calls_lock);
+
+ rxrpc_call_abort(call,-ESRCH); /* abort, dequeue and put */
+
+ rxrpc_put_call(call);
+
+ spin_lock(&afscm_calls_lock);
+ }
+ spin_unlock(&afscm_calls_lock);
+
+ /* get rid of my daemon */
+ kafscmd_die = 1;
+ wake_up(&kafscmd_sleepq);
+ wait_for_completion(&kafscmd_dead);
+
+ /* dispose of any calls waiting for attention */
+ spin_lock(&kafscmd_attention_lock);
+ while (!list_empty(&kafscmd_attention_list)) {
+ call = list_entry(kafscmd_attention_list.next,
+ struct rxrpc_call,
+ app_attn_link);
+
+ list_del_init(&call->app_attn_link);
+ spin_unlock(&kafscmd_attention_lock);
+
+ rxrpc_put_call(call);
+
+ spin_lock(&kafscmd_attention_lock);
+ }
+ spin_unlock(&kafscmd_attention_lock);
+ }
+
+ up_write(&afscm_sem);
+
+} /* end afscm_stop() */
+
+/*****************************************************************************/
+/*
+ * handle the fileserver breaking a set of callbacks
+ */
+static void _SRXAFSCM_CallBack(struct rxrpc_call *call)
+{
+ afs_server_t *server;
+ size_t count, qty, tmp;
+ int ret = 0, removed;
+
+ _enter("%p{acs=%s}",call,rxrpc_call_states[call->app_call_state]);
+
+ server = afs_server_get_from_peer(call->conn->peer);
+
+ switch (call->app_call_state) {
+ /* we've received the last packet
+ * - drain all the data from the call and send the reply
+ */
+ case RXRPC_CSTATE_SRVR_GOT_ARGS:
+ ret = -EBADMSG;
+ qty = call->app_ready_qty;
+ if (qty<8 || qty>50*(6*4)+8)
+ break;
+
+ {
+ afs_callback_t *cb, *pcb;
+ int loop;
+ u32 *fp, *bp;
+
+ fp = rxrpc_call_alloc_scratch(call,qty);
+
+ /* drag the entire argument block out to the scratch space */
+ ret = rxrpc_call_read_data(call,fp,qty,0);
+ if (ret<0)
+ break;
+
+ /* and unmarshall the parameter block */
+ ret = -EBADMSG;
+ count = ntohl(*fp++);
+ if (count>AFSCBMAX ||
+ (count*(3*4)+8 != qty && count*(6*4)+8 != qty))
+ break;
+
+ bp = fp + count*3;
+ tmp = ntohl(*bp++);
+ if (tmp>0 && tmp!=count)
+ break;
+ if (tmp==0)
+ bp = NULL;
+
+ pcb = cb = rxrpc_call_alloc_scratch_s(call,afs_callback_t);
+
+ for (loop=count-1; loop>=0; loop--) {
+ pcb->fid.vid = ntohl(*fp++);
+ pcb->fid.vnode = ntohl(*fp++);
+ pcb->fid.unique = ntohl(*fp++);
+ if (bp) {
+ pcb->version = ntohl(*bp++);
+ pcb->expiry = ntohl(*bp++);
+ pcb->type = ntohl(*bp++);
+ }
+ else {
+ pcb->version = 0;
+ pcb->expiry = 0;
+ pcb->type = AFSCM_CB_UNTYPED;
+ }
+ pcb++;
+ }
+
+ /* invoke the actual service routine */
+ ret = SRXAFSCM_CallBack(server,count,cb);
+ if (ret<0)
+ break;
+ }
+
+ /* send the reply */
+ ret = rxrpc_call_write_data(call,0,NULL,RXRPC_LAST_PACKET,GFP_KERNEL,0,&count);
+ if (ret<0)
+ break;
+ break;
+
+ /* operation complete */
+ case RXRPC_CSTATE_COMPLETE:
+ call->app_user = NULL;
+ removed = 0;
+ spin_lock(&afscm_calls_lock);
+ if (!list_empty(&call->app_link)) {
+ list_del_init(&call->app_link);
+ removed = 1;
+ }
+ spin_unlock(&afscm_calls_lock);
+
+ if (removed)
+ rxrpc_put_call(call);
+ break;
+
+ /* operation terminated on error */
+ case RXRPC_CSTATE_ERROR:
+ call->app_user = NULL;
+ break;
+
+ default:
+ break;
+ }
+
+ if (ret<0)
+ rxrpc_call_abort(call,ret);
+
+ if (server) afs_put_server(server);
+
+ _leave(" = %d",ret);
+
+} /* end _SRXAFSCM_CallBack() */
+
+/*****************************************************************************/
+/*
+ * handle the fileserver asking us to initialise our callback state
+ */
+static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call)
+{
+ afs_server_t *server;
+ size_t count;
+ int ret = 0, removed;
+
+ _enter("%p{acs=%s}",call,rxrpc_call_states[call->app_call_state]);
+
+ server = afs_server_get_from_peer(call->conn->peer);
+
+ switch (call->app_call_state) {
+ /* we've received the last packet - drain all the data from the call */
+ case RXRPC_CSTATE_SRVR_GOT_ARGS:
+ /* shouldn't be any args */
+ ret = -EBADMSG;
+ break;
+
+ /* send the reply when asked for it */
+ case RXRPC_CSTATE_SRVR_SND_REPLY:
+ /* invoke the actual service routine */
+ ret = SRXAFSCM_InitCallBackState(server);
+ if (ret<0)
+ break;
+
+ ret = rxrpc_call_write_data(call,0,NULL,RXRPC_LAST_PACKET,GFP_KERNEL,0,&count);
+ if (ret<0)
+ break;
+ break;
+
+ /* operation complete */
+ case RXRPC_CSTATE_COMPLETE:
+ call->app_user = NULL;
+ removed = 0;
+ spin_lock(&afscm_calls_lock);
+ if (!list_empty(&call->app_link)) {
+ list_del_init(&call->app_link);
+ removed = 1;
+ }
+ spin_unlock(&afscm_calls_lock);
+
+ if (removed)
+ rxrpc_put_call(call);
+ break;
+
+ /* operation terminated on error */
+ case RXRPC_CSTATE_ERROR:
+ call->app_user = NULL;
+ break;
+
+ default:
+ break;
+ }
+
+ if (ret<0)
+ rxrpc_call_abort(call,ret);
+
+ if (server) afs_put_server(server);
+
+ _leave(" = %d",ret);
+
+} /* end _SRXAFSCM_InitCallBackState() */
+
+/*****************************************************************************/
+/*
+ * handle a probe from a fileserver
+ */
+static void _SRXAFSCM_Probe(struct rxrpc_call *call)
+{
+ afs_server_t *server;
+ size_t count;
+ int ret = 0, removed;
+
+ _enter("%p{acs=%s}",call,rxrpc_call_states[call->app_call_state]);
+
+ server = afs_server_get_from_peer(call->conn->peer);
+
+ switch (call->app_call_state) {
+ /* we've received the last packet - drain all the data from the call */
+ case RXRPC_CSTATE_SRVR_GOT_ARGS:
+ /* shouldn't be any args */
+ ret = -EBADMSG;
+ break;
+
+ /* send the reply when asked for it */
+ case RXRPC_CSTATE_SRVR_SND_REPLY:
+ /* invoke the actual service routine */
+ ret = SRXAFSCM_Probe(server);
+ if (ret<0)
+ break;
+
+ ret = rxrpc_call_write_data(call,0,NULL,RXRPC_LAST_PACKET,GFP_KERNEL,0,&count);
+ if (ret<0)
+ break;
+ break;
+
+ /* operation complete */
+ case RXRPC_CSTATE_COMPLETE:
+ call->app_user = NULL;
+ removed = 0;
+ spin_lock(&afscm_calls_lock);
+ if (!list_empty(&call->app_link)) {
+ list_del_init(&call->app_link);
+ removed = 1;
+ }
+ spin_unlock(&afscm_calls_lock);
+
+ if (removed)
+ rxrpc_put_call(call);
+ break;
+
+ /* operation terminated on error */
+ case RXRPC_CSTATE_ERROR:
+ call->app_user = NULL;
+ break;
+
+ default:
+ break;
+ }
+
+ if (ret<0)
+ rxrpc_call_abort(call,ret);
+
+ if (server) afs_put_server(server);
+
+ _leave(" = %d",ret);
+
+} /* end _SRXAFSCM_Probe() */
diff --git a/fs/afs/cmservice.h b/fs/afs/cmservice.h
new file mode 100644
index 000000000000..89fb14e7615b
--- /dev/null
+++ b/fs/afs/cmservice.h
@@ -0,0 +1,27 @@
+/* cmservice.h: AFS Cache Manager Service declarations
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_CMSERVICE_H
+#define _LINUX_AFS_CMSERVICE_H
+
+#include <rxrpc/transport.h>
+#include "types.h"
+
+/* cache manager start/stop */
+extern int afscm_start(void);
+extern void afscm_stop(void);
+
+/* cache manager server functions */
+extern int SRXAFSCM_InitCallBackState(afs_server_t *server);
+extern int SRXAFSCM_CallBack(afs_server_t *server, size_t count, afs_callback_t callbacks[]);
+extern int SRXAFSCM_Probe(afs_server_t *server);
+
+#endif /* _LINUX_AFS_CMSERVICE_H */
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
new file mode 100644
index 000000000000..d39345f4e277
--- /dev/null
+++ b/fs/afs/dir.c
@@ -0,0 +1,642 @@
+/* dir.c: AFS filesystem directory handling
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/smp_lock.h>
+#include "vnode.h"
+#include "volume.h"
+#include <rxrpc/call.h>
+#include "super.h"
+#include "internal.h"
+
+static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry);
+static int afs_dir_open(struct inode *inode, struct file *file);
+static int afs_dir_readdir(struct file *file, void *dirent, filldir_t filldir);
+static int afs_d_revalidate(struct dentry *dentry, int flags);
+static int afs_d_delete(struct dentry *dentry);
+static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, loff_t fpos,
+ ino_t ino, unsigned dtype);
+
+struct file_operations afs_dir_file_operations = {
+ .open = afs_dir_open,
+ .readdir = afs_dir_readdir,
+};
+
+struct inode_operations afs_dir_inode_operations = {
+ .lookup = afs_dir_lookup,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ .getattr = afs_inode_getattr,
+#else
+ .revalidate = afs_inode_revalidate,
+#endif
+// .create = afs_dir_create,
+// .link = afs_dir_link,
+// .unlink = afs_dir_unlink,
+// .symlink = afs_dir_symlink,
+// .mkdir = afs_dir_mkdir,
+// .rmdir = afs_dir_rmdir,
+// .mknod = afs_dir_mknod,
+// .rename = afs_dir_rename,
+};
+
+static struct dentry_operations afs_fs_dentry_operations = {
+ .d_revalidate = afs_d_revalidate,
+ .d_delete = afs_d_delete,
+};
+
+#define AFS_DIR_HASHTBL_SIZE 128
+#define AFS_DIR_DIRENT_SIZE 32
+#define AFS_DIRENT_PER_BLOCK 64
+
+typedef union afs_dirent {
+ struct {
+ u8 valid;
+ u8 unused[1];
+ u16 hash_next;
+ u32 vnode;
+ u32 unique;
+ u8 name[16];
+ u8 overflow[4]; /* if any char of the name (inc NUL) reaches here, consume
+ * the next dirent too */
+ };
+ u8 extended_name[32];
+} afs_dirent_t;
+
+/* AFS directory page header (one at the beginning of every 2048-byte chunk) */
+typedef struct afs_dir_pagehdr {
+ u16 npages;
+ u16 magic;
+#define AFS_DIR_MAGIC htons(1234)
+ u8 nentries;
+ u8 bitmap[8];
+ u8 pad[19];
+} afs_dir_pagehdr_t;
+
+/* directory block layout */
+typedef union afs_dir_block {
+
+ afs_dir_pagehdr_t pagehdr;
+
+ struct {
+ afs_dir_pagehdr_t pagehdr;
+ u8 alloc_ctrs[128];
+ u16 hashtable[AFS_DIR_HASHTBL_SIZE]; /* dir hash table */
+ } hdr;
+
+ afs_dirent_t dirents[AFS_DIRENT_PER_BLOCK];
+} afs_dir_block_t;
+
+/* layout on a linux VM page */
+typedef struct afs_dir_page {
+ afs_dir_block_t blocks[PAGE_SIZE/sizeof(afs_dir_block_t)];
+} afs_dir_page_t;
+
+struct afs_dir_lookup_cookie {
+ afs_fid_t fid;
+ const char *name;
+ size_t nlen;
+ int found;
+};
+
+/*****************************************************************************/
+/*
+ * check that a directory page is valid
+ */
+static inline void afs_dir_check_page(struct inode *dir, struct page *page)
+{
+ afs_dir_page_t *dbuf;
+ loff_t latter;
+ int tmp, qty;
+
+#if 0
+ /* check the page count */
+ qty = desc.size/sizeof(dbuf->blocks[0]);
+ if (qty==0)
+ goto error;
+
+ if (page->index==0 && qty!=ntohs(dbuf->blocks[0].pagehdr.npages)) {
+ printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu\n",
+ __FUNCTION__,dir->i_ino,qty,ntohs(dbuf->blocks[0].pagehdr.npages));
+ goto error;
+ }
+#endif
+
+ /* determine how many magic numbers there should be in this page */
+ latter = dir->i_size - (page->index << PAGE_CACHE_SHIFT);
+ if (latter >= PAGE_SIZE)
+ qty = PAGE_SIZE;
+ else
+ qty = latter;
+ qty /= sizeof(afs_dir_block_t);
+
+ /* check them */
+ dbuf = page_address(page);
+ for (tmp=0; tmp<qty; tmp++) {
+ if (dbuf->blocks[tmp].pagehdr.magic != AFS_DIR_MAGIC) {
+ printk("kAFS: %s(%lu): bad magic %d/%d is %04hx\n",
+ __FUNCTION__,dir->i_ino,tmp,
+ qty,ntohs(dbuf->blocks[tmp].pagehdr.magic));
+ goto error;
+ }
+ }
+
+ SetPageChecked(page);
+ return;
+
+ error:
+ SetPageChecked(page);
+ SetPageError(page);
+
+} /* end afs_dir_check_page() */
+
+/*****************************************************************************/
+/*
+ * discard a page cached in the pagecache
+ */
+static inline void afs_dir_put_page(struct page *page)
+{
+ kunmap(page);
+ page_cache_release(page);
+
+} /* end afs_dir_put_page() */
+
+/*****************************************************************************/
+/*
+ * get a page into the pagecache
+ */
+static struct page *afs_dir_get_page(struct inode *dir, unsigned long index)
+{
+ struct page *page;
+
+ _enter("{%lu},%lu",dir->i_ino,index);
+
+ page = read_cache_page(dir->i_mapping,index,
+ (filler_t*)dir->i_mapping->a_ops->readpage,NULL);
+ if (!IS_ERR(page)) {
+ wait_on_page_locked(page);
+ kmap(page);
+ if (!PageUptodate(page))
+ goto fail;
+ if (!PageChecked(page))
+ afs_dir_check_page(dir,page);
+ if (PageError(page))
+ goto fail;
+ }
+ return page;
+
+ fail:
+ afs_dir_put_page(page);
+ return ERR_PTR(-EIO);
+} /* end afs_dir_get_page() */
+
+/*****************************************************************************/
+/*
+ * open an AFS directory file
+ */
+static int afs_dir_open(struct inode *inode, struct file *file)
+{
+ _enter("{%lu}",inode->i_ino);
+
+ if (sizeof(afs_dir_block_t) != 2048) BUG();
+ if (sizeof(afs_dirent_t) != 32) BUG();
+
+ if (AFS_FS_I(inode)->flags & AFS_VNODE_DELETED)
+ return -ENOENT;
+
+ _leave(" = 0");
+ return 0;
+
+} /* end afs_dir_open() */
+
+/*****************************************************************************/
+/*
+ * deal with one block in an AFS directory
+ */
+static int afs_dir_iterate_block(unsigned *fpos,
+ afs_dir_block_t *block,
+ unsigned blkoff,
+ void *cookie,
+ filldir_t filldir)
+{
+ afs_dirent_t *dire;
+ unsigned offset, next, curr;
+ size_t nlen;
+ int tmp, ret;
+
+ _enter("%u,%x,%p,,",*fpos,blkoff,block);
+
+ curr = (*fpos - blkoff) / sizeof(afs_dirent_t);
+
+ /* walk through the block, an entry at a time */
+ for (offset = AFS_DIRENT_PER_BLOCK - block->pagehdr.nentries;
+ offset < AFS_DIRENT_PER_BLOCK;
+ offset = next
+ ) {
+ next = offset + 1;
+
+ /* skip entries marked unused in the bitmap */
+ if (!(block->pagehdr.bitmap[offset/8] & (1 << (offset % 8)))) {
+ _debug("ENT[%u.%u]: unused\n",blkoff/sizeof(afs_dir_block_t),offset);
+ if (offset>=curr)
+ *fpos = blkoff + next * sizeof(afs_dirent_t);
+ continue;
+ }
+
+ /* got a valid entry */
+ dire = &block->dirents[offset];
+ nlen = strnlen(dire->name,sizeof(*block) - offset*sizeof(afs_dirent_t));
+
+ _debug("ENT[%u.%u]: %s %u \"%.*s\"\n",
+ blkoff/sizeof(afs_dir_block_t),offset,
+ offset<curr ? "skip" : "fill",
+ nlen,nlen,dire->name);
+
+ /* work out where the next possible entry is */
+ for (tmp=nlen; tmp>15; tmp-=sizeof(afs_dirent_t)) {
+ if (next>=AFS_DIRENT_PER_BLOCK) {
+ _debug("ENT[%u.%u]:"
+ " %u travelled beyond end dir block (len %u/%u)\n",
+ blkoff/sizeof(afs_dir_block_t),offset,next,tmp,nlen);
+ return -EIO;
+ }
+ if (!(block->pagehdr.bitmap[next/8] & (1 << (next % 8)))) {
+ _debug("ENT[%u.%u]: %u unmarked extension (len %u/%u)\n",
+ blkoff/sizeof(afs_dir_block_t),offset,next,tmp,nlen);
+ return -EIO;
+ }
+
+ _debug("ENT[%u.%u]: ext %u/%u\n",
+ blkoff/sizeof(afs_dir_block_t),next,tmp,nlen);
+ next++;
+ }
+
+ /* skip if starts before the current position */
+ if (offset<curr)
+ continue;
+
+ /* found the next entry */
+ ret = filldir(cookie,
+ dire->name,
+ nlen,
+ blkoff + offset * sizeof(afs_dirent_t),
+ ntohl(dire->vnode),
+ filldir==afs_dir_lookup_filldir ? dire->unique : DT_UNKNOWN);
+ if (ret<0) {
+ _leave(" = 0 [full]");
+ return 0;
+ }
+
+ *fpos = blkoff + next * sizeof(afs_dirent_t);
+ }
+
+ _leave(" = 1 [more]");
+ return 1;
+} /* end afs_dir_iterate_block() */
+
+/*****************************************************************************/
+/*
+ * read an AFS directory
+ */
+static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, filldir_t filldir)
+{
+ afs_dir_block_t *dblock;
+ afs_dir_page_t *dbuf;
+ struct page *page;
+ unsigned blkoff, limit;
+ int ret;
+
+ _enter("{%lu},%u,,",dir->i_ino,*fpos);
+
+ if (AFS_FS_I(dir)->flags & AFS_VNODE_DELETED) {
+ _leave(" = -ESTALE");
+ return -ESTALE;
+ }
+
+ /* round the file position up to the next entry boundary */
+ *fpos += sizeof(afs_dirent_t) - 1;
+ *fpos &= ~(sizeof(afs_dirent_t) - 1);
+
+ /* walk through the blocks in sequence */
+ ret = 0;
+ while (*fpos < dir->i_size) {
+ blkoff = *fpos & ~(sizeof(afs_dir_block_t) - 1);
+
+ /* fetch the appropriate page from the directory */
+ page = afs_dir_get_page(dir,blkoff/PAGE_SIZE);
+ if (IS_ERR(page)) {
+ ret = PTR_ERR(page);
+ break;
+ }
+
+ limit = blkoff & ~(PAGE_SIZE-1);
+
+ dbuf = page_address(page);
+
+ /* deal with the individual blocks stashed on this page */
+ do {
+ dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) / sizeof(afs_dir_block_t)];
+ ret = afs_dir_iterate_block(fpos,dblock,blkoff,cookie,filldir);
+ if (ret!=1) {
+ afs_dir_put_page(page);
+ goto out;
+ }
+
+ blkoff += sizeof(afs_dir_block_t);
+
+ } while (*fpos < dir->i_size && blkoff < limit);
+
+ afs_dir_put_page(page);
+ ret = 0;
+ }
+
+ out:
+ _leave(" = %d",ret);
+ return ret;
+} /* end afs_dir_iterate() */
+
+/*****************************************************************************/
+/*
+ * read an AFS directory
+ */
+static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir)
+{
+ unsigned fpos;
+ int ret;
+
+ _enter("{%Ld,{%lu}}",file->f_pos,file->f_dentry->d_inode->i_ino);
+
+ fpos = file->f_pos;
+ ret = afs_dir_iterate(file->f_dentry->d_inode,&fpos,cookie,filldir);
+ file->f_pos = fpos;
+
+ _leave(" = %d",ret);
+ return ret;
+} /* end afs_dir_readdir() */
+
+/*****************************************************************************/
+/*
+ * search the directory for a name
+ * - if afs_dir_iterate_block() spots this function, it'll pass the FID uniquifier through dtype
+ */
+static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, loff_t fpos,
+ ino_t ino, unsigned dtype)
+{
+ struct afs_dir_lookup_cookie *cookie = _cookie;
+
+ _enter("{%s,%u},%s,%u,,%lu,%u",cookie->name,cookie->nlen,name,nlen,ino,ntohl(dtype));
+
+ if (cookie->nlen != nlen || memcmp(cookie->name,name,nlen)!=0) {
+ _leave(" = 0 [no]");
+ return 0;
+ }
+
+ cookie->fid.vnode = ino;
+ cookie->fid.unique = ntohl(dtype);
+ cookie->found = 1;
+
+ _leave(" = -1 [found]");
+ return -1;
+} /* end afs_dir_lookup_filldir() */
+
+/*****************************************************************************/
+/*
+ * look up an entry in a directory
+ */
+static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry)
+{
+ struct afs_dir_lookup_cookie cookie;
+ struct afs_super_info *as;
+ struct inode *inode;
+ afs_vnode_t *vnode;
+ unsigned fpos;
+ int ret;
+
+ _enter("{%lu},{%s}",dir->i_ino,dentry->d_name.name);
+
+ /* insanity checks first */
+ if (sizeof(afs_dir_block_t) != 2048) BUG();
+ if (sizeof(afs_dirent_t) != 32) BUG();
+
+ if (dentry->d_name.len > 255) {
+ _leave(" = -ENAMETOOLONG");
+ return ERR_PTR(-ENAMETOOLONG);
+ }
+
+ vnode = AFS_FS_I(dir);
+ if (vnode->flags & AFS_VNODE_DELETED) {
+ _leave(" = -ESTALE");
+ return ERR_PTR(-ESTALE);
+ }
+
+ as = dir->i_sb->s_fs_info;
+
+ /* search the directory */
+ cookie.name = dentry->d_name.name;
+ cookie.nlen = dentry->d_name.len;
+ cookie.fid.vid = as->volume->vid;
+ cookie.found = 0;
+
+ fpos = 0;
+ ret = afs_dir_iterate(dir,&fpos,&cookie,afs_dir_lookup_filldir);
+ if (ret<0) {
+ _leave(" = %d",ret);
+ return ERR_PTR(ret);
+ }
+
+ ret = -ENOENT;
+ if (!cookie.found) {
+ _leave(" = %d",ret);
+ return ERR_PTR(ret);
+ }
+
+ /* instantiate the dentry */
+ ret = afs_iget(dir->i_sb,&cookie.fid,&inode);
+ if (ret<0) {
+ _leave(" = %d",ret);
+ return ERR_PTR(ret);
+ }
+
+ dentry->d_op = &afs_fs_dentry_operations;
+ dentry->d_fsdata = (void*) (unsigned) vnode->status.version;
+
+ d_add(dentry,inode);
+ _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%lu }",
+ cookie.fid.vnode,
+ cookie.fid.unique,
+ dentry->d_inode->i_ino,
+ dentry->d_inode->i_version);
+
+ return NULL;
+} /* end afs_dir_lookup() */
+
+/*****************************************************************************/
+/*
+ * check that a dentry lookup hit has found a valid entry
+ * - NOTE! the hit can be a negative hit too, so we can't assume we have an inode
+ * (derived from nfs_lookup_revalidate)
+ */
+static int afs_d_revalidate(struct dentry *dentry, int flags)
+{
+ struct afs_dir_lookup_cookie cookie;
+ struct dentry *parent;
+ struct inode *inode, *dir;
+ unsigned fpos;
+ int ret;
+
+ _enter("%s,%x",dentry->d_name.name,flags);
+
+ /* lock down the parent dentry so we can peer at it */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ read_lock(&dparent_lock);
+ parent = dget(dentry->d_parent);
+ read_unlock(&dparent_lock);
+#else
+ lock_kernel();
+ parent = dget(dentry->d_parent);
+ unlock_kernel();
+#endif
+
+ dir = parent->d_inode;
+ inode = dentry->d_inode;
+
+ /* handle a negative inode */
+ if (!inode)
+ goto out_bad;
+
+ /* handle a bad inode */
+ if (is_bad_inode(inode)) {
+ printk("kAFS: afs_d_revalidate: %s/%s has bad inode\n",
+ dentry->d_parent->d_name.name,dentry->d_name.name);
+ goto out_bad;
+ }
+
+ /* force a full look up if the parent directory changed since last the server was consulted
+ * - otherwise this inode must still exist, even if the inode details themselves have
+ * changed
+ */
+ if (AFS_FS_I(dir)->flags & AFS_VNODE_CHANGED)
+ afs_vnode_fetch_status(AFS_FS_I(dir));
+
+ if (AFS_FS_I(dir)->flags & AFS_VNODE_DELETED) {
+ _debug("%s: parent dir deleted",dentry->d_name.name);
+ goto out_bad;
+ }
+
+ if (AFS_FS_I(inode)->flags & AFS_VNODE_DELETED) {
+ _debug("%s: file already deleted",dentry->d_name.name);
+ goto out_bad;
+ }
+
+ if ((unsigned)dentry->d_fsdata != (unsigned)AFS_FS_I(dir)->status.version) {
+ _debug("%s: parent changed %u -> %u",
+ dentry->d_name.name,
+ (unsigned)dentry->d_fsdata,
+ (unsigned)AFS_FS_I(dir)->status.version);
+
+ /* search the directory for this vnode */
+ cookie.name = dentry->d_name.name;
+ cookie.nlen = dentry->d_name.len;
+ cookie.fid.vid = AFS_FS_I(inode)->volume->vid;
+ cookie.found = 0;
+
+ fpos = 0;
+ ret = afs_dir_iterate(dir,&fpos,&cookie,afs_dir_lookup_filldir);
+ if (ret<0) {
+ _debug("failed to iterate dir %s: %d",parent->d_name.name,ret);
+ goto out_bad;
+ }
+
+ if (!cookie.found) {
+ _debug("%s: dirent not found",dentry->d_name.name);
+ goto not_found;
+ }
+
+ /* if the vnode ID has changed, then the dirent points to a different file */
+ if (cookie.fid.vnode!=AFS_FS_I(inode)->fid.vnode) {
+ _debug("%s: dirent changed",dentry->d_name.name);
+ goto not_found;
+ }
+
+ /* if the vnode ID uniqifier has changed, then the file has been deleted */
+ if (cookie.fid.unique!=AFS_FS_I(inode)->fid.unique) {
+ _debug("%s: file deleted (uq %u -> %u I:%lu)",
+ dentry->d_name.name,
+ cookie.fid.unique,
+ AFS_FS_I(inode)->fid.unique,
+ inode->i_version);
+ spin_lock(&AFS_FS_I(inode)->lock);
+ AFS_FS_I(inode)->flags |= AFS_VNODE_DELETED;
+ spin_unlock(&AFS_FS_I(inode)->lock);
+ invalidate_inode_pages(inode->i_mapping);
+ goto out_bad;
+ }
+
+ dentry->d_fsdata = (void*) (unsigned) AFS_FS_I(dir)->status.version;
+ }
+
+ out_valid:
+ dput(parent);
+ _leave(" = 1 [valid]");
+ return 1;
+
+ /* the dirent, if it exists, now points to a different vnode */
+ not_found:
+ dentry->d_flags |= DCACHE_NFSFS_RENAMED;
+
+ out_bad:
+ if (inode) {
+ /* don't unhash if we have submounts */
+ if (have_submounts(dentry))
+ goto out_valid;
+ }
+
+ shrink_dcache_parent(dentry);
+
+ _debug("dropping dentry %s/%s",dentry->d_parent->d_name.name,dentry->d_name.name);
+ d_drop(dentry);
+
+ dput(parent);
+
+ _leave(" = 0 [bad]");
+ return 0;
+} /* end afs_d_revalidate() */
+
+/*****************************************************************************/
+/*
+ * allow the VFS to enquire as to whether a dentry should be unhashed (mustn't sleep)
+ * - called from dput() when d_count is going to 0.
+ * - return 1 to request dentry be unhashed, 0 otherwise
+ */
+static int afs_d_delete(struct dentry *dentry)
+{
+ _enter("%s",dentry->d_name.name);
+
+ if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
+ goto zap;
+
+ if (dentry->d_inode) {
+ if (AFS_FS_I(dentry->d_inode)->flags & AFS_VNODE_DELETED)
+ goto zap;
+ }
+
+ _leave(" = 0 [keep]");
+ return 0;
+
+ zap:
+ _leave(" = 1 [zap]");
+ return 1;
+} /* end afs_d_delete() */
diff --git a/fs/afs/errors.h b/fs/afs/errors.h
new file mode 100644
index 000000000000..115befe16450
--- /dev/null
+++ b/fs/afs/errors.h
@@ -0,0 +1,34 @@
+/* errors.h: AFS abort/error codes
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _H_DB712916_5113_11D6_9A6D_0002B3163499
+#define _H_DB712916_5113_11D6_9A6D_0002B3163499
+
+#include "types.h"
+
+/* file server abort codes */
+typedef enum {
+ VSALVAGE = 101, /* volume needs salvaging */
+ VNOVNODE = 102, /* no such file/dir (vnode) */
+ VNOVOL = 103, /* no such volume or volume unavailable */
+ VVOLEXISTS = 104, /* volume name already exists */
+ VNOSERVICE = 105, /* volume not currently in service */
+ VOFFLINE = 106, /* volume is currently offline (more info available [VVL-spec]) */
+ VONLINE = 107, /* volume is already online */
+ VDISKFULL = 108, /* disk partition is full */
+ VOVERQUOTA = 109, /* volume's maximum quota exceeded */
+ VBUSY = 110, /* volume is temporarily unavailable */
+ VMOVED = 111, /* volume moved to new server - ask this FS where */
+} afs_rxfs_abort_t;
+
+extern int afs_abort_to_error(int abortcode);
+
+#endif /* _H_DB712916_5113_11D6_9A6D_0002B3163499 */
diff --git a/fs/afs/file.c b/fs/afs/file.c
new file mode 100644
index 000000000000..d14e427b5784
--- /dev/null
+++ b/fs/afs/file.c
@@ -0,0 +1,143 @@
+/* file.c: AFS filesystem file handling
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "volume.h"
+#include "vnode.h"
+#include <rxrpc/call.h>
+#include "internal.h"
+
+//static int afs_file_open(struct inode *inode, struct file *file);
+//static int afs_file_release(struct inode *inode, struct file *file);
+
+static int afs_file_readpage(struct file *file, struct page *page);
+
+//static ssize_t afs_file_read(struct file *file, char *buf, size_t size, loff_t *off);
+
+static ssize_t afs_file_write(struct file *file, const char *buf, size_t size, loff_t *off);
+
+struct inode_operations afs_file_inode_operations = {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ .getattr = afs_inode_getattr,
+#else
+ .revalidate = afs_inode_revalidate,
+#endif
+};
+
+struct file_operations afs_file_file_operations = {
+// .open = afs_file_open,
+// .release = afs_file_release,
+ .read = generic_file_read, //afs_file_read,
+ .write = afs_file_write,
+ .mmap = generic_file_mmap,
+// .fsync = afs_file_fsync,
+};
+
+struct address_space_operations afs_fs_aops = {
+ .readpage = afs_file_readpage,
+};
+
+/*****************************************************************************/
+/*
+ * AFS file read
+ */
+#if 0
+static ssize_t afs_file_read(struct file *file, char *buf, size_t size, loff_t *off)
+{
+ struct afs_inode_info *ai;
+
+ ai = AFS_FS_I(file->f_dentry->d_inode);
+ if (ai->flags & AFS_INODE_DELETED)
+ return -ESTALE;
+
+ return -EIO;
+} /* end afs_file_read() */
+#endif
+
+/*****************************************************************************/
+/*
+ * AFS file write
+ */
+static ssize_t afs_file_write(struct file *file, const char *buf, size_t size, loff_t *off)
+{
+ afs_vnode_t *vnode;
+
+ vnode = AFS_FS_I(file->f_dentry->d_inode);
+ if (vnode->flags & AFS_VNODE_DELETED)
+ return -ESTALE;
+
+ return -EIO;
+} /* end afs_file_write() */
+
+/*****************************************************************************/
+/*
+ * AFS read page from file (or symlink)
+ */
+static int afs_file_readpage(struct file *file, struct page *page)
+{
+ struct afs_rxfs_fetch_descriptor desc;
+ struct inode *inode;
+ afs_vnode_t *vnode;
+ int ret;
+
+ inode = page->mapping->host;
+
+ _enter("{%lu},{%lu}",inode->i_ino,page->index);
+
+ vnode = AFS_FS_I(inode);
+
+ if (!PageLocked(page))
+ PAGE_BUG(page);
+
+ ret = -ESTALE;
+ if (vnode->flags & AFS_VNODE_DELETED)
+ goto error;
+
+ /* work out how much to get and from where */
+ desc.fid = vnode->fid;
+ desc.offset = page->index << PAGE_CACHE_SHIFT;
+ desc.size = min((size_t)(inode->i_size - desc.offset),(size_t)PAGE_SIZE);
+ desc.buffer = kmap(page);
+
+ clear_page(desc.buffer);
+
+ /* read the contents of the file from the server into the page */
+ ret = afs_vnode_fetch_data(vnode,&desc);
+ kunmap(page);
+ if (ret<0) {
+ if (ret==-ENOENT) {
+ _debug("got NOENT from server - marking file deleted and stale");
+ vnode->flags |= AFS_VNODE_DELETED;
+ ret = -ESTALE;
+ }
+ goto error;
+ }
+
+ SetPageUptodate(page);
+ unlock_page(page);
+
+ _leave(" = 0");
+ return 0;
+
+ error:
+ SetPageError(page);
+ unlock_page(page);
+
+ _leave(" = %d",ret);
+ return ret;
+
+} /* end afs_file_readpage() */
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
new file mode 100644
index 000000000000..e4aabcb85d7d
--- /dev/null
+++ b/fs/afs/fsclient.c
@@ -0,0 +1,816 @@
+/* fsclient.c: AFS File Server client stubs
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/call.h>
+#include "fsclient.h"
+#include "cmservice.h"
+#include "vnode.h"
+#include "server.h"
+#include "errors.h"
+#include "internal.h"
+
+#define FSFETCHSTATUS 132 /* AFS Fetch file status */
+#define FSFETCHDATA 130 /* AFS Fetch file data */
+#define FSGIVEUPCALLBACKS 147 /* AFS Discard server callback promises */
+#define FSGETVOLUMEINFO 148 /* AFS Get root volume information */
+#define FSGETROOTVOLUME 151 /* AFS Get root volume name */
+#define FSLOOKUP 161 /* AFS lookup file in directory */
+
+/*****************************************************************************/
+/*
+ * map afs abort codes to/from Linux error codes
+ * - called with call->lock held
+ */
+static void afs_rxfs_aemap(struct rxrpc_call *call)
+{
+ switch (call->app_err_state) {
+ case RXRPC_ESTATE_LOCAL_ABORT:
+ call->app_abort_code = -call->app_errno;
+ break;
+ case RXRPC_ESTATE_PEER_ABORT:
+ call->app_errno = afs_abort_to_error(call->app_abort_code);
+ break;
+ default:
+ break;
+ }
+} /* end afs_rxfs_aemap() */
+
+/*****************************************************************************/
+/*
+ * get the root volume name from a fileserver
+ * - this operation doesn't seem to work correctly in OpenAFS server 1.2.2
+ */
+#if 0
+int afs_rxfs_get_root_volume(afs_server_t *server, char *buf, size_t *buflen)
+{
+ DECLARE_WAITQUEUE(myself,current);
+
+ struct rxrpc_connection *conn;
+ struct rxrpc_call *call;
+ struct iovec piov[2];
+ size_t sent;
+ int ret;
+ u32 param[1];
+
+ kenter("%p,%p,%u",server,buf,*buflen);
+
+ /* get hold of the fileserver connection */
+ ret = afs_server_get_fsconn(server,&conn);
+ if (ret<0)
+ goto out;
+
+ /* create a call through that connection */
+ ret = rxrpc_create_call(conn,NULL,NULL,afs_rxfs_aemap,&call);
+ if (ret<0) {
+ printk("kAFS: Unable to create call: %d\n",ret);
+ goto out_put_conn;
+ }
+ call->app_opcode = FSGETROOTVOLUME;
+
+ /* we want to get event notifications from the call */
+ add_wait_queue(&call->waitq,&myself);
+
+ /* marshall the parameters */
+ param[0] = htonl(FSGETROOTVOLUME);
+
+ piov[0].iov_len = sizeof(param);
+ piov[0].iov_base = param;
+
+ /* send the parameters to the server */
+ ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+ if (ret<0)
+ goto abort;
+
+ /* wait for the reply to completely arrive */
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (call->app_call_state!=RXRPC_CSTATE_CLNT_RCV_REPLY ||
+ signal_pending(current))
+ break;
+ schedule();
+ }
+ set_current_state(TASK_RUNNING);
+
+ ret = -EINTR;
+ if (signal_pending(current))
+ goto abort;
+
+ switch (call->app_call_state) {
+ case RXRPC_CSTATE_ERROR:
+ ret = call->app_errno;
+ kdebug("Got Error: %d",ret);
+ goto out_unwait;
+
+ case RXRPC_CSTATE_CLNT_GOT_REPLY:
+ /* read the reply */
+ kdebug("Got Reply: qty=%d",call->app_ready_qty);
+
+ ret = -EBADMSG;
+ if (call->app_ready_qty <= 4)
+ goto abort;
+
+ ret = rxrpc_call_read_data(call,NULL,call->app_ready_qty,0);
+ if (ret<0)
+ goto abort;
+
+#if 0
+ /* unmarshall the reply */
+ bp = buffer;
+ for (loop=0; loop<65; loop++)
+ entry->name[loop] = ntohl(*bp++);
+ entry->name[64] = 0;
+
+ entry->type = ntohl(*bp++);
+ entry->num_servers = ntohl(*bp++);
+
+ for (loop=0; loop<8; loop++)
+ entry->servers[loop].addr.s_addr = *bp++;
+
+ for (loop=0; loop<8; loop++)
+ entry->servers[loop].partition = ntohl(*bp++);
+
+ for (loop=0; loop<8; loop++)
+ entry->servers[loop].flags = ntohl(*bp++);
+
+ for (loop=0; loop<3; loop++)
+ entry->volume_ids[loop] = ntohl(*bp++);
+
+ entry->clone_id = ntohl(*bp++);
+ entry->flags = ntohl(*bp);
+#endif
+
+ /* success */
+ ret = 0;
+ goto out_unwait;
+
+ default:
+ BUG();
+ }
+
+ abort:
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ rxrpc_call_abort(call,ret);
+ schedule();
+ out_unwait:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&call->waitq,&myself);
+ rxrpc_put_call(call);
+ out_put_conn:
+ afs_server_release_fsconn(server,conn);
+ out:
+ kleave("");
+ return ret;
+} /* end afs_rxfs_get_root_volume() */
+#endif
+
+/*****************************************************************************/
+/*
+ * get information about a volume
+ */
+#if 0
+int afs_rxfs_get_volume_info(afs_server_t *server,
+ const char *name,
+ afs_volume_info_t *vinfo)
+{
+ DECLARE_WAITQUEUE(myself,current);
+
+ struct rxrpc_connection *conn;
+ struct rxrpc_call *call;
+ struct iovec piov[3];
+ size_t sent;
+ int ret;
+ u32 param[2], *bp, zero;
+
+ _enter("%p,%s,%p",server,name,vinfo);
+
+ /* get hold of the fileserver connection */
+ ret = afs_server_get_fsconn(server,&conn);
+ if (ret<0)
+ goto out;
+
+ /* create a call through that connection */
+ ret = rxrpc_create_call(conn,NULL,NULL,afs_rxfs_aemap,&call);
+ if (ret<0) {
+ printk("kAFS: Unable to create call: %d\n",ret);
+ goto out_put_conn;
+ }
+ call->app_opcode = FSGETVOLUMEINFO;
+
+ /* we want to get event notifications from the call */
+ add_wait_queue(&call->waitq,&myself);
+
+ /* marshall the parameters */
+ piov[1].iov_len = strlen(name);
+ piov[1].iov_base = (char*)name;
+
+ zero = 0;
+ piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
+ piov[2].iov_base = &zero;
+
+ param[0] = htonl(FSGETVOLUMEINFO);
+ param[1] = htonl(piov[1].iov_len);
+
+ piov[0].iov_len = sizeof(param);
+ piov[0].iov_base = param;
+
+ /* send the parameters to the server */
+ ret = rxrpc_call_write_data(call,3,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+ if (ret<0)
+ goto abort;
+
+ /* wait for the reply to completely arrive */
+ bp = rxrpc_call_alloc_scratch(call,64);
+
+ ret = rxrpc_call_read_data(call,bp,64,RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
+ if (ret<0) {
+ if (ret==-ECONNABORTED) {
+ ret = call->app_errno;
+ goto out_unwait;
+ }
+ goto abort;
+ }
+
+ /* unmarshall the reply */
+ vinfo->vid = ntohl(*bp++);
+ vinfo->type = ntohl(*bp++);
+
+ vinfo->type_vids[0] = ntohl(*bp++);
+ vinfo->type_vids[1] = ntohl(*bp++);
+ vinfo->type_vids[2] = ntohl(*bp++);
+ vinfo->type_vids[3] = ntohl(*bp++);
+ vinfo->type_vids[4] = ntohl(*bp++);
+
+ vinfo->nservers = ntohl(*bp++);
+ vinfo->servers[0].addr.s_addr = *bp++;
+ vinfo->servers[1].addr.s_addr = *bp++;
+ vinfo->servers[2].addr.s_addr = *bp++;
+ vinfo->servers[3].addr.s_addr = *bp++;
+ vinfo->servers[4].addr.s_addr = *bp++;
+ vinfo->servers[5].addr.s_addr = *bp++;
+ vinfo->servers[6].addr.s_addr = *bp++;
+ vinfo->servers[7].addr.s_addr = *bp++;
+
+ ret = -EBADMSG;
+ if (vinfo->nservers>8)
+ goto abort;
+
+ /* success */
+ ret = 0;
+
+ out_unwait:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&call->waitq,&myself);
+ rxrpc_put_call(call);
+ out_put_conn:
+ afs_server_release_fsconn(server,conn);
+ out:
+ _leave("");
+ return ret;
+
+ abort:
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ rxrpc_call_abort(call,ret);
+ schedule();
+ goto out_unwait;
+
+} /* end afs_rxfs_get_volume_info() */
+#endif
+
+/*****************************************************************************/
+/*
+ * fetch the status information for a file
+ */
+int afs_rxfs_fetch_file_status(afs_server_t *server,
+ afs_vnode_t *vnode,
+ afs_volsync_t *volsync)
+{
+ DECLARE_WAITQUEUE(myself,current);
+
+ struct afs_server_callslot callslot;
+ struct rxrpc_call *call;
+ struct iovec piov[1];
+ size_t sent;
+ int ret;
+ u32 *bp;
+
+ _enter("%p,{%u,%u,%u}",server,vnode->fid.vid,vnode->fid.vnode,vnode->fid.unique);
+
+ /* get hold of the fileserver connection */
+ ret = afs_server_request_callslot(server,&callslot);
+ if (ret<0)
+ goto out;
+
+ /* create a call through that connection */
+ ret = rxrpc_create_call(callslot.conn,NULL,NULL,afs_rxfs_aemap,&call);
+ if (ret<0) {
+ printk("kAFS: Unable to create call: %d\n",ret);
+ goto out_put_conn;
+ }
+ call->app_opcode = FSFETCHSTATUS;
+
+ /* we want to get event notifications from the call */
+ add_wait_queue(&call->waitq,&myself);
+
+ /* marshall the parameters */
+ bp = rxrpc_call_alloc_scratch(call,16);
+ bp[0] = htonl(FSFETCHSTATUS);
+ bp[1] = htonl(vnode->fid.vid);
+ bp[2] = htonl(vnode->fid.vnode);
+ bp[3] = htonl(vnode->fid.unique);
+
+ piov[0].iov_len = 16;
+ piov[0].iov_base = bp;
+
+ /* send the parameters to the server */
+ ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+ if (ret<0)
+ goto abort;
+
+ /* wait for the reply to completely arrive */
+ bp = rxrpc_call_alloc_scratch(call,120);
+
+ ret = rxrpc_call_read_data(call,bp,120,RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
+ if (ret<0) {
+ if (ret==-ECONNABORTED) {
+ ret = call->app_errno;
+ goto out_unwait;
+ }
+ goto abort;
+ }
+
+ /* unmarshall the reply */
+ vnode->status.if_version = ntohl(*bp++);
+ vnode->status.type = ntohl(*bp++);
+ vnode->status.nlink = ntohl(*bp++);
+ vnode->status.size = ntohl(*bp++);
+ vnode->status.version = ntohl(*bp++);
+ vnode->status.author = ntohl(*bp++);
+ vnode->status.owner = ntohl(*bp++);
+ vnode->status.caller_access = ntohl(*bp++);
+ vnode->status.anon_access = ntohl(*bp++);
+ vnode->status.mode = ntohl(*bp++);
+ vnode->status.parent.vid = vnode->fid.vid;
+ vnode->status.parent.vnode = ntohl(*bp++);
+ vnode->status.parent.unique = ntohl(*bp++);
+ bp++; /* seg size */
+ vnode->status.mtime_client = ntohl(*bp++);
+ vnode->status.mtime_server = ntohl(*bp++);
+ bp++; /* group */
+ bp++; /* sync counter */
+ vnode->status.version |= ((unsigned long long) ntohl(*bp++)) << 32;
+ bp++; /* spare2 */
+ bp++; /* spare3 */
+ bp++; /* spare4 */
+
+ vnode->cb_version = ntohl(*bp++);
+ vnode->cb_expiry = ntohl(*bp++);
+ vnode->cb_type = ntohl(*bp++);
+
+ if (volsync) {
+ volsync->creation = ntohl(*bp++);
+ bp++; /* spare2 */
+ bp++; /* spare3 */
+ bp++; /* spare4 */
+ bp++; /* spare5 */
+ bp++; /* spare6 */
+ }
+
+ /* success */
+ ret = 0;
+
+ out_unwait:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&call->waitq,&myself);
+ rxrpc_put_call(call);
+ out_put_conn:
+ afs_server_release_callslot(server,&callslot);
+ out:
+ _leave("");
+ return ret;
+
+ abort:
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ rxrpc_call_abort(call,ret);
+ schedule();
+ goto out_unwait;
+} /* end afs_rxfs_fetch_file_status() */
+
+/*****************************************************************************/
+/*
+ * fetch the contents of a file or directory
+ */
+int afs_rxfs_fetch_file_data(afs_server_t *server,
+ afs_vnode_t *vnode,
+ struct afs_rxfs_fetch_descriptor *desc,
+ afs_volsync_t *volsync)
+{
+ DECLARE_WAITQUEUE(myself,current);
+
+ struct afs_server_callslot callslot;
+ struct rxrpc_call *call;
+ struct iovec piov[1];
+ size_t sent;
+ int ret;
+ u32 *bp;
+
+ _enter("%p,{fid={%u,%u,%u},sz=%u,of=%lu}",
+ server,
+ desc->fid.vid,
+ desc->fid.vnode,
+ desc->fid.unique,
+ desc->size,
+ desc->offset);
+
+ /* get hold of the fileserver connection */
+ ret = afs_server_request_callslot(server,&callslot);
+ if (ret<0)
+ goto out;
+
+ /* create a call through that connection */
+ ret = rxrpc_create_call(callslot.conn,NULL,NULL,afs_rxfs_aemap,&call);
+ if (ret<0) {
+ printk("kAFS: Unable to create call: %d\n",ret);
+ goto out_put_conn;
+ }
+ call->app_opcode = FSFETCHDATA;
+
+ /* we want to get event notifications from the call */
+ add_wait_queue(&call->waitq,&myself);
+
+ /* marshall the parameters */
+ bp = rxrpc_call_alloc_scratch(call,24);
+ bp[0] = htonl(FSFETCHDATA);
+ bp[1] = htonl(desc->fid.vid);
+ bp[2] = htonl(desc->fid.vnode);
+ bp[3] = htonl(desc->fid.unique);
+ bp[4] = htonl(desc->offset);
+ bp[5] = htonl(desc->size);
+
+ piov[0].iov_len = 24;
+ piov[0].iov_base = bp;
+
+ /* send the parameters to the server */
+ ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+ if (ret<0)
+ goto abort;
+
+ /* wait for the data count to arrive */
+ ret = rxrpc_call_read_data(call,bp,4,RXRPC_CALL_READ_BLOCK);
+ if (ret<0)
+ goto read_failed;
+
+ desc->actual = ntohl(bp[0]);
+ if (desc->actual!=desc->size) {
+ ret = -EBADMSG;
+ goto abort;
+ }
+
+ /* call the app to read the actual data */
+ rxrpc_call_reset_scratch(call);
+
+ ret = rxrpc_call_read_data(call,desc->buffer,desc->actual,RXRPC_CALL_READ_BLOCK);
+ if (ret<0)
+ goto read_failed;
+
+ /* wait for the rest of the reply to completely arrive */
+ rxrpc_call_reset_scratch(call);
+ bp = rxrpc_call_alloc_scratch(call,120);
+
+ ret = rxrpc_call_read_data(call,bp,120,RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
+ if (ret<0)
+ goto read_failed;
+
+ /* unmarshall the reply */
+ vnode->status.if_version = ntohl(*bp++);
+ vnode->status.type = ntohl(*bp++);
+ vnode->status.nlink = ntohl(*bp++);
+ vnode->status.size = ntohl(*bp++);
+ vnode->status.version = ntohl(*bp++);
+ vnode->status.author = ntohl(*bp++);
+ vnode->status.owner = ntohl(*bp++);
+ vnode->status.caller_access = ntohl(*bp++);
+ vnode->status.anon_access = ntohl(*bp++);
+ vnode->status.mode = ntohl(*bp++);
+ vnode->status.parent.vid = desc->fid.vid;
+ vnode->status.parent.vnode = ntohl(*bp++);
+ vnode->status.parent.unique = ntohl(*bp++);
+ bp++; /* seg size */
+ vnode->status.mtime_client = ntohl(*bp++);
+ vnode->status.mtime_server = ntohl(*bp++);
+ bp++; /* group */
+ bp++; /* sync counter */
+ vnode->status.version |= ((unsigned long long) ntohl(*bp++)) << 32;
+ bp++; /* spare2 */
+ bp++; /* spare3 */
+ bp++; /* spare4 */
+
+ vnode->cb_version = ntohl(*bp++);
+ vnode->cb_expiry = ntohl(*bp++);
+ vnode->cb_type = ntohl(*bp++);
+
+ if (volsync) {
+ volsync->creation = ntohl(*bp++);
+ bp++; /* spare2 */
+ bp++; /* spare3 */
+ bp++; /* spare4 */
+ bp++; /* spare5 */
+ bp++; /* spare6 */
+ }
+
+ /* success */
+ ret = 0;
+
+ out_unwait:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&call->waitq,&myself);
+ rxrpc_put_call(call);
+ out_put_conn:
+ afs_server_release_callslot(server,&callslot);
+ out:
+ _leave(" = %d",ret);
+ return ret;
+
+ read_failed:
+ if (ret==-ECONNABORTED) {
+ ret = call->app_errno;
+ goto out_unwait;
+ }
+
+ abort:
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ rxrpc_call_abort(call,ret);
+ schedule();
+ goto out_unwait;
+
+} /* end afs_rxfs_fetch_file_data() */
+
+/*****************************************************************************/
+/*
+ * ask the AFS fileserver to discard a callback request on a file
+ */
+int afs_rxfs_give_up_callback(afs_server_t *server, afs_vnode_t *vnode)
+{
+ DECLARE_WAITQUEUE(myself,current);
+
+ struct afs_server_callslot callslot;
+ struct rxrpc_call *call;
+ struct iovec piov[1];
+ size_t sent;
+ int ret;
+ u32 *bp;
+
+ _enter("%p,{%u,%u,%u}",server,vnode->fid.vid,vnode->fid.vnode,vnode->fid.unique);
+
+ /* get hold of the fileserver connection */
+ ret = afs_server_request_callslot(server,&callslot);
+ if (ret<0)
+ goto out;
+
+ /* create a call through that connection */
+ ret = rxrpc_create_call(callslot.conn,NULL,NULL,afs_rxfs_aemap,&call);
+ if (ret<0) {
+ printk("kAFS: Unable to create call: %d\n",ret);
+ goto out_put_conn;
+ }
+ call->app_opcode = FSGIVEUPCALLBACKS;
+
+ /* we want to get event notifications from the call */
+ add_wait_queue(&call->waitq,&myself);
+
+ /* marshall the parameters */
+ bp = rxrpc_call_alloc_scratch(call,(1+4+4)*4);
+
+ piov[0].iov_len = (1+4+4)*4;
+ piov[0].iov_base = bp;
+
+ *bp++ = htonl(FSGIVEUPCALLBACKS);
+ *bp++ = htonl(1);
+ *bp++ = htonl(vnode->fid.vid);
+ *bp++ = htonl(vnode->fid.vnode);
+ *bp++ = htonl(vnode->fid.unique);
+ *bp++ = htonl(1);
+ *bp++ = htonl(vnode->cb_version);
+ *bp++ = htonl(vnode->cb_expiry);
+ *bp++ = htonl(vnode->cb_type);
+
+ /* send the parameters to the server */
+ ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+ if (ret<0)
+ goto abort;
+
+ /* wait for the reply to completely arrive */
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (call->app_call_state!=RXRPC_CSTATE_CLNT_RCV_REPLY ||
+ signal_pending(current))
+ break;
+ schedule();
+ }
+ set_current_state(TASK_RUNNING);
+
+ ret = -EINTR;
+ if (signal_pending(current))
+ goto abort;
+
+ switch (call->app_call_state) {
+ case RXRPC_CSTATE_ERROR:
+ ret = call->app_errno;
+ goto out_unwait;
+
+ case RXRPC_CSTATE_CLNT_GOT_REPLY:
+ ret = 0;
+ goto out_unwait;
+
+ default:
+ BUG();
+ }
+
+ out_unwait:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&call->waitq,&myself);
+ rxrpc_put_call(call);
+ out_put_conn:
+ afs_server_release_callslot(server,&callslot);
+ out:
+ _leave("");
+ return ret;
+
+ abort:
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ rxrpc_call_abort(call,ret);
+ schedule();
+ goto out_unwait;
+} /* end afs_rxfs_give_up_callback() */
+
+/*****************************************************************************/
+/*
+ * look a filename up in a directory
+ * - this operation doesn't seem to work correctly in OpenAFS server 1.2.2
+ */
+#if 0
+int afs_rxfs_lookup(afs_server_t *server,
+ afs_vnode_t *dir,
+ const char *filename,
+ afs_vnode_t *vnode,
+ afs_volsync_t *volsync)
+{
+ DECLARE_WAITQUEUE(myself,current);
+
+ struct rxrpc_connection *conn;
+ struct rxrpc_call *call;
+ struct iovec piov[3];
+ size_t sent;
+ int ret;
+ u32 *bp, zero;
+
+ kenter("%p,{%u,%u,%u},%s",server,fid->vid,fid->vnode,fid->unique,filename);
+
+ /* get hold of the fileserver connection */
+ ret = afs_server_get_fsconn(server,&conn);
+ if (ret<0)
+ goto out;
+
+ /* create a call through that connection */
+ ret = rxrpc_create_call(conn,NULL,NULL,afs_rxfs_aemap,&call);
+ if (ret<0) {
+ printk("kAFS: Unable to create call: %d\n",ret);
+ goto out_put_conn;
+ }
+ call->app_opcode = FSLOOKUP;
+
+ /* we want to get event notifications from the call */
+ add_wait_queue(&call->waitq,&myself);
+
+ /* marshall the parameters */
+ bp = rxrpc_call_alloc_scratch(call,20);
+
+ zero = 0;
+
+ piov[0].iov_len = 20;
+ piov[0].iov_base = bp;
+ piov[1].iov_len = strlen(filename);
+ piov[1].iov_base = (char*) filename;
+ piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
+ piov[2].iov_base = &zero;
+
+ *bp++ = htonl(FSLOOKUP);
+ *bp++ = htonl(dirfid->vid);
+ *bp++ = htonl(dirfid->vnode);
+ *bp++ = htonl(dirfid->unique);
+ *bp++ = htonl(piov[1].iov_len);
+
+ /* send the parameters to the server */
+ ret = rxrpc_call_write_data(call,3,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+ if (ret<0)
+ goto abort;
+
+ /* wait for the reply to completely arrive */
+ bp = rxrpc_call_alloc_scratch(call,220);
+
+ ret = rxrpc_call_read_data(call,bp,220,RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
+ if (ret<0) {
+ if (ret==-ECONNABORTED) {
+ ret = call->app_errno;
+ goto out_unwait;
+ }
+ goto abort;
+ }
+
+ /* unmarshall the reply */
+ fid->vid = ntohl(*bp++);
+ fid->vnode = ntohl(*bp++);
+ fid->unique = ntohl(*bp++);
+
+ vnode->status.if_version = ntohl(*bp++);
+ vnode->status.type = ntohl(*bp++);
+ vnode->status.nlink = ntohl(*bp++);
+ vnode->status.size = ntohl(*bp++);
+ vnode->status.version = ntohl(*bp++);
+ vnode->status.author = ntohl(*bp++);
+ vnode->status.owner = ntohl(*bp++);
+ vnode->status.caller_access = ntohl(*bp++);
+ vnode->status.anon_access = ntohl(*bp++);
+ vnode->status.mode = ntohl(*bp++);
+ vnode->status.parent.vid = dirfid->vid;
+ vnode->status.parent.vnode = ntohl(*bp++);
+ vnode->status.parent.unique = ntohl(*bp++);
+ bp++; /* seg size */
+ vnode->status.mtime_client = ntohl(*bp++);
+ vnode->status.mtime_server = ntohl(*bp++);
+ bp++; /* group */
+ bp++; /* sync counter */
+ vnode->status.version |= ((unsigned long long) ntohl(*bp++)) << 32;
+ bp++; /* spare2 */
+ bp++; /* spare3 */
+ bp++; /* spare4 */
+
+ dir->status.if_version = ntohl(*bp++);
+ dir->status.type = ntohl(*bp++);
+ dir->status.nlink = ntohl(*bp++);
+ dir->status.size = ntohl(*bp++);
+ dir->status.version = ntohl(*bp++);
+ dir->status.author = ntohl(*bp++);
+ dir->status.owner = ntohl(*bp++);
+ dir->status.caller_access = ntohl(*bp++);
+ dir->status.anon_access = ntohl(*bp++);
+ dir->status.mode = ntohl(*bp++);
+ dir->status.parent.vid = dirfid->vid;
+ dir->status.parent.vnode = ntohl(*bp++);
+ dir->status.parent.unique = ntohl(*bp++);
+ bp++; /* seg size */
+ dir->status.mtime_client = ntohl(*bp++);
+ dir->status.mtime_server = ntohl(*bp++);
+ bp++; /* group */
+ bp++; /* sync counter */
+ dir->status.version |= ((unsigned long long) ntohl(*bp++)) << 32;
+ bp++; /* spare2 */
+ bp++; /* spare3 */
+ bp++; /* spare4 */
+
+ callback->fid = *fid;
+ callback->version = ntohl(*bp++);
+ callback->expiry = ntohl(*bp++);
+ callback->type = ntohl(*bp++);
+
+ if (volsync) {
+ volsync->creation = ntohl(*bp++);
+ bp++; /* spare2 */
+ bp++; /* spare3 */
+ bp++; /* spare4 */
+ bp++; /* spare5 */
+ bp++; /* spare6 */
+ }
+
+ /* success */
+ ret = 0;
+
+ out_unwait:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&call->waitq,&myself);
+ rxrpc_put_call(call);
+ out_put_conn:
+ afs_server_release_fsconn(server,conn);
+ out:
+ kleave("");
+ return ret;
+
+ abort:
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ rxrpc_call_abort(call,ret);
+ schedule();
+ goto out_unwait;
+} /* end afs_rxfs_lookup() */
+#endif
diff --git a/fs/afs/fsclient.h b/fs/afs/fsclient.h
new file mode 100644
index 000000000000..0931a5b1be8f
--- /dev/null
+++ b/fs/afs/fsclient.h
@@ -0,0 +1,53 @@
+/* fsclient.h: AFS File Server client stub declarations
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_FSCLIENT_H
+#define _LINUX_AFS_FSCLIENT_H
+
+#include "server.h"
+
+extern int afs_rxfs_get_volume_info(afs_server_t *server,
+ const char *name,
+ afs_volume_info_t *vinfo);
+
+extern int afs_rxfs_fetch_file_status(afs_server_t *server,
+ afs_vnode_t *vnode,
+ afs_volsync_t *volsync);
+
+struct afs_rxfs_fetch_descriptor {
+ afs_fid_t fid; /* file ID to fetch */
+ size_t size; /* total number of bytes to fetch */
+ off_t offset; /* offset in file to start from */
+ void *buffer; /* read buffer */
+ size_t actual; /* actual size sent back by server */
+};
+
+extern int afs_rxfs_fetch_file_data(afs_server_t *server,
+ afs_vnode_t *vnode,
+ struct afs_rxfs_fetch_descriptor *desc,
+ afs_volsync_t *volsync);
+
+extern int afs_rxfs_give_up_callback(afs_server_t *server, afs_vnode_t *vnode);
+
+/* this doesn't appear to work in OpenAFS server */
+extern int afs_rxfs_lookup(afs_server_t *server,
+ afs_vnode_t *dir,
+ const char *filename,
+ afs_vnode_t *vnode,
+ afs_volsync_t *volsync);
+
+/* this is apparently mis-implemented in OpenAFS server */
+extern int afs_rxfs_get_root_volume(afs_server_t *server,
+ char *buf,
+ size_t *buflen);
+
+
+#endif /* _LINUX_AFS_FSCLIENT_H */
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
new file mode 100644
index 000000000000..235b7b0bcf5e
--- /dev/null
+++ b/fs/afs/inode.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
+ *
+ * This software may be freely redistributed under the terms of the
+ * GNU General Public License.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors: David Woodhouse <dwmw2@cambridge.redhat.com>
+ * David Howells <dhowells@redhat.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "volume.h"
+#include "vnode.h"
+#include "super.h"
+#include "internal.h"
+
+struct afs_iget_data {
+ afs_fid_t fid;
+ afs_volume_t *volume; /* volume on which resides */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+ afs_vnode_t *new_vnode; /* new vnode record */
+#endif
+};
+
+/*****************************************************************************/
+/*
+ * map the AFS file status to the inode member variables
+ */
+static int afs_inode_map_status(afs_vnode_t *vnode)
+{
+ struct inode *inode = AFS_VNODE_TO_I(vnode);
+
+ _debug("FS: ft=%d lk=%d sz=%u ver=%Lu mod=%hu",
+ vnode->status.type,
+ vnode->status.nlink,
+ vnode->status.size,
+ vnode->status.version,
+ vnode->status.mode);
+
+ switch (vnode->status.type) {
+ case AFS_FTYPE_FILE:
+ inode->i_mode = S_IFREG | vnode->status.mode;
+ inode->i_op = &afs_file_inode_operations;
+ inode->i_fop = &afs_file_file_operations;
+ break;
+ case AFS_FTYPE_DIR:
+ inode->i_mode = S_IFDIR | vnode->status.mode;
+ inode->i_op = &afs_dir_inode_operations;
+ inode->i_fop = &afs_dir_file_operations;
+ break;
+ case AFS_FTYPE_SYMLINK:
+ inode->i_mode = S_IFLNK | vnode->status.mode;
+ inode->i_op = &page_symlink_inode_operations;
+ break;
+ default:
+ printk("kAFS: AFS vnode with undefined type\n");
+ return -EBADMSG;
+ }
+
+ inode->i_nlink = vnode->status.nlink;
+ inode->i_uid = vnode->status.owner;
+ inode->i_gid = 0;
+ inode->i_rdev = NODEV;
+ inode->i_size = vnode->status.size;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = vnode->status.mtime_server;
+ inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_version = vnode->fid.unique;
+ inode->i_mapping->a_ops = &afs_fs_aops;
+
+ /* check to see whether a symbolic link is really a mountpoint */
+ if (vnode->status.type==AFS_FTYPE_SYMLINK) {
+ afs_mntpt_check_symlink(vnode);
+
+ if (vnode->flags & AFS_VNODE_MOUNTPOINT) {
+ inode->i_mode = S_IFDIR | vnode->status.mode;
+ inode->i_op = &afs_mntpt_inode_operations;
+ inode->i_fop = &afs_mntpt_file_operations;
+ }
+ }
+
+ return 0;
+} /* end afs_inode_map_status() */
+
+/*****************************************************************************/
+/*
+ * attempt to fetch the status of an inode, coelescing multiple simultaneous fetches
+ */
+int afs_inode_fetch_status(struct inode *inode)
+{
+ afs_vnode_t *vnode;
+ int ret;
+
+ vnode = AFS_FS_I(inode);
+
+ ret = afs_vnode_fetch_status(vnode);
+
+ if (ret==0)
+ ret = afs_inode_map_status(vnode);
+
+ return ret;
+
+} /* end afs_inode_fetch_status() */
+
+/*****************************************************************************/
+/*
+ * iget5() comparator
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static int afs_iget5_test(struct inode *inode, void *opaque)
+{
+ struct afs_iget_data *data = opaque;
+
+ /* only match inodes with the same version number */
+ return inode->i_ino==data->fid.vnode && inode->i_version==data->fid.unique;
+} /* end afs_iget5_test() */
+#endif
+
+/*****************************************************************************/
+/*
+ * iget5() inode initialiser
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static int afs_iget5_set(struct inode *inode, void *opaque)
+{
+ struct afs_iget_data *data = opaque;
+ afs_vnode_t *vnode = AFS_FS_I(inode);
+
+ inode->i_ino = data->fid.vnode;
+ inode->i_version = data->fid.unique;
+ vnode->fid = data->fid;
+ vnode->volume = data->volume;
+
+ return 0;
+} /* end afs_iget5_set() */
+#endif
+
+/*****************************************************************************/
+/*
+ * iget4() comparator
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static int afs_iget4_test(struct inode *inode, ino_t ino, void *opaque)
+{
+ struct afs_iget_data *data = opaque;
+
+ /* only match inodes with the same version number */
+ return inode->i_ino==data->fid.vnode && inode->i_version==data->fid.unique;
+} /* end afs_iget4_test() */
+#endif
+
+/*****************************************************************************/
+/*
+ * read an inode (2.4 only)
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+void afs_read_inode2(struct inode *inode, void *opaque)
+{
+ struct afs_iget_data *data = opaque;
+ afs_vnode_t *vnode;
+ int ret;
+
+ _enter(",{{%u,%u,%u},%p}",data->fid.vid,data->fid.vnode,data->fid.unique,data->volume);
+
+ if (inode->u.generic_ip) BUG();
+
+ /* attach a pre-allocated vnode record */
+ inode->u.generic_ip = vnode = data->new_vnode;
+ data->new_vnode = NULL;
+
+ memset(vnode,0,sizeof(*vnode));
+ vnode->inode = inode;
+ init_waitqueue_head(&vnode->update_waitq);
+ spin_lock_init(&vnode->lock);
+ INIT_LIST_HEAD(&vnode->cb_link);
+ INIT_LIST_HEAD(&vnode->cb_hash_link);
+ afs_timer_init(&vnode->cb_timeout,&afs_vnode_cb_timed_out_ops);
+ vnode->flags |= AFS_VNODE_CHANGED;
+ vnode->volume = data->volume;
+ vnode->fid = data->fid;
+
+ /* ask the server for a status check */
+ ret = afs_vnode_fetch_status(vnode);
+ if (ret<0) {
+ make_bad_inode(inode);
+ _leave(" [bad inode]");
+ return;
+ }
+
+ ret = afs_inode_map_status(vnode);
+ if (ret<0) {
+ make_bad_inode(inode);
+ _leave(" [bad inode]");
+ return;
+ }
+
+ _leave("");
+ return;
+} /* end afs_read_inode2() */
+#endif
+
+/*****************************************************************************/
+/*
+ * inode retrieval
+ */
+inline int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inode)
+{
+ struct afs_iget_data data = { fid: *fid };
+ struct afs_super_info *as;
+ struct inode *inode;
+ afs_vnode_t *vnode;
+ int ret;
+
+ _enter(",{%u,%u,%u},,",fid->vid,fid->vnode,fid->unique);
+
+ as = sb->s_fs_info;
+ data.volume = as->volume;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ inode = iget5_locked(sb,fid->vnode,afs_iget5_test,afs_iget5_set,&data);
+ if (!inode) {
+ _leave(" = -ENOMEM");
+ return -ENOMEM;
+ }
+
+ vnode = AFS_FS_I(inode);
+
+ /* deal with an existing inode */
+ if (!(inode->i_state & I_NEW)) {
+ ret = afs_vnode_fetch_status(vnode);
+ if (ret==0)
+ *_inode = inode;
+ else
+ iput(inode);
+ _leave(" = %d",ret);
+ return ret;
+ }
+
+ /* okay... it's a new inode */
+ vnode->flags |= AFS_VNODE_CHANGED;
+ ret = afs_inode_fetch_status(inode);
+ if (ret<0)
+ goto bad_inode;
+
+#if 0
+ /* find a cache entry for it */
+ ret = afs_cache_lookup_vnode(as->volume,vnode);
+ if (ret<0)
+ goto bad_inode;
+#endif
+
+ /* success */
+ unlock_new_inode(inode);
+
+ *_inode = inode;
+ _leave(" = 0 [CB { v=%u x=%lu t=%u nix=%u }]",
+ vnode->cb_version,
+ vnode->cb_timeout.timo_jif,
+ vnode->cb_type,
+ vnode->nix
+ );
+ return 0;
+
+ /* failure */
+ bad_inode:
+ make_bad_inode(inode);
+ unlock_new_inode(inode);
+ iput(inode);
+
+ _leave(" = %d [bad]",ret);
+ return ret;
+
+#else
+
+ /* pre-allocate a vnode record so that afs_read_inode2() doesn't have to return an inode
+ * without one attached
+ */
+ data.new_vnode = kmalloc(sizeof(afs_vnode_t),GFP_KERNEL);
+ if (!data.new_vnode) {
+ _leave(" = -ENOMEM");
+ return -ENOMEM;
+ }
+
+ inode = iget4(sb,fid->vnode,afs_iget4_test,&data);
+ if (data.new_vnode) kfree(data.new_vnode);
+ if (!inode) {
+ _leave(" = -ENOMEM");
+ return -ENOMEM;
+ }
+
+ vnode = AFS_FS_I(inode);
+ *_inode = inode;
+ _leave(" = 0 [CB { v=%u x=%lu t=%u nix=%u }]",
+ vnode->cb_version,
+ vnode->cb_timeout.timo_jif,
+ vnode->cb_type,
+ vnode->nix
+ );
+ return 0;
+#endif
+} /* end afs_iget() */
+
+/*****************************************************************************/
+/*
+ * read the attributes of an inode
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+{
+ struct inode *inode;
+ afs_vnode_t *vnode;
+ int ret;
+
+ inode = dentry->d_inode;
+
+ _enter("{ ino=%lu v=%lu }",inode->i_ino,inode->i_version);
+
+ vnode = AFS_FS_I(inode);
+
+ ret = afs_inode_fetch_status(inode);
+ if (ret==-ENOENT) {
+ _leave(" = %d [%d %p]",ret,atomic_read(&dentry->d_count),dentry->d_inode);
+ return ret;
+ }
+ else if (ret<0) {
+ make_bad_inode(inode);
+ _leave(" = %d",ret);
+ return ret;
+ }
+
+ /* transfer attributes from the inode structure to the stat structure */
+ generic_fillattr(inode,stat);
+
+ _leave(" = 0 CB { v=%u x=%u t=%u }",
+ vnode->cb_version,
+ vnode->cb_expiry,
+ vnode->cb_type);
+
+ return 0;
+} /* end afs_inode_getattr() */
+#endif
+
+/*****************************************************************************/
+/*
+ * revalidate the inode
+ */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+int afs_inode_revalidate(struct dentry *dentry)
+{
+ struct inode *inode;
+ afs_vnode_t *vnode;
+ int ret;
+
+ inode = dentry->d_inode;
+
+ _enter("{ ino=%lu v=%lu }",inode->i_ino,inode->i_version);
+
+ vnode = AFS_FS_I(inode);
+
+ ret = afs_inode_fetch_status(inode);
+ if (ret==-ENOENT) {
+ _leave(" = %d [%d %p]",ret,atomic_read(&dentry->d_count),dentry->d_inode);
+ return ret;
+ }
+ else if (ret<0) {
+ make_bad_inode(inode);
+ _leave(" = %d",ret);
+ return ret;
+ }
+
+ _leave(" = 0 CB { v=%u x=%u t=%u }",
+ vnode->cb_version,
+ vnode->cb_expiry,
+ vnode->cb_type);
+
+ return 0;
+} /* end afs_inode_revalidate() */
+#endif
+
+/*****************************************************************************/
+/*
+ * clear an AFS inode
+ */
+void afs_clear_inode(struct inode *inode)
+{
+ afs_vnode_t *vnode;
+
+ vnode = AFS_FS_I(inode);
+
+ _enter("ino=%lu { vn=%08x v=%u x=%u t=%u }",
+ inode->i_ino,
+ vnode->fid.vnode,
+ vnode->cb_version,
+ vnode->cb_expiry,
+ vnode->cb_type
+ );
+
+ if (inode->i_ino!=vnode->fid.vnode) BUG();
+
+ afs_vnode_give_up_callback(vnode);
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+ if (inode->u.generic_ip) kfree(inode->u.generic_ip);
+#endif
+
+ _leave("");
+} /* end afs_clear_inode() */
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
new file mode 100644
index 000000000000..37f84bb11891
--- /dev/null
+++ b/fs/afs/internal.h
@@ -0,0 +1,127 @@
+/* internal.h: internal AFS stuff
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef AFS_INTERNAL_H
+#define AFS_INTERNAL_H
+
+#include <linux/version.h>
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+
+/*
+ * debug tracing
+ */
+#define kenter(FMT,...) printk("==> %s("FMT")\n",__FUNCTION__,##__VA_ARGS__)
+#define kleave(FMT,...) printk("<== %s()"FMT"\n",__FUNCTION__,##__VA_ARGS__)
+#define kdebug(FMT,...) printk(FMT"\n",##__VA_ARGS__)
+#define kproto(FMT,...) printk("### "FMT"\n",##__VA_ARGS__)
+#define knet(FMT,...) printk(FMT"\n",##__VA_ARGS__)
+
+#if 0
+#define _enter(FMT,...) kenter(FMT,##__VA_ARGS__)
+#define _leave(FMT,...) kleave(FMT,##__VA_ARGS__)
+#define _debug(FMT,...) kdebug(FMT,##__VA_ARGS__)
+#define _proto(FMT,...) kproto(FMT,##__VA_ARGS__)
+#define _net(FMT,...) knet(FMT,##__VA_ARGS__)
+#else
+#define _enter(FMT,...) do { } while(0)
+#define _leave(FMT,...) do { } while(0)
+#define _debug(FMT,...) do { } while(0)
+#define _proto(FMT,...) do { } while(0)
+#define _net(FMT,...) do { } while(0)
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+#define wait_on_page_locked wait_on_page
+#define PageUptodate Page_Uptodate
+
+static inline struct proc_dir_entry *PDE(const struct inode *inode)
+{
+ return (struct proc_dir_entry *)inode->u.generic_ip;
+}
+#endif
+
+static inline void afs_discard_my_signals(void)
+{
+ while (signal_pending(current)) {
+ siginfo_t sinfo;
+
+ spin_lock_irq(&current->sig->siglock);
+ dequeue_signal(&current->blocked,&sinfo);
+ spin_unlock_irq(&current->sig->siglock);
+ }
+}
+
+/*
+ * cell.c
+ */
+extern struct rw_semaphore afs_proc_cells_sem;
+extern struct list_head afs_proc_cells;
+
+/*
+ * dir.c
+ */
+extern struct inode_operations afs_dir_inode_operations;
+extern struct file_operations afs_dir_file_operations;
+
+/*
+ * file.c
+ */
+extern struct address_space_operations afs_fs_aops;
+extern struct inode_operations afs_file_inode_operations;
+extern struct file_operations afs_file_file_operations;
+
+/*
+ * inode.c
+ */
+extern int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inode);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+extern int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
+#else
+extern void afs_read_inode2(struct inode *inode, void *opaque);
+extern int afs_inode_revalidate(struct dentry *dentry);
+#endif
+extern void afs_clear_inode(struct inode *inode);
+
+/*
+ * mntpt.c
+ */
+extern struct inode_operations afs_mntpt_inode_operations;
+extern struct file_operations afs_mntpt_file_operations;
+
+extern int afs_mntpt_check_symlink(afs_vnode_t *vnode);
+
+/*
+ * super.c
+ */
+extern int afs_fs_init(void);
+extern void afs_fs_exit(void);
+
+#define AFS_CB_HASH_COUNT (PAGE_SIZE/sizeof(struct list_head))
+
+extern struct list_head afs_cb_hash_tbl[];
+extern spinlock_t afs_cb_hash_lock;
+
+#define afs_cb_hash(SRV,FID) \
+ afs_cb_hash_tbl[((unsigned)(SRV) + (FID)->vid + (FID)->vnode + (FID)->unique) % \
+ AFS_CB_HASH_COUNT]
+
+/*
+ * proc.c
+ */
+extern int afs_proc_init(void);
+extern void afs_proc_cleanup(void);
+extern int afs_proc_cell_setup(afs_cell_t *cell);
+extern void afs_proc_cell_remove(afs_cell_t *cell);
+
+#endif /* AFS_INTERNAL_H */
diff --git a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c
new file mode 100644
index 000000000000..2891e98be91d
--- /dev/null
+++ b/fs/afs/kafsasyncd.c
@@ -0,0 +1,260 @@
+/* kafsasyncd.c: AFS asynchronous operation daemon
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * The AFS async daemon is used to the following:
+ * - probe "dead" servers to see whether they've come back to life yet.
+ * - probe "live" servers that we haven't talked to for a while to see if they are better
+ * candidates for serving than what we're currently using
+ * - poll volume location servers to keep up to date volume location lists
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include "cell.h"
+#include "server.h"
+#include "volume.h"
+#include "kafsasyncd.h"
+#include "kafstimod.h"
+#include <rxrpc/call.h>
+#include <asm/errno.h>
+#include "internal.h"
+
+static DECLARE_COMPLETION(kafsasyncd_alive);
+static DECLARE_COMPLETION(kafsasyncd_dead);
+static DECLARE_WAIT_QUEUE_HEAD(kafsasyncd_sleepq);
+static struct task_struct *kafsasyncd_task;
+static int kafsasyncd_die;
+
+static int kafsasyncd(void *arg);
+
+static LIST_HEAD(kafsasyncd_async_attnq);
+static LIST_HEAD(kafsasyncd_async_busyq);
+static spinlock_t kafsasyncd_async_lock = SPIN_LOCK_UNLOCKED;
+
+static void kafsasyncd_null_call_attn_func(struct rxrpc_call *call)
+{
+}
+
+static void kafsasyncd_null_call_error_func(struct rxrpc_call *call)
+{
+}
+
+/*****************************************************************************/
+/*
+ * start the async daemon
+ */
+int afs_kafsasyncd_start(void)
+{
+ int ret;
+
+ ret = kernel_thread(kafsasyncd,NULL,0);
+ if (ret<0)
+ return ret;
+
+ wait_for_completion(&kafsasyncd_alive);
+
+ return ret;
+} /* end afs_kafsasyncd_start() */
+
+/*****************************************************************************/
+/*
+ * stop the async daemon
+ */
+void afs_kafsasyncd_stop(void)
+{
+ /* get rid of my daemon */
+ kafsasyncd_die = 1;
+ wake_up(&kafsasyncd_sleepq);
+ wait_for_completion(&kafsasyncd_dead);
+
+} /* end afs_kafsasyncd_stop() */
+
+/*****************************************************************************/
+/*
+ * probing daemon
+ */
+static int kafsasyncd(void *arg)
+{
+ DECLARE_WAITQUEUE(myself,current);
+
+ struct list_head *_p;
+ int die;
+
+ kafsasyncd_task = current;
+
+ printk("kAFS: Started kafsasyncd %d\n",current->pid);
+ strcpy(current->comm,"kafsasyncd");
+
+ daemonize();
+
+ complete(&kafsasyncd_alive);
+
+ /* only certain signals are of interest */
+ spin_lock_irq(&current->sig->siglock);
+ siginitsetinv(&current->blocked,0);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3)
+ recalc_sigpending();
+#else
+ recalc_sigpending(current);
+#endif
+ spin_unlock_irq(&current->sig->siglock);
+
+ /* loop around looking for things to attend to */
+ do {
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&kafsasyncd_sleepq,&myself);
+
+ for (;;) {
+ if (!list_empty(&kafsasyncd_async_attnq) ||
+ signal_pending(current) ||
+ kafsasyncd_die)
+ break;
+
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+
+ remove_wait_queue(&kafsasyncd_sleepq,&myself);
+ set_current_state(TASK_RUNNING);
+
+ /* discard pending signals */
+ afs_discard_my_signals();
+
+ die = kafsasyncd_die;
+
+ /* deal with the next asynchronous operation requiring attention */
+ if (!list_empty(&kafsasyncd_async_attnq)) {
+ struct afs_async_op *op;
+
+ _debug("@@@ Begin Asynchronous Operation");
+
+ op = NULL;
+ spin_lock(&kafsasyncd_async_lock);
+
+ if (!list_empty(&kafsasyncd_async_attnq)) {
+ op = list_entry(kafsasyncd_async_attnq.next,afs_async_op_t,link);
+ list_del(&op->link);
+ list_add_tail(&op->link,&kafsasyncd_async_busyq);
+ }
+
+ spin_unlock(&kafsasyncd_async_lock);
+
+ _debug("@@@ Operation %p {%p}\n",op,op?op->ops:NULL);
+
+ if (op)
+ op->ops->attend(op);
+
+ _debug("@@@ End Asynchronous Operation");
+ }
+
+ } while(!die);
+
+ /* need to kill all outstanding asynchronous operations before exiting */
+ kafsasyncd_task = NULL;
+ spin_lock(&kafsasyncd_async_lock);
+
+ /* fold the busy and attention queues together */
+ list_splice(&kafsasyncd_async_busyq,&kafsasyncd_async_attnq);
+ list_del_init(&kafsasyncd_async_busyq);
+
+ /* dequeue kafsasyncd from all their wait queues */
+ list_for_each(_p,&kafsasyncd_async_attnq) {
+ afs_async_op_t *op = list_entry(_p,afs_async_op_t,link);
+
+ op->call->app_attn_func = kafsasyncd_null_call_attn_func;
+ op->call->app_error_func = kafsasyncd_null_call_error_func;
+ remove_wait_queue(&op->call->waitq,&op->waiter);
+ }
+
+ spin_unlock(&kafsasyncd_async_lock);
+
+ /* abort all the operations */
+ while (!list_empty(&kafsasyncd_async_attnq)) {
+ afs_async_op_t *op = list_entry(_p,afs_async_op_t,link);
+ list_del_init(&op->link);
+
+ rxrpc_call_abort(op->call,-EIO);
+ rxrpc_put_call(op->call);
+ op->call = NULL;
+
+ op->ops->discard(op);
+ }
+
+ /* and that's all */
+ _leave("");
+ complete_and_exit(&kafsasyncd_dead,0);
+
+} /* end kafsasyncd() */
+
+/*****************************************************************************/
+/*
+ * begin an operation
+ * - place operation on busy queue
+ */
+void afs_kafsasyncd_begin_op(afs_async_op_t *op)
+{
+ _enter("");
+
+ spin_lock(&kafsasyncd_async_lock);
+
+ init_waitqueue_entry(&op->waiter,kafsasyncd_task);
+
+ list_del(&op->link);
+ list_add_tail(&op->link,&kafsasyncd_async_busyq);
+
+ spin_unlock(&kafsasyncd_async_lock);
+
+ _leave("");
+} /* end afs_kafsasyncd_begin_op() */
+
+/*****************************************************************************/
+/*
+ * request attention for an operation
+ * - move to attention queue
+ */
+void afs_kafsasyncd_attend_op(afs_async_op_t *op)
+{
+ _enter("");
+
+ spin_lock(&kafsasyncd_async_lock);
+
+ list_del(&op->link);
+ list_add_tail(&op->link,&kafsasyncd_async_attnq);
+
+ spin_unlock(&kafsasyncd_async_lock);
+
+ wake_up(&kafsasyncd_sleepq);
+
+ _leave("");
+} /* end afs_kafsasyncd_attend_op() */
+
+/*****************************************************************************/
+/*
+ * terminate an operation
+ * - remove from either queue
+ */
+void afs_kafsasyncd_terminate_op(afs_async_op_t *op)
+{
+ _enter("");
+
+ spin_lock(&kafsasyncd_async_lock);
+
+ list_del_init(&op->link);
+
+ spin_unlock(&kafsasyncd_async_lock);
+
+ wake_up(&kafsasyncd_sleepq);
+
+ _leave("");
+} /* end afs_kafsasyncd_terminate_op() */
diff --git a/fs/afs/kafsasyncd.h b/fs/afs/kafsasyncd.h
new file mode 100644
index 000000000000..6438c17833a1
--- /dev/null
+++ b/fs/afs/kafsasyncd.h
@@ -0,0 +1,49 @@
+/* kafsasyncd.h: AFS asynchronous operation daemon
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_KAFSASYNCD_H
+#define _LINUX_AFS_KAFSASYNCD_H
+
+#include "types.h"
+
+struct afs_async_op_ops {
+ void (*attend)(afs_async_op_t *op);
+ void (*discard)(afs_async_op_t *op);
+};
+
+/*****************************************************************************/
+/*
+ * asynchronous operation record
+ */
+struct afs_async_op
+{
+ struct list_head link;
+ afs_server_t *server; /* server being contacted */
+ struct rxrpc_call *call; /* RxRPC call performing op */
+ wait_queue_t waiter; /* wait queue for kafsasyncd */
+ const struct afs_async_op_ops *ops; /* operations */
+};
+
+static inline void afs_async_op_init(afs_async_op_t *op, const struct afs_async_op_ops *ops)
+{
+ INIT_LIST_HEAD(&op->link);
+ op->call = NULL;
+ op->ops = ops;
+}
+
+extern int afs_kafsasyncd_start(void);
+extern void afs_kafsasyncd_stop(void);
+
+extern void afs_kafsasyncd_begin_op(afs_async_op_t *op);
+extern void afs_kafsasyncd_attend_op(afs_async_op_t *op);
+extern void afs_kafsasyncd_terminate_op(afs_async_op_t *op);
+
+#endif /* _LINUX_AFS_KAFSASYNCD_H */
diff --git a/fs/afs/kafstimod.c b/fs/afs/kafstimod.c
new file mode 100644
index 000000000000..ccc1b4e6b94d
--- /dev/null
+++ b/fs/afs/kafstimod.c
@@ -0,0 +1,211 @@
+/* kafstimod.c: AFS timeout daemon
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include "cell.h"
+#include "volume.h"
+#include "kafstimod.h"
+#include <asm/errno.h>
+#include "internal.h"
+
+static DECLARE_COMPLETION(kafstimod_alive);
+static DECLARE_COMPLETION(kafstimod_dead);
+static DECLARE_WAIT_QUEUE_HEAD(kafstimod_sleepq);
+static int kafstimod_die;
+
+static LIST_HEAD(kafstimod_list);
+static spinlock_t kafstimod_lock = SPIN_LOCK_UNLOCKED;
+
+static int kafstimod(void *arg);
+
+/*****************************************************************************/
+/*
+ * start the timeout daemon
+ */
+int afs_kafstimod_start(void)
+{
+ int ret;
+
+ ret = kernel_thread(kafstimod,NULL,0);
+ if (ret<0)
+ return ret;
+
+ wait_for_completion(&kafstimod_alive);
+
+ return ret;
+} /* end afs_kafstimod_start() */
+
+/*****************************************************************************/
+/*
+ * stop the timeout daemon
+ */
+void afs_kafstimod_stop(void)
+{
+ /* get rid of my daemon */
+ kafstimod_die = 1;
+ wake_up(&kafstimod_sleepq);
+ wait_for_completion(&kafstimod_dead);
+
+} /* end afs_kafstimod_stop() */
+
+/*****************************************************************************/
+/*
+ * timeout processing daemon
+ */
+static int kafstimod(void *arg)
+{
+ DECLARE_WAITQUEUE(myself,current);
+
+ afs_timer_t *timer;
+
+ printk("kAFS: Started kafstimod %d\n",current->pid);
+ strcpy(current->comm,"kafstimod");
+
+ daemonize();
+
+ complete(&kafstimod_alive);
+
+ /* only certain signals are of interest */
+ spin_lock_irq(&current->sig->siglock);
+ siginitsetinv(&current->blocked,0);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3)
+ recalc_sigpending();
+#else
+ recalc_sigpending(current);
+#endif
+ spin_unlock_irq(&current->sig->siglock);
+
+ /* loop around looking for things to attend to */
+ loop:
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&kafstimod_sleepq,&myself);
+
+ for (;;) {
+ unsigned long jif;
+ signed long timeout;
+
+ /* deal with the server being asked to die */
+ if (kafstimod_die) {
+ remove_wait_queue(&kafstimod_sleepq,&myself);
+ _leave("");
+ complete_and_exit(&kafstimod_dead,0);
+ }
+
+ /* discard pending signals */
+ afs_discard_my_signals();
+
+ /* work out the time to elapse before the next event */
+ spin_lock(&kafstimod_lock);
+ if (list_empty(&kafstimod_list)) {
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ }
+ else {
+ timer = list_entry(kafstimod_list.next,afs_timer_t,link);
+ timeout = timer->timo_jif;
+ jif = jiffies;
+
+ if (time_before_eq(timeout,jif))
+ goto immediate;
+
+ else {
+ timeout = (long)timeout - (long)jiffies;
+ }
+ }
+ spin_unlock(&kafstimod_lock);
+
+ schedule_timeout(timeout);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+
+ /* the thing on the front of the queue needs processing
+ * - we come here with the lock held and timer pointing to the expired entry
+ */
+ immediate:
+ remove_wait_queue(&kafstimod_sleepq,&myself);
+ set_current_state(TASK_RUNNING);
+
+ _debug("@@@ Begin Timeout of %p",timer);
+
+ /* dequeue the timer */
+ list_del_init(&timer->link);
+ spin_unlock(&kafstimod_lock);
+
+ /* call the timeout function */
+ timer->ops->timed_out(timer);
+
+ _debug("@@@ End Timeout");
+ goto loop;
+
+} /* end kafstimod() */
+
+/*****************************************************************************/
+/*
+ * (re-)queue a timer
+ */
+void afs_kafstimod_add_timer(afs_timer_t *timer, unsigned long timeout)
+{
+ struct list_head *_p;
+ afs_timer_t *ptimer;
+
+ _enter("%p,%lu",timer,timeout);
+
+ spin_lock(&kafstimod_lock);
+
+ list_del(&timer->link);
+
+ /* the timer was deferred or reset - put it back in the queue at the right place */
+ timer->timo_jif = jiffies + timeout;
+
+ list_for_each(_p,&kafstimod_list) {
+ ptimer = list_entry(_p,afs_timer_t,link);
+ if (time_before(timer->timo_jif,ptimer->timo_jif))
+ break;
+ }
+
+ list_add_tail(&timer->link,_p); /* insert before stopping point */
+
+ spin_unlock(&kafstimod_lock);
+
+ wake_up(&kafstimod_sleepq);
+
+ _leave("");
+} /* end afs_kafstimod_queue_vlocation() */
+
+/*****************************************************************************/
+/*
+ * dequeue a timer
+ * - returns 0 if the timer was deleted or -ENOENT if it wasn't queued
+ */
+int afs_kafstimod_del_timer(afs_timer_t *timer)
+{
+ int ret = 0;
+
+ _enter("%p",timer);
+
+ spin_lock(&kafstimod_lock);
+
+ if (list_empty(&timer->link))
+ ret = -ENOENT;
+ else
+ list_del_init(&timer->link);
+
+ spin_unlock(&kafstimod_lock);
+
+ wake_up(&kafstimod_sleepq);
+
+ _leave(" = %d",ret);
+ return ret;
+} /* end afs_kafstimod_del_timer() */
diff --git a/fs/afs/kafstimod.h b/fs/afs/kafstimod.h
new file mode 100644
index 000000000000..342d81d6025b
--- /dev/null
+++ b/fs/afs/kafstimod.h
@@ -0,0 +1,45 @@
+/* kafstimod.h: AFS timeout daemon
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_KAFSTIMOD_H
+#define _LINUX_AFS_KAFSTIMOD_H
+
+#include "types.h"
+
+struct afs_timer_ops {
+ /* called when the front of the timer queue has timed out */
+ void (*timed_out)(struct afs_timer *timer);
+};
+
+/*****************************************************************************/
+/*
+ * AFS timer/timeout record
+ */
+struct afs_timer
+{
+ struct list_head link; /* link in timer queue */
+ unsigned long timo_jif; /* timeout time */
+ const struct afs_timer_ops *ops; /* timeout expiry function */
+};
+
+static inline void afs_timer_init(afs_timer_t *timer, const struct afs_timer_ops *ops)
+{
+ INIT_LIST_HEAD(&timer->link);
+ timer->ops = ops;
+}
+
+extern int afs_kafstimod_start(void);
+extern void afs_kafstimod_stop(void);
+
+extern void afs_kafstimod_add_timer(afs_timer_t *timer, unsigned long timeout);
+extern int afs_kafstimod_del_timer(afs_timer_t *timer);
+
+#endif /* _LINUX_AFS_KAFSTIMOD_H */
diff --git a/fs/afs/main.c b/fs/afs/main.c
new file mode 100644
index 000000000000..dc20f670a021
--- /dev/null
+++ b/fs/afs/main.c
@@ -0,0 +1,193 @@
+/* main.c: AFS client file system
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/call.h>
+#include <rxrpc/peer.h>
+#include "cell.h"
+#include "server.h"
+#include "fsclient.h"
+#include "cmservice.h"
+#include "kafstimod.h"
+#include "kafsasyncd.h"
+#include "internal.h"
+
+struct rxrpc_transport *afs_transport;
+
+static int afs_init(void);
+static void afs_exit(void);
+static int afs_adding_peer(struct rxrpc_peer *peer);
+static void afs_discarding_peer(struct rxrpc_peer *peer);
+
+module_init(afs_init);
+module_exit(afs_exit);
+
+MODULE_DESCRIPTION("AFS Client File System");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+static struct rxrpc_peer_ops afs_peer_ops = {
+ .adding = afs_adding_peer,
+ .discarding = afs_discarding_peer,
+};
+
+struct list_head afs_cb_hash_tbl[AFS_CB_HASH_COUNT];
+spinlock_t afs_cb_hash_lock = SPIN_LOCK_UNLOCKED;
+
+/*****************************************************************************/
+/*
+ * initialise the AFS client FS module
+ */
+static int afs_init(void)
+{
+ int loop, ret;
+
+ printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n");
+
+ /* initialise the callback hash table */
+ spin_lock_init(&afs_cb_hash_lock);
+ for (loop=AFS_CB_HASH_COUNT-1; loop>=0; loop--)
+ INIT_LIST_HEAD(&afs_cb_hash_tbl[loop]);
+
+ /* register the /proc stuff */
+ ret = afs_proc_init();
+ if (ret<0)
+ return ret;
+
+ /* initialise the cell DB */
+ ret = afs_cell_init();
+ if (ret<0)
+ goto error;
+
+ /* start the timeout daemon */
+ ret = afs_kafstimod_start();
+ if (ret<0)
+ goto error;
+
+ /* start the async operation daemon */
+ ret = afs_kafsasyncd_start();
+ if (ret<0)
+ goto error_kafstimod;
+
+ /* create the RxRPC transport */
+ ret = rxrpc_create_transport(7001,&afs_transport);
+ if (ret<0)
+ goto error_kafsasyncd;
+
+ afs_transport->peer_ops = &afs_peer_ops;
+
+ /* register the filesystems */
+ ret = afs_fs_init();
+ if (ret<0)
+ goto error_transport;
+
+ return ret;
+
+ error_transport:
+ rxrpc_put_transport(afs_transport);
+ error_kafsasyncd:
+ afs_kafsasyncd_stop();
+ error_kafstimod:
+ afs_kafstimod_stop();
+ error:
+ afs_cell_purge();
+ afs_proc_cleanup();
+ printk(KERN_ERR "kAFS: failed to register: %d\n",ret);
+ return ret;
+} /* end afs_init() */
+
+/*****************************************************************************/
+/*
+ * clean up on module removal
+ */
+static void afs_exit(void)
+{
+ printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n");
+
+ afs_fs_exit();
+ rxrpc_put_transport(afs_transport);
+ afs_kafstimod_stop();
+ afs_kafsasyncd_stop();
+ afs_cell_purge();
+ afs_proc_cleanup();
+
+} /* end afs_exit() */
+
+/*****************************************************************************/
+/*
+ * notification that new peer record is being added
+ * - called from krxsecd
+ * - return an error to induce an abort
+ * - mustn't sleep (caller holds an rwlock)
+ */
+static int afs_adding_peer(struct rxrpc_peer *peer)
+{
+ afs_server_t *server;
+ int ret;
+
+ _debug("kAFS: Adding new peer %08x\n",ntohl(peer->addr.s_addr));
+
+ /* determine which server the peer resides in (if any) */
+ ret = afs_server_find_by_peer(peer,&server);
+ if (ret<0)
+ return ret; /* none that we recognise, so abort */
+
+ _debug("Server %p{u=%d}\n",server,atomic_read(&server->usage));
+
+ _debug("Cell %p{u=%d}\n",server->cell,atomic_read(&server->cell->usage));
+
+ /* cross-point the structs under a global lock */
+ spin_lock(&afs_server_peer_lock);
+ peer->user = server;
+ server->peer = peer;
+ spin_unlock(&afs_server_peer_lock);
+
+ afs_put_server(server);
+
+ return 0;
+} /* end afs_adding_peer() */
+
+/*****************************************************************************/
+/*
+ * notification that a peer record is being discarded
+ * - called from krxiod or krxsecd
+ */
+static void afs_discarding_peer(struct rxrpc_peer *peer)
+{
+ afs_server_t *server;
+
+ _enter("%p",peer);
+
+ _debug("Discarding peer %08x (rtt=%lu.%lumS)\n",
+ ntohl(peer->addr.s_addr),
+ peer->rtt/1000,
+ peer->rtt%1000);
+
+ /* uncross-point the structs under a global lock */
+ spin_lock(&afs_server_peer_lock);
+ server = peer->user;
+ if (server) {
+ peer->user = NULL;
+ server->peer = NULL;
+
+ //_debug("Server %p{u=%d}\n",server,atomic_read(&server->usage));
+ //_debug("Cell %p{u=%d}\n",server->cell,atomic_read(&server->cell->usage));
+ }
+ spin_unlock(&afs_server_peer_lock);
+
+ _leave("");
+
+} /* end afs_discarding_peer() */
diff --git a/fs/afs/misc.c b/fs/afs/misc.c
new file mode 100644
index 000000000000..e4fce66d76e0
--- /dev/null
+++ b/fs/afs/misc.c
@@ -0,0 +1,39 @@
+/* misc.c: miscellaneous bits
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include "errors.h"
+#include "internal.h"
+
+/*****************************************************************************/
+/*
+ * convert an AFS abort code to a Linux error number
+ */
+int afs_abort_to_error(int abortcode)
+{
+ switch (abortcode) {
+ case VSALVAGE: return -EIO;
+ case VNOVNODE: return -ENOENT;
+ case VNOVOL: return -ENXIO;
+ case VVOLEXISTS: return -EEXIST;
+ case VNOSERVICE: return -EIO;
+ case VOFFLINE: return -ENOENT;
+ case VONLINE: return -EEXIST;
+ case VDISKFULL: return -ENOSPC;
+ case VOVERQUOTA: return -EDQUOT;
+ case VBUSY: return -EBUSY;
+ case VMOVED: return -ENXIO;
+ default: return -EIO;
+ }
+
+} /* end afs_abort_to_error() */
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
new file mode 100644
index 000000000000..4e88180f1c09
--- /dev/null
+++ b/fs/afs/mntpt.c
@@ -0,0 +1,112 @@
+/* mntpt.c: mountpoint management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "volume.h"
+#include "vnode.h"
+#include "internal.h"
+
+
+static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry);
+static int afs_mntpt_open(struct inode *inode, struct file *file);
+
+struct file_operations afs_mntpt_file_operations = {
+ .open = afs_mntpt_open,
+};
+
+struct inode_operations afs_mntpt_inode_operations = {
+ .lookup = afs_mntpt_lookup,
+ .readlink = page_readlink,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ .getattr = afs_inode_getattr,
+#else
+ .revalidate = afs_inode_revalidate,
+#endif
+};
+
+/*****************************************************************************/
+/*
+ * check a symbolic link to see whether it actually encodes a mountpoint
+ * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately
+ */
+int afs_mntpt_check_symlink(afs_vnode_t *vnode)
+{
+ struct page *page;
+ size_t size;
+ char *buf;
+ int ret;
+
+ _enter("{%u,%u}",vnode->fid.vnode,vnode->fid.unique);
+
+ /* read the contents of the symlink into the pagecache */
+ page = read_cache_page(AFS_VNODE_TO_I(vnode)->i_mapping,0,
+ (filler_t*)AFS_VNODE_TO_I(vnode)->i_mapping->a_ops->readpage,NULL);
+ if (IS_ERR(page)) {
+ ret = PTR_ERR(page);
+ goto out;
+ }
+
+ ret = -EIO;
+ wait_on_page_locked(page);
+ buf = kmap(page);
+ if (!PageUptodate(page))
+ goto out_free;
+ if (PageError(page))
+ goto out_free;
+
+ /* examine the symlink's contents */
+ size = vnode->status.size;
+ _debug("symlink to %*.*s",size,size,buf);
+
+ if (size>2 &&
+ (buf[0]=='%' || buf[0]=='#') &&
+ buf[size-1]=='.'
+ ) {
+ _debug("symlink is a mountpoint");
+ spin_lock(&vnode->lock);
+ vnode->flags |= AFS_VNODE_MOUNTPOINT;
+ spin_unlock(&vnode->lock);
+ }
+
+ ret = 0;
+
+ out_free:
+ kunmap(page);
+ page_cache_release(page);
+ out:
+ _leave(" = %d",ret);
+ return ret;
+
+} /* end afs_mntpt_check_symlink() */
+
+/*****************************************************************************/
+/*
+ * no valid lookup procedure on this sort of dir
+ */
+static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry)
+{
+ return ERR_PTR(-EREMOTE);
+} /* end afs_mntpt_lookup() */
+
+/*****************************************************************************/
+/*
+ * no valid open procedure on this sort of dir
+ */
+static int afs_mntpt_open(struct inode *inode, struct file *file)
+{
+ return -EREMOTE;
+} /* end afs_mntpt_open() */
diff --git a/fs/afs/mount.h b/fs/afs/mount.h
new file mode 100644
index 000000000000..fbdd77878546
--- /dev/null
+++ b/fs/afs/mount.h
@@ -0,0 +1,23 @@
+/* mount.h: mount parameters
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_MOUNT_H
+#define _LINUX_AFS_MOUNT_H
+
+struct afs_mountdata {
+ const char *volume; /* name of volume */
+ const char *cell; /* name of cell containing volume */
+ const char *cache; /* name of cache block device */
+ size_t nservers; /* number of server addresses listed */
+ u_int32_t servers[10]; /* IP addresses of servers in this cell */
+};
+
+#endif /* _LINUX_AFS_MOUNT_H */
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
new file mode 100644
index 000000000000..83fda6decf57
--- /dev/null
+++ b/fs/afs/proc.c
@@ -0,0 +1,739 @@
+/* proc.c: /proc interface for AFS
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include "cell.h"
+#include "volume.h"
+#include <asm/uaccess.h>
+#include "internal.h"
+
+static struct proc_dir_entry *proc_afs;
+
+
+static int afs_proc_cells_open(struct inode *inode, struct file *file);
+static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
+static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos);
+static void afs_proc_cells_stop(struct seq_file *p, void *v);
+static int afs_proc_cells_show(struct seq_file *m, void *v);
+static ssize_t afs_proc_cells_write(struct file *file, const char *buf, size_t size, loff_t *_pos);
+
+static struct seq_operations afs_proc_cells_ops = {
+ .start = afs_proc_cells_start,
+ .next = afs_proc_cells_next,
+ .stop = afs_proc_cells_stop,
+ .show = afs_proc_cells_show,
+};
+
+static struct file_operations afs_proc_cells_fops = {
+ .open = afs_proc_cells_open,
+ .read = seq_read,
+ .write = afs_proc_cells_write,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file);
+static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file);
+static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
+static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, loff_t *pos);
+static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v);
+static int afs_proc_cell_volumes_show(struct seq_file *m, void *v);
+
+static struct seq_operations afs_proc_cell_volumes_ops = {
+ .start = afs_proc_cell_volumes_start,
+ .next = afs_proc_cell_volumes_next,
+ .stop = afs_proc_cell_volumes_stop,
+ .show = afs_proc_cell_volumes_show,
+};
+
+static struct file_operations afs_proc_cell_volumes_fops = {
+ .open = afs_proc_cell_volumes_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = afs_proc_cell_volumes_release,
+};
+
+static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file);
+static int afs_proc_cell_vlservers_release(struct inode *inode, struct file *file);
+static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);
+static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, loff_t *pos);
+static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v);
+static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v);
+
+static struct seq_operations afs_proc_cell_vlservers_ops = {
+ .start = afs_proc_cell_vlservers_start,
+ .next = afs_proc_cell_vlservers_next,
+ .stop = afs_proc_cell_vlservers_stop,
+ .show = afs_proc_cell_vlservers_show,
+};
+
+static struct file_operations afs_proc_cell_vlservers_fops = {
+ .open = afs_proc_cell_vlservers_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = afs_proc_cell_vlservers_release,
+};
+
+static int afs_proc_cell_servers_open(struct inode *inode, struct file *file);
+static int afs_proc_cell_servers_release(struct inode *inode, struct file *file);
+static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos);
+static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, loff_t *pos);
+static void afs_proc_cell_servers_stop(struct seq_file *p, void *v);
+static int afs_proc_cell_servers_show(struct seq_file *m, void *v);
+
+static struct seq_operations afs_proc_cell_servers_ops = {
+ .start = afs_proc_cell_servers_start,
+ .next = afs_proc_cell_servers_next,
+ .stop = afs_proc_cell_servers_stop,
+ .show = afs_proc_cell_servers_show,
+};
+
+static struct file_operations afs_proc_cell_servers_fops = {
+ .open = afs_proc_cell_servers_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = afs_proc_cell_servers_release,
+};
+
+/*****************************************************************************/
+/*
+ * initialise the /proc/fs/afs/ directory
+ */
+int afs_proc_init(void)
+{
+ struct proc_dir_entry *p;
+
+ _enter("");
+
+ proc_afs = proc_mkdir("fs/afs",NULL);
+ if (!proc_afs)
+ goto error;
+ proc_afs->owner = THIS_MODULE;
+
+ p = create_proc_entry("cells",0,proc_afs);
+ if (!p)
+ goto error_proc;
+ p->proc_fops = &afs_proc_cells_fops;
+ p->owner = THIS_MODULE;
+
+ _leave(" = 0");
+ return 0;
+
+#if 0
+ error_cells:
+ remove_proc_entry("cells",proc_afs);
+#endif
+ error_proc:
+ remove_proc_entry("fs/afs",NULL);
+ error:
+ _leave(" = -ENOMEM");
+ return -ENOMEM;
+
+} /* end afs_proc_init() */
+
+/*****************************************************************************/
+/*
+ * clean up the /proc/fs/afs/ directory
+ */
+void afs_proc_cleanup(void)
+{
+ remove_proc_entry("cells",proc_afs);
+
+ remove_proc_entry("fs/afs",NULL);
+
+} /* end afs_proc_cleanup() */
+
+/*****************************************************************************/
+/*
+ * open "/proc/fs/afs/cells" which provides a summary of extant cells
+ */
+static int afs_proc_cells_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *m;
+ int ret;
+
+ ret = seq_open(file,&afs_proc_cells_ops);
+ if (ret<0)
+ return ret;
+
+ m = file->private_data;
+ m->private = PDE(inode)->data;
+
+ return 0;
+} /* end afs_proc_cells_open() */
+
+/*****************************************************************************/
+/*
+ * set up the iterator to start reading from the cells list and return the first item
+ */
+static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
+{
+ struct list_head *_p;
+ loff_t pos = *_pos;
+
+ /* lock the list against modification */
+ down_read(&afs_proc_cells_sem);
+
+ /* allow for the header line */
+ if (!pos)
+ return (void *)1;
+ pos--;
+
+ /* find the n'th element in the list */
+ list_for_each(_p,&afs_proc_cells)
+ if (!pos--)
+ break;
+
+ return _p!=&afs_proc_cells ? _p : NULL;
+} /* end afs_proc_cells_start() */
+
+/*****************************************************************************/
+/*
+ * move to next cell in cells list
+ */
+static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos)
+{
+ struct list_head *_p;
+
+ (*pos)++;
+
+ _p = v;
+ _p = v==(void*)1 ? afs_proc_cells.next : _p->next;
+
+ return _p!=&afs_proc_cells ? _p : NULL;
+} /* end afs_proc_cells_next() */
+
+/*****************************************************************************/
+/*
+ * clean up after reading from the cells list
+ */
+static void afs_proc_cells_stop(struct seq_file *p, void *v)
+{
+ up_read(&afs_proc_cells_sem);
+
+} /* end afs_proc_cells_stop() */
+
+/*****************************************************************************/
+/*
+ * display a header line followed by a load of cell lines
+ */
+static int afs_proc_cells_show(struct seq_file *m, void *v)
+{
+ afs_cell_t *cell = list_entry(v,afs_cell_t,proc_link);
+
+ /* display header on line 1 */
+ if (v == (void *)1) {
+ seq_puts(m, "USE NAME\n");
+ return 0;
+ }
+
+ /* display one cell per line on subsequent lines */
+ seq_printf(m,"%3d %s\n",atomic_read(&cell->usage),cell->name);
+
+ return 0;
+} /* end afs_proc_cells_show() */
+
+/*****************************************************************************/
+/*
+ * handle writes to /proc/fs/afs/cells
+ * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]*
+ */
+static ssize_t afs_proc_cells_write(struct file *file, const char *buf, size_t size, loff_t *_pos)
+{
+ char *kbuf, *name, *args;
+ int ret;
+
+ /* start by dragging the command into memory */
+ if (size<=1 || size>=PAGE_SIZE)
+ return -EINVAL;
+
+ kbuf = kmalloc(size+1,GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+
+ ret = -EFAULT;
+ if (copy_from_user(kbuf,buf,size)!=0)
+ goto done;
+ kbuf[size] = 0;
+
+ /* trim to first NL */
+ name = memchr(kbuf,'\n',size);
+ if (name) *name = 0;
+
+ /* split into command, name and argslist */
+ name = strchr(kbuf,' ');
+ if (!name) goto inval;
+ do { *name++ = 0; } while(*name==' ');
+ if (!*name) goto inval;
+
+ args = strchr(name,' ');
+ if (!args) goto inval;
+ do { *args++ = 0; } while(*args==' ');
+ if (!*args) goto inval;
+
+ /* determine command to perform */
+ _debug("cmd=%s name=%s args=%s",kbuf,name,args);
+
+ if (strcmp(kbuf,"add")==0) {
+ afs_cell_t *cell;
+ ret = afs_cell_create(name,args,&cell);
+ if (ret<0)
+ goto done;
+
+ printk("kAFS: Added new cell '%s'\n",name);
+ }
+ else {
+ goto inval;
+ }
+
+ ret = size;
+
+ done:
+ kfree(kbuf);
+ _leave(" = %d",ret);
+ return ret;
+
+ inval:
+ ret = -EINVAL;
+ printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
+ goto done;
+} /* end afs_proc_cells_write() */
+
+/*****************************************************************************/
+/*
+ * initialise /proc/fs/afs/<cell>/
+ */
+int afs_proc_cell_setup(afs_cell_t *cell)
+{
+ struct proc_dir_entry *p;
+
+ _enter("%p{%s}",cell,cell->name);
+
+ cell->proc_dir = proc_mkdir(cell->name,proc_afs);
+ if (!cell->proc_dir)
+ return -ENOMEM;
+
+ p = create_proc_entry("servers",0,cell->proc_dir);
+ if (!p)
+ goto error_proc;
+ p->proc_fops = &afs_proc_cell_servers_fops;
+ p->owner = THIS_MODULE;
+ p->data = cell;
+
+ p = create_proc_entry("vlservers",0,cell->proc_dir);
+ if (!p)
+ goto error_servers;
+ p->proc_fops = &afs_proc_cell_vlservers_fops;
+ p->owner = THIS_MODULE;
+ p->data = cell;
+
+ p = create_proc_entry("volumes",0,cell->proc_dir);
+ if (!p)
+ goto error_vlservers;
+ p->proc_fops = &afs_proc_cell_volumes_fops;
+ p->owner = THIS_MODULE;
+ p->data = cell;
+
+ _leave(" = 0");
+ return 0;
+
+ error_vlservers:
+ remove_proc_entry("vlservers",cell->proc_dir);
+ error_servers:
+ remove_proc_entry("servers",cell->proc_dir);
+ error_proc:
+ remove_proc_entry(cell->name,proc_afs);
+ _leave(" = -ENOMEM");
+ return -ENOMEM;
+} /* end afs_proc_cell_setup() */
+
+/*****************************************************************************/
+/*
+ * remove /proc/fs/afs/<cell>/
+ */
+void afs_proc_cell_remove(afs_cell_t *cell)
+{
+ _enter("");
+
+ remove_proc_entry("volumes",cell->proc_dir);
+ remove_proc_entry("vlservers",cell->proc_dir);
+ remove_proc_entry("servers",cell->proc_dir);
+ remove_proc_entry(cell->name,proc_afs);
+
+ _leave("");
+} /* end afs_proc_cell_remove() */
+
+/*****************************************************************************/
+/*
+ * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
+ */
+static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *m;
+ afs_cell_t *cell;
+ int ret;
+
+ cell = afs_get_cell_maybe((afs_cell_t**)&PDE(inode)->data);
+ if (!cell)
+ return -ENOENT;
+
+ ret = seq_open(file,&afs_proc_cell_volumes_ops);
+ if (ret<0)
+ return ret;
+
+ m = file->private_data;
+ m->private = cell;
+
+ return 0;
+} /* end afs_proc_cell_volumes_open() */
+
+/*****************************************************************************/
+/*
+ * close the file and release the ref to the cell
+ */
+static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file)
+{
+ afs_cell_t *cell = PDE(inode)->data;
+ int ret;
+
+ ret = seq_release(inode,file);
+
+ afs_put_cell(cell);
+
+} /* end afs_proc_cell_volumes_release() */
+
+/*****************************************************************************/
+/*
+ * set up the iterator to start reading from the cells list and return the first item
+ */
+static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
+{
+ struct list_head *_p;
+ afs_cell_t *cell = m->private;
+ loff_t pos = *_pos;
+
+ _enter("cell=%p pos=%Ld",cell,*_pos);
+
+ /* lock the list against modification */
+ down_read(&cell->vl_sem);
+
+ /* allow for the header line */
+ if (!pos)
+ return (void *)1;
+ pos--;
+
+ /* find the n'th element in the list */
+ list_for_each(_p,&cell->vl_list)
+ if (!pos--)
+ break;
+
+ return _p!=&cell->vl_list ? _p : NULL;
+} /* end afs_proc_cell_volumes_start() */
+
+/*****************************************************************************/
+/*
+ * move to next cell in cells list
+ */
+static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, loff_t *_pos)
+{
+ struct list_head *_p;
+ afs_cell_t *cell = p->private;
+
+ _enter("cell=%p pos=%Ld",cell,*_pos);
+
+ (*_pos)++;
+
+ _p = v;
+ _p = v==(void*)1 ? cell->vl_list.next : _p->next;
+
+ return _p!=&cell->vl_list ? _p : NULL;
+} /* end afs_proc_cell_volumes_next() */
+
+/*****************************************************************************/
+/*
+ * clean up after reading from the cells list
+ */
+static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
+{
+ afs_cell_t *cell = p->private;
+
+ up_read(&cell->vl_sem);
+
+} /* end afs_proc_cell_volumes_stop() */
+
+/*****************************************************************************/
+/*
+ * display a header line followed by a load of volume lines
+ */
+static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
+{
+ afs_vlocation_t *vlocation = list_entry(v,afs_vlocation_t,link);
+
+ /* display header on line 1 */
+ if (v == (void *)1) {
+ seq_puts(m, "USE VLID[0] VLID[1] VLID[2] NAME\n");
+ return 0;
+ }
+
+ /* display one cell per line on subsequent lines */
+ seq_printf(m,"%3d %08x %08x %08x %s\n",
+ atomic_read(&vlocation->usage),
+ vlocation->vldb.vid[0],
+ vlocation->vldb.vid[1],
+ vlocation->vldb.vid[2],
+ vlocation->vldb.name
+ );
+
+ return 0;
+} /* end afs_proc_cell_volumes_show() */
+
+/*****************************************************************************/
+/*
+ * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume location server
+ */
+static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *m;
+ afs_cell_t *cell;
+ int ret;
+
+ cell = afs_get_cell_maybe((afs_cell_t**)&PDE(inode)->data);
+ if (!cell)
+ return -ENOENT;
+
+ ret = seq_open(file,&afs_proc_cell_vlservers_ops);
+ if (ret<0)
+ return ret;
+
+ m = file->private_data;
+ m->private = cell;
+
+ return 0;
+} /* end afs_proc_cell_vlservers_open() */
+
+/*****************************************************************************/
+/*
+ * close the file and release the ref to the cell
+ */
+static int afs_proc_cell_vlservers_release(struct inode *inode, struct file *file)
+{
+ afs_cell_t *cell = PDE(inode)->data;
+ int ret;
+
+ ret = seq_release(inode,file);
+
+ afs_put_cell(cell);
+
+} /* end afs_proc_cell_vlservers_release() */
+
+/*****************************************************************************/
+/*
+ * set up the iterator to start reading from the cells list and return the first item
+ */
+static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
+{
+ afs_cell_t *cell = m->private;
+ loff_t pos = *_pos;
+
+ _enter("cell=%p pos=%Ld",cell,*_pos);
+
+ /* lock the list against modification */
+ down_read(&cell->vl_sem);
+
+ /* allow for the header line */
+ if (!pos)
+ return (void *)1;
+ pos--;
+
+ if (pos>=cell->vl_naddrs)
+ return NULL;
+
+ return &cell->vl_addrs[pos];
+} /* end afs_proc_cell_vlservers_start() */
+
+/*****************************************************************************/
+/*
+ * move to next cell in cells list
+ */
+static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, loff_t *_pos)
+{
+ afs_cell_t *cell = p->private;
+ loff_t pos;
+
+ _enter("cell=%p{nad=%u} pos=%Ld",cell,cell->vl_naddrs,*_pos);
+
+ pos = *_pos;
+ (*_pos)++;
+ if (pos>=cell->vl_naddrs)
+ return NULL;
+
+ return &cell->vl_addrs[pos];
+} /* end afs_proc_cell_vlservers_next() */
+
+/*****************************************************************************/
+/*
+ * clean up after reading from the cells list
+ */
+static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
+{
+ afs_cell_t *cell = p->private;
+
+ up_read(&cell->vl_sem);
+
+} /* end afs_proc_cell_vlservers_stop() */
+
+/*****************************************************************************/
+/*
+ * display a header line followed by a load of volume lines
+ */
+static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
+{
+ struct in_addr *addr = v;
+
+ /* display header on line 1 */
+ if (v == (struct in_addr *)1) {
+ seq_puts(m,"ADDRESS\n");
+ return 0;
+ }
+
+ /* display one cell per line on subsequent lines */
+ seq_printf(m,"%u.%u.%u.%u\n",NIPQUAD(addr->s_addr));
+
+ return 0;
+} /* end afs_proc_cell_vlservers_show() */
+
+/*****************************************************************************/
+/*
+ * open "/proc/fs/afs/<cell>/servers" which provides a summary of active servers
+ */
+static int afs_proc_cell_servers_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *m;
+ afs_cell_t *cell;
+ int ret;
+
+ cell = afs_get_cell_maybe((afs_cell_t**)&PDE(inode)->data);
+ if (!cell)
+ return -ENOENT;
+
+ ret = seq_open(file,&afs_proc_cell_servers_ops);
+ if (ret<0)
+ return ret;
+
+ m = file->private_data;
+ m->private = cell;
+
+ return 0;
+} /* end afs_proc_cell_servers_open() */
+
+/*****************************************************************************/
+/*
+ * close the file and release the ref to the cell
+ */
+static int afs_proc_cell_servers_release(struct inode *inode, struct file *file)
+{
+ afs_cell_t *cell = PDE(inode)->data;
+ int ret;
+
+ ret = seq_release(inode,file);
+
+ afs_put_cell(cell);
+
+} /* end afs_proc_cell_servers_release() */
+
+/*****************************************************************************/
+/*
+ * set up the iterator to start reading from the cells list and return the first item
+ */
+static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
+{
+ struct list_head *_p;
+ afs_cell_t *cell = m->private;
+ loff_t pos = *_pos;
+
+ _enter("cell=%p pos=%Ld",cell,*_pos);
+
+ /* lock the list against modification */
+ read_lock(&cell->sv_lock);
+
+ /* allow for the header line */
+ if (!pos)
+ return (void *)1;
+ pos--;
+
+ /* find the n'th element in the list */
+ list_for_each(_p,&cell->sv_list)
+ if (!pos--)
+ break;
+
+ return _p!=&cell->sv_list ? _p : NULL;
+} /* end afs_proc_cell_servers_start() */
+
+/*****************************************************************************/
+/*
+ * move to next cell in cells list
+ */
+static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, loff_t *_pos)
+{
+ struct list_head *_p;
+ afs_cell_t *cell = p->private;
+
+ _enter("cell=%p pos=%Ld",cell,*_pos);
+
+ (*_pos)++;
+
+ _p = v;
+ _p = v==(void*)1 ? cell->sv_list.next : _p->next;
+
+ return _p!=&cell->sv_list ? _p : NULL;
+} /* end afs_proc_cell_servers_next() */
+
+/*****************************************************************************/
+/*
+ * clean up after reading from the cells list
+ */
+static void afs_proc_cell_servers_stop(struct seq_file *p, void *v)
+{
+ afs_cell_t *cell = p->private;
+
+ read_unlock(&cell->sv_lock);
+
+} /* end afs_proc_cell_servers_stop() */
+
+/*****************************************************************************/
+/*
+ * display a header line followed by a load of volume lines
+ */
+static int afs_proc_cell_servers_show(struct seq_file *m, void *v)
+{
+ afs_server_t *server = list_entry(v,afs_server_t,link);
+ char ipaddr[20];
+
+ /* display header on line 1 */
+ if (v == (void *)1) {
+ seq_puts(m, "USE ADDR STATE\n");
+ return 0;
+ }
+
+ /* display one cell per line on subsequent lines */
+ sprintf(ipaddr,"%u.%u.%u.%u",NIPQUAD(server->addr));
+ seq_printf(m,"%3d %-15.15s %5d\n",
+ atomic_read(&server->usage),
+ ipaddr,
+ server->fs_state
+ );
+
+ return 0;
+} /* end afs_proc_cell_servers_show() */
diff --git a/fs/afs/server.c b/fs/afs/server.c
new file mode 100644
index 000000000000..b249d7cc3261
--- /dev/null
+++ b/fs/afs/server.c
@@ -0,0 +1,489 @@
+/* server.c: AFS server record management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <rxrpc/peer.h>
+#include <rxrpc/connection.h>
+#include "volume.h"
+#include "cell.h"
+#include "server.h"
+#include "transport.h"
+#include "vlclient.h"
+#include "kafstimod.h"
+#include "internal.h"
+
+spinlock_t afs_server_peer_lock = SPIN_LOCK_UNLOCKED;
+
+#define FS_SERVICE_ID 1 /* AFS Volume Location Service ID */
+#define VL_SERVICE_ID 52 /* AFS Volume Location Service ID */
+
+static void __afs_server_timeout(afs_timer_t *timer)
+{
+ afs_server_t *server = list_entry(timer,afs_server_t,timeout);
+
+ _debug("SERVER TIMEOUT [%p{u=%d}]",server,atomic_read(&server->usage));
+
+ afs_server_do_timeout(server);
+}
+
+static const struct afs_timer_ops afs_server_timer_ops = {
+ .timed_out = __afs_server_timeout,
+};
+
+/*****************************************************************************/
+/*
+ * lookup a server record in a cell
+ * - TODO: search the cell's server list
+ */
+int afs_server_lookup(afs_cell_t *cell, const struct in_addr *addr, afs_server_t **_server)
+{
+ struct list_head *_p;
+ afs_server_t *server, *active, *zombie;
+ int loop;
+
+ _enter("%p,%08x,",cell,ntohl(addr->s_addr));
+
+ /* allocate and initialise a server record */
+ server = kmalloc(sizeof(afs_server_t),GFP_KERNEL);
+ if (!server) {
+ _leave(" = -ENOMEM");
+ return -ENOMEM;
+ }
+
+ memset(server,0,sizeof(afs_server_t));
+ atomic_set(&server->usage,1);
+
+ INIT_LIST_HEAD(&server->link);
+ init_rwsem(&server->sem);
+ INIT_LIST_HEAD(&server->fs_callq);
+ spin_lock_init(&server->fs_lock);
+ INIT_LIST_HEAD(&server->cb_promises);
+ spin_lock_init(&server->cb_lock);
+
+ for (loop=0; loop<AFS_SERVER_CONN_LIST_SIZE; loop++)
+ server->fs_conn_cnt[loop] = 4;
+
+ memcpy(&server->addr,addr,sizeof(struct in_addr));
+ server->addr.s_addr = addr->s_addr;
+
+ afs_timer_init(&server->timeout,&afs_server_timer_ops);
+
+ /* add to the cell */
+ write_lock(&cell->sv_lock);
+
+ /* check the active list */
+ list_for_each(_p,&cell->sv_list) {
+ active = list_entry(_p,afs_server_t,link);
+
+ if (active->addr.s_addr==addr->s_addr)
+ goto use_active_server;
+ }
+
+ /* check the inactive list */
+ spin_lock(&cell->sv_gylock);
+ list_for_each(_p,&cell->sv_graveyard) {
+ zombie = list_entry(_p,afs_server_t,link);
+
+ if (zombie->addr.s_addr==addr->s_addr)
+ goto resurrect_server;
+ }
+ spin_unlock(&cell->sv_gylock);
+
+ afs_get_cell(cell);
+ server->cell = cell;
+ list_add_tail(&server->link,&cell->sv_list);
+
+ write_unlock(&cell->sv_lock);
+
+ *_server = server;
+ _leave(" = 0 (%p)",server);
+ return 0;
+
+ /* found a matching active server */
+ use_active_server:
+ _debug("active server");
+ afs_get_server(active);
+ write_unlock(&cell->sv_lock);
+
+ kfree(server);
+
+ *_server = active;
+ _leave(" = 0 (%p)",active);
+ return 0;
+
+ /* found a matching server in the graveyard, so resurrect it and dispose of the new rec */
+ resurrect_server:
+ _debug("resurrecting server");
+
+ list_del(&zombie->link);
+ list_add_tail(&zombie->link,&cell->sv_list);
+ afs_get_server(zombie);
+ afs_kafstimod_del_timer(&zombie->timeout);
+ spin_unlock(&cell->sv_gylock);
+ write_unlock(&cell->sv_lock);
+
+ kfree(server);
+
+ *_server = zombie;
+ _leave(" = 0 (%p)",zombie);
+ return 0;
+
+} /* end afs_server_lookup() */
+
+/*****************************************************************************/
+/*
+ * destroy a server record
+ * - removes from the cell list
+ */
+void afs_put_server(afs_server_t *server)
+{
+ afs_cell_t *cell;
+
+ _enter("%p",server);
+
+ cell = server->cell;
+
+ /* sanity check */
+ if (atomic_read(&server->usage)<=0)
+ BUG();
+
+ /* to prevent a race, the decrement and the dequeue must be effectively atomic */
+ write_lock(&cell->sv_lock);
+
+ if (likely(!atomic_dec_and_test(&server->usage))) {
+ write_unlock(&cell->sv_lock);
+ _leave("");
+ return;
+ }
+
+ spin_lock(&cell->sv_gylock);
+ list_del(&server->link);
+ list_add_tail(&server->link,&cell->sv_graveyard);
+
+ /* time out in 10 secs */
+ afs_kafstimod_add_timer(&server->timeout,10*HZ);
+
+ spin_unlock(&cell->sv_gylock);
+ write_unlock(&cell->sv_lock);
+
+ _leave(" [killed]");
+} /* end afs_put_server() */
+
+/*****************************************************************************/
+/*
+ * timeout server record
+ * - removes from the cell's graveyard if the usage count is zero
+ */
+void afs_server_do_timeout(afs_server_t *server)
+{
+ struct rxrpc_peer *peer;
+ afs_cell_t *cell;
+ int loop;
+
+ _enter("%p",server);
+
+ cell = server->cell;
+
+ if (atomic_read(&server->usage)<0) BUG();
+
+ /* remove from graveyard if still dead */
+ spin_lock(&cell->vl_gylock);
+ if (atomic_read(&server->usage)==0)
+ list_del_init(&server->link);
+ else
+ server = NULL;
+ spin_unlock(&cell->vl_gylock);
+
+ if (!server) {
+ _leave("");
+ return; /* resurrected */
+ }
+
+ /* we can now destroy it properly */
+ afs_put_cell(cell);
+
+ /* uncross-point the structs under a global lock */
+ spin_lock(&afs_server_peer_lock);
+ peer = server->peer;
+ if (peer) {
+ server->peer = NULL;
+ peer->user = NULL;
+ }
+ spin_unlock(&afs_server_peer_lock);
+
+ /* finish cleaning up the server */
+ for (loop=AFS_SERVER_CONN_LIST_SIZE-1; loop>=0; loop--)
+ if (server->fs_conn[loop])
+ rxrpc_put_connection(server->fs_conn[loop]);
+
+ if (server->vlserver)
+ rxrpc_put_connection(server->vlserver);
+
+ kfree(server);
+
+ _leave(" [destroyed]");
+} /* end afs_server_do_timeout() */
+
+/*****************************************************************************/
+/*
+ * get a callslot on a connection to the fileserver on the specified server
+ */
+int afs_server_request_callslot(afs_server_t *server, struct afs_server_callslot *callslot)
+{
+ struct afs_server_callslot *pcallslot;
+ struct rxrpc_connection *conn;
+ int nconn, ret;
+
+ _enter("%p,",server);
+
+ INIT_LIST_HEAD(&callslot->link);
+ callslot->task = current;
+ callslot->conn = NULL;
+ callslot->nconn = -1;
+ callslot->ready = 0;
+
+ ret = 0;
+ conn = NULL;
+
+ /* get hold of a callslot first */
+ spin_lock(&server->fs_lock);
+
+ /* resurrect the server if it's death timeout has expired */
+ if (server->fs_state) {
+ if (time_before(jiffies,server->fs_dead_jif)) {
+ ret = server->fs_state;
+ spin_unlock(&server->fs_lock);
+ _leave(" = %d [still dead]",ret);
+ return ret;
+ }
+
+ server->fs_state = 0;
+ }
+
+ /* try and find a connection that has spare callslots */
+ for (nconn=0; nconn<AFS_SERVER_CONN_LIST_SIZE; nconn++) {
+ if (server->fs_conn_cnt[nconn]>0) {
+ server->fs_conn_cnt[nconn]--;
+ spin_unlock(&server->fs_lock);
+ callslot->nconn = nconn;
+ goto obtained_slot;
+ }
+ }
+
+ /* none were available - wait interruptibly for one to become available */
+ set_current_state(TASK_INTERRUPTIBLE);
+ list_add_tail(&callslot->link,&server->fs_callq);
+ spin_unlock(&server->fs_lock);
+
+ while (!callslot->ready && !signal_pending(current)) {
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+
+ set_current_state(TASK_RUNNING);
+
+ /* even if we were interrupted we may still be queued */
+ if (!callslot->ready) {
+ spin_lock(&server->fs_lock);
+ list_del_init(&callslot->link);
+ spin_unlock(&server->fs_lock);
+ }
+
+ nconn = callslot->nconn;
+
+ /* if interrupted, we must release any slot we also got before returning an error */
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ goto error_release;
+ }
+
+ /* if we were woken up with an error, then pass that error back to the called */
+ if (nconn<0) {
+ _leave(" = %d",callslot->errno);
+ return callslot->errno;
+ }
+
+ /* were we given a connection directly? */
+ if (callslot->conn) {
+ /* yes - use it */
+ _leave(" = 0 (nc=%d)",nconn);
+ return 0;
+ }
+
+ /* got a callslot, but no connection */
+ obtained_slot:
+
+ /* need to get hold of the RxRPC connection */
+ down_write(&server->sem);
+
+ /* quick check to see if there's an outstanding error */
+ ret = server->fs_state;
+ if (ret)
+ goto error_release_upw;
+
+ if (server->fs_conn[nconn]) {
+ /* reuse an existing connection */
+ rxrpc_get_connection(server->fs_conn[nconn]);
+ callslot->conn = server->fs_conn[nconn];
+ }
+ else {
+ /* create a new connection */
+ ret = rxrpc_create_connection(afs_transport,
+ htons(7000),
+ server->addr.s_addr,
+ FS_SERVICE_ID,
+ NULL,
+ &server->fs_conn[nconn]);
+
+ if (ret<0)
+ goto error_release_upw;
+
+ callslot->conn = server->fs_conn[0];
+ rxrpc_get_connection(callslot->conn);
+ }
+
+ up_write(&server->sem);
+
+ _leave(" = 0");
+ return 0;
+
+ /* handle an error occurring */
+ error_release_upw:
+ up_write(&server->sem);
+
+ error_release:
+ /* either release the callslot or pass it along to another deserving task */
+ spin_lock(&server->fs_lock);
+
+ if (nconn<0) {
+ /* no callslot allocated */
+ }
+ else if (list_empty(&server->fs_callq)) {
+ /* no one waiting */
+ server->fs_conn_cnt[nconn]++;
+ spin_unlock(&server->fs_lock);
+ }
+ else {
+ /* someone's waiting - dequeue them and wake them up */
+ pcallslot = list_entry(server->fs_callq.next,struct afs_server_callslot,link);
+ list_del_init(&pcallslot->link);
+
+ pcallslot->errno = server->fs_state;
+ if (!pcallslot->errno) {
+ /* pass them out callslot details */
+ callslot->conn = xchg(&pcallslot->conn,callslot->conn);
+ pcallslot->nconn = nconn;
+ callslot->nconn = nconn = -1;
+ }
+ pcallslot->ready = 1;
+ wake_up_process(pcallslot->task);
+ spin_unlock(&server->fs_lock);
+ }
+
+ if (callslot->conn) rxrpc_put_connection(callslot->conn);
+ callslot->conn = NULL;
+
+ _leave(" = %d",ret);
+ return ret;
+
+} /* end afs_server_request_callslot() */
+
+/*****************************************************************************/
+/*
+ * release a callslot back to the server
+ * - transfers the RxRPC connection to the next pending callslot if possible
+ */
+void afs_server_release_callslot(afs_server_t *server, struct afs_server_callslot *callslot)
+{
+ struct afs_server_callslot *pcallslot;
+
+ _enter("{ad=%08x,cnt=%u},{%d}",
+ ntohl(server->addr.s_addr),
+ server->fs_conn_cnt[callslot->nconn],
+ callslot->nconn);
+
+ if (callslot->nconn<0) BUG();
+
+ spin_lock(&server->fs_lock);
+
+ if (list_empty(&server->fs_callq)) {
+ /* no one waiting */
+ server->fs_conn_cnt[callslot->nconn]++;
+ spin_unlock(&server->fs_lock);
+ }
+ else {
+ /* someone's waiting - dequeue them and wake them up */
+ pcallslot = list_entry(server->fs_callq.next,struct afs_server_callslot,link);
+ list_del_init(&pcallslot->link);
+
+ pcallslot->errno = server->fs_state;
+ if (!pcallslot->errno) {
+ /* pass them out callslot details */
+ callslot->conn = xchg(&pcallslot->conn,callslot->conn);
+ pcallslot->nconn = callslot->nconn;
+ callslot->nconn = -1;
+ }
+
+ pcallslot->ready = 1;
+ wake_up_process(pcallslot->task);
+ spin_unlock(&server->fs_lock);
+ }
+
+ if (callslot->conn) rxrpc_put_connection(callslot->conn);
+
+ _leave("");
+} /* end afs_server_release_callslot() */
+
+/*****************************************************************************/
+/*
+ * get a handle to a connection to the vlserver (volume location) on the specified server
+ */
+int afs_server_get_vlconn(afs_server_t *server, struct rxrpc_connection **_conn)
+{
+ struct rxrpc_connection *conn;
+ int ret;
+
+ _enter("%p,",server);
+
+ ret = 0;
+ conn = NULL;
+ down_read(&server->sem);
+
+ if (server->vlserver) {
+ /* reuse an existing connection */
+ rxrpc_get_connection(server->vlserver);
+ conn = server->vlserver;
+ up_read(&server->sem);
+ }
+ else {
+ /* create a new connection */
+ up_read(&server->sem);
+ down_write(&server->sem);
+ if (!server->vlserver) {
+ ret = rxrpc_create_connection(afs_transport,
+ htons(7003),
+ server->addr.s_addr,
+ VL_SERVICE_ID,
+ NULL,
+ &server->vlserver);
+ }
+ if (ret==0) {
+ rxrpc_get_connection(server->vlserver);
+ conn = server->vlserver;
+ }
+ up_write(&server->sem);
+ }
+
+ *_conn = conn;
+ _leave(" = %d",ret);
+ return ret;
+} /* end afs_server_get_vlconn() */
diff --git a/fs/afs/server.h b/fs/afs/server.h
new file mode 100644
index 000000000000..feddacf2c954
--- /dev/null
+++ b/fs/afs/server.h
@@ -0,0 +1,97 @@
+/* server.h: AFS server record
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_SERVER_H
+#define _LINUX_AFS_SERVER_H
+
+#include "types.h"
+#include "kafstimod.h"
+#include <rxrpc/peer.h>
+#include <linux/rwsem.h>
+
+extern spinlock_t afs_server_peer_lock;
+
+/*****************************************************************************/
+/*
+ * AFS server record
+ */
+struct afs_server
+{
+ atomic_t usage;
+ afs_cell_t *cell; /* cell in which server resides */
+ struct list_head link; /* link in cell's server list */
+ struct rw_semaphore sem; /* access lock */
+ afs_timer_t timeout; /* graveyard timeout */
+ struct in_addr addr; /* server address */
+ struct rxrpc_peer *peer; /* peer record for this server */
+ struct rxrpc_connection *vlserver; /* connection to the volume location service */
+
+ /* file service access */
+#define AFS_SERVER_CONN_LIST_SIZE 2
+ struct rxrpc_connection *fs_conn[AFS_SERVER_CONN_LIST_SIZE]; /* FS connections */
+ unsigned fs_conn_cnt[AFS_SERVER_CONN_LIST_SIZE]; /* per conn call count */
+ struct list_head fs_callq; /* queue of processes waiting to make a call */
+ spinlock_t fs_lock; /* access lock */
+ int fs_state; /* 0 or reason FS currently marked dead (-errno) */
+ unsigned fs_rtt; /* FS round trip time */
+ unsigned long fs_act_jif; /* time at which last activity occurred */
+ unsigned long fs_dead_jif; /* time at which no longer to be considered dead */
+
+ /* callback promise management */
+ struct list_head cb_promises; /* as yet unbroken promises from this server */
+ spinlock_t cb_lock; /* access lock */
+};
+
+extern int afs_server_lookup(afs_cell_t *cell, const struct in_addr *addr, afs_server_t **_server);
+
+#define afs_get_server(S) do { atomic_inc(&(S)->usage); } while(0)
+
+extern void afs_put_server(afs_server_t *server);
+extern void afs_server_do_timeout(afs_server_t *server);
+
+extern int afs_server_find_by_peer(const struct rxrpc_peer *peer, afs_server_t **_server);
+
+extern int afs_server_get_vlconn(afs_server_t *server, struct rxrpc_connection **_conn);
+
+static inline afs_server_t *afs_server_get_from_peer(struct rxrpc_peer *peer)
+{
+ afs_server_t *server;
+
+ spin_lock(&afs_server_peer_lock);
+ server = peer->user;
+ if (server)
+ afs_get_server(server);
+ spin_unlock(&afs_server_peer_lock);
+
+ return server;
+}
+
+/*****************************************************************************/
+/*
+ * AFS server callslot grant record
+ */
+struct afs_server_callslot
+{
+ struct list_head link; /* link in server's list */
+ struct task_struct *task; /* process waiting to make call */
+ struct rxrpc_connection *conn; /* connection to use (or NULL on error) */
+ short nconn; /* connection slot number (-1 on error) */
+ char ready; /* T when ready */
+ int errno; /* error number if nconn==-1 */
+};
+
+extern int afs_server_request_callslot(afs_server_t *server,
+ struct afs_server_callslot *callslot);
+
+extern void afs_server_release_callslot(afs_server_t *server,
+ struct afs_server_callslot *callslot);
+
+#endif /* _LINUX_AFS_SERVER_H */
diff --git a/fs/afs/super.c b/fs/afs/super.c
new file mode 100644
index 000000000000..18056534b504
--- /dev/null
+++ b/fs/afs/super.c
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
+ *
+ * This software may be freely redistributed under the terms of the
+ * GNU General Public License.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors: David Howells <dhowells@redhat.com>
+ * David Woodhouse <dwmw2@cambridge.redhat.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "vnode.h"
+#include "volume.h"
+#include "cell.h"
+#include "cmservice.h"
+#include "fsclient.h"
+#include "super.h"
+#include "internal.h"
+
+#define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */
+
+static inline char *strdup(const char *s)
+{
+ char *ns = kmalloc(strlen(s)+1,GFP_KERNEL);
+ if (ns)
+ strcpy(ns,s);
+ return ns;
+}
+
+static void afs_i_init_once(void *foo, kmem_cache_t *cachep, unsigned long flags);
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static struct super_block *afs_get_sb(struct file_system_type *fs_type,
+ int flags, char *dev_name, void *data);
+#else
+static struct super_block *afs_read_super(struct super_block *sb, void *data, int);
+#endif
+
+static struct inode *afs_alloc_inode(struct super_block *sb);
+
+static void afs_put_super(struct super_block *sb);
+
+static void afs_destroy_inode(struct inode *inode);
+
+static struct file_system_type afs_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "afs",
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ .get_sb = afs_get_sb,
+ .kill_sb = kill_anon_super,
+#else
+ .read_super = afs_read_super,
+#endif
+};
+
+static struct super_operations afs_super_ops = {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ .statfs = simple_statfs,
+ .alloc_inode = afs_alloc_inode,
+ .drop_inode = generic_delete_inode,
+ .destroy_inode = afs_destroy_inode,
+#else
+ .read_inode2 = afs_read_inode2,
+#endif
+ .clear_inode = afs_clear_inode,
+ .put_super = afs_put_super,
+};
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static kmem_cache_t *afs_inode_cachep;
+#endif
+
+/*****************************************************************************/
+/*
+ * initialise the filesystem
+ */
+int __init afs_fs_init(void)
+{
+ int ret;
+
+ kenter("");
+
+ /* open the cache */
+#if 0
+ ret = -EINVAL;
+ if (!cachedev) {
+ printk(KERN_NOTICE "kAFS: No cache device specified as module parm\n");
+ printk(KERN_NOTICE "kAFS: Set with \"cachedev=<devname>\" on insmod's cmdline\n");
+ return ret;
+ }
+
+ ret = afs_cache_open(cachedev,&afs_cache);
+ if (ret<0) {
+ printk(KERN_NOTICE "kAFS: Failed to open cache device\n");
+ return ret;
+ }
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ /* create ourselves an inode cache */
+ ret = -ENOMEM;
+ afs_inode_cachep = kmem_cache_create("afs_inode_cache",
+ sizeof(afs_vnode_t),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ afs_i_init_once,
+ NULL);
+ if (!afs_inode_cachep) {
+ printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n");
+#if 0
+ afs_put_cache(afs_cache);
+#endif
+ return ret;
+ }
+#endif
+
+ /* now export our filesystem to lesser mortals */
+ ret = register_filesystem(&afs_fs_type);
+ if (ret<0) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ kmem_cache_destroy(afs_inode_cachep);
+#endif
+#if 0
+ afs_put_cache(afs_cache);
+#endif
+ kleave(" = %d",ret);
+ return ret;
+ }
+
+ kleave(" = 0");
+ return 0;
+} /* end afs_fs_init() */
+
+/*****************************************************************************/
+/*
+ * clean up the filesystem
+ */
+void __exit afs_fs_exit(void)
+{
+ /* destroy our private inode cache */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ kmem_cache_destroy(afs_inode_cachep);
+#endif
+
+ unregister_filesystem(&afs_fs_type);
+
+#if 0
+ if (afs_cache)
+ afs_put_cache(afs_cache);
+#endif
+} /* end afs_fs_exit() */
+
+/*****************************************************************************/
+/*
+ * check that an argument has a value
+ */
+static int want_arg(char **_value, const char *option)
+{
+ if (!_value || !*_value || !**_value) {
+ printk(KERN_NOTICE "kAFS: %s: argument missing\n",option);
+ return 0;
+ }
+ return 1;
+} /* end want_arg() */
+
+/*****************************************************************************/
+/*
+ * check that there is a value
+ */
+#if 0
+static int want_value(char **_value, const char *option)
+{
+ if (!_value || !*_value || !**_value) {
+ printk(KERN_NOTICE "kAFS: %s: argument incomplete\n",option);
+ return 0;
+ }
+ return 1;
+} /* end want_value() */
+#endif
+
+/*****************************************************************************/
+/*
+ * check that there's no subsequent value
+ */
+static int want_no_value(char *const *_value, const char *option)
+{
+ if (*_value && **_value) {
+ printk(KERN_NOTICE "kAFS: %s: Invalid argument: %s\n",option,*_value);
+ return 0;
+ }
+ return 1;
+} /* end want_no_value() */
+
+/*****************************************************************************/
+/*
+ * extract a number from an option string value
+ */
+#if 0
+static int want_number(char **_value, const char *option, unsigned long *number,
+ unsigned long limit)
+{
+ char *value = *_value;
+
+ if (!want_value(_value,option))
+ return 0;
+
+ *number = simple_strtoul(value,_value,0);
+
+ if (value==*_value) {
+ printk(KERN_NOTICE "kAFS: %s: Invalid number: %s\n",option,value);
+ return 0;
+ }
+
+ if (*number>limit) {
+ printk(KERN_NOTICE "kAFS: %s: numeric value %lu > %lu\n",option,*number,limit);
+ return 0;
+ }
+
+ return 1;
+} /* end want_number() */
+#endif
+
+/*****************************************************************************/
+/*
+ * extract a separator from an option string value
+ */
+#if 0
+static int want_sep(char **_value, const char *option, char sep)
+{
+ if (!want_value(_value,option))
+ return 0;
+
+ if (*(*_value)++ != sep) {
+ printk(KERN_NOTICE "kAFS: %s: '%c' expected: %s\n",option,sep,*_value-1);
+ return 0;
+ }
+
+ return 1;
+} /* end want_number() */
+#endif
+
+/*****************************************************************************/
+/*
+ * extract an IP address from an option string value
+ */
+#if 0
+static int want_ipaddr(char **_value, const char *option, struct in_addr *addr)
+{
+ unsigned long number[4];
+
+ if (!want_value(_value,option))
+ return 0;
+
+ if (!want_number(_value,option,&number[0],255) ||
+ !want_sep(_value,option,'.') ||
+ !want_number(_value,option,&number[1],255) ||
+ !want_sep(_value,option,'.') ||
+ !want_number(_value,option,&number[2],255) ||
+ !want_sep(_value,option,'.') ||
+ !want_number(_value,option,&number[3],255))
+ return 0;
+
+ ((u8*)addr)[0] = number[0];
+ ((u8*)addr)[1] = number[1];
+ ((u8*)addr)[2] = number[2];
+ ((u8*)addr)[3] = number[3];
+
+ return 1;
+} /* end want_numeric() */
+#endif
+
+/*****************************************************************************/
+/*
+ * parse the mount options
+ * - this function has been shamelessly adapted from the ext3 fs which shamelessly adapted it from
+ * the msdos fs
+ */
+static int afs_super_parse_options(struct afs_super_info *as, char *options, char **devname)
+{
+ char *key, *value;
+ int ret;
+
+ _enter("%s",options);
+
+ ret = 0;
+ while ((key = strsep(&options,",")))
+ {
+ value = strchr(key,'=');
+ if (value)
+ *value++ = 0;
+
+ printk("kAFS: KEY: %s, VAL:%s\n",key,value?:"-");
+
+ if (strcmp(key,"rwpath")==0) {
+ if (!want_no_value(&value,"rwpath")) return -EINVAL;
+ as->rwparent = 1;
+ continue;
+ }
+ else if (strcmp(key,"vol")==0) {
+ if (!want_arg(&value,"vol")) return -EINVAL;
+ *devname = value;
+ continue;
+ }
+
+#if 0
+ if (strcmp(key,"servers")==0) {
+ if (!want_arg(&value,"servers")) return -EINVAL;
+
+ _debug("servers=%s",value);
+
+ for (;;) {
+ struct in_addr addr;
+
+ if (!want_ipaddr(&value,"servers",&addr))
+ return -EINVAL;
+
+ ret = afs_create_server(as->cell,&addr,&as->server);
+ if (ret<0) {
+ printk("kAFS: unable to create server: %d\n",ret);
+ return ret;
+ }
+
+ if (!*value)
+ break;
+
+ if (as->server) {
+ printk(KERN_NOTICE
+ "kAFS: only one server can be specified\n");
+ return -EINVAL;
+ }
+
+ if (!want_sep(&value,"servers",':'))
+ return -EINVAL;
+ }
+ continue;
+ }
+#endif
+
+ printk("kAFS: Unknown mount option: '%s'\n",key);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = 0;
+
+ error:
+ _leave(" = %d",ret);
+
+ return ret;
+} /* end afs_super_parse_options() */
+
+/*****************************************************************************/
+/*
+ * fill in the superblock
+ */
+static int afs_fill_super(struct super_block *sb, void *_data, int silent)
+{
+ struct afs_super_info *as = NULL;
+ struct dentry *root = NULL;
+ struct inode *inode = NULL;
+ afs_fid_t fid;
+ void **data = _data;
+ char *options, *devname;
+ int ret;
+
+ _enter("");
+
+ if (!data) {
+ _leave(" = -EINVAL");
+ return -EINVAL;
+ }
+ devname = data[0];
+ options = data[1];
+ if (options)
+ options[PAGE_SIZE-1] = 0;
+
+ /* allocate a superblock info record */
+ as = kmalloc(sizeof(struct afs_super_info),GFP_KERNEL);
+ if (!as) {
+ _leave(" = -ENOMEM");
+ return -ENOMEM;
+ }
+
+ memset(as,0,sizeof(struct afs_super_info));
+
+ /* parse the options */
+ if (options) {
+ ret = afs_super_parse_options(as,options,&devname);
+ if (ret<0)
+ goto error;
+ if (!devname) {
+ printk("kAFS: no volume name specified\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ /* parse the device name */
+ ret = afs_volume_lookup(devname,as->rwparent,&as->volume);
+ if (ret<0)
+ goto error;
+
+ /* fill in the superblock */
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ sb->s_magic = AFS_FS_MAGIC;
+ sb->s_op = &afs_super_ops;
+ sb->s_fs_info = as;
+
+ /* allocate the root inode and dentry */
+ fid.vid = as->volume->vid;
+ fid.vnode = 1;
+ fid.unique = 1;
+ ret = afs_iget(sb,&fid,&inode);
+ if (ret<0)
+ goto error;
+
+ ret = -ENOMEM;
+ root = d_alloc_root(inode);
+ if (!root)
+ goto error;
+
+ sb->s_root = root;
+
+ _leave(" = 0");
+ return 0;
+
+ error:
+ if (root) dput(root);
+ if (inode) iput(inode);
+ if (as) {
+ if (as->volume) afs_put_volume(as->volume);
+ kfree(as);
+ }
+ sb->s_fs_info = NULL;
+
+ _leave(" = %d",ret);
+ return ret;
+} /* end afs_fill_super() */
+
+/*****************************************************************************/
+/*
+ * get an AFS superblock
+ * - TODO: don't use get_sb_nodev(), but rather call sget() directly
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static struct super_block *afs_get_sb(struct file_system_type *fs_type,
+ int flags,
+ char *dev_name,
+ void *options)
+{
+ struct super_block *sb;
+ void *data[2] = { dev_name, options };
+ int ret;
+
+ _enter(",,%s,%p",dev_name,options);
+
+ /* start the cache manager */
+ ret = afscm_start();
+ if (ret<0) {
+ _leave(" = %d",ret);
+ return ERR_PTR(ret);
+ }
+
+ /* allocate a deviceless superblock */
+ sb = get_sb_nodev(fs_type,flags,data,afs_fill_super);
+ if (IS_ERR(sb)) {
+ afscm_stop();
+ return sb;
+ }
+
+ _leave("");
+ return sb;
+} /* end afs_get_sb() */
+#endif
+
+/*****************************************************************************/
+/*
+ * read an AFS superblock
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static struct super_block *afs_read_super(struct super_block *sb, void *options, int silent)
+{
+ void *data[2] = { NULL, options };
+ int ret;
+
+ _enter(",,%s",(char*)options);
+
+ /* start the cache manager */
+ ret = afscm_start();
+ if (ret<0) {
+ _leave(" = NULL (%d)",ret);
+ return NULL;
+ }
+
+ /* allocate a deviceless superblock */
+ ret = afs_fill_super(sb,data,silent);
+ if (ret<0) {
+ afscm_stop();
+ _leave(" = NULL (%d)",ret);
+ return NULL;
+ }
+
+ _leave(" = %p",sb);
+ return sb;
+} /* end afs_read_super() */
+#endif
+
+/*****************************************************************************/
+/*
+ * finish the unmounting process on the superblock
+ */
+static void afs_put_super(struct super_block *sb)
+{
+ struct afs_super_info *as = sb->s_fs_info;
+
+ _enter("");
+
+ if (as) {
+ if (as->volume) afs_put_volume(as->volume);
+ }
+
+ /* stop the cache manager */
+ afscm_stop();
+
+ _leave("");
+} /* end afs_put_super() */
+
+/*****************************************************************************/
+/*
+ * initialise an inode cache slab element prior to any use
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static void afs_i_init_once(void *_vnode, kmem_cache_t *cachep, unsigned long flags)
+{
+ afs_vnode_t *vnode = (afs_vnode_t *) _vnode;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) {
+ memset(vnode,0,sizeof(*vnode));
+ inode_init_once(&vnode->vfs_inode);
+ init_waitqueue_head(&vnode->update_waitq);
+ spin_lock_init(&vnode->lock);
+ INIT_LIST_HEAD(&vnode->cb_link);
+ INIT_LIST_HEAD(&vnode->cb_hash_link);
+ afs_timer_init(&vnode->cb_timeout,&afs_vnode_cb_timed_out_ops);
+ }
+
+} /* end afs_i_init_once() */
+#endif
+
+/*****************************************************************************/
+/*
+ * allocate an AFS inode struct from our slab cache
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static struct inode *afs_alloc_inode(struct super_block *sb)
+{
+ afs_vnode_t *vnode;
+
+ vnode = (afs_vnode_t *) kmem_cache_alloc(afs_inode_cachep,SLAB_KERNEL);
+ if (!vnode)
+ return NULL;
+
+ memset(&vnode->fid,0,sizeof(vnode->fid));
+ memset(&vnode->status,0,sizeof(vnode->status));
+
+ vnode->volume = NULL;
+ vnode->update_cnt = 0;
+ vnode->flags = 0;
+
+ return &vnode->vfs_inode;
+} /* end afs_alloc_inode() */
+#endif
+
+/*****************************************************************************/
+/*
+ * destroy an AFS inode struct
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static void afs_destroy_inode(struct inode *inode)
+{
+ _enter("{%lu}",inode->i_ino);
+ kmem_cache_free(afs_inode_cachep, AFS_FS_I(inode));
+} /* end afs_destroy_inode() */
+#endif
diff --git a/fs/afs/super.h b/fs/afs/super.h
new file mode 100644
index 000000000000..b307b0884181
--- /dev/null
+++ b/fs/afs/super.h
@@ -0,0 +1,43 @@
+/* super.h: AFS filesystem internal private data
+ *
+ * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
+ *
+ * This software may be freely redistributed under the terms of the
+ * GNU General Public License.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors: David Woodhouse <dwmw2@cambridge.redhat.com>
+ * David Howells <dhowells@redhat.com>
+ *
+ */
+
+#ifndef _LINUX_AFS_SUPER_H
+#define _LINUX_AFS_SUPER_H
+
+#include <linux/fs.h>
+#include "server.h"
+
+#ifdef __KERNEL__
+
+/*****************************************************************************/
+/*
+ * AFS superblock private data
+ * - there's one superblock per volume
+ */
+struct afs_super_info
+{
+ afs_volume_t *volume; /* volume record */
+ char rwparent; /* T if parent is R/W AFS volume */
+};
+
+static inline struct afs_super_info *AFS_FS_S(struct super_block *sb)
+{
+ return sb->s_fs_info;
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_AFS_SUPER_H */
diff --git a/fs/afs/transport.h b/fs/afs/transport.h
new file mode 100644
index 000000000000..7013ae6ccc8c
--- /dev/null
+++ b/fs/afs/transport.h
@@ -0,0 +1,21 @@
+/* transport.h: AFS transport management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_TRANSPORT_H
+#define _LINUX_AFS_TRANSPORT_H
+
+#include "types.h"
+#include <rxrpc/transport.h>
+
+/* the cache manager transport endpoint */
+extern struct rxrpc_transport *afs_transport;
+
+#endif /* _LINUX_AFS_TRANSPORT_H */
diff --git a/fs/afs/types.h b/fs/afs/types.h
new file mode 100644
index 000000000000..411925f4fa04
--- /dev/null
+++ b/fs/afs/types.h
@@ -0,0 +1,152 @@
+/* types.h: AFS types
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_TYPES_H
+#define _LINUX_AFS_TYPES_H
+
+#ifdef __KERNEL__
+#include <rxrpc/types.h>
+#endif /* __KERNEL__ */
+
+typedef unsigned afs_volid_t;
+typedef unsigned afs_vnodeid_t;
+typedef unsigned long long afs_dataversion_t;
+
+typedef struct afs_async_op afs_async_op_t;
+typedef struct afs_callback afs_callback_t;
+typedef struct afs_cell afs_cell_t;
+typedef struct afs_fid afs_fid_t;
+typedef struct afs_file_status afs_file_status_t;
+typedef struct afs_server afs_server_t;
+typedef struct afs_timer afs_timer_t;
+typedef struct afs_vlocation afs_vlocation_t;
+typedef struct afs_vnode afs_vnode_t;
+typedef struct afs_volsync afs_volsync_t;
+typedef struct afs_volume afs_volume_t;
+typedef struct afs_volume_info afs_volume_info_t;
+
+typedef struct afsc_cache afsc_cache_t;
+typedef struct afsc_cache_cell afsc_cache_cell_t;
+typedef struct afsc_cache_vldb afsc_cache_vldb_t;
+typedef struct afsc_cell_record afsc_cell_record_t;
+typedef struct afsc_inode afsc_inode_t;
+typedef struct afsc_io afsc_io_t;
+typedef struct afsc_io_subop afsc_io_subop_t;
+typedef struct afsc_io_queue afsc_io_queue_t;
+typedef struct afsc_super_block afsc_super_block_t;
+typedef struct afsc_vldb_record afsc_vldb_record_t;
+typedef struct afsc_vnode_catalogue afsc_vnode_catalogue_t;
+typedef struct afsc_vnode_meta afsc_vnode_meta_t;
+
+typedef struct afsvl_dbentry afsvl_dbentry_t;
+
+typedef enum {
+ AFSVL_RWVOL, /* read/write volume */
+ AFSVL_ROVOL, /* read-only volume */
+ AFSVL_BACKVOL, /* backup volume */
+} afs_voltype_t;
+
+extern const char *afs_voltypes[];
+
+typedef enum {
+ AFS_FTYPE_INVALID = 0,
+ AFS_FTYPE_FILE = 1,
+ AFS_FTYPE_DIR = 2,
+ AFS_FTYPE_SYMLINK = 3,
+} afs_file_type_t;
+
+#ifdef __KERNEL__
+
+/*****************************************************************************/
+/*
+ * AFS file identifier
+ */
+struct afs_fid
+{
+ afs_volid_t vid; /* volume ID */
+ afs_vnodeid_t vnode; /* file index within volume */
+ unsigned unique; /* unique ID number (file index version) */
+};
+
+/*****************************************************************************/
+/*
+ * AFS callback notification
+ */
+typedef enum {
+ AFSCM_CB_UNTYPED = 0, /* no type set on CB break */
+ AFSCM_CB_EXCLUSIVE = 1, /* CB exclusive to CM [not implemented] */
+ AFSCM_CB_SHARED = 2, /* CB shared by other CM's */
+ AFSCM_CB_DROPPED = 3, /* CB promise cancelled by file server */
+} afs_callback_type_t;
+
+struct afs_callback
+{
+ afs_server_t *server; /* server that made the promise */
+ afs_fid_t fid; /* file identifier */
+ unsigned version; /* callback version */
+ unsigned expiry; /* time at which expires */
+ afs_callback_type_t type; /* type of callback */
+};
+
+#define AFSCBMAX 50
+
+/*****************************************************************************/
+/*
+ * AFS volume information
+ */
+struct afs_volume_info
+{
+ afs_volid_t vid; /* volume ID */
+ afs_voltype_t type; /* type of this volume */
+ afs_volid_t type_vids[5]; /* volume ID's for possible types for this vol */
+
+ /* list of fileservers serving this volume */
+ size_t nservers; /* number of entries used in servers[] */
+ struct {
+ struct in_addr addr; /* fileserver address */
+ } servers[8];
+};
+
+/*****************************************************************************/
+/*
+ * AFS file status information
+ */
+struct afs_file_status
+{
+ unsigned if_version; /* interface version */
+#define AFS_FSTATUS_VERSION 1
+
+ afs_file_type_t type; /* file type */
+ unsigned nlink; /* link count */
+ size_t size; /* file size */
+ afs_dataversion_t version; /* current data version */
+ unsigned author; /* author ID */
+ unsigned owner; /* owner ID */
+ unsigned caller_access; /* access rights for authenticated caller */
+ unsigned anon_access; /* access rights for unauthenticated caller */
+ umode_t mode; /* UNIX mode */
+ afs_fid_t parent; /* parent file ID */
+ time_t mtime_client; /* last time client changed data */
+ time_t mtime_server; /* last time server changed data */
+};
+
+/*****************************************************************************/
+/*
+ * AFS volume synchronisation information
+ */
+struct afs_volsync
+{
+ time_t creation; /* volume creation time */
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_AFS_TYPES_H */
diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c
new file mode 100644
index 000000000000..564e9939af40
--- /dev/null
+++ b/fs/afs/vlclient.c
@@ -0,0 +1,662 @@
+/* vlclient.c: AFS Volume Location Service client
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/call.h>
+#include "server.h"
+#include "volume.h"
+#include "vlclient.h"
+#include "kafsasyncd.h"
+#include "kafstimod.h"
+#include "errors.h"
+#include "internal.h"
+
+#define VLGETENTRYBYID 503 /* AFS Get Cache Entry By ID operation ID */
+#define VLGETENTRYBYNAME 504 /* AFS Get Cache Entry By Name operation ID */
+#define VLPROBE 514 /* AFS Probe Volume Location Service operation ID */
+
+static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call);
+static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call);
+
+/*****************************************************************************/
+/*
+ * map afs VL abort codes to/from Linux error codes
+ * - called with call->lock held
+ */
+static void afs_rxvl_aemap(struct rxrpc_call *call)
+{
+ int err;
+
+ _enter("{%u,%u,%d}",call->app_err_state,call->app_abort_code,call->app_errno);
+
+ switch (call->app_err_state) {
+ case RXRPC_ESTATE_LOCAL_ABORT:
+ call->app_abort_code = -call->app_errno;
+ return;
+
+ case RXRPC_ESTATE_PEER_ABORT:
+ switch (call->app_abort_code) {
+ case AFSVL_IDEXIST: err = -EEXIST; break;
+ case AFSVL_IO: err = -EREMOTEIO; break;
+ case AFSVL_NAMEEXIST: err = -EEXIST; break;
+ case AFSVL_CREATEFAIL: err = -EREMOTEIO; break;
+ case AFSVL_NOENT: err = -ENOMEDIUM; break;
+ case AFSVL_EMPTY: err = -ENOMEDIUM; break;
+ case AFSVL_ENTDELETED: err = -ENOMEDIUM; break;
+ case AFSVL_BADNAME: err = -EINVAL; break;
+ case AFSVL_BADINDEX: err = -EINVAL; break;
+ case AFSVL_BADVOLTYPE: err = -EINVAL; break;
+ case AFSVL_BADSERVER: err = -EINVAL; break;
+ case AFSVL_BADPARTITION: err = -EINVAL; break;
+ case AFSVL_REPSFULL: err = -EFBIG; break;
+ case AFSVL_NOREPSERVER: err = -ENOENT; break;
+ case AFSVL_DUPREPSERVER: err = -EEXIST; break;
+ case AFSVL_RWNOTFOUND: err = -ENOENT; break;
+ case AFSVL_BADREFCOUNT: err = -EINVAL; break;
+ case AFSVL_SIZEEXCEEDED: err = -EINVAL; break;
+ case AFSVL_BADENTRY: err = -EINVAL; break;
+ case AFSVL_BADVOLIDBUMP: err = -EINVAL; break;
+ case AFSVL_IDALREADYHASHED: err = -EINVAL; break;
+ case AFSVL_ENTRYLOCKED: err = -EBUSY; break;
+ case AFSVL_BADVOLOPER: err = -EBADRQC; break;
+ case AFSVL_BADRELLOCKTYPE: err = -EINVAL; break;
+ case AFSVL_RERELEASE: err = -EREMOTEIO; break;
+ case AFSVL_BADSERVERFLAG: err = -EINVAL; break;
+ case AFSVL_PERM: err = -EACCES; break;
+ case AFSVL_NOMEM: err = -EREMOTEIO; break;
+ default:
+ err = afs_abort_to_error(call->app_abort_code);
+ break;
+ }
+ call->app_errno = err;
+ return;
+
+ default:
+ return;
+ }
+} /* end afs_rxvl_aemap() */
+
+/*****************************************************************************/
+/*
+ * probe a volume location server to see if it is still alive
+ */
+int afs_rxvl_probe(afs_server_t *server, int alloc_flags)
+{
+ DECLARE_WAITQUEUE(myself,current);
+
+ struct rxrpc_connection *conn;
+ struct rxrpc_call *call;
+ struct iovec piov[1];
+ size_t sent;
+ int ret;
+ u32 param[1];
+
+ /* get hold of the vlserver connection */
+ ret = afs_server_get_vlconn(server,&conn);
+ if (ret<0)
+ goto out;
+
+ /* create a call through that connection */
+ ret = rxrpc_create_call(conn,NULL,NULL,afs_rxvl_aemap,&call);
+ if (ret<0) {
+ printk("kAFS: Unable to create call: %d\n",ret);
+ goto out_put_conn;
+ }
+ call->app_opcode = VLPROBE;
+
+ /* we want to get event notifications from the call */
+ add_wait_queue(&call->waitq,&myself);
+
+ /* marshall the parameters */
+ param[0] = htonl(VLPROBE);
+ piov[0].iov_len = sizeof(param);
+ piov[0].iov_base = param;
+
+ /* send the parameters to the server */
+ ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,alloc_flags,0,&sent);
+ if (ret<0)
+ goto abort;
+
+ /* wait for the reply to completely arrive */
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (call->app_call_state!=RXRPC_CSTATE_CLNT_RCV_REPLY ||
+ signal_pending(current))
+ break;
+ schedule();
+ }
+ set_current_state(TASK_RUNNING);
+
+ ret = -EINTR;
+ if (signal_pending(current))
+ goto abort;
+
+ switch (call->app_call_state) {
+ case RXRPC_CSTATE_ERROR:
+ ret = call->app_errno;
+ goto out_unwait;
+
+ case RXRPC_CSTATE_CLNT_GOT_REPLY:
+ ret = 0;
+ goto out_unwait;
+
+ default:
+ BUG();
+ }
+
+ abort:
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ rxrpc_call_abort(call,ret);
+ schedule();
+
+ out_unwait:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&call->waitq,&myself);
+ rxrpc_put_call(call);
+ out_put_conn:
+ rxrpc_put_connection(conn);
+ out:
+ return ret;
+
+} /* end afs_rxvl_probe() */
+
+/*****************************************************************************/
+/*
+ * look up a volume location database entry by name
+ */
+int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname,
+ afsc_vldb_record_t *entry)
+{
+ DECLARE_WAITQUEUE(myself,current);
+
+ struct rxrpc_connection *conn;
+ struct rxrpc_call *call;
+ struct iovec piov[3];
+ unsigned tmp;
+ size_t sent;
+ int ret, loop;
+ u32 *bp, param[2], zero;
+
+ _enter(",%s,",volname);
+
+ memset(entry,0,sizeof(*entry));
+
+ /* get hold of the vlserver connection */
+ ret = afs_server_get_vlconn(server,&conn);
+ if (ret<0)
+ goto out;
+
+ /* create a call through that connection */
+ ret = rxrpc_create_call(conn,NULL,NULL,afs_rxvl_aemap,&call);
+ if (ret<0) {
+ printk("kAFS: Unable to create call: %d\n",ret);
+ goto out_put_conn;
+ }
+ call->app_opcode = VLGETENTRYBYNAME;
+
+ /* we want to get event notifications from the call */
+ add_wait_queue(&call->waitq,&myself);
+
+ /* marshall the parameters */
+ piov[1].iov_len = strlen(volname);
+ piov[1].iov_base = (char*)volname;
+
+ zero = 0;
+ piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
+ piov[2].iov_base = &zero;
+
+ param[0] = htonl(VLGETENTRYBYNAME);
+ param[1] = htonl(piov[1].iov_len);
+
+ piov[0].iov_len = sizeof(param);
+ piov[0].iov_base = param;
+
+ /* send the parameters to the server */
+ ret = rxrpc_call_write_data(call,3,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+ if (ret<0)
+ goto abort;
+
+ /* wait for the reply to completely arrive */
+ bp = rxrpc_call_alloc_scratch(call,384);
+
+ ret = rxrpc_call_read_data(call,bp,384,RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
+ if (ret<0) {
+ if (ret==-ECONNABORTED) {
+ ret = call->app_errno;
+ goto out_unwait;
+ }
+ goto abort;
+ }
+
+ /* unmarshall the reply */
+ for (loop=0; loop<64; loop++)
+ entry->name[loop] = ntohl(*bp++);
+ bp++; /* final NUL */
+
+ bp++; /* type */
+ entry->nservers = ntohl(*bp++);
+
+ for (loop=0; loop<8; loop++)
+ entry->servers[loop].s_addr = *bp++;
+
+ bp += 8; /* partition IDs */
+
+ for (loop=0; loop<8; loop++) {
+ tmp = ntohl(*bp++);
+ if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RW;
+ if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RO;
+ if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFSC_VOL_STM_BAK;
+ }
+
+ entry->vid[0] = ntohl(*bp++);
+ entry->vid[1] = ntohl(*bp++);
+ entry->vid[2] = ntohl(*bp++);
+
+ bp++; /* clone ID */
+
+ tmp = ntohl(*bp++); /* flags */
+ if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFSC_VOL_STM_RW;
+ if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFSC_VOL_STM_RO;
+ if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFSC_VOL_STM_BAK;
+
+ ret = -ENOMEDIUM;
+ if (!entry->vidmask)
+ goto abort;
+
+ /* success */
+ entry->ctime = xtime.tv_sec;
+ ret = 0;
+
+ out_unwait:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&call->waitq,&myself);
+ rxrpc_put_call(call);
+ out_put_conn:
+ rxrpc_put_connection(conn);
+ out:
+ _leave(" = %d",ret);
+ return ret;
+
+ abort:
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ rxrpc_call_abort(call,ret);
+ schedule();
+ goto out_unwait;
+} /* end afs_rxvl_get_entry_by_name() */
+
+/*****************************************************************************/
+/*
+ * look up a volume location database entry by ID
+ */
+int afs_rxvl_get_entry_by_id(afs_server_t *server,
+ afs_volid_t volid,
+ afs_voltype_t voltype,
+ afsc_vldb_record_t *entry)
+{
+ DECLARE_WAITQUEUE(myself,current);
+
+ struct rxrpc_connection *conn;
+ struct rxrpc_call *call;
+ struct iovec piov[1];
+ unsigned tmp;
+ size_t sent;
+ int ret, loop;
+ u32 *bp, param[3];
+
+ _enter(",%x,%d,",volid,voltype);
+
+ memset(entry,0,sizeof(*entry));
+
+ /* get hold of the vlserver connection */
+ ret = afs_server_get_vlconn(server,&conn);
+ if (ret<0)
+ goto out;
+
+ /* create a call through that connection */
+ ret = rxrpc_create_call(conn,NULL,NULL,afs_rxvl_aemap,&call);
+ if (ret<0) {
+ printk("kAFS: Unable to create call: %d\n",ret);
+ goto out_put_conn;
+ }
+ call->app_opcode = VLGETENTRYBYID;
+
+ /* we want to get event notifications from the call */
+ add_wait_queue(&call->waitq,&myself);
+
+ /* marshall the parameters */
+ param[0] = htonl(VLGETENTRYBYID);
+ param[1] = htonl(volid);
+ param[2] = htonl(voltype);
+
+ piov[0].iov_len = sizeof(param);
+ piov[0].iov_base = param;
+
+ /* send the parameters to the server */
+ ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+ if (ret<0)
+ goto abort;
+
+ /* wait for the reply to completely arrive */
+ bp = rxrpc_call_alloc_scratch(call,384);
+
+ ret = rxrpc_call_read_data(call,bp,384,RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
+ if (ret<0) {
+ if (ret==-ECONNABORTED) {
+ ret = call->app_errno;
+ goto out_unwait;
+ }
+ goto abort;
+ }
+
+ /* unmarshall the reply */
+ for (loop=0; loop<64; loop++)
+ entry->name[loop] = ntohl(*bp++);
+ bp++; /* final NUL */
+
+ bp++; /* type */
+ entry->nservers = ntohl(*bp++);
+
+ for (loop=0; loop<8; loop++)
+ entry->servers[loop].s_addr = *bp++;
+
+ bp += 8; /* partition IDs */
+
+ for (loop=0; loop<8; loop++) {
+ tmp = ntohl(*bp++);
+ if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RW;
+ if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RO;
+ if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFSC_VOL_STM_BAK;
+ }
+
+ entry->vid[0] = ntohl(*bp++);
+ entry->vid[1] = ntohl(*bp++);
+ entry->vid[2] = ntohl(*bp++);
+
+ bp++; /* clone ID */
+
+ tmp = ntohl(*bp++); /* flags */
+ if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFSC_VOL_STM_RW;
+ if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFSC_VOL_STM_RO;
+ if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFSC_VOL_STM_BAK;
+
+ ret = -ENOMEDIUM;
+ if (!entry->vidmask)
+ goto abort;
+
+#if 0 /* TODO: remove */
+ entry->nservers = 3;
+ entry->servers[0].s_addr = htonl(0xac101249);
+ entry->servers[1].s_addr = htonl(0xac101243);
+ entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
+
+ entry->srvtmask[0] = AFSC_VOL_STM_RO;
+ entry->srvtmask[1] = AFSC_VOL_STM_RO;
+ entry->srvtmask[2] = AFSC_VOL_STM_RO | AFSC_VOL_STM_RW;
+#endif
+
+ /* success */
+ entry->ctime = xtime.tv_sec;
+ ret = 0;
+
+ out_unwait:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&call->waitq,&myself);
+ rxrpc_put_call(call);
+ out_put_conn:
+ rxrpc_put_connection(conn);
+ out:
+ _leave(" = %d",ret);
+ return ret;
+
+ abort:
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ rxrpc_call_abort(call,ret);
+ schedule();
+ goto out_unwait;
+} /* end afs_rxvl_get_entry_by_id() */
+
+/*****************************************************************************/
+/*
+ * look up a volume location database entry by ID asynchronously
+ */
+int afs_rxvl_get_entry_by_id_async(afs_async_op_t *op,
+ afs_volid_t volid,
+ afs_voltype_t voltype)
+{
+ struct rxrpc_connection *conn;
+ struct rxrpc_call *call;
+ struct iovec piov[1];
+ size_t sent;
+ int ret;
+ u32 param[3];
+
+ _enter(",%x,%d,",volid,voltype);
+
+ /* get hold of the vlserver connection */
+ ret = afs_server_get_vlconn(op->server,&conn);
+ if (ret<0) {
+ _leave(" = %d",ret);
+ return ret;
+ }
+
+ /* create a call through that connection */
+ ret = rxrpc_create_call(conn,
+ afs_rxvl_get_entry_by_id_attn,
+ afs_rxvl_get_entry_by_id_error,
+ afs_rxvl_aemap,
+ &op->call);
+ rxrpc_put_connection(conn);
+
+ if (ret<0) {
+ printk("kAFS: Unable to create call: %d\n",ret);
+ _leave(" = %d",ret);
+ return ret;
+ }
+
+ op->call->app_opcode = VLGETENTRYBYID;
+ op->call->app_user = op;
+
+ call = op->call;
+ rxrpc_get_call(call);
+
+ /* send event notifications from the call to kafsasyncd */
+ afs_kafsasyncd_begin_op(op);
+
+ /* marshall the parameters */
+ param[0] = htonl(VLGETENTRYBYID);
+ param[1] = htonl(volid);
+ param[2] = htonl(voltype);
+
+ piov[0].iov_len = sizeof(param);
+ piov[0].iov_base = param;
+
+ /* allocate result read buffer in scratch space */
+ call->app_scr_ptr = rxrpc_call_alloc_scratch(op->call,384);
+
+ /* send the parameters to the server */
+ ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+ if (ret<0) {
+ rxrpc_call_abort(call,ret); /* handle from kafsasyncd */
+ ret = 0;
+ goto out;
+ }
+
+ /* wait for the reply to completely arrive */
+ ret = rxrpc_call_read_data(call,call->app_scr_ptr,384,0);
+ switch (ret) {
+ case 0:
+ case -EAGAIN:
+ case -ECONNABORTED:
+ ret = 0;
+ break; /* all handled by kafsasyncd */
+
+ default:
+ rxrpc_call_abort(call,ret); /* force kafsasyncd to handle it */
+ ret = 0;
+ break;
+ }
+
+ out:
+ rxrpc_put_call(call);
+ _leave(" = %d",ret);
+ return ret;
+
+} /* end afs_rxvl_get_entry_by_id_async() */
+
+/*****************************************************************************/
+/*
+ * attend to the asynchronous get VLDB entry by ID
+ */
+int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op,
+ afsc_vldb_record_t *entry)
+{
+ unsigned *bp, tmp;
+ int loop, ret;
+
+ _enter("{op=%p cst=%u}",op,op->call->app_call_state);
+
+ memset(entry,0,sizeof(*entry));
+
+ if (op->call->app_call_state==RXRPC_CSTATE_COMPLETE) {
+ /* operation finished */
+ afs_kafsasyncd_terminate_op(op);
+
+ bp = op->call->app_scr_ptr;
+
+ /* unmarshall the reply */
+ for (loop=0; loop<64; loop++)
+ entry->name[loop] = ntohl(*bp++);
+ bp++; /* final NUL */
+
+ bp++; /* type */
+ entry->nservers = ntohl(*bp++);
+
+ for (loop=0; loop<8; loop++)
+ entry->servers[loop].s_addr = *bp++;
+
+ bp += 8; /* partition IDs */
+
+ for (loop=0; loop<8; loop++) {
+ tmp = ntohl(*bp++);
+ if (tmp & AFS_VLSF_RWVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RW;
+ if (tmp & AFS_VLSF_ROVOL ) entry->srvtmask[loop] |= AFSC_VOL_STM_RO;
+ if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFSC_VOL_STM_BAK;
+ }
+
+ entry->vid[0] = ntohl(*bp++);
+ entry->vid[1] = ntohl(*bp++);
+ entry->vid[2] = ntohl(*bp++);
+
+ bp++; /* clone ID */
+
+ tmp = ntohl(*bp++); /* flags */
+ if (tmp & AFS_VLF_RWEXISTS ) entry->vidmask |= AFSC_VOL_STM_RW;
+ if (tmp & AFS_VLF_ROEXISTS ) entry->vidmask |= AFSC_VOL_STM_RO;
+ if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFSC_VOL_STM_BAK;
+
+ ret = -ENOMEDIUM;
+ if (!entry->vidmask) {
+ rxrpc_call_abort(op->call,ret);
+ goto done;
+ }
+
+#if 0 /* TODO: remove */
+ entry->nservers = 3;
+ entry->servers[0].s_addr = htonl(0xac101249);
+ entry->servers[1].s_addr = htonl(0xac101243);
+ entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
+
+ entry->srvtmask[0] = AFSC_VOL_STM_RO;
+ entry->srvtmask[1] = AFSC_VOL_STM_RO;
+ entry->srvtmask[2] = AFSC_VOL_STM_RO | AFSC_VOL_STM_RW;
+#endif
+
+ /* success */
+ entry->ctime = xtime.tv_sec;
+ ret = 0;
+ goto done;
+ }
+
+ if (op->call->app_call_state==RXRPC_CSTATE_ERROR) {
+ /* operation error */
+ ret = op->call->app_errno;
+ goto done;
+ }
+
+ _leave(" = -EAGAIN");
+ return -EAGAIN;
+
+ done:
+ rxrpc_put_call(op->call);
+ op->call = NULL;
+ _leave(" = %d",ret);
+ return ret;
+} /* end afs_rxvl_get_entry_by_id_async2() */
+
+/*****************************************************************************/
+/*
+ * handle attention events on an async get-entry-by-ID op
+ * - called from krxiod
+ */
+static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call)
+{
+ afs_async_op_t *op = call->app_user;
+
+ _enter("{op=%p cst=%u}",op,call->app_call_state);
+
+ switch (call->app_call_state) {
+ case RXRPC_CSTATE_COMPLETE:
+ afs_kafsasyncd_attend_op(op);
+ break;
+ case RXRPC_CSTATE_CLNT_RCV_REPLY:
+ if (call->app_async_read)
+ break;
+ case RXRPC_CSTATE_CLNT_GOT_REPLY:
+ if (call->app_read_count==0)
+ break;
+ printk("kAFS: Reply bigger than expected {cst=%u asyn=%d mark=%d rdy=%u pr=%u%s}",
+ call->app_call_state,
+ call->app_async_read,
+ call->app_mark,
+ call->app_ready_qty,
+ call->pkt_rcv_count,
+ call->app_last_rcv ? " last" : "");
+
+ rxrpc_call_abort(call,-EBADMSG);
+ break;
+ default:
+ BUG();
+ }
+
+ _leave("");
+
+} /* end afs_rxvl_get_entry_by_id_attn() */
+
+/*****************************************************************************/
+/*
+ * handle error events on an async get-entry-by-ID op
+ * - called from krxiod
+ */
+static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call)
+{
+ afs_async_op_t *op = call->app_user;
+
+ _enter("{op=%p cst=%u}",op,call->app_call_state);
+
+ afs_kafsasyncd_attend_op(op);
+
+ _leave("");
+
+} /* end afs_rxvl_get_entry_by_id_error() */
diff --git a/fs/afs/vlclient.h b/fs/afs/vlclient.h
new file mode 100644
index 000000000000..5791e04d6382
--- /dev/null
+++ b/fs/afs/vlclient.h
@@ -0,0 +1,95 @@
+/* vlclient.h: Volume Location Service client interface
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_VLCLIENT_H
+#define _LINUX_AFS_VLCLIENT_H
+
+#include "types.h"
+
+enum AFSVL_Errors {
+ AFSVL_IDEXIST = 363520, /* Volume Id entry exists in vl database */
+ AFSVL_IO = 363521, /* I/O related error */
+ AFSVL_NAMEEXIST = 363522, /* Volume name entry exists in vl database */
+ AFSVL_CREATEFAIL = 363523, /* Internal creation failure */
+ AFSVL_NOENT = 363524, /* No such entry */
+ AFSVL_EMPTY = 363525, /* Vl database is empty */
+ AFSVL_ENTDELETED = 363526, /* Entry is deleted (soft delete) */
+ AFSVL_BADNAME = 363527, /* Volume name is illegal */
+ AFSVL_BADINDEX = 363528, /* Index is out of range */
+ AFSVL_BADVOLTYPE = 363529, /* Bad volume type */
+ AFSVL_BADSERVER = 363530, /* Illegal server number (out of range) */
+ AFSVL_BADPARTITION = 363531, /* Bad partition number */
+ AFSVL_REPSFULL = 363532, /* Run out of space for Replication sites */
+ AFSVL_NOREPSERVER = 363533, /* No such Replication server site exists */
+ AFSVL_DUPREPSERVER = 363534, /* Replication site already exists */
+ AFSVL_RWNOTFOUND = 363535, /* Parent R/W entry not found */
+ AFSVL_BADREFCOUNT = 363536, /* Illegal Reference Count number */
+ AFSVL_SIZEEXCEEDED = 363537, /* Vl size for attributes exceeded */
+ AFSVL_BADENTRY = 363538, /* Bad incoming vl entry */
+ AFSVL_BADVOLIDBUMP = 363539, /* Illegal max volid increment */
+ AFSVL_IDALREADYHASHED = 363540, /* RO/BACK id already hashed */
+ AFSVL_ENTRYLOCKED = 363541, /* Vl entry is already locked */
+ AFSVL_BADVOLOPER = 363542, /* Bad volume operation code */
+ AFSVL_BADRELLOCKTYPE = 363543, /* Bad release lock type */
+ AFSVL_RERELEASE = 363544, /* Status report: last release was aborted */
+ AFSVL_BADSERVERFLAG = 363545, /* Invalid replication site server °ag */
+ AFSVL_PERM = 363546, /* No permission access */
+ AFSVL_NOMEM = 363547, /* malloc/realloc failed to alloc enough memory */
+};
+
+/* maps to "struct vldbentry" in vvl-spec.pdf */
+struct afsvl_dbentry {
+ char name[65]; /* name of volume (including NUL char) */
+ afs_voltype_t type; /* volume type */
+ unsigned num_servers; /* num servers that hold instances of this vol */
+ unsigned clone_id; /* cloning ID */
+
+ unsigned flags;
+#define AFS_VLF_RWEXISTS 0x1000 /* R/W volume exists */
+#define AFS_VLF_ROEXISTS 0x2000 /* R/O volume exists */
+#define AFS_VLF_BACKEXISTS 0x4000 /* backup volume exists */
+
+ afs_volid_t volume_ids[3]; /* volume IDs */
+
+ struct {
+ struct in_addr addr; /* server address */
+ unsigned partition; /* partition ID on this server */
+ unsigned flags; /* server specific flags */
+#define AFS_VLSF_NEWREPSITE 0x0001 /* unused */
+#define AFS_VLSF_ROVOL 0x0002 /* this server holds a R/O instance of the volume */
+#define AFS_VLSF_RWVOL 0x0004 /* this server holds a R/W instance of the volume */
+#define AFS_VLSF_BACKVOL 0x0008 /* this server holds a backup instance of the volume */
+ } servers[8];
+
+};
+
+/* probe a volume location server to see if it is still alive */
+extern int afs_rxvl_probe(afs_server_t *server, int alloc_flags);
+
+/* look up a volume location database entry by name */
+extern int afs_rxvl_get_entry_by_name(afs_server_t *server,
+ const char *volname,
+ afsc_vldb_record_t *entry);
+
+/* look up a volume location database entry by ID */
+extern int afs_rxvl_get_entry_by_id(afs_server_t *server,
+ afs_volid_t volid,
+ afs_voltype_t voltype,
+ afsc_vldb_record_t *entry);
+
+extern int afs_rxvl_get_entry_by_id_async(afs_async_op_t *op,
+ afs_volid_t volid,
+ afs_voltype_t voltype);
+
+extern int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op,
+ afsc_vldb_record_t *entry);
+
+#endif /* _LINUX_AFS_VLCLIENT_H */
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c
new file mode 100644
index 000000000000..8d9f4d7e8f29
--- /dev/null
+++ b/fs/afs/vlocation.c
@@ -0,0 +1,824 @@
+/* vlocation.c: volume location management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "volume.h"
+#include "cell.h"
+#include "cmservice.h"
+#include "fsclient.h"
+#include "vlclient.h"
+#include "kafstimod.h"
+#include <rxrpc/connection.h>
+#include "internal.h"
+
+#define AFS_VLDB_TIMEOUT HZ*1000
+
+static void afs_vlocation_update_timer(afs_timer_t *timer);
+static void afs_vlocation_update_attend(afs_async_op_t *op);
+static void afs_vlocation_update_discard(afs_async_op_t *op);
+
+static void __afs_vlocation_timeout(afs_timer_t *timer)
+{
+ afs_vlocation_t *vlocation = list_entry(timer,afs_vlocation_t,timeout);
+
+ _debug("VL TIMEOUT [%s{u=%d}]",vlocation->vldb.name,atomic_read(&vlocation->usage));
+
+ afs_vlocation_do_timeout(vlocation);
+}
+
+static const struct afs_timer_ops afs_vlocation_timer_ops = {
+ .timed_out = __afs_vlocation_timeout,
+};
+
+static const struct afs_timer_ops afs_vlocation_update_timer_ops = {
+ .timed_out = afs_vlocation_update_timer,
+};
+
+static const struct afs_async_op_ops afs_vlocation_update_op_ops = {
+ .attend = afs_vlocation_update_attend,
+ .discard = afs_vlocation_update_discard,
+};
+
+static LIST_HEAD(afs_vlocation_update_pendq); /* queue of VLs awaiting update */
+static afs_vlocation_t *afs_vlocation_update; /* VL currently being updated */
+static spinlock_t afs_vlocation_update_lock = SPIN_LOCK_UNLOCKED; /* lock guarding update queue */
+
+/*****************************************************************************/
+/*
+ * iterate through the VL servers in a cell until one of them admits knowing about the volume in
+ * question
+ * - caller must have cell->vl_sem write-locked
+ */
+static int afs_vlocation_access_vl_by_name(afs_vlocation_t *vlocation,
+ const char *name,
+ afsc_vldb_record_t *vldb)
+{
+ afs_server_t *server = NULL;
+ afs_cell_t *cell = vlocation->cell;
+ int count, ret;
+
+ _enter("%s,%s,",cell->name,name);
+
+ ret = -ENOMEDIUM;
+ for (count=cell->vl_naddrs; count>0; count--) {
+ _debug("CellServ[%hu]: %08x",
+ cell->vl_curr_svix,cell->vl_addrs[cell->vl_curr_svix].s_addr);
+
+ /* try and create a server */
+ ret = afs_server_lookup(cell,&cell->vl_addrs[cell->vl_curr_svix],&server);
+ switch (ret) {
+ case 0:
+ break;
+ case -ENOMEM:
+ case -ENONET:
+ goto out;
+ default:
+ goto rotate;
+ }
+
+ /* attempt to access the VL server */
+ ret = afs_rxvl_get_entry_by_name(server,name,vldb);
+ switch (ret) {
+ case 0:
+ afs_put_server(server);
+ goto out;
+ case -ENOMEM:
+ case -ENONET:
+ case -ENETUNREACH:
+ case -EHOSTUNREACH:
+ case -ECONNREFUSED:
+ down_write(&server->sem);
+ if (server->vlserver) {
+ rxrpc_put_connection(server->vlserver);
+ server->vlserver = NULL;
+ }
+ up_write(&server->sem);
+ afs_put_server(server);
+ if (ret==-ENOMEM || ret==-ENONET)
+ goto out;
+ goto rotate;
+ case -ENOMEDIUM:
+ afs_put_server(server);
+ goto out;
+ default:
+ afs_put_server(server);
+ ret = -ENOMEDIUM;
+ goto rotate;
+ }
+
+ /* rotate the server records upon lookup failure */
+ rotate:
+ cell->vl_curr_svix++;
+ cell->vl_curr_svix %= cell->vl_naddrs;
+ }
+
+ out:
+ _leave(" = %d",ret);
+ return ret;
+
+} /* end afs_vlocation_access_vl_by_name() */
+
+/*****************************************************************************/
+/*
+ * iterate through the VL servers in a cell until one of them admits knowing about the volume in
+ * question
+ * - caller must have cell->vl_sem write-locked
+ */
+static int afs_vlocation_access_vl_by_id(afs_vlocation_t *vlocation,
+ afs_volid_t volid,
+ afs_voltype_t voltype,
+ afsc_vldb_record_t *vldb)
+{
+ afs_server_t *server = NULL;
+ afs_cell_t *cell = vlocation->cell;
+ int count, ret;
+
+ _enter("%s,%x,%d,",cell->name,volid,voltype);
+
+ ret = -ENOMEDIUM;
+ for (count=cell->vl_naddrs; count>0; count--) {
+ _debug("CellServ[%hu]: %08x",
+ cell->vl_curr_svix,cell->vl_addrs[cell->vl_curr_svix].s_addr);
+
+ /* try and create a server */
+ ret = afs_server_lookup(cell,&cell->vl_addrs[cell->vl_curr_svix],&server);
+ switch (ret) {
+ case 0:
+ break;
+ case -ENOMEM:
+ case -ENONET:
+ goto out;
+ default:
+ goto rotate;
+ }
+
+ /* attempt to access the VL server */
+ ret = afs_rxvl_get_entry_by_id(server,volid,voltype,vldb);
+ switch (ret) {
+ case 0:
+ afs_put_server(server);
+ goto out;
+ case -ENOMEM:
+ case -ENONET:
+ case -ENETUNREACH:
+ case -EHOSTUNREACH:
+ case -ECONNREFUSED:
+ down_write(&server->sem);
+ if (server->vlserver) {
+ rxrpc_put_connection(server->vlserver);
+ server->vlserver = NULL;
+ }
+ up_write(&server->sem);
+ afs_put_server(server);
+ if (ret==-ENOMEM || ret==-ENONET)
+ goto out;
+ goto rotate;
+ case -ENOMEDIUM:
+ afs_put_server(server);
+ goto out;
+ default:
+ afs_put_server(server);
+ ret = -ENOMEDIUM;
+ goto rotate;
+ }
+
+ /* rotate the server records upon lookup failure */
+ rotate:
+ cell->vl_curr_svix++;
+ cell->vl_curr_svix %= cell->vl_naddrs;
+ }
+
+ out:
+ _leave(" = %d",ret);
+ return ret;
+
+} /* end afs_vlocation_access_vl_by_id() */
+
+/*****************************************************************************/
+/*
+ * lookup volume location
+ * - caller must have cell->vol_sem write-locked
+ * - iterate through the VL servers in a cell until one of them admits knowing about the volume in
+ * question
+ * - lookup in the local cache if not able to find on the VL server
+ * - insert/update in the local cache if did get a VL response
+ */
+int afs_vlocation_lookup(afs_cell_t *cell, const char *name, afs_vlocation_t **_vlocation)
+{
+ afsc_vldb_record_t vldb;
+ struct list_head *_p;
+ afs_vlocation_t *vlocation;
+ afs_voltype_t voltype;
+ afs_volid_t vid;
+ int active = 0, ret;
+
+ _enter(",%s,%s,",cell->name,name);
+
+ if (strlen(name)>sizeof(vlocation->vldb.name)) {
+ _leave(" = -ENAMETOOLONG");
+ return -ENAMETOOLONG;
+ }
+
+ /* search the cell's active list first */
+ list_for_each(_p,&cell->vl_list) {
+ vlocation = list_entry(_p,afs_vlocation_t,link);
+ if (strncmp(vlocation->vldb.name,name,sizeof(vlocation->vldb.name))==0)
+ goto found_in_memory;
+ }
+
+ /* search the cell's graveyard list second */
+ spin_lock(&cell->vl_gylock);
+ list_for_each(_p,&cell->vl_graveyard) {
+ vlocation = list_entry(_p,afs_vlocation_t,link);
+ if (strncmp(vlocation->vldb.name,name,sizeof(vlocation->vldb.name))==0)
+ goto found_in_graveyard;
+ }
+ spin_unlock(&cell->vl_gylock);
+
+ /* not in the cell's in-memory lists - create a new record */
+ vlocation = kmalloc(sizeof(afs_vlocation_t),GFP_KERNEL);
+ if (!vlocation)
+ return -ENOMEM;
+
+ memset(vlocation,0,sizeof(afs_vlocation_t));
+ atomic_set(&vlocation->usage,1);
+ INIT_LIST_HEAD(&vlocation->link);
+ rwlock_init(&vlocation->lock);
+ strncpy(vlocation->vldb.name,name,sizeof(vlocation->vldb.name));
+
+ afs_timer_init(&vlocation->timeout,&afs_vlocation_timer_ops);
+ afs_timer_init(&vlocation->upd_timer,&afs_vlocation_update_timer_ops);
+ afs_async_op_init(&vlocation->upd_op,&afs_vlocation_update_op_ops);
+
+ INIT_LIST_HEAD(&vlocation->caches);
+
+ afs_get_cell(cell);
+ vlocation->cell = cell;
+
+ list_add_tail(&vlocation->link,&cell->vl_list);
+
+#if 0
+ /* search local cache if wasn't in memory */
+ ret = afsc_lookup_vlocation(vlocation);
+ switch (ret) {
+ default: goto error; /* disk error */
+ case 0: goto found_in_cache; /* pulled from local cache into memory */
+ case -ENOENT: break; /* not in local cache */
+ }
+#endif
+
+ /* try to look up an unknown volume in the cell VL databases by name */
+ ret = afs_vlocation_access_vl_by_name(vlocation,name,&vldb);
+ if (ret<0) {
+ printk("kAFS: failed to locate '%s' in cell '%s'\n",name,cell->name);
+ goto error;
+ }
+
+ goto found_on_vlserver;
+
+ found_in_graveyard:
+ /* found in the graveyard - resurrect */
+ _debug("found in graveyard");
+ atomic_inc(&vlocation->usage);
+ list_del(&vlocation->link);
+ list_add_tail(&vlocation->link,&cell->vl_list);
+ spin_unlock(&cell->vl_gylock);
+
+ afs_kafstimod_del_timer(&vlocation->timeout);
+ goto active;
+
+ found_in_memory:
+ /* found in memory - check to see if it's active */
+ _debug("found in memory");
+ atomic_inc(&vlocation->usage);
+
+ active:
+ active = 1;
+
+/* found_in_cache: */
+ /* try to look up a cached volume in the cell VL databases by ID */
+ _debug("found in cache");
+
+ _debug("Locally Cached: %s %02x { %08x(%x) %08x(%x) %08x(%x) }",
+ vlocation->vldb.name,
+ vlocation->vldb.vidmask,
+ ntohl(vlocation->vldb.servers[0].s_addr),vlocation->vldb.srvtmask[0],
+ ntohl(vlocation->vldb.servers[1].s_addr),vlocation->vldb.srvtmask[1],
+ ntohl(vlocation->vldb.servers[2].s_addr),vlocation->vldb.srvtmask[2]
+ );
+
+ _debug("Vids: %08x %08x %08x",
+ vlocation->vldb.vid[0],vlocation->vldb.vid[1],vlocation->vldb.vid[2]);
+
+ if (vlocation->vldb.vidmask & AFSC_VOL_STM_RW) {
+ vid = vlocation->vldb.vid[0];
+ voltype = AFSVL_RWVOL;
+ }
+ else if (vlocation->vldb.vidmask & AFSC_VOL_STM_RO) {
+ vid = vlocation->vldb.vid[1];
+ voltype = AFSVL_ROVOL;
+ }
+ else if (vlocation->vldb.vidmask & AFSC_VOL_STM_BAK) {
+ vid = vlocation->vldb.vid[2];
+ voltype = AFSVL_BACKVOL;
+ }
+ else {
+ BUG();
+ vid = 0;
+ voltype = 0;
+ }
+
+ ret = afs_vlocation_access_vl_by_id(vlocation,vid,voltype,&vldb);
+ switch (ret) {
+ /* net error */
+ default:
+ printk("kAFS: failed to volume '%s' (%x) up in '%s': %d\n",
+ name,vid,cell->name,ret);
+ goto error;
+
+ /* pulled from local cache into memory */
+ case 0:
+ goto found_on_vlserver;
+
+ /* uh oh... looks like the volume got deleted */
+ case -ENOMEDIUM:
+ printk("kAFS: volume '%s' (%x) does not exist '%s'\n",name,vid,cell->name);
+
+ /* TODO: make existing record unavailable */
+ goto error;
+ }
+
+ found_on_vlserver:
+ _debug("Done VL Lookup: %s %02x { %08x(%x) %08x(%x) %08x(%x) }",
+ name,
+ vldb.vidmask,
+ ntohl(vldb.servers[0].s_addr),vldb.srvtmask[0],
+ ntohl(vldb.servers[1].s_addr),vldb.srvtmask[1],
+ ntohl(vldb.servers[2].s_addr),vldb.srvtmask[2]
+ );
+
+ _debug("Vids: %08x %08x %08x",vldb.vid[0],vldb.vid[1],vldb.vid[2]);
+
+ if (strncmp(vldb.name,name,sizeof(vlocation->vldb.name))!=0)
+ printk("kAFS: name of volume '%s' changed to '%s' on server\n",name,vldb.name);
+
+ memcpy(&vlocation->vldb,&vldb,sizeof(vlocation->vldb));
+
+#if 0
+ /* add volume entry to local cache */
+ ret = afsc_update_vlocation(vlocation);
+ if (ret<0)
+ goto error;
+#endif
+
+ afs_kafstimod_add_timer(&vlocation->upd_timer,10*HZ);
+
+ *_vlocation = vlocation;
+ _leave(" = 0 (%p)",vlocation);
+ return 0;
+
+ error:
+ if (vlocation) {
+ if (active) {
+ __afs_put_vlocation(vlocation);
+ }
+ else {
+ list_del(&vlocation->link);
+ afs_put_cell(vlocation->cell);
+#if 0
+ afs_put_cache(vlocation->cache);
+#endif
+ kfree(vlocation);
+ }
+ }
+
+ _leave(" = %d",ret);
+ return ret;
+} /* end afs_vlocation_lookup() */
+
+/*****************************************************************************/
+/*
+ * finish using a volume location record
+ * - caller must have cell->vol_sem write-locked
+ */
+void __afs_put_vlocation(afs_vlocation_t *vlocation)
+{
+ afs_cell_t *cell = vlocation->cell;
+
+ _enter("%s",vlocation->vldb.name);
+
+ /* sanity check */
+ if (atomic_read(&vlocation->usage)<=0)
+ BUG();
+
+ spin_lock(&cell->vl_gylock);
+ if (likely(!atomic_dec_and_test(&vlocation->usage))) {
+ spin_unlock(&cell->vl_gylock);
+ _leave("");
+ return;
+ }
+
+ /* move to graveyard queue */
+ list_del(&vlocation->link);
+ list_add_tail(&vlocation->link,&cell->vl_graveyard);
+
+ /* remove from pending timeout queue (refcounted if actually being updated) */
+ list_del_init(&vlocation->upd_op.link);
+
+ /* time out in 10 secs */
+ afs_kafstimod_del_timer(&vlocation->upd_timer);
+ afs_kafstimod_add_timer(&vlocation->timeout,10*HZ);
+
+ spin_unlock(&cell->vl_gylock);
+
+ _leave(" [killed]");
+} /* end __afs_put_vlocation() */
+
+/*****************************************************************************/
+/*
+ * finish using a volume location record
+ */
+void afs_put_vlocation(afs_vlocation_t *vlocation)
+{
+ afs_cell_t *cell = vlocation->cell;
+
+ down_write(&cell->vl_sem);
+ __afs_put_vlocation(vlocation);
+ up_write(&cell->vl_sem);
+} /* end afs_put_vlocation() */
+
+/*****************************************************************************/
+/*
+ * timeout vlocation record
+ * - removes from the cell's graveyard if the usage count is zero
+ */
+void afs_vlocation_do_timeout(afs_vlocation_t *vlocation)
+{
+ afs_cell_t *cell;
+
+ _enter("%s",vlocation->vldb.name);
+
+ cell = vlocation->cell;
+
+ if (atomic_read(&vlocation->usage)<0) BUG();
+
+ /* remove from graveyard if still dead */
+ spin_lock(&cell->vl_gylock);
+ if (atomic_read(&vlocation->usage)==0)
+ list_del_init(&vlocation->link);
+ else
+ vlocation = NULL;
+ spin_unlock(&cell->vl_gylock);
+
+ if (!vlocation) {
+ _leave("");
+ return; /* resurrected */
+ }
+
+ /* we can now destroy it properly */
+ afs_put_cell(cell);
+#if 0
+ afs_put_cache(vlocation->cache);
+#endif
+
+ kfree(vlocation);
+
+ _leave(" [destroyed]");
+} /* end afs_vlocation_do_timeout() */
+
+/*****************************************************************************/
+/*
+ * send an update operation to the currently selected server
+ */
+static int afs_vlocation_update_begin(afs_vlocation_t *vlocation)
+{
+ afs_voltype_t voltype;
+ afs_volid_t vid;
+ int ret;
+
+ _enter("%s{ufs=%u ucs=%u}",
+ vlocation->vldb.name,vlocation->upd_first_svix,vlocation->upd_curr_svix);
+
+ /* try to look up a cached volume in the cell VL databases by ID */
+ if (vlocation->vldb.vidmask & AFSC_VOL_STM_RW) {
+ vid = vlocation->vldb.vid[0];
+ voltype = AFSVL_RWVOL;
+ }
+ else if (vlocation->vldb.vidmask & AFSC_VOL_STM_RO) {
+ vid = vlocation->vldb.vid[1];
+ voltype = AFSVL_ROVOL;
+ }
+ else if (vlocation->vldb.vidmask & AFSC_VOL_STM_BAK) {
+ vid = vlocation->vldb.vid[2];
+ voltype = AFSVL_BACKVOL;
+ }
+ else {
+ BUG();
+ vid = 0;
+ voltype = 0;
+ }
+
+ /* contact the chosen server */
+ ret = afs_server_lookup(vlocation->cell,
+ &vlocation->cell->vl_addrs[vlocation->upd_curr_svix],
+ &vlocation->upd_op.server);
+ switch (ret) {
+ case 0:
+ break;
+ case -ENOMEM:
+ case -ENONET:
+ default:
+ _leave(" = %d",ret);
+ return ret;
+ }
+
+ /* initiate the update operation */
+ ret = afs_rxvl_get_entry_by_id_async(&vlocation->upd_op,vid,voltype);
+ if (ret<0) {
+ _leave(" = %d",ret);
+ return ret;
+ }
+
+ _leave(" = %d",ret);
+ return ret;
+} /* end afs_vlocation_update_begin() */
+
+/*****************************************************************************/
+/*
+ * abandon updating a VL record
+ * - does not restart the update timer
+ */
+static void afs_vlocation_update_abandon(afs_vlocation_t *vlocation,
+ afs_vlocation_upd_t state,
+ int ret)
+{
+ _enter("%s,%u",vlocation->vldb.name,state);
+
+ if (ret<0)
+ printk("kAFS: Abandoning VL update '%s': %d\n",vlocation->vldb.name,ret);
+
+ /* discard the server record */
+ if (vlocation->upd_op.server) {
+ afs_put_server(vlocation->upd_op.server);
+ vlocation->upd_op.server = NULL;
+ }
+
+ spin_lock(&afs_vlocation_update_lock);
+ afs_vlocation_update = NULL;
+ vlocation->upd_state = state;
+
+ /* TODO: start updating next VL record on pending list */
+
+ spin_unlock(&afs_vlocation_update_lock);
+
+ _leave("");
+} /* end afs_vlocation_update_abandon() */
+
+/*****************************************************************************/
+/*
+ * handle periodic update timeouts and busy retry timeouts
+ * - called from kafstimod
+ */
+static void afs_vlocation_update_timer(afs_timer_t *timer)
+{
+ afs_vlocation_t *vlocation = list_entry(timer,afs_vlocation_t,upd_timer);
+ int ret;
+
+ _enter("%s",vlocation->vldb.name);
+
+ /* only update if not in the graveyard (defend against putting too) */
+ spin_lock(&vlocation->cell->vl_gylock);
+
+ if (!atomic_read(&vlocation->usage))
+ goto out_unlock1;
+
+ spin_lock(&afs_vlocation_update_lock);
+
+ /* if we were woken up due to EBUSY sleep then restart immediately if possible or else jump
+ * to front of pending queue */
+ if (vlocation->upd_state==AFS_VLUPD_BUSYSLEEP) {
+ if (afs_vlocation_update) {
+ list_add(&vlocation->upd_op.link,&afs_vlocation_update_pendq);
+ }
+ else {
+ afs_get_vlocation(vlocation);
+ afs_vlocation_update = vlocation;
+ vlocation->upd_state = AFS_VLUPD_INPROGRESS;
+ }
+ goto out_unlock2;
+ }
+
+ /* put on pending queue if there's already another update in progress */
+ if (afs_vlocation_update) {
+ vlocation->upd_state = AFS_VLUPD_PENDING;
+ list_add_tail(&vlocation->upd_op.link,&afs_vlocation_update_pendq);
+ goto out_unlock2;
+ }
+
+ /* hold a ref on it while actually updating */
+ afs_get_vlocation(vlocation);
+ afs_vlocation_update = vlocation;
+ vlocation->upd_state = AFS_VLUPD_INPROGRESS;
+
+ spin_unlock(&afs_vlocation_update_lock);
+ spin_unlock(&vlocation->cell->vl_gylock);
+
+ /* okay... we can start the update */
+ _debug("BEGIN VL UPDATE [%s]",vlocation->vldb.name);
+ vlocation->upd_first_svix = vlocation->cell->vl_curr_svix;
+ vlocation->upd_curr_svix = vlocation->upd_first_svix;
+ vlocation->upd_rej_cnt = 0;
+ vlocation->upd_busy_cnt = 0;
+
+ ret = afs_vlocation_update_begin(vlocation);
+ if (ret<0) {
+ afs_vlocation_update_abandon(vlocation,AFS_VLUPD_SLEEP,ret);
+ afs_kafstimod_add_timer(&vlocation->upd_timer,AFS_VLDB_TIMEOUT);
+ afs_put_vlocation(vlocation);
+ }
+
+ _leave("");
+ return;
+
+ out_unlock2:
+ spin_unlock(&afs_vlocation_update_lock);
+ out_unlock1:
+ spin_unlock(&vlocation->cell->vl_gylock);
+ _leave("");
+ return;
+
+} /* end afs_vlocation_update_timer() */
+
+/*****************************************************************************/
+/*
+ * attend to an update operation upon which an event happened
+ * - called in kafsasyncd context
+ */
+static void afs_vlocation_update_attend(afs_async_op_t *op)
+{
+ afsc_vldb_record_t vldb;
+ afs_vlocation_t *vlocation = list_entry(op,afs_vlocation_t,upd_op);
+ unsigned tmp;
+ int ret;
+
+ _enter("%s",vlocation->vldb.name);
+
+ ret = afs_rxvl_get_entry_by_id_async2(op,&vldb);
+ switch (ret) {
+ case -EAGAIN:
+ _leave(" [unfinished]");
+ return;
+
+ case 0:
+ _debug("END VL UPDATE: %d\n",ret);
+ vlocation->valid = 1;
+
+ _debug("Done VL Lookup: %02x { %08x(%x) %08x(%x) %08x(%x) }",
+ vldb.vidmask,
+ ntohl(vldb.servers[0].s_addr),vldb.srvtmask[0],
+ ntohl(vldb.servers[1].s_addr),vldb.srvtmask[1],
+ ntohl(vldb.servers[2].s_addr),vldb.srvtmask[2]
+ );
+
+ _debug("Vids: %08x %08x %08x",vldb.vid[0],vldb.vid[1],vldb.vid[2]);
+
+ afs_vlocation_update_abandon(vlocation,AFS_VLUPD_SLEEP,0);
+
+ down_write(&vlocation->cell->vl_sem);
+
+ /* actually update the cache */
+ if (strncmp(vldb.name,vlocation->vldb.name,sizeof(vlocation->vldb.name))!=0)
+ printk("kAFS: name of volume '%s' changed to '%s' on server\n",
+ vlocation->vldb.name,vldb.name);
+
+ memcpy(&vlocation->vldb,&vldb,sizeof(vlocation->vldb));
+
+#if 0
+ /* add volume entry to local cache */
+ ret = afsc_update_vlocation(vlocation);
+#endif
+
+ up_write(&vlocation->cell->vl_sem);
+
+ if (ret<0)
+ printk("kAFS: failed to update local cache: %d\n",ret);
+
+ afs_kafstimod_add_timer(&vlocation->upd_timer,AFS_VLDB_TIMEOUT);
+ afs_put_vlocation(vlocation);
+ _leave(" [found]");
+ return;
+
+ case -ENOMEDIUM:
+ vlocation->upd_rej_cnt++;
+ goto try_next;
+
+ /* the server is locked - retry in a very short while */
+ case -EBUSY:
+ vlocation->upd_busy_cnt++;
+ if (vlocation->upd_busy_cnt>3)
+ goto try_next; /* too many retries */
+
+ afs_vlocation_update_abandon(vlocation,AFS_VLUPD_BUSYSLEEP,0);
+ afs_kafstimod_add_timer(&vlocation->upd_timer,HZ/2);
+ afs_put_vlocation(vlocation);
+ _leave(" [busy]");
+ return;
+
+ case -ENETUNREACH:
+ case -EHOSTUNREACH:
+ case -ECONNREFUSED:
+ case -EREMOTEIO:
+ /* record bad vlserver info in the cell too
+ * - TODO: use down_write_trylock() if available
+ */
+ if (vlocation->upd_curr_svix == vlocation->cell->vl_curr_svix)
+ vlocation->cell->vl_curr_svix =
+ vlocation->cell->vl_curr_svix % vlocation->cell->vl_naddrs;
+
+ case -EBADRQC:
+ case -EINVAL:
+ case -EACCES:
+ case -EBADMSG:
+ goto try_next;
+
+ default:
+ goto abandon;
+ }
+
+ /* try contacting the next server */
+ try_next:
+ vlocation->upd_busy_cnt = 0;
+
+ if (vlocation->upd_op.server) {
+ /* discard the server record */
+ afs_put_server(vlocation->upd_op.server);
+ vlocation->upd_op.server = NULL;
+ }
+
+ tmp = vlocation->cell->vl_naddrs;
+ if (tmp==0)
+ goto abandon;
+
+ vlocation->upd_curr_svix++;
+ if (vlocation->upd_curr_svix >= tmp) vlocation->upd_curr_svix = 0;
+ if (vlocation->upd_first_svix >= tmp) vlocation->upd_first_svix = tmp - 1;
+
+ /* move to the next server */
+ if (vlocation->upd_curr_svix!=vlocation->upd_first_svix) {
+ afs_vlocation_update_begin(vlocation);
+ _leave(" [next]");
+ return;
+ }
+
+ /* run out of servers to try - was the volume rejected? */
+ if (vlocation->upd_rej_cnt>0) {
+ printk("kAFS: Active volume no longer valid '%s'\n",vlocation->vldb.name);
+ vlocation->valid = 0;
+ afs_vlocation_update_abandon(vlocation,AFS_VLUPD_SLEEP,0);
+ afs_kafstimod_add_timer(&vlocation->upd_timer,AFS_VLDB_TIMEOUT);
+ afs_put_vlocation(vlocation);
+ _leave(" [invalidated]");
+ return;
+ }
+
+ /* abandon the update */
+ abandon:
+ afs_vlocation_update_abandon(vlocation,AFS_VLUPD_SLEEP,ret);
+ afs_kafstimod_add_timer(&vlocation->upd_timer,HZ*10);
+ afs_put_vlocation(vlocation);
+ _leave(" [abandoned]");
+
+} /* end afs_vlocation_update_attend() */
+
+/*****************************************************************************/
+/*
+ * deal with an update operation being discarded
+ * - called in kafsasyncd context when it's dying due to rmmod
+ * - the call has already been aborted and put()'d
+ */
+static void afs_vlocation_update_discard(afs_async_op_t *op)
+{
+ afs_vlocation_t *vlocation = list_entry(op,afs_vlocation_t,upd_op);
+
+ _enter("%s",vlocation->vldb.name);
+
+ afs_put_server(op->server);
+ op->server = NULL;
+
+ afs_put_vlocation(vlocation);
+
+ _leave("");
+} /* end afs_vlocation_update_discard() */
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c
new file mode 100644
index 000000000000..ab2d7b241fc3
--- /dev/null
+++ b/fs/afs/vnode.c
@@ -0,0 +1,316 @@
+/* vnode.c: AFS vnode management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "volume.h"
+#include "cell.h"
+#include "cmservice.h"
+#include "fsclient.h"
+#include "vlclient.h"
+#include "vnode.h"
+#include "internal.h"
+
+static void afs_vnode_cb_timed_out(struct afs_timer *timer);
+
+struct afs_timer_ops afs_vnode_cb_timed_out_ops = {
+ .timed_out = afs_vnode_cb_timed_out,
+};
+
+/*****************************************************************************/
+/*
+ * handle a callback timing out
+ * TODO: retain a ref to vnode struct for an outstanding callback timeout
+ */
+static void afs_vnode_cb_timed_out(struct afs_timer *timer)
+{
+ afs_server_t *oldserver;
+ afs_vnode_t *vnode;
+
+ vnode = list_entry(timer,afs_vnode_t,cb_timeout);
+
+ _enter("%p",vnode);
+
+ /* set the changed flag in the vnode and release the server */
+ spin_lock(&vnode->lock);
+
+ oldserver = xchg(&vnode->cb_server,NULL);
+ if (oldserver) {
+ vnode->flags |= AFS_VNODE_CHANGED;
+
+ spin_lock(&afs_cb_hash_lock);
+ list_del_init(&vnode->cb_hash_link);
+ spin_unlock(&afs_cb_hash_lock);
+
+ spin_lock(&oldserver->cb_lock);
+ list_del_init(&vnode->cb_link);
+ spin_unlock(&oldserver->cb_lock);
+ }
+
+ spin_unlock(&vnode->lock);
+
+ if (oldserver)
+ afs_put_server(oldserver);
+
+ _leave("");
+} /* end afs_vnode_cb_timed_out() */
+
+/*****************************************************************************/
+/*
+ * finish off updating the recorded status of a file
+ * - starts callback expiry timer
+ * - adds to server's callback list
+ */
+void afs_vnode_finalise_status_update(afs_vnode_t *vnode, afs_server_t *server, int ret)
+{
+ afs_server_t *oldserver = NULL;
+
+ _enter("%p,%p,%d",vnode,server,ret);
+
+ spin_lock(&vnode->lock);
+
+ vnode->flags &= ~AFS_VNODE_CHANGED;
+
+ if (ret==0) {
+ /* adjust the callback timeout appropriately */
+ afs_kafstimod_add_timer(&vnode->cb_timeout,vnode->cb_expiry*HZ);
+
+ spin_lock(&afs_cb_hash_lock);
+ list_del(&vnode->cb_hash_link);
+ list_add_tail(&vnode->cb_hash_link,&afs_cb_hash(server,&vnode->fid));
+ spin_unlock(&afs_cb_hash_lock);
+
+ /* swap ref to old callback server with that for new callback server */
+ oldserver = xchg(&vnode->cb_server,server);
+ if (oldserver!=server) {
+ if (oldserver) {
+ spin_lock(&oldserver->cb_lock);
+ list_del_init(&vnode->cb_link);
+ spin_unlock(&oldserver->cb_lock);
+ }
+
+ afs_get_server(server);
+ spin_lock(&server->cb_lock);
+ list_add_tail(&vnode->cb_link,&server->cb_promises);
+ spin_unlock(&server->cb_lock);
+ }
+ else {
+ /* same server */
+ oldserver = NULL;
+ }
+ }
+ else if (ret==-ENOENT) {
+ /* the file was deleted - clear the callback timeout */
+ oldserver = xchg(&vnode->cb_server,NULL);
+ afs_kafstimod_del_timer(&vnode->cb_timeout);
+
+ _debug("got NOENT from server - marking file deleted");
+ vnode->flags |= AFS_VNODE_DELETED;
+ }
+
+ vnode->update_cnt--;
+
+ spin_unlock(&vnode->lock);
+
+ wake_up_all(&vnode->update_waitq);
+
+ if (oldserver)
+ afs_put_server(oldserver);
+
+ _leave("");
+
+} /* end afs_vnode_finalise_status_update() */
+
+/*****************************************************************************/
+/*
+ * fetch file status from the volume
+ * - don't issue a fetch if:
+ * - the changed bit is not set and there's a valid callback
+ * - there are any outstanding ops that will fetch the status
+ * - TODO implement local caching
+ */
+int afs_vnode_fetch_status(afs_vnode_t *vnode)
+{
+ afs_server_t *server;
+ int ret;
+
+ DECLARE_WAITQUEUE(myself,current);
+
+ _enter("%s,{%u,%u,%u}",vnode->volume->vlocation->vldb.name,
+ vnode->fid.vid,vnode->fid.vnode,vnode->fid.unique);
+
+ if (!(vnode->flags & AFS_VNODE_CHANGED) && vnode->cb_server) {
+ _leave(" [unchanged]");
+ return 0;
+ }
+
+ if (vnode->flags & AFS_VNODE_DELETED) {
+ _leave(" [deleted]");
+ return -ENOENT;
+ }
+
+ spin_lock(&vnode->lock);
+
+ if (!(vnode->flags & AFS_VNODE_CHANGED)) {
+ spin_unlock(&vnode->lock);
+ _leave(" [unchanged]");
+ return 0;
+ }
+
+ if (vnode->update_cnt>0) {
+ /* someone else started a fetch */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&vnode->update_waitq,&myself);
+
+ /* wait for the status to be updated */
+ for (;;) {
+ if (!(vnode->flags & AFS_VNODE_CHANGED)) break;
+ if (vnode->flags & AFS_VNODE_DELETED) break;
+
+ /* it got updated and invalidated all before we saw it */
+ if (vnode->update_cnt==0) {
+ remove_wait_queue(&vnode->update_waitq,&myself);
+ set_current_state(TASK_RUNNING);
+ goto get_anyway;
+ }
+
+ spin_unlock(&vnode->lock);
+
+ schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+
+ spin_lock(&vnode->lock);
+ }
+
+ remove_wait_queue(&vnode->update_waitq,&myself);
+ spin_unlock(&vnode->lock);
+ set_current_state(TASK_RUNNING);
+
+ return vnode->flags & AFS_VNODE_DELETED ? -ENOENT : 0;
+ }
+
+ get_anyway:
+ /* okay... we're going to have to initiate the op */
+ vnode->update_cnt++;
+
+ spin_unlock(&vnode->lock);
+
+ /* merge AFS status fetches and clear outstanding callback on this vnode */
+ do {
+ /* pick a server to query */
+ ret = afs_volume_pick_fileserver(vnode->volume,&server);
+ if (ret<0)
+ return ret;
+
+ _debug("USING SERVER: %08x\n",ntohl(server->addr.s_addr));
+
+ ret = afs_rxfs_fetch_file_status(server,vnode,NULL);
+
+ } while (!afs_volume_release_fileserver(vnode->volume,server,ret));
+
+ /* adjust the flags */
+ afs_vnode_finalise_status_update(vnode,server,ret);
+
+ _leave(" = %d",ret);
+ return ret;
+} /* end afs_vnode_fetch_status() */
+
+/*****************************************************************************/
+/*
+ * fetch file data from the volume
+ * - TODO implement caching and server failover
+ */
+int afs_vnode_fetch_data(afs_vnode_t *vnode, struct afs_rxfs_fetch_descriptor *desc)
+{
+ afs_server_t *server;
+ int ret;
+
+ _enter("%s,{%u,%u,%u}",
+ vnode->volume->vlocation->vldb.name,
+ vnode->fid.vid,
+ vnode->fid.vnode,
+ vnode->fid.unique);
+
+ /* this op will fetch the status */
+ spin_lock(&vnode->lock);
+ vnode->update_cnt++;
+ spin_unlock(&vnode->lock);
+
+ /* merge in AFS status fetches and clear outstanding callback on this vnode */
+ do {
+ /* pick a server to query */
+ ret = afs_volume_pick_fileserver(vnode->volume,&server);
+ if (ret<0)
+ return ret;
+
+ _debug("USING SERVER: %08x\n",ntohl(server->addr.s_addr));
+
+ ret = afs_rxfs_fetch_file_data(server,vnode,desc,NULL);
+
+ } while (!afs_volume_release_fileserver(vnode->volume,server,ret));
+
+ /* adjust the flags */
+ afs_vnode_finalise_status_update(vnode,server,ret);
+
+ _leave(" = %d",ret);
+ return ret;
+
+} /* end afs_vnode_fetch_data() */
+
+/*****************************************************************************/
+/*
+ * break any outstanding callback on a vnode
+ * - only relevent to server that issued it
+ */
+int afs_vnode_give_up_callback(afs_vnode_t *vnode)
+{
+ afs_server_t *server;
+ int ret;
+
+ _enter("%s,{%u,%u,%u}",
+ vnode->volume->vlocation->vldb.name,
+ vnode->fid.vid,
+ vnode->fid.vnode,
+ vnode->fid.unique);
+
+ spin_lock(&afs_cb_hash_lock);
+ list_del_init(&vnode->cb_hash_link);
+ spin_unlock(&afs_cb_hash_lock);
+
+ /* set the changed flag in the vnode and release the server */
+ spin_lock(&vnode->lock);
+
+ afs_kafstimod_del_timer(&vnode->cb_timeout);
+
+ server = xchg(&vnode->cb_server,NULL);
+ if (server) {
+ vnode->flags |= AFS_VNODE_CHANGED;
+
+ spin_lock(&server->cb_lock);
+ list_del_init(&vnode->cb_link);
+ spin_unlock(&server->cb_lock);
+ }
+
+ spin_unlock(&vnode->lock);
+
+ ret = 0;
+ if (server) {
+ ret = afs_rxfs_give_up_callback(server,vnode);
+ afs_put_server(server);
+ }
+
+ _leave(" = %d",ret);
+ return ret;
+} /* end afs_vnode_give_up_callback() */
diff --git a/fs/afs/vnode.h b/fs/afs/vnode.h
new file mode 100644
index 000000000000..ec2c412c4214
--- /dev/null
+++ b/fs/afs/vnode.h
@@ -0,0 +1,88 @@
+/* vnode.h: AFS vnode record
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_VNODE_H
+#define _LINUX_AFS_VNODE_H
+
+#include <linux/fs.h>
+#include <linux/version.h>
+#include "server.h"
+#include "kafstimod.h"
+
+#ifdef __KERNEL__
+
+struct afs_rxfs_fetch_descriptor;
+
+/*****************************************************************************/
+/*
+ * AFS inode private data
+ */
+struct afs_vnode
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ struct inode vfs_inode; /* the VFS's inode record */
+#else
+ struct inode *inode; /* the VFS's inode */
+#endif
+
+ afs_volume_t *volume; /* volume on which vnode resides */
+ afs_fid_t fid; /* the file identifier for this inode */
+ afs_file_status_t status; /* AFS status info for this file */
+ unsigned nix; /* vnode index in cache */
+
+ wait_queue_head_t update_waitq; /* status fetch waitqueue */
+ unsigned update_cnt; /* number of outstanding ops that will update the
+ * status */
+ spinlock_t lock; /* waitqueue/flags lock */
+ unsigned flags;
+#define AFS_VNODE_CHANGED 0x00000001 /* set if vnode reported changed by callback */
+#define AFS_VNODE_DELETED 0x00000002 /* set if vnode deleted on server */
+#define AFS_VNODE_MOUNTPOINT 0x00000004 /* set if vnode is a mountpoint symlink */
+
+ /* outstanding callback notification on this file */
+ afs_server_t *cb_server; /* server that made the current promise */
+ struct list_head cb_link; /* link in server's promises list */
+ struct list_head cb_hash_link; /* link in master callback hash */
+ afs_timer_t cb_timeout; /* timeout on promise */
+ unsigned cb_version; /* callback version */
+ unsigned cb_expiry; /* callback expiry time */
+ afs_callback_type_t cb_type; /* type of callback */
+};
+
+static inline afs_vnode_t *AFS_FS_I(struct inode *inode)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ return list_entry(inode,afs_vnode_t,vfs_inode);
+#else
+ return inode->u.generic_ip;
+#endif
+}
+
+static inline struct inode *AFS_VNODE_TO_I(afs_vnode_t *vnode)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+ return &vnode->vfs_inode;
+#else
+ return vnode->inode;
+#endif
+}
+
+extern int afs_vnode_fetch_status(afs_vnode_t *vnode);
+
+extern int afs_vnode_fetch_data(afs_vnode_t *vnode, struct afs_rxfs_fetch_descriptor *desc);
+
+extern int afs_vnode_give_up_callback(afs_vnode_t *vnode);
+
+extern struct afs_timer_ops afs_vnode_cb_timed_out_ops;
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_AFS_VNODE_H */
diff --git a/fs/afs/volume.c b/fs/afs/volume.c
new file mode 100644
index 000000000000..198c355c715b
--- /dev/null
+++ b/fs/afs/volume.c
@@ -0,0 +1,430 @@
+/* volume.c: AFS volume management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "volume.h"
+#include "cell.h"
+#include "cmservice.h"
+#include "fsclient.h"
+#include "vlclient.h"
+#include "internal.h"
+
+const char *afs_voltypes[] = { "R/W", "R/O", "BAK" };
+
+/*****************************************************************************/
+/*
+ * lookup a volume by name
+ * - this can be one of the following:
+ * "%[cell:]volume[.]" R/W volume
+ * "#[cell:]volume[.]" R/O or R/W volume (rwparent=0), or R/W (rwparent=1) volume
+ * "%[cell:]volume.readonly" R/O volume
+ * "#[cell:]volume.readonly" R/O volume
+ * "%[cell:]volume.backup" Backup volume
+ * "#[cell:]volume.backup" Backup volume
+ *
+ * The cell name is optional, and defaults to the current cell.
+ *
+ * See "The Rules of Mount Point Traversal" in Chapter 5 of the AFS SysAdmin Guide
+ * - Rule 1: Explicit type suffix forces access of that type or nothing
+ * (no suffix, then use Rule 2 & 3)
+ * - Rule 2: If parent volume is R/O, then mount R/O volume by preference, R/W if not available
+ * - Rule 3: If parent volume is R/W, then only mount R/W volume unless explicitly told otherwise
+ */
+int afs_volume_lookup(char *name, int rwparent, afs_volume_t **_volume)
+{
+ afs_vlocation_t *vlocation = NULL;
+ afs_voltype_t type;
+ afs_volume_t *volume = NULL;
+ afs_cell_t *cell = NULL;
+ char *cellname, *volname, *suffix;
+ char srvtmask;
+ int force, ret, loop;
+
+ _enter(",%s,",name);
+
+ if (!name || (name[0]!='%' && name[0]!='#') || !name[1]) {
+ printk("kAFS: unparsable volume name\n");
+ return -EINVAL;
+ }
+
+ /* determine the type of volume we're looking for */
+ force = 0;
+ type = AFSVL_ROVOL;
+
+ if (rwparent || name[0]=='%') {
+ type = AFSVL_RWVOL;
+ force = 1;
+ }
+
+ suffix = strrchr(name,'.');
+ if (suffix) {
+ if (strcmp(suffix,".readonly")==0) {
+ type = AFSVL_ROVOL;
+ force = 1;
+ }
+ else if (strcmp(suffix,".backup")==0) {
+ type = AFSVL_BACKVOL;
+ force = 1;
+ }
+ else if (suffix[1]==0) {
+ *suffix = 0;
+ suffix = NULL;
+ }
+ else {
+ suffix = NULL;
+ }
+ }
+
+ /* split the cell and volume names */
+ name++;
+ volname = strchr(name,':');
+ if (volname) {
+ *volname++ = 0;
+ cellname = name;
+ }
+ else {
+ volname = name;
+ cellname = NULL;
+ }
+
+ _debug("CELL:%s VOLUME:%s SUFFIX:%s TYPE:%d%s",
+ cellname,volname,suffix?:"-",type,force?" FORCE":"");
+
+ /* lookup the cell record */
+ ret = afs_cell_lookup(cellname,&cell);
+ if (ret<0)
+ printk("kAFS: unable to lookup cell '%s'\n",cellname?:"");
+
+ if (cellname) volname[-1] = ':';
+ if (ret<0)
+ goto error;
+
+ /* lookup the volume location record */
+ if (suffix) *suffix = 0;
+ ret = afs_vlocation_lookup(cell,volname,&vlocation);
+ if (suffix) *suffix = '.';
+ if (ret<0)
+ goto error;
+
+ /* make the final decision on the type we want */
+ ret = -ENOMEDIUM;
+ if (force && !(vlocation->vldb.vidmask & (1<<type)))
+ goto error;
+
+ srvtmask = 0;
+ for (loop=0; loop<vlocation->vldb.nservers; loop++)
+ srvtmask |= vlocation->vldb.srvtmask[loop];
+
+ if (force) {
+ if (!(srvtmask & (1 <<type)))
+ goto error;
+ }
+ else if (srvtmask & AFSC_VOL_STM_RO) {
+ type = AFSVL_ROVOL;
+ }
+ else if (srvtmask & AFSC_VOL_STM_RW) {
+ type = AFSVL_RWVOL;
+ }
+ else {
+ goto error;
+ }
+
+ down_write(&cell->vl_sem);
+
+ /* is the volume already active? */
+ if (vlocation->vols[type]) {
+ /* yes - re-use it */
+ volume = vlocation->vols[type];
+ afs_get_volume(volume);
+ goto success;
+ }
+
+ /* create a new volume record */
+ _debug("creating new volume record");
+
+ ret = -ENOMEM;
+ volume = kmalloc(sizeof(afs_volume_t),GFP_KERNEL);
+ if (!volume)
+ goto error_up;
+
+ memset(volume,0,sizeof(afs_volume_t));
+ atomic_set(&volume->usage,1);
+ volume->type = type;
+ volume->type_force = force;
+ volume->cell = cell;
+ volume->vid = vlocation->vldb.vid[type];
+
+ init_rwsem(&volume->server_sem);
+
+ /* look up all the applicable server records */
+ for (loop=0; loop<8; loop++) {
+ if (vlocation->vldb.srvtmask[loop] & (1 << volume->type)) {
+ ret = afs_server_lookup(volume->cell,
+ &vlocation->vldb.servers[loop],
+ &volume->servers[volume->nservers]);
+ if (ret<0)
+ goto error_discard;
+
+ volume->nservers++;
+ }
+ }
+
+ /* attach the cache and volume location */
+#if 0
+ afs_get_cache(cache); volume->cache = cache;
+#endif
+ afs_get_vlocation(vlocation); volume->vlocation = vlocation;
+
+ vlocation->vols[type] = volume;
+
+ success:
+ _debug("kAFS selected %s volume %08x",afs_voltypes[volume->type],volume->vid);
+ *_volume = volume;
+ ret = 0;
+
+ /* clean up */
+ error_up:
+ up_write(&cell->vl_sem);
+ error:
+ if (vlocation) afs_put_vlocation(vlocation);
+ if (cell) afs_put_cell(cell);
+
+ _leave(" = %d (%p)",ret,volume);
+ return ret;
+
+ error_discard:
+ up_write(&cell->vl_sem);
+
+ for (loop=volume->nservers-1; loop>=0; loop--)
+ if (volume->servers[loop])
+ afs_put_server(volume->servers[loop]);
+
+ kfree(volume);
+ goto error;
+} /* end afs_volume_lookup() */
+
+/*****************************************************************************/
+/*
+ * destroy a volume record
+ */
+void afs_put_volume(afs_volume_t *volume)
+{
+ afs_vlocation_t *vlocation;
+ int loop;
+
+ _enter("%p",volume);
+
+ vlocation = volume->vlocation;
+
+ /* sanity check */
+ if (atomic_read(&volume->usage)<=0)
+ BUG();
+
+ /* to prevent a race, the decrement and the dequeue must be effectively atomic */
+ down_write(&vlocation->cell->vl_sem);
+
+ if (likely(!atomic_dec_and_test(&volume->usage))) {
+ up_write(&vlocation->cell->vl_sem);
+ _leave("");
+ return;
+ }
+
+ vlocation->vols[volume->type] = NULL;
+
+ up_write(&vlocation->cell->vl_sem);
+
+ afs_put_vlocation(vlocation);
+
+ /* finish cleaning up the volume */
+#if 0
+ if (volume->cache) afs_put_cache(volume->cache);
+#endif
+
+ for (loop=volume->nservers-1; loop>=0; loop--)
+ if (volume->servers[loop])
+ afs_put_server(volume->servers[loop]);
+
+ kfree(volume);
+
+ _leave(" [destroyed]");
+} /* end afs_put_volume() */
+
+/*****************************************************************************/
+/*
+ * pick a server to use to try accessing this volume
+ * - returns with an elevated usage count on the server chosen
+ */
+int afs_volume_pick_fileserver(afs_volume_t *volume, afs_server_t **_server)
+{
+ afs_server_t *server;
+ int ret, state, loop;
+
+ _enter("%s",volume->vlocation->vldb.name);
+
+ down_read(&volume->server_sem);
+
+ /* handle the no-server case */
+ if (volume->nservers==0) {
+ ret = volume->rjservers ? -ENOMEDIUM : -ESTALE;
+ up_read(&volume->server_sem);
+ _leave(" = %d [no servers]",ret);
+ return ret;
+ }
+
+ /* basically, just search the list for the first live server and use that */
+ ret = 0;
+ for (loop=0; loop<volume->nservers; loop++) {
+ server = volume->servers[loop];
+ state = server->fs_state;
+
+ switch (state) {
+ /* found an apparently healthy server */
+ case 0:
+ afs_get_server(server);
+ up_read(&volume->server_sem);
+ *_server = server;
+ _leave(" = 0 (picked %08x)",ntohl(server->addr.s_addr));
+ return 0;
+
+ case -ENETUNREACH:
+ if (ret==0)
+ ret = state;
+ break;
+
+ case -EHOSTUNREACH:
+ if (ret==0 || ret==-ENETUNREACH)
+ ret = state;
+ break;
+
+ case -ECONNREFUSED:
+ if (ret==0 || ret==-ENETUNREACH || ret==-EHOSTUNREACH)
+ ret = state;
+ break;
+
+ default:
+ case -EREMOTEIO:
+ if (ret==0 ||
+ ret==-ENETUNREACH ||
+ ret==-EHOSTUNREACH ||
+ ret==-ECONNREFUSED)
+ ret = state;
+ break;
+ }
+ }
+
+ /* no available servers
+ * - TODO: handle the no active servers case better
+ */
+ up_read(&volume->server_sem);
+ _leave(" = %d",ret);
+ return ret;
+} /* end afs_volume_pick_fileserver() */
+
+/*****************************************************************************/
+/*
+ * release a server after use
+ * - releases the ref on the server struct that was acquired by picking
+ * - records result of using a particular server to access a volume
+ * - return 0 to try again, 1 if okay or to issue error
+ */
+int afs_volume_release_fileserver(afs_volume_t *volume, afs_server_t *server, int result)
+{
+ unsigned loop;
+
+ _enter("%s,%08x,%d",volume->vlocation->vldb.name,ntohl(server->addr.s_addr),result);
+
+ switch (result) {
+ /* success */
+ case 0:
+ server->fs_act_jif = jiffies;
+ break;
+
+ /* the fileserver denied all knowledge of the volume */
+ case -ENOMEDIUM:
+ server->fs_act_jif = jiffies;
+ down_write(&volume->server_sem);
+
+ /* first, find where the server is in the active list (if it is) */
+ for (loop=0; loop<volume->nservers; loop++)
+ if (volume->servers[loop]==server)
+ goto present;
+
+ /* no longer there - may have been discarded by another op */
+ goto try_next_server_upw;
+
+ present:
+ volume->nservers--;
+ memmove(&volume->servers[loop],
+ &volume->servers[loop+1],
+ sizeof(volume->servers[loop]) * (volume->nservers - loop)
+ );
+ volume->servers[volume->nservers] = NULL;
+ afs_put_server(server);
+ volume->rjservers++;
+
+ if (volume->nservers>0)
+ /* another server might acknowledge its existence */
+ goto try_next_server_upw;
+
+ /* handle the case where all the fileservers have rejected the volume
+ * - TODO: try asking the fileservers for volume information
+ * - TODO: contact the VL server again to see if the volume is no longer registered
+ */
+ up_write(&volume->server_sem);
+ afs_put_server(server);
+ _leave(" [completely rejected]");
+ return 1;
+
+ /* problem reaching the server */
+ case -ENETUNREACH:
+ case -EHOSTUNREACH:
+ case -ECONNREFUSED:
+ case -ETIMEDOUT:
+ case -EREMOTEIO:
+ /* mark the server as dead
+ * TODO: vary dead timeout depending on error
+ */
+ spin_lock(&server->fs_lock);
+ if (!server->fs_state) {
+ server->fs_dead_jif = jiffies + HZ * 10;
+ server->fs_state = result;
+ printk("kAFS: SERVER DEAD state=%d\n",result);
+ }
+ spin_unlock(&server->fs_lock);
+ goto try_next_server;
+
+ /* miscellaneous error */
+ default:
+ server->fs_act_jif = jiffies;
+ case -ENOMEM:
+ case -ENONET:
+ break;
+ }
+
+ /* tell the caller to accept the result */
+ afs_put_server(server);
+ _leave("");
+ return 1;
+
+ /* tell the caller to loop around and try the next server */
+ try_next_server_upw:
+ up_write(&volume->server_sem);
+ try_next_server:
+ afs_put_server(server);
+ _leave(" [try next server]");
+ return 0;
+
+} /* end afs_volume_release_fileserver() */
diff --git a/fs/afs/volume.h b/fs/afs/volume.h
new file mode 100644
index 000000000000..1842d983677f
--- /dev/null
+++ b/fs/afs/volume.h
@@ -0,0 +1,92 @@
+/* volume.h: AFS volume management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_VOLUME_H
+#define _LINUX_AFS_VOLUME_H
+
+#include "types.h"
+#include "fsclient.h"
+#include "kafstimod.h"
+#include "kafsasyncd.h"
+#include "cache-layout.h"
+
+#define __packed __attribute__((packed))
+
+typedef enum {
+ AFS_VLUPD_SLEEP, /* sleeping waiting for update timer to fire */
+ AFS_VLUPD_PENDING, /* on pending queue */
+ AFS_VLUPD_INPROGRESS, /* op in progress */
+ AFS_VLUPD_BUSYSLEEP, /* sleeping because server returned EBUSY */
+
+} __attribute__((packed)) afs_vlocation_upd_t;
+
+/*****************************************************************************/
+/*
+ * AFS volume location record
+ */
+struct afs_vlocation
+{
+ atomic_t usage;
+ struct list_head link; /* link in cell volume location list */
+ afs_timer_t timeout; /* decaching timer */
+ afs_cell_t *cell; /* cell to which volume belongs */
+ struct list_head caches; /* backing caches */
+ afsc_vldb_record_t vldb; /* volume information DB record */
+ struct afs_volume *vols[3]; /* volume access record pointer (index by type) */
+ rwlock_t lock; /* access lock */
+ unsigned long read_jif; /* time at which last read from vlserver */
+ afs_timer_t upd_timer; /* update timer */
+ afs_async_op_t upd_op; /* update operation */
+ afs_vlocation_upd_t upd_state; /* update state */
+ unsigned short upd_first_svix; /* first server index during update */
+ unsigned short upd_curr_svix; /* current server index during update */
+ unsigned short upd_rej_cnt; /* ENOMEDIUM count during update */
+ unsigned short upd_busy_cnt; /* EBUSY count during update */
+ unsigned short valid; /* T if valid */
+};
+
+extern int afs_vlocation_lookup(afs_cell_t *cell, const char *name, afs_vlocation_t **_vlocation);
+
+#define afs_get_vlocation(V) do { atomic_inc(&(V)->usage); } while(0)
+
+extern void __afs_put_vlocation(afs_vlocation_t *vlocation);
+extern void afs_put_vlocation(afs_vlocation_t *vlocation);
+extern void afs_vlocation_do_timeout(afs_vlocation_t *vlocation);
+
+/*****************************************************************************/
+/*
+ * AFS volume access record
+ */
+struct afs_volume
+{
+ atomic_t usage;
+ afs_cell_t *cell; /* cell to which belongs (unrefd ptr) */
+ afs_vlocation_t *vlocation; /* volume location */
+ afs_volid_t vid; /* volume ID */
+ afs_voltype_t __packed type; /* type of volume */
+ char type_force; /* force volume type (suppress R/O -> R/W) */
+ unsigned short nservers; /* number of server slots filled */
+ unsigned short rjservers; /* number of servers discarded due to -ENOMEDIUM */
+ afs_server_t *servers[8]; /* servers on which volume resides (ordered) */
+ struct rw_semaphore server_sem; /* lock for accessing current server */
+};
+
+extern int afs_volume_lookup(char *name, int ro, afs_volume_t **_volume);
+
+#define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0)
+
+extern void afs_put_volume(afs_volume_t *volume);
+
+extern int afs_volume_pick_fileserver(afs_volume_t *volume, afs_server_t **_server);
+
+extern int afs_volume_release_fileserver(afs_volume_t *volume, afs_server_t *server, int result);
+
+#endif /* _LINUX_AFS_VOLUME_H */
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 33fc669b7842..1ad7f467993b 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -526,8 +526,6 @@ int check_disk_change(struct block_device *bdev)
{
struct block_device_operations * bdops = bdev->bd_op;
kdev_t dev = to_kdev_t(bdev->bd_dev);
- struct gendisk *disk;
- int part;
if (bdops->check_media_change == NULL)
return 0;
@@ -537,10 +535,9 @@ int check_disk_change(struct block_device *bdev)
if (invalidate_device(dev, 0))
printk("VFS: busy inodes on changed media.\n");
- disk = get_gendisk(bdev->bd_dev, &part);
if (bdops->revalidate)
bdops->revalidate(dev);
- if (disk && disk->minor_shift)
+ if (bdev->bd_disk->minors > 1)
bdev->bd_invalidated = 1;
return 1;
}
@@ -548,12 +545,11 @@ int check_disk_change(struct block_device *bdev)
int full_check_disk_change(struct block_device *bdev)
{
int res = 0;
- int n;
if (bdev->bd_contains != bdev)
BUG();
down(&bdev->bd_sem);
if (check_disk_change(bdev)) {
- rescan_partitions(get_gendisk(bdev->bd_dev, &n), bdev);
+ rescan_partitions(bdev->bd_disk, bdev);
res = 1;
}
up(&bdev->bd_sem);
@@ -595,6 +591,8 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
kdev_t dev = to_kdev_t(bdev->bd_dev);
struct module *owner = NULL;
struct block_device_operations *ops, *old;
+ struct gendisk *disk;
+ int part;
lock_kernel();
ops = get_blkfops(major(dev));
@@ -614,33 +612,32 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
if (owner)
__MOD_DEC_USE_COUNT(owner);
}
+ disk = get_gendisk(bdev->bd_dev, &part);
+ if (!disk)
+ goto out1;
if (!bdev->bd_contains) {
- int part;
- struct gendisk *g = get_gendisk(bdev->bd_dev, &part);
bdev->bd_contains = bdev;
- if (g && part) {
- struct block_device *disk;
- disk = bdget(MKDEV(g->major, g->first_minor));
+ if (part) {
+ struct block_device *whole;
+ whole = bdget(MKDEV(disk->major, disk->first_minor));
ret = -ENOMEM;
- if (!disk)
+ if (!whole)
goto out1;
- ret = blkdev_get(disk, file->f_mode, file->f_flags, BDEV_RAW);
+ ret = blkdev_get(whole, file->f_mode, file->f_flags, BDEV_RAW);
if (ret)
goto out1;
- bdev->bd_contains = disk;
+ bdev->bd_contains = whole;
}
}
if (bdev->bd_contains == bdev) {
- int part;
- struct gendisk *g = get_gendisk(bdev->bd_dev, &part);
-
+ if (!bdev->bd_openers)
+ bdev->bd_disk = disk;
if (!bdev->bd_queue) {
struct blk_dev_struct *p = blk_dev + major(dev);
bdev->bd_queue = &p->request_queue;
if (p->queue)
bdev->bd_queue = p->queue(dev);
}
-
if (bdev->bd_op->open) {
ret = bdev->bd_op->open(inode, file);
if (ret)
@@ -648,12 +645,8 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
}
if (!bdev->bd_openers) {
struct backing_dev_info *bdi;
- sector_t sect = 0;
-
bdev->bd_offset = 0;
- if (g)
- sect = get_capacity(g);
- bd_set_size(bdev, (loff_t)sect << 9);
+ bd_set_size(bdev, (loff_t)get_capacity(disk) << 9);
bdi = blk_get_backing_dev_info(bdev);
if (bdi == NULL)
bdi = &default_backing_dev_info;
@@ -661,19 +654,17 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
bdev->bd_inode->i_data.backing_dev_info = bdi;
}
if (bdev->bd_invalidated)
- rescan_partitions(g, bdev);
+ rescan_partitions(disk, bdev);
} else {
down(&bdev->bd_contains->bd_sem);
bdev->bd_contains->bd_part_count++;
if (!bdev->bd_openers) {
- int part;
- struct gendisk *g = get_gendisk(bdev->bd_dev, &part);
struct hd_struct *p;
- p = g->part + part - 1;
+ p = disk->part + part - 1;
inode->i_data.backing_dev_info =
bdev->bd_inode->i_data.backing_dev_info =
bdev->bd_contains->bd_inode->i_data.backing_dev_info;
- if (!p->nr_sects) {
+ if (!(disk->flags & GENHD_FL_UP) || !p->nr_sects) {
bdev->bd_contains->bd_part_count--;
up(&bdev->bd_contains->bd_sem);
ret = -ENXIO;
@@ -682,10 +673,12 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
bdev->bd_queue = bdev->bd_contains->bd_queue;
bdev->bd_offset = p->start_sect;
bd_set_size(bdev, (loff_t) p->nr_sects << 9);
+ bdev->bd_disk = disk;
}
up(&bdev->bd_contains->bd_sem);
}
- bdev->bd_openers++;
+ if (bdev->bd_openers++)
+ put_disk(disk);
up(&bdev->bd_sem);
unlock_kernel();
return 0;
@@ -699,6 +692,7 @@ out2:
}
}
out1:
+ put_disk(disk);
if (!old) {
bdev->bd_op = NULL;
if (owner)
@@ -772,15 +766,18 @@ int blkdev_put(struct block_device *bdev, int kind)
up(&bdev->bd_contains->bd_sem);
}
if (!bdev->bd_openers) {
+ struct gendisk *disk = bdev->bd_disk;
if (bdev->bd_op->owner)
__MOD_DEC_USE_COUNT(bdev->bd_op->owner);
bdev->bd_op = NULL;
bdev->bd_queue = NULL;
+ bdev->bd_disk = NULL;
bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
if (bdev != bdev->bd_contains) {
blkdev_put(bdev->bd_contains, BDEV_RAW);
bdev->bd_contains = NULL;
}
+ put_disk(disk);
}
unlock_kernel();
up(&bdev->bd_sem);
@@ -793,25 +790,6 @@ int blkdev_close(struct inode * inode, struct file * filp)
return blkdev_put(inode->i_bdev, BDEV_FILE);
}
-static int blkdev_reread_part(struct block_device *bdev)
-{
- int part;
- struct gendisk *disk = get_gendisk(bdev->bd_dev, &part);
- int res = 0;
-
- if (!disk || !disk->minor_shift || bdev != bdev->bd_contains)
- return -EINVAL;
- if (part)
- BUG();
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- if (down_trylock(&bdev->bd_sem))
- return -EBUSY;
- res = rescan_partitions(disk, bdev);
- up(&bdev->bd_sem);
- return res;
-}
-
static ssize_t blkdev_file_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{
@@ -820,51 +798,6 @@ static ssize_t blkdev_file_write(struct file *file, const char *buf,
return generic_file_write_nolock(file, &local_iov, 1, ppos);
}
-static int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
- unsigned long arg)
-{
- struct block_device *bdev = inode->i_bdev;
- int ret = -EINVAL;
- switch (cmd) {
- /*
- * deprecated, use the /proc/iosched interface instead
- */
- case BLKELVGET:
- case BLKELVSET:
- ret = -ENOTTY;
- break;
- case BLKRAGET:
- case BLKROGET:
- case BLKBSZGET:
- case BLKSSZGET:
- case BLKFRAGET:
- case BLKSECTGET:
- case BLKRASET:
- case BLKFRASET:
- case BLKBSZSET:
- case BLKPG:
- ret = blk_ioctl(bdev, cmd, arg);
- break;
- case BLKRRPART:
- ret = blkdev_reread_part(bdev);
- break;
- default:
- if (bdev->bd_op->ioctl)
- ret =bdev->bd_op->ioctl(inode, file, cmd, arg);
- if (ret == -EINVAL) {
- switch (cmd) {
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKFLSBUF:
- case BLKROSET:
- ret = blk_ioctl(bdev,cmd,arg);
- break;
- }
- }
- }
- return ret;
-}
-
struct address_space_operations def_blk_aops = {
.readpage = blkdev_readpage,
.writepage = blkdev_writepage,
diff --git a/fs/buffer.c b/fs/buffer.c
index d024b78c3e60..35d43421c3a8 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -811,6 +811,13 @@ int fsync_buffers_list(spinlock_t *lock, struct list_head *list)
if (buffer_dirty(bh)) {
get_bh(bh);
spin_unlock(lock);
+ /*
+ * Ensure any pending I/O completes so that
+ * ll_rw_block() actually writes the current
+ * contents - it is a noop if I/O is still in
+ * flight on potentially older contents.
+ */
+ wait_on_buffer(bh);
ll_rw_block(WRITE, 1, &bh);
brelse(bh);
spin_lock(lock);
diff --git a/fs/dcache.c b/fs/dcache.c
index ef0871dbcdb2..d0fcfeba16ee 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -637,6 +637,7 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
dentry->d_op = NULL;
dentry->d_fsdata = NULL;
dentry->d_mounted = 0;
+ dentry->d_cookie = NULL;
INIT_LIST_HEAD(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_LIST_HEAD(&dentry->d_subdirs);
diff --git a/fs/dcookies.c b/fs/dcookies.c
new file mode 100644
index 000000000000..d589103eb820
--- /dev/null
+++ b/fs/dcookies.c
@@ -0,0 +1,323 @@
+/*
+ * dcookies.c
+ *
+ * Copyright 2002 John Levon <levon@movementarian.org>
+ *
+ * Persistent cookie-path mappings. These are used by
+ * profilers to convert a per-task EIP value into something
+ * non-transitory that can be processed at a later date.
+ * This is done by locking the dentry/vfsmnt pair in the
+ * kernel until released by the tasks needing the persistent
+ * objects. The tag is simply an u32 that refers
+ * to the pair and can be looked up from userspace.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/mount.h>
+#include <linux/dcache.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/dcookies.h>
+#include <asm/uaccess.h>
+
+/* The dcookies are allocated from a kmem_cache and
+ * hashed onto a small number of lists. None of the
+ * code here is particularly performance critical
+ */
+struct dcookie_struct {
+ struct dentry * dentry;
+ struct vfsmount * vfsmnt;
+ struct list_head hash_list;
+};
+
+static LIST_HEAD(dcookie_users);
+static DECLARE_MUTEX(dcookie_sem);
+static kmem_cache_t * dcookie_cache;
+static struct list_head * dcookie_hashtable;
+static size_t hash_size;
+
+static inline int is_live(void)
+{
+ return !(list_empty(&dcookie_users));
+}
+
+
+/* The dentry is locked, its address will do for the cookie */
+static inline u32 dcookie_value(struct dcookie_struct * dcs)
+{
+ return (u32)dcs->dentry;
+}
+
+
+static size_t dcookie_hash(u32 dcookie)
+{
+ return (dcookie >> 2) & (hash_size - 1);
+}
+
+
+static struct dcookie_struct * find_dcookie(u32 dcookie)
+{
+ struct dcookie_struct * found = 0;
+ struct dcookie_struct * dcs;
+ struct list_head * pos;
+ struct list_head * list;
+
+ list = dcookie_hashtable + dcookie_hash(dcookie);
+
+ list_for_each(pos, list) {
+ dcs = list_entry(pos, struct dcookie_struct, hash_list);
+ if (dcookie_value(dcs) == dcookie) {
+ found = dcs;
+ break;
+ }
+ }
+
+ return found;
+}
+
+
+static void hash_dcookie(struct dcookie_struct * dcs)
+{
+ struct list_head * list = dcookie_hashtable + dcookie_hash(dcookie_value(dcs));
+ list_add(&dcs->hash_list, list);
+}
+
+
+static struct dcookie_struct * alloc_dcookie(struct dentry * dentry,
+ struct vfsmount * vfsmnt)
+{
+ struct dcookie_struct * dcs = kmem_cache_alloc(dcookie_cache, GFP_KERNEL);
+ if (!dcs)
+ return NULL;
+
+ atomic_inc(&dentry->d_count);
+ atomic_inc(&vfsmnt->mnt_count);
+ dentry->d_cookie = dcs;
+
+ dcs->dentry = dentry;
+ dcs->vfsmnt = vfsmnt;
+ hash_dcookie(dcs);
+
+ return dcs;
+}
+
+
+/* This is the main kernel-side routine that retrieves the cookie
+ * value for a dentry/vfsmnt pair.
+ */
+int get_dcookie(struct dentry * dentry, struct vfsmount * vfsmnt,
+ u32 * cookie)
+{
+ int err = 0;
+ struct dcookie_struct * dcs;
+
+ down(&dcookie_sem);
+
+ if (!is_live()) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ dcs = dentry->d_cookie;
+
+ if (!dcs)
+ dcs = alloc_dcookie(dentry, vfsmnt);
+
+ if (!dcs) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ *cookie = dcookie_value(dcs);
+
+out:
+ up(&dcookie_sem);
+ return err;
+}
+
+
+/* And here is where the userspace process can look up the cookie value
+ * to retrieve the path.
+ */
+asmlinkage int sys_lookup_dcookie(u32 cookie, char * buf, size_t len)
+{
+ char * kbuf;
+ char * path;
+ int err = -EINVAL;
+ size_t pathlen;
+ struct dcookie_struct * dcs;
+
+ /* we could leak path information to users
+ * without dir read permission without this
+ */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ down(&dcookie_sem);
+
+ if (!is_live()) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (!(dcs = find_dcookie(cookie)))
+ goto out;
+
+ err = -ENOMEM;
+ kbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!kbuf)
+ goto out;
+ memset(kbuf, 0, PAGE_SIZE);
+
+ /* FIXME: (deleted) ? */
+ path = d_path(dcs->dentry, dcs->vfsmnt, kbuf, PAGE_SIZE);
+
+ err = 0;
+
+ pathlen = kbuf + PAGE_SIZE - path;
+ if (len > pathlen)
+ len = pathlen;
+
+ if (copy_to_user(buf, path, len))
+ err = -EFAULT;
+
+ kfree(kbuf);
+out:
+ up(&dcookie_sem);
+ return err;
+}
+
+
+static int dcookie_init(void)
+{
+ struct list_head * d;
+ unsigned int i, hash_bits;
+ int err = -ENOMEM;
+
+ dcookie_cache = kmem_cache_create("dcookie_cache",
+ sizeof(struct dcookie_struct),
+ 0, 0, NULL, NULL);
+
+ if (!dcookie_cache)
+ goto out;
+
+ dcookie_hashtable = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!dcookie_hashtable)
+ goto out_kmem;
+
+ err = 0;
+
+ /*
+ * Find the power-of-two list-heads that can fit into the allocation..
+ * We don't guarantee that "sizeof(struct list_head)" is necessarily
+ * a power-of-two.
+ */
+ hash_size = PAGE_SIZE / sizeof(struct list_head);
+ hash_bits = 0;
+ do {
+ hash_bits++;
+ } while ((hash_size >> hash_bits) != 0);
+ hash_bits--;
+
+ /*
+ * Re-calculate the actual number of entries and the mask
+ * from the number of bits we can fit.
+ */
+ hash_size = 1UL << hash_bits;
+
+ /* And initialize the newly allocated array */
+ d = dcookie_hashtable;
+ i = hash_size;
+ do {
+ INIT_LIST_HEAD(d);
+ d++;
+ i--;
+ } while (i);
+
+out:
+ return err;
+out_kmem:
+ kmem_cache_destroy(dcookie_cache);
+ goto out;
+}
+
+
+static void free_dcookie(struct dcookie_struct * dcs)
+{
+ dcs->dentry->d_cookie = NULL;
+ dput(dcs->dentry);
+ mntput(dcs->vfsmnt);
+ kmem_cache_free(dcookie_cache, dcs);
+}
+
+
+static void dcookie_exit(void)
+{
+ struct list_head * list;
+ struct list_head * pos;
+ struct list_head * pos2;
+ struct dcookie_struct * dcs;
+ size_t i;
+
+ for (i = 0; i < hash_size; ++i) {
+ list = dcookie_hashtable + i;
+ list_for_each_safe(pos, pos2, list) {
+ dcs = list_entry(pos, struct dcookie_struct, hash_list);
+ list_del(&dcs->hash_list);
+ free_dcookie(dcs);
+ }
+ }
+
+ kfree(dcookie_hashtable);
+ kmem_cache_destroy(dcookie_cache);
+}
+
+
+struct dcookie_user {
+ struct list_head next;
+};
+
+struct dcookie_user * dcookie_register(void)
+{
+ struct dcookie_user * user;
+
+ down(&dcookie_sem);
+
+ user = kmalloc(sizeof(struct dcookie_user), GFP_KERNEL);
+ if (!user)
+ goto out;
+
+ if (!is_live() && dcookie_init())
+ goto out_free;
+
+ list_add(&user->next, &dcookie_users);
+
+out:
+ up(&dcookie_sem);
+ return user;
+out_free:
+ kfree(user);
+ user = NULL;
+ goto out;
+}
+
+
+void dcookie_unregister(struct dcookie_user * user)
+{
+ down(&dcookie_sem);
+
+ list_del(&user->next);
+ kfree(user);
+
+ if (!is_live())
+ dcookie_exit();
+
+ up(&dcookie_sem);
+}
+
+EXPORT_SYMBOL_GPL(dcookie_register);
+EXPORT_SYMBOL_GPL(dcookie_unregister);
+EXPORT_SYMBOL_GPL(get_dcookie);
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index 72b3148cb038..df2fa4d8d0fd 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -490,11 +490,11 @@ static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
}
/*
- * get_index()
+ * read_index()
*
* reads a directory table slot
*/
-static int get_index(struct inode *ip, u32 index,
+static int read_index(struct inode *ip, u32 index,
struct dir_table_slot * dirtab_slot)
{
struct metapage *mp = 0;
@@ -2978,7 +2978,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
return 0;
}
repeat:
- rc = get_index(ip, dir_index, &dirtab_slot);
+ rc = read_index(ip, dir_index, &dirtab_slot);
if (rc) {
filp->f_pos = DIREND;
return rc;
diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
index 223d700da927..7859b2f22d28 100644
--- a/fs/jfs/jfs_mount.c
+++ b/fs/jfs/jfs_mount.c
@@ -478,12 +478,12 @@ int readSuper(struct super_block *sb, struct buffer_head **bpp)
{
/* read in primary superblock */
*bpp = sb_bread(sb, SUPER1_OFF >> sb->s_blocksize_bits);
- if (bpp)
+ if (*bpp)
return 0;
/* read in secondary/replicated superblock */
*bpp = sb_bread(sb, SUPER2_OFF >> sb->s_blocksize_bits);
- if (bpp)
+ if (*bpp)
return 0;
return -EIO;
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 836322c2be06..c098a522553b 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -8,6 +8,7 @@ nfs-y := dir.o file.o flushd.o inode.o nfs2xdr.o pagelist.o \
proc.o read.o symlink.o unlink.o write.o
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
+nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o
nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
nfs-objs := $(nfs-y)
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 3443f647ed2f..f02b7c9c7f36 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -259,6 +259,12 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
if (!inode)
return -EINVAL;
+ /* This will be in a forthcoming patch. */
+ if (NFS_PROTO(inode)->version == 4) {
+ printk(KERN_INFO "NFS: file locking over NFSv4 is not yet supported\n");
+ return -EIO;
+ }
+
/* No mandatory locks over NFS */
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
return -ENOLCK;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index f7e1e442c9e7..39027f2af310 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -28,6 +28,7 @@
#include <linux/sunrpc/stats.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
+#include <linux/nfs4_mount.h>
#include <linux/nfs_flushd.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
@@ -76,8 +77,13 @@ static struct rpc_version * nfs_version[] = {
NULL,
NULL,
&nfs_version2,
-#ifdef CONFIG_NFS_V3
+#if defined(CONFIG_NFS_V3)
&nfs_version3,
+#elif defined(CONFIG_NFS_V4)
+ NULL,
+#endif
+#if defined(CONFIG_NFS_V4)
+ &nfs_version4,
#endif
};
@@ -157,6 +163,7 @@ nfs_put_super(struct super_block *sb)
lockd_down(); /* release rpc.lockd */
rpciod_down(); /* release rpciod */
+ destroy_nfsv4_state(server);
kfree(server->hostname);
}
@@ -234,6 +241,120 @@ nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh)
}
/*
+ * Do NFS version-independent mount processing, and sanity checking
+ */
+int nfs_sb_init(struct super_block *sb)
+{
+ struct nfs_server *server;
+ struct inode *root_inode = NULL;
+ struct nfs_fattr fattr;
+ struct nfs_fsinfo fsinfo = {
+ .fattr = &fattr,
+ };
+ struct nfs_pathconf pathinfo = {
+ .fattr = &fattr,
+ };
+
+ /* We probably want something more informative here */
+ snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
+
+ server = NFS_SB(sb);
+
+ sb->s_magic = NFS_SUPER_MAGIC;
+ sb->s_op = &nfs_sops;
+ INIT_LIST_HEAD(&server->lru_read);
+ INIT_LIST_HEAD(&server->lru_dirty);
+ INIT_LIST_HEAD(&server->lru_commit);
+ INIT_LIST_HEAD(&server->lru_busy);
+
+ /* Did getting the root inode fail? */
+ root_inode = nfs_get_root(sb, &server->fh);
+ if (!root_inode)
+ goto out_no_root;
+ sb->s_root = d_alloc_root(root_inode);
+ if (!sb->s_root)
+ goto out_no_root;
+
+ sb->s_root->d_op = &nfs_dentry_operations;
+
+ /* Get some general file system info */
+ if (server->rpc_ops->fsinfo(server, &server->fh, &fsinfo) < 0) {
+ printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
+ goto out_no_root;
+ }
+ if (server->namelen == 0 &&
+ server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
+ server->namelen = pathinfo.max_namelen;
+ /* Work out a lot of parameters */
+ if (server->rsize == 0)
+ server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
+ if (server->wsize == 0)
+ server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
+ if (sb->s_blocksize == 0) {
+ if (fsinfo.wtmult == 0) {
+ sb->s_blocksize = 512;
+ sb->s_blocksize_bits = 9;
+ } else
+ sb->s_blocksize = nfs_block_bits(fsinfo.wtmult,
+ &sb->s_blocksize_bits);
+ }
+
+ if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
+ server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
+ if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
+ server->wsize = nfs_block_size(fsinfo.wtmax, NULL);
+
+ server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ if (server->rpages > NFS_READ_MAXIOV) {
+ server->rpages = NFS_READ_MAXIOV;
+ server->rsize = server->rpages << PAGE_CACHE_SHIFT;
+ }
+
+ server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ if (server->wpages > NFS_WRITE_MAXIOV) {
+ server->wpages = NFS_WRITE_MAXIOV;
+ server->wsize = server->wpages << PAGE_CACHE_SHIFT;
+ }
+
+ server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
+ if (server->dtsize > PAGE_CACHE_SIZE)
+ server->dtsize = PAGE_CACHE_SIZE;
+ if (server->dtsize > server->rsize)
+ server->dtsize = server->rsize;
+
+ if (server->flags & NFS_MOUNT_NOAC) {
+ server->acregmin = server->acregmax = 0;
+ server->acdirmin = server->acdirmax = 0;
+ sb->s_flags |= MS_SYNCHRONOUS;
+ }
+
+ sb->s_maxbytes = fsinfo.maxfilesize;
+ if (sb->s_maxbytes > MAX_LFS_FILESIZE)
+ sb->s_maxbytes = MAX_LFS_FILESIZE;
+
+ /* Fire up the writeback cache */
+ if (nfs_reqlist_alloc(server) < 0) {
+ printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n");
+ goto failure_kill_reqlist;
+ }
+
+ /* We're airborne Set socket buffersize */
+ rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
+ return 0;
+ /* Yargs. It didn't work out. */
+failure_kill_reqlist:
+ nfs_reqlist_exit(server);
+out_free_all:
+ if (root_inode)
+ iput(root_inode);
+ nfs_reqlist_free(server);
+ return -EINVAL;
+out_no_root:
+ printk("nfs_read_super: get root inode failed\n");
+ goto out_free_all;
+}
+
+/*
* The way this works is that the mount process passes a structure
* in the data argument which contains the server's IP address
* and the root file handle obtained from the server's mount
@@ -244,29 +365,20 @@ int nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int sile
struct nfs_server *server;
struct rpc_xprt *xprt = NULL;
struct rpc_clnt *clnt = NULL;
- struct inode *root_inode = NULL;
- rpc_authflavor_t authflavor;
struct rpc_timeout timeparms;
- struct nfs_fsinfo fsinfo;
- int tcp, version, maxlen;
+ int tcp, err = -EIO;
- /* We probably want something more informative here */
- snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
-
- sb->s_magic = NFS_SUPER_MAGIC;
- sb->s_op = &nfs_sops;
- sb->s_blocksize_bits = 0;
- sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
server = NFS_SB(sb);
- server->rsize = nfs_block_size(data->rsize, NULL);
- server->wsize = nfs_block_size(data->wsize, NULL);
+ sb->s_blocksize_bits = 0;
+ sb->s_blocksize = 0;
+ if (data->bsize)
+ sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
+ if (data->rsize)
+ server->rsize = nfs_block_size(data->rsize, NULL);
+ if (data->wsize)
+ server->wsize = nfs_block_size(data->wsize, NULL);
server->flags = data->flags & NFS_MOUNT_FLAGMASK;
- if (data->flags & NFS_MOUNT_NOAC) {
- data->acregmin = data->acregmax = 0;
- data->acdirmin = data->acdirmax = 0;
- sb->s_flags |= MS_SYNCHRONOUS;
- }
server->acregmin = data->acregmin*HZ;
server->acregmax = data->acregmax*HZ;
server->acdirmin = data->acdirmin*HZ;
@@ -275,34 +387,26 @@ int nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int sile
server->namelen = data->namlen;
server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
if (!server->hostname)
- goto out_unlock;
+ goto out_fail;
strcpy(server->hostname, data->hostname);
- INIT_LIST_HEAD(&server->lru_read);
- INIT_LIST_HEAD(&server->lru_dirty);
- INIT_LIST_HEAD(&server->lru_commit);
- INIT_LIST_HEAD(&server->lru_busy);
- nfsv3_try_again:
- server->caps = 0;
/* Check NFS protocol revision and initialize RPC op vector
* and file handle pool. */
- if (data->flags & NFS_MOUNT_VER3) {
+ if (server->flags & NFS_MOUNT_VER3) {
#ifdef CONFIG_NFS_V3
server->rpc_ops = &nfs_v3_clientops;
- version = 3;
server->caps |= NFS_CAP_READDIRPLUS;
if (data->version < 4) {
printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n");
- goto out_unlock;
+ goto out_fail;
}
#else
printk(KERN_NOTICE "NFS: NFSv3 not supported.\n");
- goto out_unlock;
+ goto out_fail;
#endif
} else {
server->rpc_ops = &nfs_v2_clientops;
- version = 2;
- }
+ }
/* Which protocol do we use? */
tcp = (data->flags & NFS_MOUNT_TCP);
@@ -321,155 +425,54 @@ int nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int sile
/* Now create transport and client */
xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP,
&server->addr, &timeparms);
- if (xprt == NULL)
- goto out_no_xprt;
-
- /* Choose authentication flavor */
- authflavor = RPC_AUTH_UNIX;
- if (data->flags & NFS_MOUNT_SECURE)
- authflavor = RPC_AUTH_DES;
- else if (data->flags & NFS_MOUNT_KERBEROS)
- authflavor = RPC_AUTH_KRB;
-
+ if (xprt == NULL) {
+ printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
+ goto out_fail;
+ }
clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
- version, authflavor);
- if (clnt == NULL)
- goto out_no_client;
+ server->rpc_ops->version, RPC_AUTH_UNIX);
+ if (clnt == NULL) {
+ printk(KERN_WARNING "NFS: cannot create RPC client.\n");
+ xprt_destroy(xprt);
+ goto out_fail;
+ }
- clnt->cl_intr = (data->flags & NFS_MOUNT_INTR)? 1 : 0;
- clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0;
- clnt->cl_droppriv = (data->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0;
+ clnt->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0;
+ clnt->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0;
+ clnt->cl_droppriv = (server->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0;
clnt->cl_chatty = 1;
server->client = clnt;
/* Fire up rpciod if not yet running */
- if (rpciod_up() != 0)
- goto out_no_iod;
-
- /*
- * Keep the super block locked while we try to get
- * the root fh attributes.
- */
- /* Did getting the root inode fail? */
- if (!(root_inode = nfs_get_root(sb, &server->fh))
- && (data->flags & NFS_MOUNT_VER3)) {
- data->flags &= ~NFS_MOUNT_VER3;
- rpciod_down();
- rpc_shutdown_client(server->client);
- goto nfsv3_try_again;
+ if (rpciod_up() != 0) {
+ printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
+ goto out_shutdown;
}
- if (!root_inode)
- goto out_no_root;
- sb->s_root = d_alloc_root(root_inode);
- if (!sb->s_root)
- goto out_no_root;
+ err = nfs_sb_init(sb);
+ if (err != 0)
+ goto out_noinit;
- sb->s_root->d_op = &nfs_dentry_operations;
-
- /* Get some general file system info */
- if (server->rpc_ops->statfs(server, &server->fh, &fsinfo) >= 0) {
- if (server->namelen == 0)
- server->namelen = fsinfo.namelen;
+ if (server->flags & NFS_MOUNT_VER3) {
+ if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
+ server->namelen = NFS3_MAXNAMLEN;
} else {
- printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
- goto out_no_root;
- }
-
- /* Work out a lot of parameters */
- if (data->rsize == 0)
- server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
- if (data->wsize == 0)
- server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
- /* NFSv3: we don't have bsize, but rather rtmult and wtmult... */
- if (!fsinfo.bsize)
- fsinfo.bsize = (fsinfo.rtmult>fsinfo.wtmult) ? fsinfo.rtmult : fsinfo.wtmult;
- /* Also make sure we don't go below rsize/wsize since
- * RPC calls are expensive */
- if (fsinfo.bsize < server->rsize)
- fsinfo.bsize = server->rsize;
- if (fsinfo.bsize < server->wsize)
- fsinfo.bsize = server->wsize;
-
- if (data->bsize == 0)
- sb->s_blocksize = nfs_block_bits(fsinfo.bsize, &sb->s_blocksize_bits);
- if (server->rsize > fsinfo.rtmax)
- server->rsize = fsinfo.rtmax;
- if (server->wsize > fsinfo.wtmax)
- server->wsize = fsinfo.wtmax;
-
- server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- if (server->rpages > NFS_READ_MAXIOV) {
- server->rpages = NFS_READ_MAXIOV;
- server->rsize = server->rpages << PAGE_CACHE_SHIFT;
+ if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
+ server->namelen = NFS2_MAXNAMLEN;
}
- server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- if (server->wpages > NFS_WRITE_MAXIOV) {
- server->wpages = NFS_WRITE_MAXIOV;
- server->wsize = server->wpages << PAGE_CACHE_SHIFT;
- }
-
- server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
- if (server->dtsize > PAGE_CACHE_SIZE)
- server->dtsize = PAGE_CACHE_SIZE;
- if (server->dtsize > server->rsize)
- server->dtsize = server->rsize;
-
- maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN;
-
- if (server->namelen == 0 || server->namelen > maxlen)
- server->namelen = maxlen;
-
- sb->s_maxbytes = fsinfo.maxfilesize;
- if (sb->s_maxbytes > MAX_LFS_FILESIZE)
- sb->s_maxbytes = MAX_LFS_FILESIZE;
-
- /* Fire up the writeback cache */
- if (nfs_reqlist_alloc(server) < 0) {
- printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n");
- goto failure_kill_reqlist;
- }
-
- /* We're airborne Set socket buffersize */
- rpc_setbufsize(clnt, server->wsize + 100, server->rsize + 100);
-
/* Check whether to start the lockd process */
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_up();
return 0;
-
- /* Yargs. It didn't work out. */
- failure_kill_reqlist:
- nfs_reqlist_exit(server);
-out_no_root:
- printk("nfs_read_super: get root inode failed\n");
- iput(root_inode);
+out_noinit:
rpciod_down();
- goto out_shutdown;
-
-out_no_iod:
- printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
out_shutdown:
rpc_shutdown_client(server->client);
- goto out_free_host;
-
-out_no_client:
- printk(KERN_WARNING "NFS: cannot create RPC client.\n");
- xprt_destroy(xprt);
- goto out_free_host;
-
-out_no_xprt:
- printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
-
-out_free_host:
- nfs_reqlist_free(server);
- kfree(server->hostname);
-out_unlock:
- goto out_fail;
-
out_fail:
- return -EINVAL;
+ if (server->hostname)
+ kfree(server->hostname);
+ return err;
}
static int
@@ -478,29 +481,30 @@ nfs_statfs(struct super_block *sb, struct statfs *buf)
struct nfs_server *server = NFS_SB(sb);
unsigned char blockbits;
unsigned long blockres;
- struct nfs_fsinfo res;
+ struct nfs_fh *rootfh = NFS_FH(sb->s_root->d_inode);
+ struct nfs_fattr fattr;
+ struct nfs_fsstat res = {
+ .fattr = &fattr,
+ };
int error;
lock_kernel();
- error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root->d_inode), &res);
+ error = server->rpc_ops->statfs(server, rootfh, &res);
buf->f_type = NFS_SUPER_MAGIC;
if (error < 0)
goto out_err;
- if (res.bsize == 0)
- res.bsize = sb->s_blocksize;
- buf->f_bsize = nfs_block_bits(res.bsize, &blockbits);
+ buf->f_bsize = sb->s_blocksize;
+ blockbits = sb->s_blocksize_bits;
blockres = (1 << blockbits) - 1;
buf->f_blocks = (res.tbytes + blockres) >> blockbits;
buf->f_bfree = (res.fbytes + blockres) >> blockbits;
buf->f_bavail = (res.abytes + blockres) >> blockbits;
buf->f_files = res.tfiles;
buf->f_ffree = res.afiles;
- if (res.namelen == 0 || res.namelen > server->namelen)
- res.namelen = server->namelen;
- buf->f_namelen = res.namelen;
+ buf->f_namelen = server->namelen;
out:
unlock_kernel();
@@ -1286,6 +1290,239 @@ static struct file_system_type nfs_fs_type = {
.fs_flags = FS_ODD_RENAME,
};
+#ifdef CONFIG_NFS_V4
+
+static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent)
+{
+ struct nfs_server *server;
+ struct rpc_xprt *xprt = NULL;
+ struct rpc_clnt *clnt = NULL;
+ struct rpc_timeout timeparms;
+ rpc_authflavor_t authflavour;
+ int proto, err = -EIO;
+
+ sb->s_blocksize_bits = 0;
+ sb->s_blocksize = 0;
+ server = NFS_SB(sb);
+ if (data->rsize != 0)
+ server->rsize = nfs_block_size(data->rsize, NULL);
+ if (data->wsize != 0)
+ server->wsize = nfs_block_size(data->wsize, NULL);
+ server->flags = data->flags & NFS_MOUNT_FLAGMASK;
+
+ /* NFSv4 doesn't use NLM locking */
+ server->flags |= NFS_MOUNT_NONLM;
+
+ server->acregmin = data->acregmin*HZ;
+ server->acregmax = data->acregmax*HZ;
+ server->acdirmin = data->acdirmin*HZ;
+ server->acdirmax = data->acdirmax*HZ;
+
+ server->rpc_ops = &nfs_v4_clientops;
+ /* Initialize timeout values */
+
+ timeparms.to_initval = data->timeo * HZ / 10;
+ timeparms.to_retries = data->retrans;
+ timeparms.to_exponential = 1;
+ if (!timeparms.to_retries)
+ timeparms.to_retries = 5;
+
+ proto = data->proto;
+ /* Which IP protocol do we use? */
+ switch (proto) {
+ case IPPROTO_TCP:
+ timeparms.to_maxval = RPC_MAX_TCP_TIMEOUT;
+ if (!timeparms.to_initval)
+ timeparms.to_initval = 600 * HZ / 10;
+ break;
+ case IPPROTO_UDP:
+ timeparms.to_maxval = RPC_MAX_UDP_TIMEOUT;
+ if (!timeparms.to_initval)
+ timeparms.to_initval = 11 * HZ / 10;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Now create transport and client */
+ xprt = xprt_create_proto(proto, &server->addr, &timeparms);
+ if (xprt == NULL) {
+ printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
+ goto out_fail;
+ }
+
+ authflavour = RPC_AUTH_UNIX;
+ if (data->auth_flavourlen != 0) {
+ if (data->auth_flavourlen > 1)
+ printk(KERN_INFO "NFS: cannot yet deal with multiple auth flavours.\n");
+ if (copy_from_user(authflavour, data->auth_flavours, sizeof(authflavour))) {
+ err = -EFAULT;
+ goto out_fail;
+ }
+ }
+ clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
+ server->rpc_ops->version, authflavour);
+ if (clnt == NULL) {
+ printk(KERN_WARNING "NFS: cannot create RPC client.\n");
+ xprt_destroy(xprt);
+ goto out_fail;
+ }
+
+ clnt->cl_intr = (server->flags & NFS4_MOUNT_INTR) ? 1 : 0;
+ clnt->cl_softrtry = (server->flags & NFS4_MOUNT_SOFT) ? 1 : 0;
+ clnt->cl_chatty = 1;
+ server->client = clnt;
+
+ /* Fire up rpciod if not yet running */
+ if (rpciod_up() != 0) {
+ printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
+ goto out_shutdown;
+ }
+
+ if (create_nfsv4_state(server, data))
+ goto out_shutdown;
+
+ err = nfs_sb_init(sb);
+ if (err == 0)
+ return 0;
+ rpciod_down();
+ destroy_nfsv4_state(server);
+out_shutdown:
+ rpc_shutdown_client(server->client);
+out_fail:
+ return err;
+}
+
+static int nfs4_compare_super(struct super_block *sb, void *data)
+{
+ struct nfs_server *server = data;
+ struct nfs_server *old = NFS_SB(sb);
+
+ if (strcmp(server->hostname, old->hostname) != 0)
+ return 0;
+ if (strcmp(server->mnt_path, old->mnt_path) != 0)
+ return 0;
+ return 1;
+}
+
+static void *
+nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
+{
+ void *p = NULL;
+
+ if (!src->len)
+ return ERR_PTR(-EINVAL);
+ if (src->len < maxlen)
+ maxlen = src->len;
+ if (dst == NULL) {
+ p = dst = kmalloc(maxlen + 1, GFP_KERNEL);
+ if (p == NULL)
+ return ERR_PTR(-ENOMEM);
+ }
+ if (copy_from_user(dst, src->data, maxlen)) {
+ if (p != NULL)
+ kfree(p);
+ return ERR_PTR(-EFAULT);
+ }
+ dst[maxlen] = '\0';
+ return dst;
+}
+
+static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
+ int flags, char *dev_name, void *raw_data)
+{
+ int error;
+ struct nfs_server *server;
+ struct super_block *s;
+ struct nfs4_mount_data *data = raw_data;
+ void *p;
+
+ if (!data) {
+ printk("nfs_read_super: missing data argument\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL);
+ if (!server)
+ return ERR_PTR(-ENOMEM);
+ memset(server, 0, sizeof(struct nfs_server));
+
+ if (data->version != NFS4_MOUNT_VERSION) {
+ printk("nfs warning: mount version %s than kernel\n",
+ data->version < NFS_MOUNT_VERSION ? "older" : "newer");
+ }
+
+ p = nfs_copy_user_string(NULL, &data->hostname, 256);
+ if (IS_ERR(p))
+ goto out_err;
+ server->hostname = p;
+
+ p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
+ if (IS_ERR(p))
+ goto out_err;
+ server->mnt_path = p;
+
+ p = nfs_copy_user_string(server->ip_addr, &data->client_addr,
+ sizeof(server->ip_addr));
+ if (IS_ERR(p))
+ goto out_err;
+
+ /* We now require that the mount process passes the remote address */
+ if (data->host_addrlen != sizeof(server->addr)) {
+ s = ERR_PTR(-EINVAL);
+ goto out_free;
+ }
+ if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) {
+ s = ERR_PTR(-EFAULT);
+ goto out_free;
+ }
+ if (server->addr.sin_family != AF_INET ||
+ server->addr.sin_addr.s_addr == INADDR_ANY) {
+ printk("NFS: mount program didn't pass remote IP address!\n");
+ s = ERR_PTR(-EINVAL);
+ goto out_free;
+ }
+
+ s = sget(fs_type, nfs4_compare_super, nfs_set_super, server);
+
+ if (IS_ERR(s) || s->s_root)
+ goto out_free;
+
+ s->s_flags = flags;
+
+ error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
+ if (error) {
+ up_write(&s->s_umount);
+ deactivate_super(s);
+ return ERR_PTR(error);
+ }
+ s->s_flags |= MS_ACTIVE;
+ return s;
+out_err:
+ s = (struct super_block *)p;
+out_free:
+ if (server->mnt_path)
+ kfree(server->mnt_path);
+ if (server->hostname)
+ kfree(server->hostname);
+ kfree(server);
+ return s;
+}
+
+static struct file_system_type nfs4_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "nfs4",
+ .get_sb = nfs4_get_sb,
+ .kill_sb = nfs_kill_super,
+ .fs_flags = FS_ODD_RENAME,
+};
+#define register_nfs4fs() register_filesystem(&nfs4_fs_type)
+#define unregister_nfs4fs() unregister_filesystem(&nfs4_fs_type)
+#else
+#define register_nfs4fs() (0)
+#define unregister_nfs4fs()
+#endif
+
extern int nfs_init_nfspagecache(void);
extern void nfs_destroy_nfspagecache(void);
extern int nfs_init_readpagecache(void);
@@ -1377,6 +1614,8 @@ static int __init init_nfs_fs(void)
err = register_filesystem(&nfs_fs_type);
if (err)
goto out;
+ if ((err = register_nfs4fs()) != 0)
+ goto out;
return 0;
out:
rpc_proc_unregister("nfs");
@@ -1401,6 +1640,7 @@ static void __exit exit_nfs_fs(void)
rpc_proc_unregister("nfs");
#endif
unregister_filesystem(&nfs_fs_type);
+ unregister_nfs4fs();
}
/* Not quite true; I just maintain it */
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 8dc92b8b3a1c..8e652afdfea4 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -596,37 +596,18 @@ nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
* Decode STATFS reply
*/
static int
-nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res)
{
int status;
- u32 xfer_size;
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
- /* For NFSv2, we more or less have to guess the preferred
- * read/write/readdir sizes from the single 'transfer size'
- * value.
- */
- xfer_size = ntohl(*p++); /* tsize */
- res->rtmax = 8 * 1024;
- res->rtpref = xfer_size;
- res->rtmult = xfer_size;
- res->wtmax = 8 * 1024;
- res->wtpref = xfer_size;
- res->wtmult = xfer_size;
- res->dtpref = PAGE_CACHE_SIZE;
- res->maxfilesize = 0x7FFFFFFF; /* just a guess */
+ res->tsize = ntohl(*p++);
res->bsize = ntohl(*p++);
-
- res->tbytes = ntohl(*p++) * res->bsize;
- res->fbytes = ntohl(*p++) * res->bsize;
- res->abytes = ntohl(*p++) * res->bsize;
- res->tfiles = 0;
- res->ffiles = 0;
- res->afiles = 0;
- res->namelen = 0;
-
+ res->blocks = ntohl(*p++);
+ res->bfree = ntohl(*p++);
+ res->bavail = ntohl(*p++);
return 0;
}
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 1ddb51374cba..790c27ead44f 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -639,24 +639,42 @@ nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
return status;
}
-/*
- * This is a combo call of fsstat and fsinfo
- */
static int
nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fsinfo *info)
+ struct nfs_fsstat *stat)
{
int status;
dprintk("NFS call fsstat\n");
- memset((char *)info, 0, sizeof(*info));
- status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, info, 0);
- if (status < 0)
- goto error;
+ stat->fattr->valid = 0;
+ status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, stat, 0);
+ dprintk("NFS reply statfs: %d\n", status);
+ return status;
+}
+
+static int
+nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fsinfo *info)
+{
+ int status;
+
+ dprintk("NFS call fsinfo\n");
+ info->fattr->valid = 0;
status = rpc_call(server->client, NFS3PROC_FSINFO, fhandle, info, 0);
+ dprintk("NFS reply fsinfo: %d\n", status);
+ return status;
+}
-error:
- dprintk("NFS reply statfs: %d\n", status);
+static int
+nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_pathconf *info)
+{
+ int status;
+
+ dprintk("NFS call pathconf\n");
+ info->fattr->valid = 0;
+ status = rpc_call(server->client, NFS3PROC_PATHCONF, fhandle, info, 0);
+ dprintk("NFS reply pathconf: %d\n", status);
return status;
}
@@ -824,6 +842,8 @@ struct nfs_rpc_ops nfs_v3_clientops = {
.readdir = nfs3_proc_readdir,
.mknod = nfs3_proc_mknod,
.statfs = nfs3_proc_statfs,
+ .fsinfo = nfs3_proc_fsinfo,
+ .pathconf = nfs3_proc_pathconf,
.decode_dirent = nfs3_decode_dirent,
.read_setup = nfs3_proc_read_setup,
.write_setup = nfs3_proc_write_setup,
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index b0c77b19fff9..2a813fb65365 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -912,14 +912,13 @@ nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
* Decode FSSTAT reply
*/
static int
-nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
{
- struct nfs_fattr dummy;
int status;
status = ntohl(*p++);
- p = xdr_decode_post_op_attr(p, &dummy);
+ p = xdr_decode_post_op_attr(p, res->fattr);
if (status != 0)
return -nfs_stat_to_errno(status);
@@ -940,12 +939,11 @@ nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
static int
nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
{
- struct nfs_fattr dummy;
int status;
status = ntohl(*p++);
- p = xdr_decode_post_op_attr(p, &dummy);
+ p = xdr_decode_post_op_attr(p, res->fattr);
if (status != 0)
return -nfs_stat_to_errno(status);
@@ -959,6 +957,7 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
p = xdr_decode_hyper(p, &res->maxfilesize);
/* ignore time_delta and properties */
+ res->lease_time = 0;
return 0;
}
@@ -966,18 +965,17 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
* Decode PATHCONF reply
*/
static int
-nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
{
- struct nfs_fattr dummy;
int status;
status = ntohl(*p++);
- p = xdr_decode_post_op_attr(p, &dummy);
+ p = xdr_decode_post_op_attr(p, res->fattr);
if (status != 0)
return -nfs_stat_to_errno(status);
- res->linkmax = ntohl(*p++);
- res->namelen = ntohl(*p++);
+ res->max_link = ntohl(*p++);
+ res->max_namelen = ntohl(*p++);
/* ignore remaining fields */
return 0;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
new file mode 100644
index 000000000000..8608fd9b3a30
--- /dev/null
+++ b/fs/nfs/nfs4proc.c
@@ -0,0 +1,1577 @@
+/*
+ * fs/nfs/nfs4proc.c
+ *
+ * Client-side procedure declarations for NFSv4.
+ *
+ * Copyright (c) 2002 The Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Kendrick Smith <kmsmith@umich.edu>
+ * Andy Adamson <andros@umich.edu>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/mm.h>
+#include <linux/utsname.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_page.h>
+#include <linux/smp_lock.h>
+
+#define NFSDBG_FACILITY NFSDBG_PROC
+
+#define GET_OP(cp,name) &cp->ops[cp->req_nops].u.name
+#define OPNUM(cp) cp->ops[cp->req_nops].opnum
+
+extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
+
+static nfs4_stateid zero_stateid =
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+static spinlock_t renew_lock = SPIN_LOCK_UNLOCKED;
+
+static void
+nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops,
+ struct nfs_server *server, char *tag)
+{
+ memset(cp, 0, sizeof(*cp));
+ cp->ops = ops;
+ cp->server = server;
+
+#if NFS4_DEBUG
+ cp->taglen = strlen(tag);
+ cp->tag = tag;
+#endif
+}
+
+static void
+nfs4_setup_access(struct nfs4_compound *cp, u32 req_access, u32 *resp_supported, u32 *resp_access)
+{
+ struct nfs4_access *access = GET_OP(cp, access);
+
+ access->ac_req_access = req_access;
+ access->ac_resp_supported = resp_supported;
+ access->ac_resp_access = resp_access;
+
+ OPNUM(cp) = OP_ACCESS;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_close(struct nfs4_compound *cp, nfs4_stateid stateid, u32 seqid)
+{
+ struct nfs4_close *close = GET_OP(cp, close);
+
+ close->cl_stateid = stateid;
+ close->cl_seqid = seqid;
+
+ OPNUM(cp) = OP_CLOSE;
+ cp->req_nops++;
+ cp->renew_index = cp->req_nops;
+}
+
+static void
+nfs4_setup_commit(struct nfs4_compound *cp, u64 start, u32 len, struct nfs_writeverf *verf)
+{
+ struct nfs4_commit *commit = GET_OP(cp, commit);
+
+ commit->co_start = start;
+ commit->co_len = len;
+ commit->co_verifier = verf;
+
+ OPNUM(cp) = OP_COMMIT;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_create_dir(struct nfs4_compound *cp, struct qstr *name,
+ struct iattr *sattr, struct nfs4_change_info *info)
+{
+ struct nfs4_create *create = GET_OP(cp, create);
+
+ create->cr_ftype = NF4DIR;
+ create->cr_namelen = name->len;
+ create->cr_name = name->name;
+ create->cr_attrs = sattr;
+ create->cr_cinfo = info;
+
+ OPNUM(cp) = OP_CREATE;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_create_symlink(struct nfs4_compound *cp, struct qstr *name,
+ struct qstr *linktext, struct iattr *sattr,
+ struct nfs4_change_info *info)
+{
+ struct nfs4_create *create = GET_OP(cp, create);
+
+ create->cr_ftype = NF4LNK;
+ create->cr_textlen = linktext->len;
+ create->cr_text = linktext->name;
+ create->cr_namelen = name->len;
+ create->cr_name = name->name;
+ create->cr_attrs = sattr;
+ create->cr_cinfo = info;
+
+ OPNUM(cp) = OP_CREATE;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_create_special(struct nfs4_compound *cp, struct qstr *name,
+ dev_t dev, struct iattr *sattr,
+ struct nfs4_change_info *info)
+{
+ int mode = sattr->ia_mode;
+ struct nfs4_create *create = GET_OP(cp, create);
+
+ BUG_ON(!(sattr->ia_valid & ATTR_MODE));
+ BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
+
+ if (S_ISFIFO(mode))
+ create->cr_ftype = NF4FIFO;
+ else if (S_ISBLK(mode)) {
+ create->cr_ftype = NF4BLK;
+ create->cr_specdata1 = MAJOR(dev);
+ create->cr_specdata2 = MINOR(dev);
+ }
+ else if (S_ISCHR(mode)) {
+ create->cr_ftype = NF4CHR;
+ create->cr_specdata1 = MAJOR(dev);
+ create->cr_specdata2 = MINOR(dev);
+ }
+ else
+ create->cr_ftype = NF4SOCK;
+
+ create->cr_namelen = name->len;
+ create->cr_name = name->name;
+ create->cr_attrs = sattr;
+ create->cr_cinfo = info;
+
+ OPNUM(cp) = OP_CREATE;
+ cp->req_nops++;
+}
+
+/*
+ * This is our standard bitmap for GETATTR requests.
+ */
+u32 nfs4_fattr_bitmap[2] = {
+ FATTR4_WORD0_TYPE
+ | FATTR4_WORD0_CHANGE
+ | FATTR4_WORD0_SIZE
+ | FATTR4_WORD0_FSID
+ | FATTR4_WORD0_FILEID,
+ FATTR4_WORD1_MODE
+ | FATTR4_WORD1_NUMLINKS
+ | FATTR4_WORD1_OWNER
+ | FATTR4_WORD1_OWNER_GROUP
+ | FATTR4_WORD1_RAWDEV
+ | FATTR4_WORD1_SPACE_USED
+ | FATTR4_WORD1_TIME_ACCESS
+ | FATTR4_WORD1_TIME_METADATA
+ | FATTR4_WORD1_TIME_MODIFY
+};
+
+u32 nfs4_statfs_bitmap[2] = {
+ FATTR4_WORD0_FILES_AVAIL
+ | FATTR4_WORD0_FILES_FREE
+ | FATTR4_WORD0_FILES_TOTAL,
+ FATTR4_WORD1_SPACE_AVAIL
+ | FATTR4_WORD1_SPACE_FREE
+ | FATTR4_WORD1_SPACE_TOTAL
+};
+
+u32 nfs4_fsinfo_bitmap[2] = {
+ FATTR4_WORD0_MAXFILESIZE
+ | FATTR4_WORD0_MAXREAD
+ | FATTR4_WORD0_MAXWRITE
+ | FATTR4_WORD0_LEASE_TIME,
+ 0
+};
+
+u32 nfs4_pathconf_bitmap[2] = {
+ FATTR4_WORD0_MAXLINK
+ | FATTR4_WORD0_MAXNAME,
+ 0
+};
+
+/* mount bitmap: fattr bitmap + lease time */
+u32 nfs4_mount_bitmap[2] = {
+ FATTR4_WORD0_TYPE
+ | FATTR4_WORD0_CHANGE
+ | FATTR4_WORD0_SIZE
+ | FATTR4_WORD0_FSID
+ | FATTR4_WORD0_FILEID
+ | FATTR4_WORD0_LEASE_TIME,
+ FATTR4_WORD1_MODE
+ | FATTR4_WORD1_NUMLINKS
+ | FATTR4_WORD1_OWNER
+ | FATTR4_WORD1_OWNER_GROUP
+ | FATTR4_WORD1_RAWDEV
+ | FATTR4_WORD1_SPACE_USED
+ | FATTR4_WORD1_TIME_ACCESS
+ | FATTR4_WORD1_TIME_METADATA
+ | FATTR4_WORD1_TIME_MODIFY
+};
+
+static inline void
+__nfs4_setup_getattr(struct nfs4_compound *cp, u32 *bitmap,
+ struct nfs_fattr *fattr,
+ struct nfs_fsstat *fsstat,
+ struct nfs_fsinfo *fsinfo,
+ struct nfs_pathconf *pathconf,
+ u32 *bmres)
+{
+ struct nfs4_getattr *getattr = GET_OP(cp, getattr);
+
+ getattr->gt_bmval = bitmap;
+ getattr->gt_attrs = fattr;
+ getattr->gt_fsstat = fsstat;
+ getattr->gt_fsinfo = fsinfo;
+ getattr->gt_pathconf = pathconf;
+ getattr->gt_bmres = bmres;
+
+ OPNUM(cp) = OP_GETATTR;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_getattr(struct nfs4_compound *cp,
+ struct nfs_fattr *fattr,
+ u32 *bmres)
+{
+ __nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr,
+ NULL, NULL, NULL, bmres);
+}
+
+static void
+nfs4_setup_getrootattr(struct nfs4_compound *cp,
+ struct nfs_fattr *fattr,
+ struct nfs_fsinfo *fsinfo,
+ u32 *bmres)
+{
+ __nfs4_setup_getattr(cp, nfs4_mount_bitmap,
+ fattr, NULL, fsinfo, NULL, bmres);
+}
+
+static void
+nfs4_setup_statfs(struct nfs4_compound *cp,
+ struct nfs_fsstat *fsstat,
+ u32 *bmres)
+{
+ __nfs4_setup_getattr(cp, nfs4_statfs_bitmap,
+ NULL, fsstat, NULL, NULL, bmres);
+}
+
+static void
+nfs4_setup_fsinfo(struct nfs4_compound *cp,
+ struct nfs_fsinfo *fsinfo,
+ u32 *bmres)
+{
+ __nfs4_setup_getattr(cp, nfs4_fsinfo_bitmap,
+ NULL, NULL, fsinfo, NULL, bmres);
+}
+
+static void
+nfs4_setup_pathconf(struct nfs4_compound *cp,
+ struct nfs_pathconf *pathconf,
+ u32 *bmres)
+{
+ __nfs4_setup_getattr(cp, nfs4_pathconf_bitmap,
+ NULL, NULL, NULL, pathconf, bmres);
+}
+
+static void
+nfs4_setup_getfh(struct nfs4_compound *cp, struct nfs_fh *fhandle)
+{
+ struct nfs4_getfh *getfh = GET_OP(cp, getfh);
+
+ getfh->gf_fhandle = fhandle;
+
+ OPNUM(cp) = OP_GETFH;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_link(struct nfs4_compound *cp, struct qstr *name,
+ struct nfs4_change_info *info)
+{
+ struct nfs4_link *link = GET_OP(cp, link);
+
+ link->ln_namelen = name->len;
+ link->ln_name = name->name;
+ link->ln_cinfo = info;
+
+ OPNUM(cp) = OP_LINK;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_lookup(struct nfs4_compound *cp, struct qstr *q)
+{
+ struct nfs4_lookup *lookup = GET_OP(cp, lookup);
+
+ lookup->lo_name = q;
+
+ OPNUM(cp) = OP_LOOKUP;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_putfh(struct nfs4_compound *cp, struct nfs_fh *fhandle)
+{
+ struct nfs4_putfh *putfh = GET_OP(cp, putfh);
+
+ putfh->pf_fhandle = fhandle;
+
+ OPNUM(cp) = OP_PUTFH;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_putrootfh(struct nfs4_compound *cp)
+{
+ OPNUM(cp) = OP_PUTROOTFH;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_open(struct nfs4_compound *cp, int flags, struct qstr *name,
+ struct iattr *sattr, char *stateid, struct nfs4_change_info *cinfo,
+ u32 *rflags)
+{
+ struct nfs4_open *open = GET_OP(cp, open);
+
+ BUG_ON(cp->flags);
+
+ open->op_share_access = flags & 3;
+ open->op_opentype = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE;
+ open->op_createmode = NFS4_CREATE_UNCHECKED;
+ open->op_attrs = sattr;
+ if (flags & O_EXCL) {
+ u32 *p = (u32 *) open->op_verifier;
+ p[0] = jiffies;
+ p[1] = current->pid;
+ open->op_createmode = NFS4_CREATE_EXCLUSIVE;
+ }
+ open->op_name = name;
+ open->op_stateid = stateid;
+ open->op_cinfo = cinfo;
+ open->op_rflags = rflags;
+
+ OPNUM(cp) = OP_OPEN;
+ cp->req_nops++;
+ cp->renew_index = cp->req_nops;
+}
+
+static void
+nfs4_setup_open_confirm(struct nfs4_compound *cp, char *stateid)
+{
+ struct nfs4_open_confirm *open_confirm = GET_OP(cp, open_confirm);
+
+ open_confirm->oc_stateid = stateid;
+
+ OPNUM(cp) = OP_OPEN_CONFIRM;
+ cp->req_nops++;
+ cp->renew_index = cp->req_nops;
+}
+
+static void
+nfs4_setup_read(struct nfs4_compound *cp, u64 offset, u32 length,
+ struct page **pages, unsigned int pgbase, u32 *eofp, u32 *bytes_read)
+{
+ struct nfs4_read *read = GET_OP(cp, read);
+
+ read->rd_offset = offset;
+ read->rd_length = length;
+ read->rd_pages = pages;
+ read->rd_pgbase = pgbase;
+ read->rd_eof = eofp;
+ read->rd_bytes_read = bytes_read;
+
+ OPNUM(cp) = OP_READ;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier,
+ struct page **pages, unsigned int bufsize, struct dentry *dentry)
+{
+ u32 *start, *p;
+ struct nfs4_readdir *readdir = GET_OP(cp, readdir);
+
+ BUG_ON(bufsize < 80);
+ readdir->rd_cookie = (cookie > 2) ? cookie : 0;
+ memcpy(readdir->rd_req_verifier, verifier, sizeof(nfs4_verifier));
+ readdir->rd_count = bufsize;
+ readdir->rd_bmval[0] = FATTR4_WORD0_FILEID;
+ readdir->rd_bmval[1] = 0;
+ readdir->rd_pages = pages;
+ readdir->rd_pgbase = 0;
+
+ OPNUM(cp) = OP_READDIR;
+ cp->req_nops++;
+
+ if (cookie >= 2)
+ return;
+
+ /*
+ * NFSv4 servers do not return entries for '.' and '..'
+ * Therefore, we fake these entries here. We let '.'
+ * have cookie 0 and '..' have cookie 1. Note that
+ * when talking to the server, we always send cookie 0
+ * instead of 1 or 2.
+ */
+ start = p = (u32 *)kmap(*pages);
+
+ if (cookie == 0) {
+ *p++ = xdr_one; /* next */
+ *p++ = xdr_zero; /* cookie, first word */
+ *p++ = xdr_one; /* cookie, second word */
+ *p++ = xdr_one; /* entry len */
+ memcpy(p, ".\0\0\0", 4); /* entry */
+ p++;
+ *p++ = xdr_one; /* bitmap length */
+ *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */
+ *p++ = htonl(8); /* attribute buffer length */
+ p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode));
+ }
+
+ *p++ = xdr_one; /* next */
+ *p++ = xdr_zero; /* cookie, first word */
+ *p++ = xdr_two; /* cookie, second word */
+ *p++ = xdr_two; /* entry len */
+ memcpy(p, "..\0\0", 4); /* entry */
+ p++;
+ *p++ = xdr_one; /* bitmap length */
+ *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */
+ *p++ = htonl(8); /* attribute buffer length */
+ p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode));
+
+ readdir->rd_pgbase = (char *)p - (char *)start;
+ readdir->rd_count -= readdir->rd_pgbase;
+ kunmap(*pages);
+}
+
+static void
+nfs4_setup_readlink(struct nfs4_compound *cp, int count, struct page **pages)
+{
+ struct nfs4_readlink *readlink = GET_OP(cp, readlink);
+
+ readlink->rl_count = count;
+ readlink->rl_pages = pages;
+
+ OPNUM(cp) = OP_READLINK;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_remove(struct nfs4_compound *cp, struct qstr *name, struct nfs4_change_info *cinfo)
+{
+ struct nfs4_remove *remove = GET_OP(cp, remove);
+
+ remove->rm_namelen = name->len;
+ remove->rm_name = name->name;
+ remove->rm_cinfo = cinfo;
+
+ OPNUM(cp) = OP_REMOVE;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_rename(struct nfs4_compound *cp, struct qstr *old, struct qstr *new,
+ struct nfs4_change_info *old_cinfo, struct nfs4_change_info *new_cinfo)
+{
+ struct nfs4_rename *rename = GET_OP(cp, rename);
+
+ rename->rn_oldnamelen = old->len;
+ rename->rn_oldname = old->name;
+ rename->rn_newnamelen = new->len;
+ rename->rn_newname = new->name;
+ rename->rn_src_cinfo = old_cinfo;
+ rename->rn_dst_cinfo = new_cinfo;
+
+ OPNUM(cp) = OP_RENAME;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_renew(struct nfs4_compound *cp)
+{
+ OPNUM(cp) = OP_RENEW;
+ cp->req_nops++;
+ cp->renew_index = cp->req_nops;
+}
+
+static void
+nfs4_setup_restorefh(struct nfs4_compound *cp)
+{
+ OPNUM(cp) = OP_RESTOREFH;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_savefh(struct nfs4_compound *cp)
+{
+ OPNUM(cp) = OP_SAVEFH;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_setattr(struct nfs4_compound *cp, char *stateid, struct iattr *iap)
+{
+ struct nfs4_setattr *setattr = GET_OP(cp, setattr);
+
+ setattr->st_stateid = stateid;
+ setattr->st_iap = iap;
+
+ OPNUM(cp) = OP_SETATTR;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_setclientid(struct nfs4_compound *cp, u32 program, unsigned short port)
+{
+ struct nfs4_setclientid *setclientid = GET_OP(cp, setclientid);
+ struct nfs_server *server = cp->server;
+ struct timeval tv;
+ u32 *p;
+
+ do_gettimeofday(&tv);
+ p = (u32 *)setclientid->sc_verifier;
+ *p++ = tv.tv_sec;
+ *p++ = tv.tv_usec;
+ setclientid->sc_name = server->ip_addr;
+ sprintf(setclientid->sc_netid, "udp");
+ sprintf(setclientid->sc_uaddr, "%s.%d.%d", server->ip_addr, port >> 8, port & 255);
+ setclientid->sc_prog = program;
+ setclientid->sc_cb_ident = 0;
+
+ OPNUM(cp) = OP_SETCLIENTID;
+ cp->req_nops++;
+}
+
+static void
+nfs4_setup_setclientid_confirm(struct nfs4_compound *cp)
+{
+ OPNUM(cp) = OP_SETCLIENTID_CONFIRM;
+ cp->req_nops++;
+ cp->renew_index = cp->req_nops;
+}
+
+static void
+nfs4_setup_write(struct nfs4_compound *cp, u64 offset, u32 length, int stable,
+ struct page **pages, unsigned int pgbase, u32 *bytes_written,
+ struct nfs_writeverf *verf)
+{
+ struct nfs4_write *write = GET_OP(cp, write);
+
+ write->wr_offset = offset;
+ write->wr_stable_how = stable;
+ write->wr_len = length;
+ write->wr_bytes_written = bytes_written;
+ write->wr_verf = verf;
+
+ write->wr_pages = pages;
+ write->wr_pgbase = pgbase;
+
+ OPNUM(cp) = OP_WRITE;
+ cp->req_nops++;
+}
+
+static inline void
+process_lease(struct nfs4_compound *cp)
+{
+ struct nfs_server *server;
+
+ /*
+ * Generic lease processing: If this operation contains a
+ * lease-renewing operation, and it succeeded, update the RENEW time
+ * in the superblock. Instead of the current time, we use the time
+ * when the request was sent out. (All we know is that the lease was
+ * renewed sometime between then and now, and we have to assume the
+ * worst case.)
+ *
+ * Notes:
+ * (1) renewd doesn't acquire the spinlock when messing with
+ * server->last_renewal; this is OK since rpciod always runs
+ * under the BKL.
+ * (2) cp->timestamp was set at the end of XDR encode.
+ */
+ if (!cp->renew_index)
+ return;
+ if (!cp->toplevel_status || cp->resp_nops > cp->renew_index) {
+ server = cp->server;
+ spin_lock(&renew_lock);
+ if (server->last_renewal < cp->timestamp)
+ server->last_renewal = cp->timestamp;
+ spin_unlock(&renew_lock);
+ }
+}
+
+static int
+nfs4_call_compound(struct nfs4_compound *cp, struct rpc_cred *cred, int flags)
+{
+ int status;
+ struct rpc_message msg = {
+ .rpc_proc = NFSPROC4_COMPOUND,
+ .rpc_argp = cp,
+ .rpc_resp = cp,
+ .rpc_cred = cred,
+ };
+
+ status = rpc_call_sync(cp->server->client, &msg, flags);
+ if (!status)
+ process_lease(cp);
+
+ return status;
+}
+
+static inline void
+process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr)
+{
+ BUG_ON((fattr->valid & NFS_ATTR_FATTR) == 0);
+ BUG_ON((fattr->valid & NFS_ATTR_FATTR_V4) == 0);
+
+ if (fattr->change_attr == info->after) {
+ fattr->pre_change_attr = info->before;
+ fattr->valid |= NFS_ATTR_PRE_CHANGE;
+ fattr->timestamp = jiffies;
+ }
+}
+
+static int
+do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr,
+ struct nfs_fattr *fattr, struct nfs_fh *fhandle, u32 *seqid, char *stateid)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[7];
+ struct nfs4_change_info dir_cinfo;
+ struct nfs_fattr dir_attr;
+ u32 dir_bmres[2];
+ u32 bmres[2];
+ u32 rflags;
+ int status;
+
+ dir_attr.valid = 0;
+ fattr->valid = 0;
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "open");
+ nfs4_setup_putfh(&compound, NFS_FH(dir));
+ nfs4_setup_savefh(&compound);
+ nfs4_setup_open(&compound, flags, name, sattr, stateid, &dir_cinfo, &rflags);
+ nfs4_setup_getattr(&compound, fattr, bmres);
+ nfs4_setup_getfh(&compound, fhandle);
+ nfs4_setup_restorefh(&compound);
+ nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+ if ((status = nfs4_call_compound(&compound, NULL, 0)))
+ return status;
+
+ process_cinfo(&dir_cinfo, &dir_attr);
+ nfs_refresh_inode(dir, &dir_attr);
+ if (!(rflags & NFS4_OPEN_RESULT_CONFIRM)) {
+ *seqid = 1;
+ return 0;
+ }
+ *seqid = 2;
+
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "open_confirm");
+ nfs4_setup_putfh(&compound, fhandle);
+ nfs4_setup_open_confirm(&compound, stateid);
+ return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
+ struct nfs_fh *fhandle, struct iattr *sattr, char *stateid)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[3];
+ u32 bmres[2];
+
+ fattr->valid = 0;
+ nfs4_setup_compound(&compound, ops, server, "setattr");
+ nfs4_setup_putfh(&compound, fhandle);
+ nfs4_setup_setattr(&compound, stateid, sattr);
+ nfs4_setup_getattr(&compound, fattr, bmres);
+ return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+do_close(struct nfs_server *server, struct nfs_fh *fhandle, u32 seqid, char *stateid)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[2];
+
+ nfs4_setup_compound(&compound, ops, server, "close");
+ nfs4_setup_putfh(&compound, fhandle);
+ nfs4_setup_close(&compound, stateid, seqid);
+ return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[4];
+ struct nfs_fsinfo fsinfo;
+ u32 bmres[2];
+ unsigned char * p;
+ struct qstr q;
+ int status;
+
+ fattr->valid = 0;
+
+ if (!(server->nfs4_state = nfs4_get_client()))
+ return -ENOMEM;
+
+ /*
+ * SETCLIENTID.
+ * Until delegations are imported, we don't bother setting the program
+ * number and port to anything meaningful.
+ */
+ nfs4_setup_compound(&compound, ops, server, "setclientid");
+ nfs4_setup_setclientid(&compound, 0, 0);
+ if ((status = nfs4_call_compound(&compound, NULL, 0)))
+ goto out;
+
+ /*
+ * SETCLIENTID_CONFIRM, plus root filehandle.
+ * We also get the lease time here.
+ */
+ nfs4_setup_compound(&compound, ops, server, "setclientid_confirm");
+ nfs4_setup_setclientid_confirm(&compound);
+ nfs4_setup_putrootfh(&compound);
+ nfs4_setup_getrootattr(&compound, fattr, &fsinfo, bmres);
+ nfs4_setup_getfh(&compound, fhandle);
+ if ((status = nfs4_call_compound(&compound, NULL, 0)))
+ goto out;
+
+ /*
+ * Now that we have instantiated the clientid and determined
+ * the lease time, we can initialize the renew daemon for this
+ * server.
+ */
+ server->lease_time = fsinfo.lease_time * HZ;
+ if ((status = nfs4_init_renewd(server)))
+ goto out;
+
+ /*
+ * Now we do a seperate LOOKUP for each component of the mount path.
+ * The LOOKUPs are done seperately so that we can conveniently
+ * catch an ERR_WRONGSEC if it occurs along the way...
+ */
+ p = server->mnt_path;
+ for (;;) {
+ while (*p == '/')
+ p++;
+ if (!*p)
+ break;
+ q.name = p;
+ while (*p && (*p != '/'))
+ p++;
+ q.len = p - q.name;
+
+ nfs4_setup_compound(&compound, ops, server, "mount");
+ nfs4_setup_putfh(&compound, fhandle);
+ nfs4_setup_lookup(&compound, &q);
+ nfs4_setup_getattr(&compound, fattr, bmres);
+ nfs4_setup_getfh(&compound, fhandle);
+ status = nfs4_call_compound(&compound, NULL, 0);
+ if (!status)
+ continue;
+ if (status == -ENOENT) {
+ printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path);
+ printk(KERN_NOTICE "NFS: suggestion: try mounting '/' instead.\n");
+ }
+ break;
+ }
+
+out:
+ return status;
+}
+
+static int
+nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[2];
+ u32 bmres[2];
+
+ fattr->valid = 0;
+
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "getattr");
+ nfs4_setup_putfh(&compound, NFS_FH(inode));
+ nfs4_setup_getattr(&compound, fattr, bmres);
+ return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+ struct iattr *sattr)
+{
+ struct inode * inode = dentry->d_inode;
+ int size_change = sattr->ia_valid & ATTR_SIZE;
+ struct nfs_fh throwaway_fh;
+ u32 seqid;
+ nfs4_stateid stateid;
+ int status;
+
+ fattr->valid = 0;
+
+ if (size_change) {
+ status = do_open(dentry->d_parent->d_inode, &dentry->d_name,
+ NFS4_SHARE_ACCESS_WRITE, NULL, fattr,
+ &throwaway_fh, &seqid, stateid);
+ if (status)
+ return status;
+
+ /*
+ * Because OPEN is always done by name in nfsv4, it is
+ * possible that we opened a different file by the same
+ * name. We can recognize this race condition, but we
+ * can't do anything about it besides returning an error.
+ *
+ * XXX: Should we compare filehandles too, as in
+ * nfs_find_actor()?
+ */
+ if (fattr->fileid != NFS_FILEID(inode)) {
+ printk(KERN_WARNING "nfs: raced in setattr, returning -EIO\n");
+ do_close(NFS_SERVER(inode), NFS_FH(inode), seqid, stateid);
+ return -EIO;
+ }
+ }
+ else
+ memcpy(stateid, zero_stateid, sizeof(nfs4_stateid));
+
+ status = do_setattr(NFS_SERVER(inode), fattr, NFS_FH(inode), sattr, stateid);
+ if (size_change)
+ do_close(NFS_SERVER(inode), NFS_FH(inode), seqid, stateid);
+ return status;
+}
+
+static int
+nfs4_proc_lookup(struct inode *dir, struct qstr *name,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[5];
+ struct nfs_fattr dir_attr;
+ u32 dir_bmres[2];
+ u32 bmres[2];
+ int status;
+
+ dir_attr.valid = 0;
+ fattr->valid = 0;
+
+ dprintk("NFS call lookup %s\n", name->name);
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "lookup");
+ nfs4_setup_putfh(&compound, NFS_FH(dir));
+ nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+ nfs4_setup_lookup(&compound, name);
+ nfs4_setup_getattr(&compound, fattr, bmres);
+ nfs4_setup_getfh(&compound, fhandle);
+ status = nfs4_call_compound(&compound, NULL, 0);
+ dprintk("NFS reply lookup: %d\n", status);
+
+ if (status >= 0)
+ status = nfs_refresh_inode(dir, &dir_attr);
+ return status;
+}
+
+static int
+nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[3];
+ struct nfs_fattr fattr;
+ u32 bmres[2];
+ u32 req_access = 0, resp_supported, resp_access;
+ int status;
+
+ fattr.valid = 0;
+
+ /*
+ * Determine which access bits we want to ask for...
+ */
+ if (mode & MAY_READ)
+ req_access |= NFS4_ACCESS_READ;
+ if (S_ISDIR(inode->i_mode)) {
+ if (mode & MAY_WRITE)
+ req_access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE;
+ if (mode & MAY_EXEC)
+ req_access |= NFS4_ACCESS_LOOKUP;
+ }
+ else {
+ if (mode & MAY_WRITE)
+ req_access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND;
+ if (mode & MAY_EXEC)
+ req_access |= NFS4_ACCESS_EXECUTE;
+ }
+
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "access");
+ nfs4_setup_putfh(&compound, NFS_FH(inode));
+ nfs4_setup_getattr(&compound, &fattr, bmres);
+ nfs4_setup_access(&compound, req_access, &resp_supported, &resp_access);
+ status = nfs4_call_compound(&compound, cred, 0);
+ nfs_refresh_inode(inode, &fattr);
+
+ if (!status) {
+ if (req_access != resp_supported) {
+ printk(KERN_NOTICE "NFS: server didn't support all access bits!\n");
+ status = -ENOTSUPP;
+ }
+ else if (req_access != resp_access)
+ status = -EACCES;
+ }
+ return status;
+}
+
+/*
+ * TODO: For the time being, we don't try to get any attributes
+ * along with any of the zero-copy operations READ, READDIR,
+ * READLINK, WRITE.
+ *
+ * In the case of the first three, we want to put the GETATTR
+ * after the read-type operation -- this is because it is hard
+ * to predict the length of a GETATTR response in v4, and thus
+ * align the READ data correctly. This means that the GETATTR
+ * may end up partially falling into the page cache, and we should
+ * shift it into the 'tail' of the xdr_buf before processing.
+ * To do this efficiently, we need to know the total length
+ * of data received, which doesn't seem to be available outside
+ * of the RPC layer.
+ *
+ * In the case of WRITE, we also want to put the GETATTR after
+ * the operation -- in this case because we want to make sure
+ * we get the post-operation mtime and size. This means that
+ * we can't use xdr_encode_pages() as written: we need a variant
+ * of it which would leave room in the 'tail' iovec.
+ *
+ * Both of these changes to the XDR layer would in fact be quite
+ * minor, but I decided to leave them for a subsequent patch.
+ */
+static int
+nfs4_proc_readlink(struct inode *inode, struct page *page)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[2];
+
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "readlink");
+ nfs4_setup_putfh(&compound, NFS_FH(inode));
+ nfs4_setup_readlink(&compound, PAGE_CACHE_SIZE, &page);
+ return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+nfs4_proc_read(struct inode *inode, struct rpc_cred *cred,
+ struct nfs_fattr *fattr, int flags,
+ unsigned int base, unsigned int count,
+ struct page *page, int *eofp)
+{
+ u64 offset = page_offset(page) + base;
+ struct nfs4_compound compound;
+ struct nfs4_op ops[2];
+ u32 bytes_read;
+ int status;
+
+ fattr->valid = 0;
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "read [sync]");
+ nfs4_setup_putfh(&compound, NFS_FH(inode));
+ nfs4_setup_read(&compound, offset, count, &page, base, eofp, &bytes_read);
+ status = nfs4_call_compound(&compound, cred, 0);
+
+ if (status >= 0)
+ status = bytes_read;
+ return status;
+}
+
+static int
+nfs4_proc_write(struct inode *inode, struct rpc_cred *cred,
+ struct nfs_fattr *fattr, int flags,
+ unsigned int base, unsigned int count,
+ struct page *page, struct nfs_writeverf *verf)
+{
+ u64 offset = page_offset(page) + base;
+ struct nfs4_compound compound;
+ struct nfs4_op ops[2];
+ u32 bytes_written;
+ int stable = (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE;
+ int rpcflags = (flags & NFS_RW_SWAP) ? NFS_RPC_SWAPFLAGS : 0;
+ int status;
+
+ fattr->valid = 0;
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "write [sync]");
+ nfs4_setup_putfh(&compound, NFS_FH(inode));
+ nfs4_setup_write(&compound, offset, count, stable, &page, base, &bytes_written, verf);
+ status = nfs4_call_compound(&compound, cred, rpcflags);
+
+ if (status >= 0)
+ status = bytes_written;
+ return status;
+}
+
+static int
+nfs4_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr,
+ int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+ int oflags;
+ u32 seqid;
+ nfs4_stateid stateid;
+ int status;
+
+ oflags = NFS4_SHARE_ACCESS_READ | O_CREAT | (flags & O_EXCL);
+ status = do_open(dir, name, oflags, sattr, fattr, fhandle, &seqid, stateid);
+ if (!status) {
+ if (flags & O_EXCL)
+ status = do_setattr(NFS_SERVER(dir), fattr, fhandle, sattr, stateid);
+ do_close(NFS_SERVER(dir), fhandle, seqid, stateid);
+ }
+ return status;
+}
+
+static int
+nfs4_proc_remove(struct inode *dir, struct qstr *name)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[3];
+ struct nfs4_change_info dir_cinfo;
+ struct nfs_fattr dir_attr;
+ u32 dir_bmres[2];
+ int status;
+
+ dir_attr.valid = 0;
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "remove");
+ nfs4_setup_putfh(&compound, NFS_FH(dir));
+ nfs4_setup_remove(&compound, name, &dir_cinfo);
+ nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+ status = nfs4_call_compound(&compound, NULL, 0);
+
+ if (!status) {
+ process_cinfo(&dir_cinfo, &dir_attr);
+ nfs_refresh_inode(dir, &dir_attr);
+ }
+ return status;
+}
+
+struct unlink_desc {
+ struct nfs4_compound compound;
+ struct nfs4_op ops[3];
+ struct nfs4_change_info cinfo;
+ struct nfs_fattr attrs;
+};
+
+static int
+nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name)
+{
+ struct unlink_desc * up;
+ struct nfs4_compound * cp;
+ u32 bmres[2];
+
+ up = (struct unlink_desc *) kmalloc(sizeof(*up), GFP_KERNEL);
+ if (!up)
+ return -ENOMEM;
+ cp = &up->compound;
+
+ nfs4_setup_compound(cp, up->ops, NFS_SERVER(dir->d_inode), "unlink_setup");
+ nfs4_setup_putfh(cp, NFS_FH(dir->d_inode));
+ nfs4_setup_remove(cp, name, &up->cinfo);
+ nfs4_setup_getattr(cp, &up->attrs, bmres);
+
+ msg->rpc_proc = NFSPROC4_COMPOUND;
+ msg->rpc_argp = cp;
+ msg->rpc_resp = cp;
+ return 0;
+}
+
+static int
+nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
+{
+ struct rpc_message *msg = &task->tk_msg;
+ struct unlink_desc *up;
+
+ if (msg->rpc_argp) {
+ up = (struct unlink_desc *) msg->rpc_argp;
+ process_lease(&up->compound);
+ process_cinfo(&up->cinfo, &up->attrs);
+ nfs_refresh_inode(dir->d_inode, &up->attrs);
+ kfree(up);
+ msg->rpc_argp = NULL;
+ }
+ return 0;
+}
+
+static int
+nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
+ struct inode *new_dir, struct qstr *new_name)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[7];
+ struct nfs4_change_info old_cinfo, new_cinfo;
+ struct nfs_fattr old_dir_attr, new_dir_attr;
+ u32 old_dir_bmres[2], new_dir_bmres[2];
+ int status;
+
+ old_dir_attr.valid = 0;
+ new_dir_attr.valid = 0;
+
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(old_dir), "rename");
+ nfs4_setup_putfh(&compound, NFS_FH(old_dir));
+ nfs4_setup_savefh(&compound);
+ nfs4_setup_putfh(&compound, NFS_FH(new_dir));
+ nfs4_setup_rename(&compound, old_name, new_name, &old_cinfo, &new_cinfo);
+ nfs4_setup_getattr(&compound, &new_dir_attr, new_dir_bmres);
+ nfs4_setup_restorefh(&compound);
+ nfs4_setup_getattr(&compound, &old_dir_attr, old_dir_bmres);
+ status = nfs4_call_compound(&compound, NULL, 0);
+
+ if (!status) {
+ process_cinfo(&old_cinfo, &old_dir_attr);
+ process_cinfo(&new_cinfo, &new_dir_attr);
+ nfs_refresh_inode(old_dir, &old_dir_attr);
+ nfs_refresh_inode(new_dir, &new_dir_attr);
+ }
+ return status;
+}
+
+static int
+nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[7];
+ struct nfs4_change_info dir_cinfo;
+ struct nfs_fattr dir_attr, fattr;
+ u32 dir_bmres[2], bmres[2];
+ int status;
+
+ dir_attr.valid = 0;
+ fattr.valid = 0;
+
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "link");
+ nfs4_setup_putfh(&compound, NFS_FH(inode));
+ nfs4_setup_savefh(&compound);
+ nfs4_setup_putfh(&compound, NFS_FH(dir));
+ nfs4_setup_link(&compound, name, &dir_cinfo);
+ nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+ nfs4_setup_restorefh(&compound);
+ nfs4_setup_getattr(&compound, &fattr, bmres);
+ status = nfs4_call_compound(&compound, NULL, 0);
+
+ if (!status) {
+ process_cinfo(&dir_cinfo, &dir_attr);
+ nfs_refresh_inode(dir, &dir_attr);
+ nfs_refresh_inode(inode, &fattr);
+ }
+ return status;
+}
+
+static int
+nfs4_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
+ struct iattr *sattr, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[7];
+ struct nfs_fattr dir_attr;
+ u32 dir_bmres[2], bmres[2];
+ struct nfs4_change_info dir_cinfo;
+ int status;
+
+ dir_attr.valid = 0;
+ fattr->valid = 0;
+
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "symlink");
+ nfs4_setup_putfh(&compound, NFS_FH(dir));
+ nfs4_setup_savefh(&compound);
+ nfs4_setup_create_symlink(&compound, name, path, sattr, &dir_cinfo);
+ nfs4_setup_getattr(&compound, fattr, bmres);
+ nfs4_setup_getfh(&compound, fhandle);
+ nfs4_setup_restorefh(&compound);
+ nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+ status = nfs4_call_compound(&compound, NULL, 0);
+
+ if (!status) {
+ process_cinfo(&dir_cinfo, &dir_attr);
+ nfs_refresh_inode(dir, &dir_attr);
+ }
+ return status;
+}
+
+static int
+nfs4_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[7];
+ struct nfs_fattr dir_attr;
+ u32 dir_bmres[2], bmres[2];
+ struct nfs4_change_info dir_cinfo;
+ int status;
+
+ dir_attr.valid = 0;
+ fattr->valid = 0;
+
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mkdir");
+ nfs4_setup_putfh(&compound, NFS_FH(dir));
+ nfs4_setup_savefh(&compound);
+ nfs4_setup_create_dir(&compound, name, sattr, &dir_cinfo);
+ nfs4_setup_getattr(&compound, fattr, bmres);
+ nfs4_setup_getfh(&compound, fhandle);
+ nfs4_setup_restorefh(&compound);
+ nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+ status = nfs4_call_compound(&compound, NULL, 0);
+
+ if (!status) {
+ process_cinfo(&dir_cinfo, &dir_attr);
+ nfs_refresh_inode(dir, &dir_attr);
+ }
+ return status;
+}
+
+static int
+nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
+ u64 cookie, struct page *page, unsigned int count, int plus)
+{
+ struct inode *dir = dentry->d_inode;
+ struct nfs4_compound compound;
+ struct nfs4_op ops[2];
+ int status;
+
+ lock_kernel();
+
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "readdir");
+ nfs4_setup_putfh(&compound, NFS_FH(dir));
+ nfs4_setup_readdir(&compound, cookie, NFS_COOKIEVERF(dir), &page, count, dentry);
+ status = nfs4_call_compound(&compound, cred, 0);
+
+ unlock_kernel();
+ return status;
+}
+
+static int
+nfs4_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
+ dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[7];
+ struct nfs_fattr dir_attr;
+ u32 dir_bmres[2], bmres[2];
+ struct nfs4_change_info dir_cinfo;
+ int status;
+
+ dir_attr.valid = 0;
+ fattr->valid = 0;
+
+ nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mknod");
+ nfs4_setup_putfh(&compound, NFS_FH(dir));
+ nfs4_setup_savefh(&compound);
+ nfs4_setup_create_special(&compound, name, rdev,sattr, &dir_cinfo);
+ nfs4_setup_getattr(&compound, fattr, bmres);
+ nfs4_setup_getfh(&compound, fh);
+ nfs4_setup_restorefh(&compound);
+ nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+ status = nfs4_call_compound(&compound, NULL, 0);
+
+ if (!status) {
+ process_cinfo(&dir_cinfo, &dir_attr);
+ nfs_refresh_inode(dir, &dir_attr);
+ }
+ return status;
+}
+
+static int
+nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fsstat *fsstat)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[2];
+ u32 bmres[2];
+
+ memset(fsstat, 0, sizeof(*fsstat));
+ nfs4_setup_compound(&compound, ops, server, "statfs");
+ nfs4_setup_putfh(&compound, fhandle);
+ nfs4_setup_statfs(&compound, fsstat, bmres);
+ return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fsinfo *fsinfo)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[2];
+ u32 bmres[2];
+
+ memset(fsinfo, 0, sizeof(*fsinfo));
+ nfs4_setup_compound(&compound, ops, server, "statfs");
+ nfs4_setup_putfh(&compound, fhandle);
+ nfs4_setup_fsinfo(&compound, fsinfo, bmres);
+ return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_pathconf *pathconf)
+{
+ struct nfs4_compound compound;
+ struct nfs4_op ops[2];
+ u32 bmres[2];
+
+ memset(pathconf, 0, sizeof(*pathconf));
+ nfs4_setup_compound(&compound, ops, server, "statfs");
+ nfs4_setup_putfh(&compound, fhandle);
+ nfs4_setup_pathconf(&compound, pathconf, bmres);
+ return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static void
+nfs4_read_done(struct rpc_task *task)
+{
+ struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
+
+ process_lease(&data->u.v4.compound);
+ nfs_readpage_result(task, data->u.v4.res_count, data->u.v4.res_eof);
+}
+
+static void
+nfs4_proc_read_setup(struct nfs_read_data *data, unsigned int count)
+{
+ struct rpc_task *task = &data->task;
+ struct nfs4_compound *cp = &data->u.v4.compound;
+ struct rpc_message msg = {
+ .rpc_proc = NFSPROC4_COMPOUND,
+ .rpc_argp = cp,
+ .rpc_resp = cp,
+ .rpc_cred = data->cred,
+ };
+ struct inode *inode = data->inode;
+ struct nfs_page *req = nfs_list_entry(data->pages.next);
+ int flags;
+
+ nfs4_setup_compound(cp, data->u.v4.ops, NFS_SERVER(inode), "read [async]");
+ nfs4_setup_putfh(cp, NFS_FH(inode));
+ nfs4_setup_read(cp, req_offset(req) + req->wb_offset,
+ count, data->pagevec, req->wb_offset,
+ &data->u.v4.res_eof,
+ &data->u.v4.res_count);
+
+ /* N.B. Do we need to test? Never called for swapfile inode */
+ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
+
+ /* Finalize the task. */
+ rpc_init_task(task, NFS_CLIENT(inode), nfs4_read_done, flags);
+ task->tk_calldata = data;
+ /* Release requests */
+ task->tk_release = nfs_readdata_release;
+
+ rpc_call_setup(task, &msg, 0);
+}
+
+static void
+nfs4_write_done(struct rpc_task *task)
+{
+ struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+
+ process_lease(&data->u.v4.compound);
+ nfs_writeback_done(task, data->u.v4.arg_stable,
+ data->u.v4.arg_count, data->u.v4.res_count);
+}
+
+static void
+nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
+{
+ struct rpc_task *task = &data->task;
+ struct nfs4_compound *cp = &data->u.v4.compound;
+ struct rpc_message msg = {
+ .rpc_proc = NFSPROC4_COMPOUND,
+ .rpc_argp = cp,
+ .rpc_resp = cp,
+ .rpc_cred = data->cred,
+ };
+ struct inode *inode = data->inode;
+ struct nfs_page *req = nfs_list_entry(data->pages.next);
+ int stable;
+ int flags;
+
+ if (how & FLUSH_STABLE) {
+ if (!NFS_I(inode)->ncommit)
+ stable = NFS_FILE_SYNC;
+ else
+ stable = NFS_DATA_SYNC;
+ } else
+ stable = NFS_UNSTABLE;
+
+ nfs4_setup_compound(cp, data->u.v4.ops, NFS_SERVER(inode), "write [async]");
+ nfs4_setup_putfh(cp, NFS_FH(inode));
+ nfs4_setup_write(cp, req_offset(req) + req->wb_offset,
+ count, stable, data->pagevec, req->wb_offset,
+ &data->u.v4.res_count, &data->verf);
+
+ /* Set the initial flags for the task. */
+ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
+
+ /* Finalize the task. */
+ rpc_init_task(task, NFS_CLIENT(inode), nfs4_write_done, flags);
+ task->tk_calldata = data;
+ /* Release requests */
+ task->tk_release = nfs_writedata_release;
+
+ rpc_call_setup(task, &msg, 0);
+}
+
+static void
+nfs4_commit_done(struct rpc_task *task)
+{
+ struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+
+ process_lease(&data->u.v4.compound);
+ nfs_commit_done(task);
+}
+
+static void
+nfs4_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
+{
+ struct rpc_task *task = &data->task;
+ struct nfs4_compound *cp = &data->u.v4.compound;
+ struct rpc_message msg = {
+ .rpc_proc = NFSPROC4_COMPOUND,
+ .rpc_argp = cp,
+ .rpc_resp = cp,
+ .rpc_cred = data->cred,
+ };
+ struct inode *inode = data->inode;
+ int flags;
+
+ nfs4_setup_compound(cp, data->u.v4.ops, NFS_SERVER(inode), "commit [async]");
+ nfs4_setup_putfh(cp, NFS_FH(inode));
+ nfs4_setup_commit(cp, start, len, &data->verf);
+
+ /* Set the initial flags for the task. */
+ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
+
+ /* Finalize the task. */
+ rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags);
+ task->tk_calldata = data;
+ /* Release requests */
+ task->tk_release = nfs_writedata_release;
+
+ rpc_call_setup(task, &msg, 0);
+}
+
+/*
+ * nfs4_proc_renew(): This is not one of the nfs_rpc_ops; it is a special
+ * standalone procedure for queueing an asynchronous RENEW.
+ */
+struct renew_desc {
+ struct rpc_task task;
+ struct nfs4_compound compound;
+ struct nfs4_op ops[1];
+};
+
+static void
+renew_done(struct rpc_task *task)
+{
+ struct nfs4_compound *cp = (struct nfs4_compound *) task->tk_msg.rpc_argp;
+ process_lease(cp);
+}
+
+static void
+renew_release(struct rpc_task *task)
+{
+ kfree(task->tk_calldata);
+ task->tk_calldata = NULL;
+}
+
+int
+nfs4_proc_renew(struct nfs_server *server)
+{
+ struct renew_desc *rp;
+ struct rpc_task *task;
+ struct nfs4_compound *cp;
+ struct rpc_message msg;
+
+ rp = (struct renew_desc *) kmalloc(sizeof(*rp), GFP_KERNEL);
+ if (!rp)
+ return -ENOMEM;
+ cp = &rp->compound;
+ task = &rp->task;
+
+ nfs4_setup_compound(cp, rp->ops, server, "renew");
+ nfs4_setup_renew(cp);
+
+ msg.rpc_proc = NFSPROC4_COMPOUND;
+ msg.rpc_argp = cp;
+ msg.rpc_resp = cp;
+ msg.rpc_cred = NULL;
+ rpc_init_task(task, server->client, renew_done, RPC_TASK_ASYNC);
+ rpc_call_setup(task, &msg, 0);
+ task->tk_calldata = rp;
+ task->tk_release = renew_release;
+
+ return rpc_execute(task);
+}
+
+struct nfs_rpc_ops nfs_v4_clientops = {
+ .version = 4, /* protocol version */
+ .getroot = nfs4_proc_get_root,
+ .getattr = nfs4_proc_getattr,
+ .setattr = nfs4_proc_setattr,
+ .lookup = nfs4_proc_lookup,
+ .access = nfs4_proc_access,
+ .readlink = nfs4_proc_readlink,
+ .read = nfs4_proc_read,
+ .write = nfs4_proc_write,
+ .commit = NULL,
+ .create = nfs4_proc_create,
+ .remove = nfs4_proc_remove,
+ .unlink_setup = nfs4_proc_unlink_setup,
+ .unlink_done = nfs4_proc_unlink_done,
+ .rename = nfs4_proc_rename,
+ .link = nfs4_proc_link,
+ .symlink = nfs4_proc_symlink,
+ .mkdir = nfs4_proc_mkdir,
+ .rmdir = nfs4_proc_remove,
+ .readdir = nfs4_proc_readdir,
+ .mknod = nfs4_proc_mknod,
+ .statfs = nfs4_proc_statfs,
+ .fsinfo = nfs4_proc_fsinfo,
+ .pathconf = nfs4_proc_pathconf,
+ .decode_dirent = nfs4_decode_dirent,
+ .read_setup = nfs4_proc_read_setup,
+ .write_setup = nfs4_proc_write_setup,
+ .commit_setup = nfs4_proc_commit_setup,
+};
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
new file mode 100644
index 000000000000..4ba871885dbc
--- /dev/null
+++ b/fs/nfs/nfs4renewd.c
@@ -0,0 +1,110 @@
+/*
+ * fs/nfs/nfs4renewd.c
+ *
+ * Copyright (c) 2002 The Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Kendrick Smith <kmsmith@umich.edu>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Implementation of the NFSv4 "renew daemon", which wakes up periodically to
+ * send a RENEW, to keep state alive on the server. The daemon is implemented
+ * as an rpc_task, not a real kernel thread, so it always runs in rpciod's
+ * context. There is one renewd per nfs_server.
+ *
+ * TODO: If the send queue gets backlogged (e.g., if the server goes down),
+ * we will keep filling the queue with periodic RENEW requests. We need a
+ * mechanism for ensuring that if renewd successfully sends off a request,
+ * then it only wakes up when the request is finished. Maybe use the
+ * child task framework of the RPC layer?
+ */
+
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/clnt.h>
+
+#include <linux/nfs.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_fs.h>
+
+static RPC_WAITQ(nfs4_renewd_queue, "nfs4_renewd_queue");
+
+static void
+renewd(struct rpc_task *task)
+{
+ struct nfs_server *server = (struct nfs_server *)task->tk_calldata;
+ unsigned long lease = server->lease_time;
+ unsigned long last = server->last_renewal;
+ unsigned long timeout;
+
+ if (!server->nfs4_state)
+ timeout = (2 * lease) / 3;
+ else if (jiffies < last + lease/3)
+ timeout = (2 * lease) / 3 + last - jiffies;
+ else {
+ /* Queue an asynchronous RENEW. */
+ nfs4_proc_renew(server);
+ timeout = (2 * lease) / 3;
+ }
+
+ if (timeout < 5 * HZ) /* safeguard */
+ timeout = 5 * HZ;
+ task->tk_timeout = timeout;
+ task->tk_action = renewd;
+ task->tk_exit = NULL;
+ rpc_sleep_on(&nfs4_renewd_queue, task, NULL, NULL);
+ return;
+}
+
+int
+nfs4_init_renewd(struct nfs_server *server)
+{
+ struct rpc_task *task;
+ int status;
+
+ lock_kernel();
+ status = -ENOMEM;
+ task = rpc_new_task(server->client, NULL, RPC_TASK_ASYNC);
+ if (!task)
+ goto out;
+ task->tk_calldata = server;
+ task->tk_action = renewd;
+ status = rpc_execute(task);
+
+out:
+ unlock_kernel();
+ return status;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
new file mode 100644
index 000000000000..ecbc54fb1048
--- /dev/null
+++ b/fs/nfs/nfs4state.c
@@ -0,0 +1,81 @@
+/*
+ * fs/nfs/nfs4state.c
+ *
+ * Client-side XDR for NFSv4.
+ *
+ * Copyright (c) 2002 The Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Kendrick Smith <kmsmith@umich.edu>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Implementation of the NFSv4 state model. For the time being,
+ * this is minimal, but will be made much more complex in a
+ * subsequent patch.
+ */
+
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/nfs_fs.h>
+
+/*
+ * nfs4_get_client(): returns an empty client structure
+ * nfs4_put_client(): drops reference to client structure
+ *
+ * Since these are allocated/deallocated very rarely, we don't
+ * bother putting them in a slab cache...
+ */
+struct nfs4_client *
+nfs4_get_client(void)
+{
+ struct nfs4_client *clp;
+
+ if ((clp = kmalloc(sizeof(*clp), GFP_KERNEL))) {
+ atomic_set(&clp->cl_count, 1);
+ clp->cl_clientid = 0;
+ INIT_LIST_HEAD(&clp->cl_lockowners);
+ }
+ return clp;
+}
+
+void
+nfs4_put_client(struct nfs4_client *clp)
+{
+ BUG_ON(!clp);
+ BUG_ON(!atomic_read(&clp->cl_count));
+
+ if (atomic_dec_and_test(&clp->cl_count)) {
+ BUG_ON(!list_empty(&clp->cl_lockowners));
+ kfree(clp);
+ }
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
new file mode 100644
index 000000000000..edbf0e2a02d7
--- /dev/null
+++ b/fs/nfs/nfs4xdr.c
@@ -0,0 +1,1777 @@
+/*
+ * fs/nfs/nfs4xdr.c
+ *
+ * Client-side XDR for NFSv4.
+ *
+ * Copyright (c) 2002 The Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Kendrick Smith <kmsmith@umich.edu>
+ * Andy Adamson <andros@umich.edu>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/param.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/utsname.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/pagemap.h>
+#include <linux/proc_fs.h>
+#include <linux/kdev_t.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_fs.h>
+
+/* Emperically, it seems that the NFS client gets confused if
+ * cookies larger than this are returned -- presumably a
+ * signedness issue?
+ */
+#define COOKIE_MAX 0x7fffffff
+
+#define NFS4_CLIENTID(server) ((server)->nfs4_state->cl_clientid)
+
+#define NFSDBG_FACILITY NFSDBG_XDR
+
+/* Mapping from NFS error code to "errno" error code. */
+#define errno_NFSERR_IO EIO
+
+extern int nfs_stat_to_errno(int);
+
+#define NFS4_enc_void_sz 0
+#define NFS4_dec_void_sz 0
+#define NFS4_enc_compound_sz 1024 /* XXX: large enough? */
+#define NFS4_dec_compound_sz 1024 /* XXX: large enough? */
+
+static struct {
+ unsigned int mode;
+ unsigned int nfs2type;
+} nfs_type2fmt[] = {
+ { 0, NFNON },
+ { S_IFREG, NFREG },
+ { S_IFDIR, NFDIR },
+ { S_IFBLK, NFBLK },
+ { S_IFCHR, NFCHR },
+ { S_IFLNK, NFLNK },
+ { S_IFSOCK, NFSOCK },
+ { S_IFIFO, NFFIFO },
+ { 0, NFNON },
+ { 0, NFNON },
+};
+
+/*
+ * START OF "GENERIC" ENCODE ROUTINES.
+ * These may look a little ugly since they are imported from a "generic"
+ * set of XDR encode/decode routines which are intended to be shared by
+ * all of our NFSv4 implementations (OpenBSD, MacOS X...).
+ *
+ * If the pain of reading these is too great, it should be a straightforward
+ * task to translate them into Linux-specific versions which are more
+ * consistent with the style used in NFSv2/v3...
+ */
+#define ENCODE_HEAD \
+ u32 *p;
+#define ENCODE_TAIL \
+ return 0
+
+#define WRITE32(n) *p++ = htonl(n)
+#define WRITE64(n) do { \
+ *p++ = htonl((u32)((n) >> 32)); \
+ *p++ = htonl((u32)(n)); \
+} while (0)
+#define WRITEMEM(ptr,nbytes) do { \
+ p = xdr_writemem(p, ptr, nbytes); \
+} while (0)
+
+#define RESERVE_SPACE(nbytes) do { BUG_ON(cp->p + XDR_QUADLEN(nbytes) > cp->end); p = cp->p; } while (0)
+#define ADJUST_ARGS() cp->p = p
+
+static inline
+u32 *xdr_writemem(u32 *p, const void *ptr, int nbytes)
+{
+ int tmp = XDR_QUADLEN(nbytes);
+ if (!tmp)
+ return p;
+ p[tmp-1] = 0;
+ memcpy(p, ptr, nbytes);
+ return p + tmp;
+}
+
+/*
+ * FIXME: The following dummy entries will be replaced once the userland
+ * upcall gets in...
+ */
+static int
+encode_uid(char *p, uid_t uid)
+{
+ strcpy(p, "nobody");
+ return 6;
+}
+
+/*
+ * FIXME: The following dummy entries will be replaced once the userland
+ * upcall gets in...
+ */
+static int
+encode_gid(char *p, gid_t gid)
+{
+ strcpy(p, "nobody");
+ return 6;
+}
+
+static int
+encode_attrs(struct nfs4_compound *cp, struct iattr *iap)
+{
+ char owner_name[256];
+ char owner_group[256];
+ int owner_namelen = 0;
+ int owner_grouplen = 0;
+ u32 *q;
+ int len;
+ u32 bmval0 = 0;
+ u32 bmval1 = 0;
+ int status;
+ ENCODE_HEAD;
+
+ /*
+ * We reserve enough space to write the entire attribute buffer at once.
+ * In the worst-case, this would be
+ * 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
+ * = 36 bytes, plus any contribution from variable-length fields
+ * such as owner/group/acl's.
+ */
+ len = 36;
+
+ /* Sigh */
+ if (iap->ia_valid & ATTR_UID) {
+ status = owner_namelen = encode_uid(owner_name, iap->ia_uid);
+ if (status < 0) {
+ printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n",
+ iap->ia_uid);
+ goto out;
+ }
+ len += XDR_QUADLEN(owner_namelen);
+ }
+ if (iap->ia_valid & ATTR_GID) {
+ status = owner_grouplen = encode_gid(owner_group, iap->ia_gid);
+ if (status < 0) {
+ printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n",
+ iap->ia_gid);
+ goto out;
+ }
+ len += XDR_QUADLEN(owner_grouplen);
+ }
+ RESERVE_SPACE(len);
+
+ /*
+ * We write the bitmap length now, but leave the bitmap and the attribute
+ * buffer length to be backfilled at the end of this routine.
+ */
+ WRITE32(2);
+ q = p;
+ p += 3;
+
+ if (iap->ia_valid & ATTR_SIZE) {
+ bmval0 |= FATTR4_WORD0_SIZE;
+ WRITE64(iap->ia_size);
+ }
+ if (iap->ia_valid & ATTR_MODE) {
+ bmval1 |= FATTR4_WORD1_MODE;
+ WRITE32(iap->ia_mode);
+ }
+ if (iap->ia_valid & ATTR_UID) {
+ bmval1 |= FATTR4_WORD1_OWNER;
+ WRITE32(owner_namelen);
+ WRITEMEM(owner_name, owner_namelen);
+ p += owner_namelen;
+ }
+ if (iap->ia_valid & ATTR_GID) {
+ bmval1 |= FATTR4_WORD1_OWNER_GROUP;
+ WRITE32(owner_grouplen);
+ WRITEMEM(owner_group, owner_grouplen);
+ p += owner_namelen;
+ }
+ if (iap->ia_valid & ATTR_ATIME_SET) {
+ bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
+ WRITE32(NFS4_SET_TO_CLIENT_TIME);
+ WRITE32(0);
+ WRITE32(iap->ia_mtime);
+ WRITE32(0);
+ }
+ else if (iap->ia_valid & ATTR_ATIME) {
+ bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
+ WRITE32(NFS4_SET_TO_SERVER_TIME);
+ }
+ if (iap->ia_valid & ATTR_MTIME_SET) {
+ bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
+ WRITE32(NFS4_SET_TO_CLIENT_TIME);
+ WRITE32(0);
+ WRITE32(iap->ia_mtime);
+ WRITE32(0);
+ }
+ else if (iap->ia_valid & ATTR_MTIME) {
+ bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
+ WRITE32(NFS4_SET_TO_SERVER_TIME);
+ }
+
+ ADJUST_ARGS();
+
+ /*
+ * Now we backfill the bitmap and the attribute buffer length.
+ */
+ len = (char *)p - (char *)q - 12;
+ *q++ = htonl(bmval0);
+ *q++ = htonl(bmval1);
+ *q++ = htonl(len);
+
+ status = 0;
+out:
+ return status;
+}
+
+static int
+encode_access(struct nfs4_compound *cp, struct nfs4_access *access)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(8);
+ WRITE32(OP_ACCESS);
+ WRITE32(access->ac_req_access);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_close(struct nfs4_compound *cp, struct nfs4_close *close)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(20);
+ WRITE32(OP_CLOSE);
+ WRITE32(close->cl_seqid);
+ WRITEMEM(close->cl_stateid, sizeof(nfs4_stateid));
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_commit(struct nfs4_compound *cp, struct nfs4_commit *commit)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(16);
+ WRITE32(OP_COMMIT);
+ WRITE64(commit->co_start);
+ WRITE32(commit->co_len);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_create(struct nfs4_compound *cp, struct nfs4_create *create)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(8);
+ WRITE32(OP_CREATE);
+ WRITE32(create->cr_ftype);
+ ADJUST_ARGS();
+
+ switch (create->cr_ftype) {
+ case NF4LNK:
+ RESERVE_SPACE(4 + create->cr_textlen);
+ WRITE32(create->cr_textlen);
+ WRITEMEM(create->cr_text, create->cr_textlen);
+ ADJUST_ARGS();
+ break;
+
+ case NF4BLK: case NF4CHR:
+ RESERVE_SPACE(8);
+ WRITE32(create->cr_specdata1);
+ WRITE32(create->cr_specdata2);
+ ADJUST_ARGS();
+ break;
+
+ default:
+ break;
+ }
+
+ RESERVE_SPACE(4 + create->cr_namelen);
+ WRITE32(create->cr_namelen);
+ WRITEMEM(create->cr_name, create->cr_namelen);
+ ADJUST_ARGS();
+
+ return encode_attrs(cp, create->cr_attrs);
+}
+
+static int
+encode_getattr(struct nfs4_compound *cp, struct nfs4_getattr *getattr)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(16);
+ WRITE32(OP_GETATTR);
+ WRITE32(2);
+ WRITE32(getattr->gt_bmval[0]);
+ WRITE32(getattr->gt_bmval[1]);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_getfh(struct nfs4_compound *cp)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(4);
+ WRITE32(OP_GETFH);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_link(struct nfs4_compound *cp, struct nfs4_link *link)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(8 + link->ln_namelen);
+ WRITE32(OP_LINK);
+ WRITE32(link->ln_namelen);
+ WRITEMEM(link->ln_name, link->ln_namelen);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_lookup(struct nfs4_compound *cp, struct nfs4_lookup *lookup)
+{
+ int len = lookup->lo_name->len;
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(8 + len);
+ WRITE32(OP_LOOKUP);
+ WRITE32(len);
+ WRITEMEM(lookup->lo_name->name, len);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_open(struct nfs4_compound *cp, struct nfs4_open *open)
+{
+ static int global_id = 0;
+ int id = global_id++;
+ int status;
+ ENCODE_HEAD;
+
+ /* seqid, share_access, share_deny, clientid, ownerlen, owner, opentype */
+ RESERVE_SPACE(52);
+ WRITE32(OP_OPEN);
+ WRITE32(0); /* seqid */
+ WRITE32(open->op_share_access);
+ WRITE32(0); /* for us, share_deny== 0 always */
+ WRITE64(NFS4_CLIENTID(cp->server));
+ WRITE32(4);
+ WRITE32(id);
+ WRITE32(open->op_opentype);
+ ADJUST_ARGS();
+
+ if (open->op_opentype == NFS4_OPEN_CREATE) {
+ if (open->op_createmode == NFS4_CREATE_EXCLUSIVE) {
+ RESERVE_SPACE(12);
+ WRITE32(open->op_createmode);
+ WRITEMEM(open->op_verifier, sizeof(nfs4_verifier));
+ ADJUST_ARGS();
+ }
+ else if (open->op_attrs) {
+ RESERVE_SPACE(4);
+ WRITE32(open->op_createmode);
+ ADJUST_ARGS();
+ if ((status = encode_attrs(cp, open->op_attrs)))
+ return status;
+ }
+ else {
+ RESERVE_SPACE(12);
+ WRITE32(open->op_createmode);
+ WRITE32(0);
+ WRITE32(0);
+ ADJUST_ARGS();
+ }
+ }
+
+ RESERVE_SPACE(8 + open->op_name->len);
+ WRITE32(NFS4_OPEN_CLAIM_NULL);
+ WRITE32(open->op_name->len);
+ WRITEMEM(open->op_name->name, open->op_name->len);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_open_confirm(struct nfs4_compound *cp, struct nfs4_open_confirm *open_confirm)
+{
+ ENCODE_HEAD;
+
+ /*
+ * Note: In this "stateless" implementation, the OPEN_CONFIRM
+ * seqid is always equal to 1.
+ */
+ RESERVE_SPACE(24);
+ WRITE32(OP_OPEN_CONFIRM);
+ WRITEMEM(open_confirm->oc_stateid, sizeof(nfs4_stateid));
+ WRITE32(1);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_putfh(struct nfs4_compound *cp, struct nfs4_putfh *putfh)
+{
+ int len = putfh->pf_fhandle->size;
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(8 + len);
+ WRITE32(OP_PUTFH);
+ WRITE32(len);
+ WRITEMEM(putfh->pf_fhandle->data, len);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_putrootfh(struct nfs4_compound *cp)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(4);
+ WRITE32(OP_PUTROOTFH);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_read(struct nfs4_compound *cp, struct nfs4_read *read, struct rpc_rqst *req)
+{
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+ int replen;
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(32);
+ WRITE32(OP_READ);
+ WRITE32(0); /* all-zero stateid! */
+ WRITE32(0);
+ WRITE32(0);
+ WRITE32(0);
+ WRITE64(read->rd_offset);
+ WRITE32(read->rd_length);
+ ADJUST_ARGS();
+
+ /* set up reply iovec
+ * toplevel status + taglen + rescount + OP_PUTFH + status
+ * + OP_READ + status + eof + datalen = 9
+ */
+ replen = (RPC_REPHDRSIZE + auth->au_rslack + 9 + XDR_QUADLEN(cp->taglen)) << 2;
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ xdr_inline_pages(&req->rq_rcv_buf, replen,
+ read->rd_pages, read->rd_pgbase, read->rd_length);
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_readdir(struct nfs4_compound *cp, struct nfs4_readdir *readdir, struct rpc_rqst *req)
+{
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+ int replen;
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(40);
+ WRITE32(OP_READDIR);
+ WRITE64(readdir->rd_cookie);
+ WRITEMEM(readdir->rd_req_verifier, sizeof(nfs4_verifier));
+ WRITE32(readdir->rd_count >> 5); /* meaningless "dircount" field */
+ WRITE32(readdir->rd_count);
+ WRITE32(2);
+ WRITE32(readdir->rd_bmval[0]);
+ WRITE32(readdir->rd_bmval[1]);
+ ADJUST_ARGS();
+
+ /* set up reply iovec
+ * toplevel_status + taglen + rescount + OP_PUTFH + status
+ * + OP_READDIR + status + verifer(2) = 9
+ */
+ replen = (RPC_REPHDRSIZE + auth->au_rslack + 9 + XDR_QUADLEN(cp->taglen)) << 2;
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->rd_pages,
+ readdir->rd_pgbase, readdir->rd_count);
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_readlink(struct nfs4_compound *cp, struct nfs4_readlink *readlink, struct rpc_rqst *req)
+{
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+ int replen;
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(4);
+ WRITE32(OP_READLINK);
+ ADJUST_ARGS();
+
+ /* set up reply iovec
+ * toplevel_status + taglen + rescount + OP_PUTFH + status
+ * + OP_READLINK + status = 7
+ */
+ replen = (RPC_REPHDRSIZE + auth->au_rslack + 7 + XDR_QUADLEN(cp->taglen)) << 2;
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->rl_pages, 0, readlink->rl_count);
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_remove(struct nfs4_compound *cp, struct nfs4_remove *remove)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(8 + remove->rm_namelen);
+ WRITE32(OP_REMOVE);
+ WRITE32(remove->rm_namelen);
+ WRITEMEM(remove->rm_name, remove->rm_namelen);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_rename(struct nfs4_compound *cp, struct nfs4_rename *rename)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(8 + rename->rn_oldnamelen);
+ WRITE32(OP_RENAME);
+ WRITE32(rename->rn_oldnamelen);
+ WRITEMEM(rename->rn_oldname, rename->rn_oldnamelen);
+ ADJUST_ARGS();
+
+ RESERVE_SPACE(8 + rename->rn_newnamelen);
+ WRITE32(rename->rn_newnamelen);
+ WRITEMEM(rename->rn_newname, rename->rn_newnamelen);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_renew(struct nfs4_compound *cp)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(12);
+ WRITE32(OP_RENEW);
+ WRITE64(NFS4_CLIENTID(cp->server));
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_restorefh(struct nfs4_compound *cp)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(4);
+ WRITE32(OP_RESTOREFH);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_savefh(struct nfs4_compound *cp)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(4);
+ WRITE32(OP_SAVEFH);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_setattr(struct nfs4_compound *cp, struct nfs4_setattr *setattr)
+{
+ int status;
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(20);
+ WRITE32(OP_SETATTR);
+ WRITEMEM(setattr->st_stateid, sizeof(nfs4_stateid));
+ ADJUST_ARGS();
+
+ if ((status = encode_attrs(cp, setattr->st_iap)))
+ return status;
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_setclientid(struct nfs4_compound *cp, struct nfs4_setclientid *setclientid)
+{
+ u32 total_len;
+ u32 len1, len2, len3;
+ ENCODE_HEAD;
+
+ len1 = strlen(setclientid->sc_name);
+ len2 = strlen(setclientid->sc_netid);
+ len3 = strlen(setclientid->sc_uaddr);
+ total_len = XDR_QUADLEN(len1) + XDR_QUADLEN(len2) + XDR_QUADLEN(len3);
+ total_len = (total_len << 2) + 32;
+
+ RESERVE_SPACE(total_len);
+ WRITE32(OP_SETCLIENTID);
+ WRITEMEM(setclientid->sc_verifier, sizeof(nfs4_verifier));
+ WRITE32(len1);
+ WRITEMEM(setclientid->sc_name, len1);
+ WRITE32(setclientid->sc_prog);
+ WRITE32(len2);
+ WRITEMEM(setclientid->sc_netid, len2);
+ WRITE32(len3);
+ WRITEMEM(setclientid->sc_uaddr, len3);
+ WRITE32(setclientid->sc_cb_ident);
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_setclientid_confirm(struct nfs4_compound *cp)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(12 + sizeof(nfs4_verifier));
+ WRITE32(OP_SETCLIENTID_CONFIRM);
+ WRITE64(cp->server->nfs4_state->cl_clientid);
+ WRITEMEM(cp->server->nfs4_state->cl_confirm,sizeof(nfs4_verifier));
+ ADJUST_ARGS();
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_write(struct nfs4_compound *cp, struct nfs4_write *write, struct rpc_rqst *req)
+{
+ struct xdr_buf *sndbuf = &req->rq_snd_buf;
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(36);
+ WRITE32(OP_WRITE);
+ WRITE32(0xffffffff); /* magic stateid -1 */
+ WRITE32(0xffffffff);
+ WRITE32(0xffffffff);
+ WRITE32(0xffffffff);
+ WRITE64(write->wr_offset);
+ WRITE32(write->wr_stable_how);
+ WRITE32(write->wr_len);
+ ADJUST_ARGS();
+
+ sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
+ xdr_encode_pages(sndbuf, write->wr_pages, write->wr_pgbase, write->wr_len);
+
+ ENCODE_TAIL;
+}
+
+static int
+encode_compound(struct nfs4_compound *cp, struct rpc_rqst *req)
+{
+ int i, status = 0;
+ ENCODE_HEAD;
+
+ dprintk("encode_compound: tag=%.*s\n", (int)cp->taglen, cp->tag);
+
+ RESERVE_SPACE(12 + cp->taglen);
+ WRITE32(cp->taglen);
+ WRITEMEM(cp->tag, cp->taglen);
+ WRITE32(NFS4_MINOR_VERSION);
+ WRITE32(cp->req_nops);
+ ADJUST_ARGS();
+
+ for (i = 0; i < cp->req_nops; i++) {
+ switch (cp->ops[i].opnum) {
+ case OP_ACCESS:
+ status = encode_access(cp, &cp->ops[i].u.access);
+ break;
+ case OP_CLOSE:
+ status = encode_close(cp, &cp->ops[i].u.close);
+ break;
+ case OP_COMMIT:
+ status = encode_commit(cp, &cp->ops[i].u.commit);
+ break;
+ case OP_CREATE:
+ status = encode_create(cp, &cp->ops[i].u.create);
+ break;
+ case OP_GETATTR:
+ status = encode_getattr(cp, &cp->ops[i].u.getattr);
+ break;
+ case OP_GETFH:
+ status = encode_getfh(cp);
+ break;
+ case OP_LINK:
+ status = encode_link(cp, &cp->ops[i].u.link);
+ break;
+ case OP_LOOKUP:
+ status = encode_lookup(cp, &cp->ops[i].u.lookup);
+ break;
+ case OP_OPEN:
+ status = encode_open(cp, &cp->ops[i].u.open);
+ break;
+ case OP_OPEN_CONFIRM:
+ status = encode_open_confirm(cp, &cp->ops[i].u.open_confirm);
+ break;
+ case OP_PUTFH:
+ status = encode_putfh(cp, &cp->ops[i].u.putfh);
+ break;
+ case OP_PUTROOTFH:
+ status = encode_putrootfh(cp);
+ break;
+ case OP_READ:
+ status = encode_read(cp, &cp->ops[i].u.read, req);
+ break;
+ case OP_READDIR:
+ status = encode_readdir(cp, &cp->ops[i].u.readdir, req);
+ break;
+ case OP_READLINK:
+ status = encode_readlink(cp, &cp->ops[i].u.readlink, req);
+ break;
+ case OP_REMOVE:
+ status = encode_remove(cp, &cp->ops[i].u.remove);
+ break;
+ case OP_RENAME:
+ status = encode_rename(cp, &cp->ops[i].u.rename);
+ break;
+ case OP_RENEW:
+ status = encode_renew(cp);
+ break;
+ case OP_RESTOREFH:
+ status = encode_restorefh(cp);
+ break;
+ case OP_SAVEFH:
+ status = encode_savefh(cp);
+ break;
+ case OP_SETATTR:
+ status = encode_setattr(cp, &cp->ops[i].u.setattr);
+ break;
+ case OP_SETCLIENTID:
+ status = encode_setclientid(cp, &cp->ops[i].u.setclientid);
+ break;
+ case OP_SETCLIENTID_CONFIRM:
+ status = encode_setclientid_confirm(cp);
+ break;
+ case OP_WRITE:
+ status = encode_write(cp, &cp->ops[i].u.write, req);
+ break;
+ default:
+ BUG();
+ }
+ if (status)
+ return status;
+ }
+
+ ENCODE_TAIL;
+}
+/*
+ * END OF "GENERIC" ENCODE ROUTINES.
+ */
+
+
+/*
+ * Encode void argument
+ */
+static int
+nfs4_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
+{
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
+/*
+ * Encode COMPOUND argument
+ */
+static int
+nfs4_xdr_enc_compound(struct rpc_rqst *req, u32 *p, struct nfs4_compound *cp)
+{
+ int status;
+ struct xdr_buf *sndbuf = &req->rq_snd_buf;
+
+ cp->p = p;
+ cp->end = (u32 *) ((char *)req->rq_svec[0].iov_base + req->rq_svec[0].iov_len);
+ status = encode_compound(cp, req);
+ cp->timestamp = jiffies;
+
+ if (!status && !sndbuf->page_len)
+ req->rq_slen = xdr_adjust_iovec(sndbuf->head, cp->p);
+ return status;
+}
+
+
+/*
+ * START OF "GENERIC" DECODE ROUTINES.
+ * These may look a little ugly since they are imported from a "generic"
+ * set of XDR encode/decode routines which are intended to be shared by
+ * all of our NFSv4 implementations (OpenBSD, MacOS X...).
+ *
+ * If the pain of reading these is too great, it should be a straightforward
+ * task to translate them into Linux-specific versions which are more
+ * consistent with the style used in NFSv2/v3...
+ */
+#define DECODE_HEAD \
+ u32 *p; \
+ int status
+#define DECODE_TAIL \
+ status = 0; \
+out: \
+ return status; \
+xdr_error: \
+ printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
+ status = -EIO; \
+ goto out
+
+#define READ32(x) (x) = ntohl(*p++)
+#define READ64(x) do { \
+ (x) = (u64)ntohl(*p++) << 32; \
+ (x) |= ntohl(*p++); \
+} while (0)
+#define READTIME(x) do { \
+ p++; \
+ (x) = (u64)ntohl(*p++) << 32; \
+ (x) |= ntohl(*p++); \
+} while (0)
+#define COPYMEM(x,nbytes) do { \
+ memcpy((x), p, nbytes); \
+ p += XDR_QUADLEN(nbytes); \
+} while (0)
+
+#define READ_BUF(nbytes) do { \
+ if (nbytes > (u32)((char *)cp->end - (char *)cp->p)) \
+ goto xdr_error; \
+ p = cp->p; \
+ cp->p += XDR_QUADLEN(nbytes); \
+} while (0)
+
+/*
+ * FIXME: The following dummy entry will be replaced once the userland
+ * upcall gets in...
+ */
+static int
+decode_uid(char *p, u32 len, uid_t *uid)
+{
+ *uid = -2;
+ return 0;
+}
+
+/*
+ * FIXME: The following dummy entry will be replaced once the userland
+ * upcall gets in...
+ */
+static int
+decode_gid(char *p, u32 len, gid_t *gid)
+{
+ *gid = -2;
+ return 0;
+}
+
+static int
+decode_change_info(struct nfs4_compound *cp, struct nfs4_change_info *cinfo)
+{
+ DECODE_HEAD;
+
+ READ_BUF(20);
+ READ32(cinfo->atomic);
+ READ64(cinfo->before);
+ READ64(cinfo->after);
+
+ DECODE_TAIL;
+}
+
+static int
+decode_access(struct nfs4_compound *cp, int nfserr, struct nfs4_access *access)
+{
+ u32 supp, acc;
+ DECODE_HEAD;
+
+ if (!nfserr) {
+ READ_BUF(8);
+ READ32(supp);
+ READ32(acc);
+
+ status = -EIO;
+ if ((supp & ~access->ac_req_access) || (acc & ~supp)) {
+ printk(KERN_NOTICE "NFS: server returned bad bits in access call!\n");
+ goto out;
+ }
+ *access->ac_resp_supported = supp;
+ *access->ac_resp_access = acc;
+ }
+
+ DECODE_TAIL;
+}
+
+static int
+decode_close(struct nfs4_compound *cp, int nfserr, struct nfs4_close *close)
+{
+ DECODE_HEAD;
+
+ if (!nfserr) {
+ READ_BUF(sizeof(nfs4_stateid));
+ COPYMEM(close->cl_stateid, sizeof(nfs4_stateid));
+ }
+
+ DECODE_TAIL;
+}
+
+static int
+decode_commit(struct nfs4_compound *cp, int nfserr, struct nfs4_commit *commit)
+{
+ DECODE_HEAD;
+
+ if (!nfserr) {
+ READ_BUF(8);
+ COPYMEM(commit->co_verifier->verifier, 8);
+ }
+
+ DECODE_TAIL;
+}
+
+static int
+decode_create(struct nfs4_compound *cp, int nfserr, struct nfs4_create *create)
+{
+ u32 bmlen;
+ DECODE_HEAD;
+
+ if (!nfserr) {
+ if ((status = decode_change_info(cp, create->cr_cinfo)))
+ goto out;
+ READ_BUF(4);
+ READ32(bmlen);
+ if (bmlen > 2)
+ goto xdr_error;
+ READ_BUF(bmlen << 2);
+ }
+
+ DECODE_TAIL;
+}
+
+extern u32 nfs4_fattr_bitmap[2];
+extern u32 nfs4_fsinfo_bitmap[2];
+extern u32 nfs4_fsstat_bitmap[2];
+extern u32 nfs4_pathconf_bitmap[2];
+
+static int
+decode_getattr(struct nfs4_compound *cp, int nfserr, struct nfs4_getattr *getattr)
+{
+ struct nfs_fattr *nfp = getattr->gt_attrs;
+ struct nfs_fsstat *fsstat = getattr->gt_fsstat;
+ struct nfs_fsinfo *fsinfo = getattr->gt_fsinfo;
+ struct nfs_pathconf *pathconf = getattr->gt_pathconf;
+ u32 bmlen;
+ u32 bmval0 = 0;
+ u32 bmval1 = 0;
+ u32 attrlen;
+ u32 dummy32;
+ u32 len = 0;
+ unsigned int type;
+ int fmode = 0;
+ DECODE_HEAD;
+
+ if (nfserr)
+ goto success;
+
+ READ_BUF(4);
+ READ32(bmlen);
+ if (bmlen > 2)
+ goto xdr_error;
+
+ READ_BUF((bmlen << 2) + 4);
+ if (bmlen > 0)
+ READ32(bmval0);
+ if (bmlen > 1)
+ READ32(bmval1);
+ READ32(attrlen);
+
+ if ((bmval0 & ~getattr->gt_bmval[0]) ||
+ (bmval1 & ~getattr->gt_bmval[1])) {
+ dprintk("read_attrs: server returned bad attributes!\n");
+ goto xdr_error;
+ }
+ getattr->gt_bmres[0] = bmval0;
+ getattr->gt_bmres[1] = bmval1;
+
+ /*
+ * In case the server doesn't return some attributes,
+ * we initialize them here to some nominal values..
+ */
+ if (nfp) {
+ nfp->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
+ nfp->nlink = 1;
+ nfp->timestamp = jiffies;
+ }
+ if (fsinfo) {
+ fsinfo->rtmult = fsinfo->wtmult = 512; /* ??? */
+ fsinfo->lease_time = 60;
+ }
+
+ if (bmval0 & FATTR4_WORD0_TYPE) {
+ READ_BUF(4);
+ len += 4;
+ READ32(type);
+ if (type < NF4REG || type > NF4NAMEDATTR) {
+ dprintk("read_attrs: bad type %d\n", type);
+ goto xdr_error;
+ }
+ nfp->type = nfs_type2fmt[type].nfs2type;
+ fmode = nfs_type2fmt[type].mode;
+ dprintk("read_attrs: type=%d\n", (u32)nfp->type);
+ }
+ if (bmval0 & FATTR4_WORD0_CHANGE) {
+ READ_BUF(8);
+ len += 8;
+ READ64(nfp->change_attr);
+ dprintk("read_attrs: changeid=%Ld\n", (u64)nfp->change_attr);
+ }
+ if (bmval0 & FATTR4_WORD0_SIZE) {
+ READ_BUF(8);
+ len += 8;
+ READ64(nfp->size);
+ dprintk("read_attrs: size=%Ld\n", (u64)nfp->size);
+ }
+ if (bmval0 & FATTR4_WORD0_FSID) {
+ READ_BUF(16);
+ len += 16;
+ READ64(nfp->fsid_u.nfs4.major);
+ READ64(nfp->fsid_u.nfs4.minor);
+ dprintk("read_attrs: fsid=0x%Lx/0x%Lx\n",
+ nfp->fsid_u.nfs4.major, nfp->fsid_u.nfs4.minor);
+ }
+ if (bmval0 & FATTR4_WORD0_LEASE_TIME) {
+ READ_BUF(4);
+ len += 4;
+ READ32(fsinfo->lease_time);
+ dprintk("read_attrs: lease_time=%d\n", fsinfo->lease_time);
+ }
+ if (bmval0 & FATTR4_WORD0_FILEID) {
+ READ_BUF(8);
+ len += 8;
+ READ64(nfp->fileid);
+ dprintk("read_attrs: fileid=%Ld\n", nfp->fileid);
+ }
+ if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
+ READ_BUF(8);
+ len += 8;
+ READ64(fsstat->afiles);
+ dprintk("read_attrs: files_avail=0x%Lx\n", fsstat->afiles);
+ }
+ if (bmval0 & FATTR4_WORD0_FILES_FREE) {
+ READ_BUF(8);
+ len += 8;
+ READ64(fsstat->ffiles);
+ dprintk("read_attrs: files_free=0x%Lx\n", fsstat->ffiles);
+ }
+ if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
+ READ_BUF(8);
+ len += 8;
+ READ64(fsstat->tfiles);
+ dprintk("read_attrs: files_tot=0x%Lx\n", fsstat->tfiles);
+ }
+ if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
+ READ_BUF(8);
+ len += 8;
+ READ64(fsinfo->maxfilesize);
+ dprintk("read_attrs: maxfilesize=0x%Lx\n", fsinfo->maxfilesize);
+ }
+ if (bmval0 & FATTR4_WORD0_MAXLINK) {
+ READ_BUF(4);
+ len += 4;
+ READ32(pathconf->max_link);
+ dprintk("read_attrs: maxlink=%d\n", pathconf->max_link);
+ }
+ if (bmval0 & FATTR4_WORD0_MAXNAME) {
+ READ_BUF(4);
+ len += 4;
+ READ32(pathconf->max_namelen);
+ dprintk("read_attrs: maxname=%d\n", pathconf->max_namelen);
+ }
+ if (bmval0 & FATTR4_WORD0_MAXREAD) {
+ READ_BUF(8);
+ len += 8;
+ READ64(fsinfo->rtmax);
+ fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
+ dprintk("read_attrs: maxread=%d\n", fsinfo->rtmax);
+ }
+ if (bmval0 & FATTR4_WORD0_MAXWRITE) {
+ READ_BUF(8);
+ len += 8;
+ READ64(fsinfo->wtmax);
+ fsinfo->wtpref = fsinfo->wtmax;
+ dprintk("read_attrs: maxwrite=%d\n", fsinfo->wtmax);
+ }
+
+ if (bmval1 & FATTR4_WORD1_MODE) {
+ READ_BUF(4);
+ len += 4;
+ READ32(dummy32);
+ nfp->mode = (dummy32 & ~S_IFMT) | fmode;
+ dprintk("read_attrs: mode=0%o\n", nfp->mode);
+ }
+ if (bmval1 & FATTR4_WORD1_NUMLINKS) {
+ READ_BUF(4);
+ len += 4;
+ READ32(nfp->nlink);
+ dprintk("read_attrs: nlinks=0%o\n", nfp->nlink);
+ }
+ if (bmval1 & FATTR4_WORD1_OWNER) {
+ READ_BUF(4);
+ len += 4;
+ READ32(dummy32); /* name length */
+ if (dummy32 > XDR_MAX_NETOBJ) {
+ dprintk("read_attrs: name too long!\n");
+ goto xdr_error;
+ }
+ READ_BUF(dummy32);
+ len += (XDR_QUADLEN(dummy32) << 2);
+ if ((status = decode_uid((char *)p, dummy32, &nfp->uid))) {
+ dprintk("read_attrs: gss_get_num failed!\n");
+ goto out;
+ }
+ dprintk("read_attrs: uid=%d\n", (int)nfp->uid);
+ }
+ if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
+ READ_BUF(4);
+ len += 4;
+ READ32(dummy32);
+ if (dummy32 > XDR_MAX_NETOBJ) {
+ dprintk("read_attrs: name too long!\n");
+ goto xdr_error;
+ }
+ READ_BUF(dummy32);
+ len += (XDR_QUADLEN(dummy32) << 2);
+ if ((status = decode_gid((char *)p, dummy32, &nfp->gid))) {
+ dprintk("read_attrs: gss_get_num failed!\n");
+ goto out;
+ }
+ dprintk("read_attrs: gid=%d\n", (int)nfp->gid);
+ }
+ if (bmval1 & FATTR4_WORD1_RAWDEV) {
+ READ_BUF(8);
+ len += 8;
+ READ32(dummy32);
+ nfp->rdev = (dummy32 << MINORBITS);
+ READ32(dummy32);
+ nfp->rdev |= (dummy32 & MINORMASK);
+ dprintk("read_attrs: rdev=%d\n", nfp->rdev);
+ }
+ if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
+ READ_BUF(8);
+ len += 8;
+ READ64(fsstat->abytes);
+ dprintk("read_attrs: savail=0x%Lx\n", fsstat->abytes);
+ }
+ if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
+ READ_BUF(8);
+ len += 8;
+ READ64(fsstat->fbytes);
+ dprintk("read_attrs: sfree=0x%Lx\n", fsstat->fbytes);
+ }
+ if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
+ READ_BUF(8);
+ len += 8;
+ READ64(fsstat->tbytes);
+ dprintk("read_attrs: stotal=0x%Lx\n", fsstat->tbytes);
+ }
+ if (bmval1 & FATTR4_WORD1_SPACE_USED) {
+ READ_BUF(8);
+ len += 8;
+ READ64(nfp->du.nfs3.used);
+ dprintk("read_attrs: sused=0x%Lx\n", nfp->du.nfs3.used);
+ }
+ if (bmval1 & FATTR4_WORD1_TIME_ACCESS) {
+ READ_BUF(12);
+ len += 12;
+ READTIME(nfp->atime);
+ dprintk("read_attrs: atime=%d\n", (int)nfp->atime);
+ }
+ if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
+ READ_BUF(12);
+ len += 12;
+ READTIME(nfp->ctime);
+ dprintk("read_attrs: ctime=%d\n", (int)nfp->ctime);
+ }
+ if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
+ READ_BUF(12);
+ len += 12;
+ READTIME(nfp->mtime);
+ dprintk("read_attrs: mtime=%d\n", (int)nfp->mtime);
+ }
+ if (len != attrlen)
+ goto xdr_error;
+
+success:
+ DECODE_TAIL;
+}
+
+static int
+decode_getfh(struct nfs4_compound *cp, int nfserr, struct nfs4_getfh *getfh)
+{
+ struct nfs_fh *fh = getfh->gf_fhandle;
+ int len;
+ DECODE_HEAD;
+
+ /* Zero handle first to allow comparisons */
+ memset(fh, 0, sizeof(*fh));
+
+ if (!nfserr) {
+ READ_BUF(4);
+ READ32(len);
+ if (len > NFS_MAXFHSIZE)
+ goto xdr_error;
+ fh->size = len;
+ READ_BUF(len);
+ COPYMEM(fh->data, len);
+ }
+
+ DECODE_TAIL;
+}
+
+static int
+decode_link(struct nfs4_compound *cp, int nfserr, struct nfs4_link *link)
+{
+ int status = 0;
+
+ if (!nfserr)
+ status = decode_change_info(cp, link->ln_cinfo);
+ return status;
+}
+
+static int
+decode_open(struct nfs4_compound *cp, int nfserr, struct nfs4_open *open)
+{
+ u32 bmlen, delegation_type;
+ DECODE_HEAD;
+
+ if (!nfserr) {
+ READ_BUF(sizeof(nfs4_stateid));
+ COPYMEM(open->op_stateid, sizeof(nfs4_stateid));
+
+ decode_change_info(cp, open->op_cinfo);
+
+ READ_BUF(8);
+ READ32(*open->op_rflags);
+ READ32(bmlen);
+ if (bmlen > 10)
+ goto xdr_error;
+
+ READ_BUF((bmlen << 2) + 4);
+ p += bmlen;
+ READ32(delegation_type);
+ if (delegation_type != NFS4_OPEN_DELEGATE_NONE)
+ goto xdr_error;
+ }
+
+ DECODE_TAIL;
+}
+
+static int
+decode_open_confirm(struct nfs4_compound *cp, int nfserr, struct nfs4_open_confirm *open_confirm)
+{
+ DECODE_HEAD;
+
+ if (!nfserr) {
+ READ_BUF(sizeof(nfs4_stateid));
+ COPYMEM(open_confirm->oc_stateid, sizeof(nfs4_stateid));
+ }
+
+ DECODE_TAIL;
+}
+
+static int
+decode_read(struct nfs4_compound *cp, int nfserr, struct nfs4_read *read)
+{
+ u32 throwaway;
+ DECODE_HEAD;
+
+ if (!nfserr) {
+ READ_BUF(8);
+ if (read->rd_eof)
+ READ32(*read->rd_eof);
+ else
+ READ32(throwaway);
+ READ32(*read->rd_bytes_read);
+ if (*read->rd_bytes_read > read->rd_length)
+ goto xdr_error;
+ }
+
+ DECODE_TAIL;
+}
+
+static int
+decode_readdir(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, struct nfs4_readdir *readdir)
+{
+ struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+ struct page *page = *rcvbuf->pages;
+ unsigned int pglen = rcvbuf->page_len;
+ u32 *end, *entry;
+ u32 len, attrlen, word;
+ int i;
+ DECODE_HEAD;
+
+ if (!nfserr) {
+ READ_BUF(8);
+ COPYMEM(readdir->rd_resp_verifier, 8);
+
+ BUG_ON(pglen > PAGE_CACHE_SIZE);
+ p = (u32 *) kmap(page);
+ end = (u32 *) ((char *)p + pglen + readdir->rd_pgbase);
+
+ while (*p++) {
+ entry = p - 1;
+ if (p + 3 > end)
+ goto short_pkt;
+ p += 2; /* cookie */
+ len = ntohl(*p++); /* filename length */
+ if (len > NFS4_MAXNAMLEN) {
+ printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len);
+ goto err_unmap;
+ }
+
+ p += XDR_QUADLEN(len);
+ if (p + 1 > end)
+ goto short_pkt;
+ len = ntohl(*p++); /* bitmap length */
+ if (len > 10) {
+ printk(KERN_WARNING "NFS: giant bitmap in readdir (len 0x%x)\n", len);
+ goto err_unmap;
+ }
+ if (p + len + 1 > end)
+ goto short_pkt;
+ attrlen = 0;
+ for (i = 0; i < len; i++) {
+ word = ntohl(*p++);
+ if (!word)
+ continue;
+ else if (i == 0 && word == FATTR4_WORD0_FILEID) {
+ attrlen = 8;
+ continue;
+ }
+ printk(KERN_WARNING "NFS: unexpected bitmap word in readdir (0x%x)\n", word);
+ goto err_unmap;
+ }
+ if (ntohl(*p++) != attrlen) {
+ printk(KERN_WARNING "NFS: unexpected attrlen in readdir\n");
+ goto err_unmap;
+ }
+ p += XDR_QUADLEN(attrlen);
+ if (p + 1 > end)
+ goto short_pkt;
+ }
+ kunmap(page);
+ }
+
+ DECODE_TAIL;
+short_pkt:
+ printk(KERN_NOTICE "NFS: short packet in readdir reply!\n");
+ /* truncate listing */
+ kunmap(page);
+ entry[0] = entry[1] = 0;
+ return 0;
+err_unmap:
+ kunmap(page);
+ return -errno_NFSERR_IO;
+}
+
+static int
+decode_readlink(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, struct nfs4_readlink *readlink)
+{
+ struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+ u32 *strlen;
+ u32 len;
+ char *string;
+
+ if (!nfserr) {
+ /*
+ * The XDR encode routine has set things up so that
+ * the link text will be copied directly into the
+ * buffer. We just have to do overflow-checking,
+ * and and null-terminate the text (the VFS expects
+ * null-termination).
+ */
+ strlen = (u32 *) kmap(rcvbuf->pages[0]);
+ len = ntohl(*strlen);
+ if (len > PAGE_CACHE_SIZE - 5) {
+ printk(KERN_WARNING "nfs: server returned giant symlink!\n");
+ kunmap(rcvbuf->pages[0]);
+ return -EIO;
+ }
+ *strlen = len;
+
+ string = (char *)(strlen + 1);
+ string[len] = '\0';
+ kunmap(rcvbuf->pages[0]);
+ }
+ return 0;
+}
+
+static int
+decode_remove(struct nfs4_compound *cp, int nfserr, struct nfs4_remove *remove)
+{
+ int status;
+
+ status = 0;
+ if (!nfserr)
+ status = decode_change_info(cp, remove->rm_cinfo);
+ return status;
+}
+
+static int
+decode_rename(struct nfs4_compound *cp, int nfserr, struct nfs4_rename *rename)
+{
+ int status = 0;
+
+ if (!nfserr) {
+ if ((status = decode_change_info(cp, rename->rn_src_cinfo)))
+ goto out;
+ if ((status = decode_change_info(cp, rename->rn_dst_cinfo)))
+ goto out;
+ }
+out:
+ return status;
+}
+
+static int
+decode_setattr(struct nfs4_compound *cp)
+{
+ u32 bmlen;
+ DECODE_HEAD;
+
+ READ_BUF(4);
+ READ32(bmlen);
+ if (bmlen > 10)
+ goto xdr_error;
+ READ_BUF(bmlen << 2);
+
+ DECODE_TAIL;
+}
+
+static int
+decode_setclientid(struct nfs4_compound *cp, int nfserr)
+{
+ DECODE_HEAD;
+
+ if (!nfserr) {
+ READ_BUF(8 + sizeof(nfs4_verifier));
+ READ64(cp->server->nfs4_state->cl_clientid);
+ COPYMEM(cp->server->nfs4_state->cl_confirm, sizeof(nfs4_verifier));
+ }
+ else if (nfserr == NFSERR_CLID_INUSE) {
+ u32 len;
+
+ /* skip netid string */
+ READ_BUF(4);
+ READ32(len);
+ READ_BUF(len);
+
+ /* skip uaddr string */
+ READ_BUF(4);
+ READ32(len);
+ READ_BUF(len);
+ }
+
+ DECODE_TAIL;
+}
+
+static int
+decode_write(struct nfs4_compound *cp, int nfserr, struct nfs4_write *write)
+{
+ DECODE_HEAD;
+
+ if (!nfserr) {
+ READ_BUF(16);
+ READ32(*write->wr_bytes_written);
+ if (*write->wr_bytes_written > write->wr_len)
+ goto xdr_error;
+ READ32(write->wr_verf->committed);
+ COPYMEM(write->wr_verf->verifier, 8);
+ }
+
+ DECODE_TAIL;
+}
+
+static int
+decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req)
+{
+ u32 taglen;
+ u32 opnum, nfserr;
+ DECODE_HEAD;
+
+ READ_BUF(8);
+ READ32(cp->toplevel_status);
+ READ32(taglen);
+
+ /*
+ * We need this if our zero-copy I/O is going to work. Rumor has
+ * it that the spec will soon mandate it...
+ */
+ if (taglen != cp->taglen)
+ dprintk("nfs4: non-conforming server returns tag length mismatch!\n");
+
+ READ_BUF(taglen + 4);
+ p += XDR_QUADLEN(taglen);
+ READ32(cp->resp_nops);
+ if (cp->resp_nops > cp->req_nops) {
+ dprintk("nfs4: resp_nops > req_nops!\n");
+ goto xdr_error;
+ }
+
+ for (cp->nops = 0; cp->nops < cp->resp_nops; cp->nops++) {
+ READ_BUF(8);
+ READ32(opnum);
+ if (opnum != cp->ops[cp->nops].opnum) {
+ dprintk("nfs4: operation mismatch!\n");
+ goto xdr_error;
+ }
+ READ32(nfserr);
+ if (cp->nops == cp->resp_nops - 1) {
+ if (nfserr != cp->toplevel_status) {
+ dprintk("nfs4: status mismatch!\n");
+ goto xdr_error;
+ }
+ }
+ else if (nfserr) {
+ dprintk("nfs4: intermediate status nonzero!\n");
+ goto xdr_error;
+ }
+ cp->ops[cp->nops].nfserr = nfserr;
+
+ switch (opnum) {
+ case OP_ACCESS:
+ status = decode_access(cp, nfserr, &cp->ops[cp->nops].u.access);
+ break;
+ case OP_CLOSE:
+ status = decode_close(cp, nfserr, &cp->ops[cp->nops].u.close);
+ break;
+ case OP_COMMIT:
+ status = decode_commit(cp, nfserr, &cp->ops[cp->nops].u.commit);
+ break;
+ case OP_CREATE:
+ status = decode_create(cp, nfserr, &cp->ops[cp->nops].u.create);
+ break;
+ case OP_GETATTR:
+ status = decode_getattr(cp, nfserr, &cp->ops[cp->nops].u.getattr);
+ break;
+ case OP_GETFH:
+ status = decode_getfh(cp, nfserr, &cp->ops[cp->nops].u.getfh);
+ break;
+ case OP_LINK:
+ status = decode_link(cp, nfserr, &cp->ops[cp->nops].u.link);
+ break;
+ case OP_LOOKUP:
+ status = 0;
+ break;
+ case OP_OPEN:
+ status = decode_open(cp, nfserr, &cp->ops[cp->nops].u.open);
+ break;
+ case OP_OPEN_CONFIRM:
+ status = decode_open_confirm(cp, nfserr, &cp->ops[cp->nops].u.open_confirm);
+ break;
+ case OP_PUTFH:
+ status = 0;
+ break;
+ case OP_PUTROOTFH:
+ status = 0;
+ break;
+ case OP_READ:
+ status = decode_read(cp, nfserr, &cp->ops[cp->nops].u.read);
+ break;
+ case OP_READDIR:
+ status = decode_readdir(cp, nfserr, req, &cp->ops[cp->nops].u.readdir);
+ break;
+ case OP_READLINK:
+ status = decode_readlink(cp, nfserr, req, &cp->ops[cp->nops].u.readlink);
+ break;
+ case OP_RESTOREFH:
+ status = 0;
+ break;
+ case OP_REMOVE:
+ status = decode_remove(cp, nfserr, &cp->ops[cp->nops].u.remove);
+ break;
+ case OP_RENAME:
+ status = decode_rename(cp, nfserr, &cp->ops[cp->nops].u.rename);
+ break;
+ case OP_RENEW:
+ status = 0;
+ break;
+ case OP_SAVEFH:
+ status = 0;
+ break;
+ case OP_SETATTR:
+ status = decode_setattr(cp);
+ break;
+ case OP_SETCLIENTID:
+ status = decode_setclientid(cp, nfserr);
+ break;
+ case OP_SETCLIENTID_CONFIRM:
+ status = 0;
+ break;
+ case OP_WRITE:
+ status = decode_write(cp, nfserr, &cp->ops[cp->nops].u.write);
+ break;
+ default:
+ BUG();
+ return -EIO;
+ }
+ if (status)
+ goto xdr_error;
+ }
+
+ DECODE_TAIL;
+}
+/*
+ * END OF "GENERIC" DECODE ROUTINES.
+ */
+
+/*
+ * Decode void reply
+ */
+static int
+nfs4_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
+{
+ return 0;
+}
+
+/*
+ * Decode COMPOUND response
+ */
+static int
+nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, u32 *p, struct nfs4_compound *cp)
+{
+ int status;
+
+ cp->p = p;
+ cp->end = (u32 *) ((u8 *) rqstp->rq_rvec->iov_base + rqstp->rq_rvec->iov_len);
+
+ if ((status = decode_compound(cp, rqstp)))
+ goto out;
+
+ status = 0;
+ if (cp->toplevel_status)
+ status = -nfs_stat_to_errno(cp->toplevel_status);
+
+out:
+ return status;
+}
+
+u32 *
+nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
+{
+ u32 len;
+
+ if (!*p++) {
+ if (!*p)
+ return ERR_PTR(-EAGAIN);
+ entry->eof = 1;
+ return ERR_PTR(-EBADCOOKIE);
+ }
+
+ entry->prev_cookie = entry->cookie;
+ p = xdr_decode_hyper(p, &entry->cookie);
+ entry->len = ntohl(*p++);
+ entry->name = (const char *) p;
+ p += XDR_QUADLEN(entry->len);
+
+ if (entry->cookie > COOKIE_MAX)
+ entry->cookie = COOKIE_MAX;
+
+ /*
+ * In case the server doesn't return an inode number,
+ * we fake one here. (We don't use inode number 0,
+ * since glibc seems to choke on it...)
+ */
+ entry->ino = 1;
+
+ len = ntohl(*p++); /* bitmap length */
+ p += len;
+ len = ntohl(*p++); /* attribute buffer length */
+ if (len)
+ p = xdr_decode_hyper(p, &entry->ino);
+
+ entry->eof = !p[0] && p[1];
+ return p;
+}
+
+#ifndef MAX
+# define MAX(a, b) (((a) > (b))? (a) : (b))
+#endif
+
+#define PROC(proc, argtype, restype) \
+ { "nfs4_" #proc, \
+ (kxdrproc_t) nfs4_xdr_##argtype, \
+ (kxdrproc_t) nfs4_xdr_##restype, \
+ MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \
+ 0 \
+ }
+
+static struct rpc_procinfo nfs4_procedures[] = {
+ PROC(null, enc_void, dec_void),
+ PROC(compound, enc_compound, dec_compound)
+};
+
+struct rpc_version nfs_version4 = {
+ .number = 4,
+ .nrprocs = sizeof(nfs4_procedures)/sizeof(nfs4_procedures[0]),
+ .procs = nfs4_procedures
+};
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 2ad13ec4cd27..a5a1c373444d 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -460,17 +460,62 @@ nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
static int
nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fsinfo *info)
+ struct nfs_fsstat *stat)
{
+ struct nfs2_fsstat fsinfo;
int status;
dprintk("NFS call statfs\n");
- memset((char *)info, 0, sizeof(*info));
- status = rpc_call(server->client, NFSPROC_STATFS, fhandle, info, 0);
+ stat->fattr->valid = 0;
+ status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0);
dprintk("NFS reply statfs: %d\n", status);
+ if (status)
+ goto out;
+ stat->tbytes = (u64)fsinfo.blocks * fsinfo.bsize;
+ stat->fbytes = (u64)fsinfo.bfree * fsinfo.bsize;
+ stat->abytes = (u64)fsinfo.bavail * fsinfo.bsize;
+ stat->tfiles = 0;
+ stat->ffiles = 0;
+ stat->afiles = 0;
+out:
+ return status;
+}
+
+static int
+nfs_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fsinfo *info)
+{
+ struct nfs2_fsstat fsinfo;
+ int status;
+
+ dprintk("NFS call fsinfo\n");
+ info->fattr->valid = 0;
+ status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &info, 0);
+ dprintk("NFS reply fsinfo: %d\n", status);
+ if (status)
+ goto out;
+ info->rtmax = NFS_MAXDATA;
+ info->rtpref = fsinfo.tsize;
+ info->rtmult = fsinfo.bsize;
+ info->wtmax = NFS_MAXDATA;
+ info->wtpref = fsinfo.tsize;
+ info->wtmult = fsinfo.bsize;
+ info->dtpref = fsinfo.tsize;
+ info->maxfilesize = 0x7FFFFFFF;
+ info->lease_time = 0;
+out:
return status;
}
+static int
+nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_pathconf *info)
+{
+ info->max_link = 0;
+ info->max_namelen = NFS2_MAXNAMLEN;
+ return 0;
+}
+
extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
static void
@@ -590,6 +635,8 @@ struct nfs_rpc_ops nfs_v2_clientops = {
.readdir = nfs_proc_readdir,
.mknod = nfs_proc_mknod,
.statfs = nfs_proc_statfs,
+ .fsinfo = nfs_proc_fsinfo,
+ .pathconf = nfs_proc_pathconf,
.decode_dirent = nfs_decode_dirent,
.read_setup = nfs_proc_read_setup,
.write_setup = nfs_proc_write_setup,
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 5976fa3e466f..e6ed1a443116 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -18,6 +18,7 @@
#include <linux/blk.h>
#include <linux/kmod.h>
#include <linux/ctype.h>
+#include <../drivers/base/fs/fs.h> /* Eeeeewwwww */
#include "check.h"
@@ -111,115 +112,17 @@ char *disk_name(struct gendisk *hd, int part, char *buf)
return buf;
}
-/* Driverfs file support */
-static ssize_t partition_device_kdev_read(struct device *driverfs_dev,
- char *page, size_t count, loff_t off)
-{
- kdev_t kdev;
- kdev.value=(int)(long)driverfs_dev->driver_data;
- return off ? 0 : sprintf (page, "%x\n",kdev.value);
-}
-static DEVICE_ATTR(kdev,S_IRUGO,partition_device_kdev_read,NULL);
-
-static ssize_t partition_device_type_read(struct device *driverfs_dev,
- char *page, size_t count, loff_t off)
-{
- return off ? 0 : sprintf (page, "BLK\n");
-}
-static DEVICE_ATTR(type,S_IRUGO,partition_device_type_read,NULL);
-
-static void driverfs_create_partitions(struct gendisk *hd)
-{
- int max_p = 1<<hd->minor_shift;
- struct hd_struct *p = hd->part;
- char name[DEVICE_NAME_SIZE];
- char bus_id[BUS_ID_SIZE];
- struct device *dev, *parent;
- int part;
-
- /* if driverfs not supported by subsystem, skip partitions */
- if (!(hd->flags & GENHD_FL_DRIVERFS))
- return;
-
- parent = hd->driverfs_dev;
-
- if (parent) {
- sprintf(name, "%s", parent->name);
- sprintf(bus_id, "%s:", parent->bus_id);
- } else {
- *name = *bus_id = '\0';
- }
-
- dev = &hd->disk_dev;
- dev->driver_data = (void *)(long)__mkdev(hd->major, hd->first_minor);
- sprintf(dev->name, "%sdisc", name);
- sprintf(dev->bus_id, "%sdisc", bus_id);
- for (part=1; part < max_p; part++) {
- dev = &p[part-1].hd_driverfs_dev;
- sprintf(dev->name, "%spart%d", name, part);
- sprintf(dev->bus_id, "%s:p%d", bus_id, part);
- if (!p[part-1].nr_sects)
- continue;
- dev->driver_data =
- (void *)(long)__mkdev(hd->major, hd->first_minor+part);
- }
-
- dev = &hd->disk_dev;
- dev->parent = parent;
- if (parent)
- dev->bus = parent->bus;
- device_register(dev);
- device_create_file(dev, &dev_attr_type);
- device_create_file(dev, &dev_attr_kdev);
-
- for (part=0; part < max_p-1; part++) {
- dev = &p[part].hd_driverfs_dev;
- dev->parent = parent;
- if (parent)
- dev->bus = parent->bus;
- if (!dev->driver_data)
- continue;
- device_register(dev);
- device_create_file(dev, &dev_attr_type);
- device_create_file(dev, &dev_attr_kdev);
- }
-}
-
-static void driverfs_remove_partitions(struct gendisk *hd)
-{
- int max_p = 1<<hd->minor_shift;
- struct device *dev;
- struct hd_struct *p;
- int part;
-
- for (part=1, p = hd->part; part < max_p; part++, p++) {
- dev = &p->hd_driverfs_dev;
- if (dev->driver_data) {
- device_remove_file(dev, &dev_attr_type);
- device_remove_file(dev, &dev_attr_kdev);
- put_device(dev);
- dev->driver_data = NULL;
- }
- }
- dev = &hd->disk_dev;
- if (dev->driver_data) {
- device_remove_file(dev, &dev_attr_type);
- device_remove_file(dev, &dev_attr_kdev);
- put_device(dev);
- dev->driver_data = NULL;
- }
-}
-
-static void check_partition(struct gendisk *hd, struct block_device *bdev)
+static struct parsed_partitions *
+check_partition(struct gendisk *hd, struct block_device *bdev)
{
+ struct parsed_partitions *state;
devfs_handle_t de = NULL;
char buf[64];
- struct parsed_partitions *state;
- int i;
+ int i, res;
state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
if (!state)
- return;
+ return NULL;
if (hd->flags & GENHD_FL_DEVFS)
de = hd->de;
@@ -233,32 +136,20 @@ static void check_partition(struct gendisk *hd, struct block_device *bdev)
if (isdigit(state->name[strlen(state->name)-1]))
sprintf(state->name, "p");
}
- state->limit = 1<<hd->minor_shift;
- for (i = 0; check_part[i]; i++) {
- int res, j;
- struct hd_struct *p;
+ state->limit = hd->minors;
+ i = res = 0;
+ while (!res && check_part[i]) {
memset(&state->parts, 0, sizeof(state->parts));
- res = check_part[i](state, bdev);
- if (!res)
- continue;
- if (res < 0) {
- if (warn_no_part)
- printk(" unable to read partition table\n");
- return;
- }
- p = hd->part;
- for (j = 1; j < state->limit; j++) {
- p[j-1].start_sect = state->parts[j].from;
- p[j-1].nr_sects = state->parts[j].size;
-#if CONFIG_BLK_DEV_MD
- if (!state->parts[j].flags)
- continue;
- md_autodetect_dev(bdev->bd_dev+j);
-#endif
- }
- return;
+ res = check_part[i++](state, bdev);
}
- printk(" unknown partition table\n");
+ if (res > 0)
+ return state;
+ if (!res)
+ printk(" unknown partition table\n");
+ else if (warn_no_part)
+ printk(" unable to read partition table\n");
+ kfree(state);
+ return NULL;
}
static void devfs_register_partition(struct gendisk *dev, int part)
@@ -298,7 +189,7 @@ static void devfs_create_partitions(struct gendisk *dev)
unsigned int devfs_flags = DEVFS_FL_DEFAULT;
char dirname[64], symlink[16];
static devfs_handle_t devfs_handle;
- int part, max_p = 1<<dev->minor_shift;
+ int part, max_p = dev->minors;
struct hd_struct *p = dev->part;
if (dev->flags & GENHD_FL_REMOVABLE)
@@ -329,9 +220,6 @@ static void devfs_create_partitions(struct gendisk *dev)
devfs_auto_unregister(dev->disk_de, slave);
if (!(dev->flags & GENHD_FL_DEVFS))
devfs_auto_unregister (slave, dir);
- for (part = 1; part < max_p; part++, p++)
- if (p->nr_sects)
- devfs_register_partition(dev, part);
#endif
}
@@ -379,11 +267,6 @@ static void devfs_create_cdrom(struct gendisk *dev)
static void devfs_remove_partitions(struct gendisk *dev)
{
#ifdef CONFIG_DEVFS_FS
- int part;
- for (part = (1<<dev->minor_shift)-1; part--; ) {
- devfs_unregister(dev->part[part].de);
- dev->part[part].de = NULL;
- }
devfs_unregister(dev->disk_de);
dev->disk_de = NULL;
if (dev->flags & GENHD_FL_CD)
@@ -393,15 +276,196 @@ static void devfs_remove_partitions(struct gendisk *dev)
#endif
}
+static ssize_t part_dev_read(struct device *dev,
+ char *page, size_t count, loff_t off)
+{
+ struct gendisk *disk = dev->parent->driver_data;
+ struct hd_struct *p = dev->driver_data;
+ int part = p - disk->part + 1;
+ dev_t base = MKDEV(disk->major, disk->first_minor);
+ return off ? 0 : sprintf(page, "%04x\n",base + part);
+}
+static ssize_t part_start_read(struct device *dev,
+ char *page, size_t count, loff_t off)
+{
+ struct hd_struct *p = dev->driver_data;
+ return off ? 0 : sprintf(page, "%llu\n",(u64)p->start_sect);
+}
+static ssize_t part_size_read(struct device *dev,
+ char *page, size_t count, loff_t off)
+{
+ struct hd_struct *p = dev->driver_data;
+ return off ? 0 : sprintf(page, "%llu\n",(u64)p->nr_sects);
+}
+static struct device_attribute part_attr_dev = {
+ .attr = {.name = "dev", .mode = S_IRUGO },
+ .show = part_dev_read
+};
+static struct device_attribute part_attr_start = {
+ .attr = {.name = "start", .mode = S_IRUGO },
+ .show = part_start_read
+};
+static struct device_attribute part_attr_size = {
+ .attr = {.name = "size", .mode = S_IRUGO },
+ .show = part_size_read
+};
+
+void delete_partition(struct gendisk *disk, int part)
+{
+ struct hd_struct *p = disk->part + part - 1;
+ struct device *dev;
+ if (!p->nr_sects)
+ return;
+ p->start_sect = 0;
+ p->nr_sects = 0;
+ devfs_unregister(p->de);
+ dev = p->hd_driverfs_dev;
+ p->hd_driverfs_dev = NULL;
+ if (dev) {
+ device_remove_file(dev, &part_attr_size);
+ device_remove_file(dev, &part_attr_start);
+ device_remove_file(dev, &part_attr_dev);
+ device_unregister(dev);
+ }
+}
+
+static void part_release(struct device *dev)
+{
+ kfree(dev);
+}
+
+void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
+{
+ struct hd_struct *p = disk->part + part - 1;
+ struct device *parent = &disk->disk_dev;
+ struct device *dev;
+
+ p->start_sect = start;
+ p->nr_sects = len;
+ devfs_register_partition(disk, part);
+ dev = kmalloc(sizeof(struct device), GFP_KERNEL);
+ if (!dev)
+ return;
+ memset(dev, 0, sizeof(struct device));
+ dev->parent = parent;
+ sprintf(dev->bus_id, "p%d", part);
+ dev->release = part_release;
+ dev->driver_data = p;
+ device_register(dev);
+ device_create_file(dev, &part_attr_dev);
+ device_create_file(dev, &part_attr_start);
+ device_create_file(dev, &part_attr_size);
+ p->hd_driverfs_dev = dev;
+}
+
+static ssize_t disk_dev_read(struct device *dev,
+ char *page, size_t count, loff_t off)
+{
+ struct gendisk *disk = dev->driver_data;
+ dev_t base = MKDEV(disk->major, disk->first_minor);
+ return off ? 0 : sprintf(page, "%04x\n",base);
+}
+static ssize_t disk_range_read(struct device *dev,
+ char *page, size_t count, loff_t off)
+{
+ struct gendisk *disk = dev->driver_data;
+ return off ? 0 : sprintf(page, "%d\n",disk->minors);
+}
+static ssize_t disk_size_read(struct device *dev,
+ char *page, size_t count, loff_t off)
+{
+ struct gendisk *disk = dev->driver_data;
+ return off ? 0 : sprintf(page, "%llu\n",(u64)get_capacity(disk));
+}
+static struct device_attribute disk_attr_dev = {
+ .attr = {.name = "dev", .mode = S_IRUGO },
+ .show = disk_dev_read
+};
+static struct device_attribute disk_attr_range = {
+ .attr = {.name = "range", .mode = S_IRUGO },
+ .show = disk_range_read
+};
+static struct device_attribute disk_attr_size = {
+ .attr = {.name = "size", .mode = S_IRUGO },
+ .show = disk_size_read
+};
+
+static void disk_driverfs_symlinks(struct gendisk *disk)
+{
+ struct device *target = disk->driverfs_dev;
+ struct device *dev = &disk->disk_dev;
+ struct device *p;
+ char *path;
+ char *s;
+ int length;
+ int depth;
+
+ if (!target)
+ return;
+
+ get_device(target);
+
+ length = get_devpath_length(target);
+ length += strlen("..");
+
+ if (length > PATH_MAX)
+ return;
+
+ if (!(path = kmalloc(length,GFP_KERNEL)))
+ return;
+ memset(path,0,length);
+
+ /* our relative position */
+ strcpy(path,"..");
+
+ fill_devpath(target, path, length);
+ driverfs_create_symlink(&dev->dir, "device", path);
+ kfree(path);
+
+ for (p = target, depth = 0; p; p = p->parent, depth++)
+ ;
+ length = get_devpath_length(dev);
+ length += 3 * depth - 1;
+
+ if (length > PATH_MAX)
+ return;
+
+ if (!(path = kmalloc(length,GFP_KERNEL)))
+ return;
+ memset(path,0,length);
+ for (s = path; depth--; s += 3)
+ strcpy(s, "../");
+
+ fill_devpath(dev, path, length);
+ driverfs_create_symlink(&target->dir, "block", path);
+ kfree(path);
+}
+
/* Not exported, helper to add_disk(). */
void register_disk(struct gendisk *disk)
{
+ struct device *dev = &disk->disk_dev;
+ struct parsed_partitions *state;
struct block_device *bdev;
+ char *s;
+ int j;
+
+ strcpy(dev->bus_id, disk->disk_name);
+ /* ewww... some of these buggers have / in name... */
+ s = strchr(dev->bus_id, '/');
+ if (s)
+ *s = '!';
+ device_add(dev);
+ device_create_file(dev, &disk_attr_dev);
+ device_create_file(dev, &disk_attr_range);
+ device_create_file(dev, &disk_attr_size);
+ disk_driverfs_symlinks(disk);
+
if (disk->flags & GENHD_FL_CD)
devfs_create_cdrom(disk);
/* No minors to use for partitions */
- if (!disk->minor_shift)
+ if (disk->minors == 1)
return;
/* No such device (e.g., media were just removed) */
@@ -411,45 +475,32 @@ void register_disk(struct gendisk *disk)
bdev = bdget(MKDEV(disk->major, disk->first_minor));
if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW) < 0)
return;
- check_partition(disk, bdev);
- driverfs_create_partitions(disk);
+ state = check_partition(disk, bdev);
devfs_create_partitions(disk);
- blkdev_put(bdev, BDEV_RAW);
-}
-
-void update_partition(struct gendisk *disk, int part)
-{
- struct hd_struct *p = disk->part + part - 1;
- struct device *dev = &p->hd_driverfs_dev;
-
- if (!p->nr_sects) {
- if (p->de) {
- devfs_unregister(p->de);
- p->de = NULL;
- }
- if (dev->driver_data) {
- device_remove_file(dev, &dev_attr_type);
- device_remove_file(dev, &dev_attr_kdev);
- put_device(dev);
- dev->driver_data = NULL;
+ if (state) {
+ for (j = 1; j < state->limit; j++) {
+ sector_t size = state->parts[j].size;
+ sector_t from = state->parts[j].from;
+ if (!size)
+ continue;
+ add_partition(disk, j, from, size);
+#if CONFIG_BLK_DEV_MD
+ if (!state->parts[j].flags)
+ continue;
+ md_autodetect_dev(bdev->bd_dev+j);
+#endif
}
- return;
+ kfree(state);
}
- if (!p->de)
- devfs_register_partition(disk, part);
- if (dev->driver_data || !(disk->flags & GENHD_FL_DRIVERFS))
- return;
- dev->driver_data =
- (void *)(long)__mkdev(disk->major, disk->first_minor+part);
- device_register(dev);
- device_create_file(dev, &dev_attr_type);
- device_create_file(dev, &dev_attr_kdev);
+ blkdev_put(bdev, BDEV_RAW);
}
int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
{
kdev_t dev = to_kdev_t(bdev->bd_dev);
+ struct parsed_partitions *state;
int p, res;
+
if (!bdev->bd_invalidated)
return 0;
if (bdev->bd_part_count)
@@ -458,16 +509,25 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
if (res)
return res;
bdev->bd_invalidated = 0;
- for (p = 0; p < (1<<disk->minor_shift) - 1; p++) {
- disk->part[p].start_sect = 0;
- disk->part[p].nr_sects = 0;
- }
+ for (p = 1; p < disk->minors; p++)
+ delete_partition(disk, p);
if (bdev->bd_op->revalidate)
bdev->bd_op->revalidate(dev);
- if (get_capacity(disk))
- check_partition(disk, bdev);
- for (p = 1; p < (1<<disk->minor_shift); p++)
- update_partition(disk, p);
+ if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
+ return res;
+ for (p = 1; p < state->limit; p++) {
+ sector_t size = state->parts[p].size;
+ sector_t from = state->parts[p].from;
+ if (!size)
+ continue;
+ add_partition(disk, p, from, size);
+#if CONFIG_BLK_DEV_MD
+ if (!state->parts[j].flags)
+ continue;
+ md_autodetect_dev(bdev->bd_dev+p);
+#endif
+ }
+ kfree(state);
return res;
}
@@ -493,48 +553,33 @@ fail:
return NULL;
}
-static int wipe_partitions(struct gendisk *disk)
+void del_gendisk(struct gendisk *disk)
{
- int max_p = 1 << disk->minor_shift;
+ int max_p = disk->minors;
kdev_t devp;
- int res;
int p;
/* invalidate stuff */
for (p = max_p - 1; p > 0; p--) {
devp = mk_kdev(disk->major,disk->first_minor + p);
-#if 0 /* %%% superfluous? */
- if (disk->part[p-1].nr_sects == 0)
- continue;
-#endif
- res = invalidate_device(devp, 1);
- if (res)
- return res;
- disk->part[p-1].start_sect = 0;
- disk->part[p-1].nr_sects = 0;
+ invalidate_device(devp, 1);
+ delete_partition(disk, p);
}
devp = mk_kdev(disk->major,disk->first_minor);
-#if 0 /* %%% superfluous? */
- if (disk->part[p].nr_sects == 0)
- continue;
-#endif
- res = invalidate_device(devp, 1);
- if (res)
- return res;
+ invalidate_device(devp, 1);
disk->capacity = 0;
- return 0;
-}
-
-void del_gendisk(struct gendisk *disk)
-{
- driverfs_remove_partitions(disk);
- wipe_partitions(disk);
+ disk->flags &= ~GENHD_FL_UP;
unlink_gendisk(disk);
devfs_remove_partitions(disk);
- if (disk->part) {
- kfree(disk->part);
- disk->part = NULL;
+ device_remove_file(&disk->disk_dev, &disk_attr_dev);
+ device_remove_file(&disk->disk_dev, &disk_attr_range);
+ device_remove_file(&disk->disk_dev, &disk_attr_size);
+ driverfs_remove_file(&disk->disk_dev.dir, "device");
+ if (disk->driverfs_dev) {
+ driverfs_remove_file(&disk->driverfs_dev->dir, "block");
+ put_device(disk->driverfs_dev);
}
+ device_del(&disk->disk_dev);
}
struct dev_name {
@@ -571,6 +616,7 @@ char *partition_name(dev_t dev)
dname->name = NULL;
if (hd)
dname->name = disk_name(hd, part, dname->namebuf);
+ put_disk(hd);
if (!dname->name) {
sprintf(dname->namebuf, "[dev %s]", kdevname(to_kdev_t(dev)));
dname->name = dname->namebuf;
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 7bdea5bbe922..cbafa4129498 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -38,6 +38,7 @@
#include <linux/smp_lock.h>
#include <linux/seq_file.h>
#include <linux/times.h>
+#include <linux/profile.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/fs/xfs/linux/xfs_aops.c b/fs/xfs/linux/xfs_aops.c
index e749c3c3bbed..8364f6c3eb41 100644
--- a/fs/xfs/linux/xfs_aops.c
+++ b/fs/xfs/linux/xfs_aops.c
@@ -36,7 +36,6 @@
#include <linux/mpage.h>
-STATIC int delalloc_convert(struct inode *, struct page *, int, int);
STATIC int
map_blocks(
@@ -50,17 +49,11 @@ map_blocks(
int error, nmaps = 1;
retry:
- if (flags & PBF_FILE_ALLOCATE) {
- VOP_STRATEGY(vp, offset, count, flags, NULL,
- pbmapp, &nmaps, error);
- } else {
- VOP_BMAP(vp, offset, count, flags, NULL,
- pbmapp, &nmaps, error);
- }
+ VOP_BMAP(vp, offset, count, flags, pbmapp, &nmaps, error);
if (flags & PBF_WRITE) {
if (unlikely((flags & PBF_DIRECT) && nmaps &&
(pbmapp->pbm_flags & PBMF_DELAY))) {
- flags = PBF_WRITE | PBF_FILE_ALLOCATE;
+ flags = PBF_FILE_ALLOCATE;
goto retry;
}
VMODIFY(vp);
@@ -130,83 +123,6 @@ map_buffer_at_offset(
}
/*
- * Convert delalloc space to real space, do not flush the
- * data out to disk, that will be done by the caller.
- */
-STATIC int
-release_page(
- struct page *page)
-{
- struct inode *inode = (struct inode*)page->mapping->host;
- unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
- int ret;
-
- /* Are we off the end of the file ? */
- if (page->index >= end_index) {
- unsigned offset = inode->i_size & (PAGE_CACHE_SIZE-1);
- if ((page->index >= end_index+1) || !offset) {
- ret = -EIO;
- goto out;
- }
- }
-
- ret = delalloc_convert(inode, page, 0, 0);
-
-out:
- if (ret < 0) {
- block_invalidatepage(page, 0);
- ClearPageUptodate(page);
-
- return 0;
- }
-
- return 1;
-}
-
-/*
- * Convert delalloc or unmapped space to real space and flush out
- * to disk.
- */
-STATIC int
-write_full_page(
- struct page *page,
- int delalloc)
-{
- struct inode *inode = (struct inode*)page->mapping->host;
- unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
- int ret;
-
- /* Are we off the end of the file ? */
- if (page->index >= end_index) {
- unsigned offset = inode->i_size & (PAGE_CACHE_SIZE-1);
- if ((page->index >= end_index+1) || !offset) {
- ret = -EIO;
- goto out;
- }
- }
-
- if (!page_has_buffers(page)) {
- create_empty_buffers(page, 1 << inode->i_blkbits, 0);
- }
-
- ret = delalloc_convert(inode, page, 1, delalloc == 0);
-
-out:
- if (ret < 0) {
- /*
- * If it's delalloc and we have nowhere to put it,
- * throw it away.
- */
- if (delalloc)
- block_invalidatepage(page, 0);
- ClearPageUptodate(page);
- unlock_page(page);
- }
-
- return ret;
-}
-
-/*
* Look for a page at index which is unlocked and not mapped
* yet - clustering for mmap write case.
*/
@@ -347,16 +263,21 @@ submit_page(
end_page_writeback(page);
}
-STATIC int
-map_page(
+/*
+ * Allocate & map buffers for page given the extent map. Write it out.
+ * except for the original page of a writepage, this is called on
+ * delalloc pages only, for the original page it is possible that
+ * the page has no mapping at all.
+ */
+STATIC void
+convert_page(
struct inode *inode,
struct page *page,
page_buf_bmap_t *maps,
- struct buffer_head *bh_arr[],
int startio,
int all_bh)
{
- struct buffer_head *bh, *head;
+ struct buffer_head *bh_arr[MAX_BUF_PER_PAGE], *bh, *head;
page_buf_bmap_t *mp = maps, *tmp;
unsigned long end, offset, end_index;
int i = 0, index = 0;
@@ -393,32 +314,12 @@ map_page(
}
} while (i++, (bh = bh->b_this_page) != head);
- return index;
-}
-
-/*
- * Allocate & map buffers for page given the extent map. Write it out.
- * except for the original page of a writepage, this is called on
- * delalloc pages only, for the original page it is possible that
- * the page has no mapping at all.
- */
-STATIC void
-convert_page(
- struct inode *inode,
- struct page *page,
- page_buf_bmap_t *maps,
- int startio,
- int all_bh)
-{
- struct buffer_head *bh_arr[MAX_BUF_PER_PAGE];
- int cnt;
-
- cnt = map_page(inode, page, maps, bh_arr, startio, all_bh);
if (startio) {
- submit_page(page, bh_arr, cnt);
+ submit_page(page, bh_arr, index);
} else {
unlock_page(page);
}
+
page_cache_release(page);
}
@@ -439,40 +340,47 @@ cluster_write(
tlast = (mp->pbm_offset + mp->pbm_bsize) >> PAGE_CACHE_SHIFT;
for (; tindex < tlast; tindex++) {
- if (!(page = probe_page(inode, tindex)))
+ page = probe_page(inode, tindex);
+ if (!page)
break;
convert_page(inode, page, mp, startio, all_bh);
}
}
/*
- * Calling this without allocate_space set means we are being asked to
- * flush a dirty buffer head. When called with async_write set then we
- * are coming from writepage. A writepage call with allocate_space set
- * means we are being asked to write out all of the page which is before
- * EOF and therefore need to allocate space for unmapped portions of the
- * page.
+ * Calling this without startio set means we are being asked to make a dirty
+ * page ready for freeing it's buffers. When called with startio set then
+ * we are coming from writepage.
*/
STATIC int
delalloc_convert(
- struct inode *inode, /* inode containing page */
- struct page *page, /* page to convert - locked */
- int startio, /* start io on the page */
+ struct page *page,
+ int startio,
int allocate_space)
{
- struct buffer_head *bh, *head;
- struct buffer_head *bh_arr[MAX_BUF_PER_PAGE];
+ struct inode *inode = page->mapping->host;
+ struct buffer_head *bh_arr[MAX_BUF_PER_PAGE], *bh, *head;
page_buf_bmap_t *mp, map;
- int i, cnt = 0;
- int len, err;
- unsigned long p_offset = 0;
- loff_t offset;
- loff_t end_offset;
+ unsigned long p_offset = 0, end_index;
+ loff_t offset, end_offset;
+ int len, err, i, cnt = 0;
+
+ /* Are we off the end of the file ? */
+ end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+ if (page->index >= end_index) {
+ unsigned remaining = inode->i_size & (PAGE_CACHE_SIZE-1);
+ if ((page->index >= end_index+1) || !remaining) {
+ return -EIO;
+ }
+ }
offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
end_offset = offset + PAGE_CACHE_SIZE;
if (end_offset > inode->i_size)
end_offset = inode->i_size;
+
+ if (startio && !page_has_buffers(page))
+ create_empty_buffers(page, 1 << inode->i_blkbits, 0);
bh = head = page_buffers(page);
mp = NULL;
@@ -490,9 +398,10 @@ delalloc_convert(
if (buffer_delay(bh)) {
if (!mp) {
err = map_blocks(inode, offset, len, &map,
- PBF_WRITE|PBF_FILE_ALLOCATE);
- if (err)
+ PBF_FILE_ALLOCATE);
+ if (err) {
goto error;
+ }
mp = match_offset_to_mapping(page, &map,
p_offset);
}
@@ -517,8 +426,9 @@ delalloc_convert(
bh, head);
err = map_blocks(inode, offset, size, &map,
PBF_WRITE|PBF_DIRECT);
- if (err)
+ if (err) {
goto error;
+ }
mp = match_offset_to_mapping(page, &map,
p_offset);
}
@@ -544,12 +454,14 @@ next_bh:
bh = bh->b_this_page;
} while (offset < end_offset);
- if (startio)
+ if (startio) {
submit_page(page, bh_arr, cnt);
+ }
- if (mp)
+ if (mp) {
cluster_write(inode, page->index + 1, mp,
startio, allocate_space);
+ }
return 0;
@@ -557,7 +469,15 @@ error:
for (i = 0; i < cnt; i++) {
unlock_buffer(bh_arr[i]);
}
-
+
+ /*
+ * If it's delalloc and we have nowhere to put it,
+ * throw it away.
+ */
+ if (!allocate_space) {
+ block_invalidatepage(page, 0);
+ }
+ ClearPageUptodate(page);
return err;
}
@@ -591,7 +511,7 @@ linvfs_get_block_core(
}
VOP_BMAP(vp, offset, size,
- create ? flags : PBF_READ, NULL,
+ create ? flags : PBF_READ,
(struct page_buf_bmap_s *)&pbmap, &retpbbm, error);
if (error)
return -error;
@@ -745,14 +665,12 @@ count_page_state(
bh = head = page_buffers(page);
do {
- if (buffer_uptodate(bh) && !buffer_mapped(bh)) {
+ if (buffer_uptodate(bh) && !buffer_mapped(bh))
(*nr_unmapped)++;
- continue;
- }
- if (!buffer_delay(bh))
- continue;
- (*nr_delalloc)++;
+ else if (buffer_delay(bh))
+ (*nr_delalloc)++;
} while ((bh = bh->b_this_page) != head);
+
return 1;
}
@@ -764,20 +682,22 @@ linvfs_writepage(
struct page *page)
{
int error;
- int need_trans;
+ int need_trans = 1;
int nr_delalloc, nr_unmapped;
- if (count_page_state(page, &nr_delalloc, &nr_unmapped)) {
+ if (count_page_state(page, &nr_delalloc, &nr_unmapped))
need_trans = nr_delalloc + nr_unmapped;
- } else {
- need_trans = 1;
- }
if ((current->flags & (PF_FSTRANS)) && need_trans)
goto out_fail;
- error = write_full_page(page, nr_delalloc);
-
+ /*
+ * Convert delalloc or unmapped space to real space and flush out
+ * to disk.
+ */
+ error = delalloc_convert(page, 1, nr_delalloc == 0);
+ if (unlikely(error))
+ unlock_page(page);
return error;
out_fail:
@@ -812,24 +732,26 @@ linvfs_release_page(
struct page *page,
int gfp_mask)
{
- int need_trans;
int nr_delalloc, nr_unmapped;
if (count_page_state(page, &nr_delalloc, &nr_unmapped)) {
- need_trans = nr_delalloc;
- } else {
- need_trans = 0;
- }
-
- if (need_trans == 0) {
- return try_to_free_buffers(page);
- }
+ if (!nr_delalloc)
+ goto free_buffers;
+ }
if (gfp_mask & __GFP_FS) {
- if (release_page(page) == 0)
- return try_to_free_buffers(page);
+ /*
+ * Convert delalloc space to real space, do not flush the
+ * data out to disk, that will be done by the caller.
+ */
+ if (delalloc_convert(page, 0, 0) == 0)
+ goto free_buffers;
}
+
return 0;
+
+free_buffers:
+ return try_to_free_buffers(page);
}
diff --git a/fs/xfs/linux/xfs_fs_subr.c b/fs/xfs/linux/xfs_fs_subr.c
index 8d50bd04d718..eea74fce0050 100644
--- a/fs/xfs/linux/xfs_fs_subr.c
+++ b/fs/xfs/linux/xfs_fs_subr.c
@@ -135,7 +135,6 @@ fs_flushinval_pages(
struct inode *ip = LINVFS_GET_IP(vp);
if (VN_CACHED(vp)) {
- filemap_fdatawait(ip->i_mapping);
filemap_fdatawrite(ip->i_mapping);
filemap_fdatawait(ip->i_mapping);
@@ -159,7 +158,6 @@ fs_flush_pages(
struct inode *ip = LINVFS_GET_IP(vp);
if (VN_CACHED(vp)) {
- filemap_fdatawait(ip->i_mapping);
filemap_fdatawrite(ip->i_mapping);
filemap_fdatawait(ip->i_mapping);
}
diff --git a/fs/xfs/linux/xfs_globals.c b/fs/xfs/linux/xfs_globals.c
index 54a4343289f1..7f0ac30a83ba 100644
--- a/fs/xfs/linux/xfs_globals.c
+++ b/fs/xfs/linux/xfs_globals.c
@@ -41,12 +41,6 @@ uint64_t xfs_panic_mask; /* set to cause more panics */
unsigned long xfs_physmem;
/*
- * restricted_chown = 1 bsd style chown(2), only super-user can give away files
- * restricted_chown = 0 sysV style chown(2), non super-user can give away files
- */
-int restricted_chown = 1;
-
-/*
* Used to serialize atomicIncWithWrap.
*/
spinlock_t Atomic_spin = SPIN_LOCK_UNLOCKED;
@@ -69,3 +63,6 @@ mutex_t xfs_Gqm_lock;
EXPORT_SYMBOL(xfs_Gqm);
EXPORT_SYMBOL(xfs_next_bit);
EXPORT_SYMBOL(xfs_contig_bits);
+EXPORT_SYMBOL(xfs_bmbt_get_all);
+EXPORT_SYMBOL(xfs_bmbt_disk_get_all);
+
diff --git a/fs/xfs/linux/xfs_globals.h b/fs/xfs/linux/xfs_globals.h
index 943e029f1d42..07c9856b1353 100644
--- a/fs/xfs/linux/xfs_globals.h
+++ b/fs/xfs/linux/xfs_globals.h
@@ -39,7 +39,6 @@
extern uint64_t xfs_panic_mask; /* set to cause more panics */
-extern int restricted_chown;
extern unsigned long xfs_physmem;
extern struct cred *sys_cred;
diff --git a/fs/xfs/linux/xfs_ioctl.c b/fs/xfs/linux/xfs_ioctl.c
index 5dbf4fd9debf..03451043e983 100644
--- a/fs/xfs/linux/xfs_ioctl.c
+++ b/fs/xfs/linux/xfs_ioctl.c
@@ -67,7 +67,7 @@ xfs_find_handle(
if (copy_from_user(&hreq, (xfs_fsop_handlereq_t *)arg, sizeof(hreq)))
return -XFS_ERROR(EFAULT);
- bzero((char *)&handle, sizeof(handle));
+ memset((char *)&handle, 0, sizeof(handle));
switch (cmd) {
case XFS_IOC_PATH_TO_FSHANDLE:
@@ -228,7 +228,7 @@ xfs_vget_fsop_handlereq(
if (copy_from_user(handlep, hanp, hlen))
return XFS_ERROR(EFAULT);
if (hlen < sizeof(*handlep))
- bzero(((char *)handlep) + hlen, sizeof(*handlep) - hlen);
+ memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen);
if (hlen > sizeof(handlep->ha_fsid)) {
if (handlep->ha_fid.xfs_fid_len !=
(hlen - sizeof(handlep->ha_fsid)
@@ -264,12 +264,6 @@ xfs_vget_fsop_handlereq(
vpp = XFS_ITOV(ip);
inodep = LINVFS_GET_IP(vpp);
xfs_iunlock(ip, XFS_ILOCK_SHARED);
- error = linvfs_revalidate_core(inodep, ATTR_COMM);
- if (error) {
- iput(inodep);
- /* this error is (-) but our callers expect + */
- return XFS_ERROR(-error);
- }
*vp = vpp;
*inode = inodep;
diff --git a/fs/xfs/linux/xfs_iops.c b/fs/xfs/linux/xfs_iops.c
index 3beca5b8fd34..d2ca5a30238a 100644
--- a/fs/xfs/linux/xfs_iops.c
+++ b/fs/xfs/linux/xfs_iops.c
@@ -91,14 +91,14 @@ linvfs_mknod(
mode &= ~current->fs->umask;
#endif
- bzero(&va, sizeof(va));
+ memset(&va, 0, sizeof(va));
va.va_mask = AT_TYPE|AT_MODE;
va.va_type = IFTOVT(mode);
va.va_mode = mode;
switch (mode & S_IFMT) {
case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
- va.va_rdev = rdev;
+ va.va_rdev = XFS_MKDEV(MAJOR(rdev), MINOR(rdev));
va.va_mask |= AT_RDEV;
/*FALLTHROUGH*/
case S_IFREG:
@@ -122,8 +122,6 @@ linvfs_mknod(
if (S_ISCHR(mode) || S_ISBLK(mode))
ip->i_rdev = to_kdev_t(rdev);
- /* linvfs_revalidate_core returns (-) errors */
- error = -linvfs_revalidate_core(ip, ATTR_COMM);
validate_fields(dir);
d_instantiate(dentry, ip);
mark_inode_dirty_sync(ip);
@@ -186,7 +184,6 @@ linvfs_lookup(
VN_RELE(cvp);
return ERR_PTR(-EACCES);
}
- error = -linvfs_revalidate_core(ip, ATTR_COMM);
}
if (error && (error != ENOENT))
return ERR_PTR(-error);
@@ -262,14 +259,13 @@ linvfs_symlink(
dvp = LINVFS_GET_VP(dir);
- bzero(&va, sizeof(va));
+ memset(&va, 0, sizeof(va));
va.va_type = VLNK;
- va.va_mode = 0777 & ~current->fs->umask;
- va.va_mask = AT_TYPE|AT_MODE; /* AT_PROJID? */
+ va.va_mode = irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO;
+ va.va_mask = AT_TYPE|AT_MODE;
error = 0;
- VOP_SYMLINK(dvp, dentry, &va, (char *)symname,
- &cvp, NULL, error);
+ VOP_SYMLINK(dvp, dentry, &va, (char *)symname, &cvp, NULL, error);
if (!error) {
ASSERT(cvp);
ASSERT(cvp->v_type == VLNK);
@@ -278,10 +274,9 @@ linvfs_symlink(
error = ENOMEM;
VN_RELE(cvp);
} else {
- /* linvfs_revalidate_core returns (-) errors */
- error = -linvfs_revalidate_core(ip, ATTR_COMM);
d_instantiate(dentry, ip);
validate_fields(dir);
+ validate_fields(ip); /* size needs update */
mark_inode_dirty_sync(ip);
mark_inode_dirty_sync(dir);
}
@@ -369,7 +364,7 @@ linvfs_readlink(
}
/*
- * careful here - this function can get called recusively, so
+ * careful here - this function can get called recursively, so
* we need to be very careful about how much stack we use.
* uio is kmalloced for this reason...
*/
@@ -441,16 +436,6 @@ linvfs_permission(
* from the results of a getattr. This gets called out of things
* like stat.
*/
-int
-linvfs_revalidate_core(
- struct inode *inode,
- int flags)
-{
- vnode_t *vp = LINVFS_GET_VP(inode);
-
- /* vn_revalidate returns (-) error so this is ok */
- return vn_revalidate(vp, flags);
-}
STATIC int
linvfs_getattr(
@@ -463,7 +448,7 @@ linvfs_getattr(
int error = 0;
if (unlikely(vp->v_flag & VMODIFIED)) {
- error = linvfs_revalidate_core(inode, 0);
+ error = vn_revalidate(vp);
}
if (!error)
generic_fillattr(inode, stat);
@@ -528,7 +513,7 @@ linvfs_setattr(
}
if (!error) {
- vn_revalidate(vp, 0);
+ vn_revalidate(vp);
mark_inode_dirty_sync(inode);
}
return error;
@@ -618,30 +603,17 @@ linvfs_setxattr(
error = -ENOATTR;
p += xfs_namespaces[SYSTEM_NAMES].namelen;
if (strcmp(p, POSIXACL_ACCESS) == 0) {
- if (vp->v_flag & VMODIFIED) {
- error = linvfs_revalidate_core(inode, 0);
- if (error)
- return error;
- }
error = xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS);
- if (!error) {
- VMODIFY(vp);
- error = linvfs_revalidate_core(inode, 0);
- }
}
else if (strcmp(p, POSIXACL_DEFAULT) == 0) {
- error = linvfs_revalidate_core(inode, 0);
- if (error)
- return error;
error = xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT);
- if (!error) {
- VMODIFY(vp);
- error = linvfs_revalidate_core(inode, 0);
- }
}
else if (strcmp(p, POSIXCAP) == 0) {
error = xfs_cap_vset(vp, data, size);
}
+ if (!error) {
+ error = vn_revalidate(vp);
+ }
return error;
}
@@ -689,19 +661,9 @@ linvfs_getxattr(
error = -ENOATTR;
p += xfs_namespaces[SYSTEM_NAMES].namelen;
if (strcmp(p, POSIXACL_ACCESS) == 0) {
- if (vp->v_flag & VMODIFIED) {
- error = linvfs_revalidate_core(inode, 0);
- if (error)
- return error;
- }
error = xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
}
else if (strcmp(p, POSIXACL_DEFAULT) == 0) {
- if (vp->v_flag & VMODIFIED) {
- error = linvfs_revalidate_core(inode, 0);
- if (error)
- return error;
- }
error = xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
}
else if (strcmp(p, POSIXCAP) == 0) {
diff --git a/fs/xfs/linux/xfs_iops.h b/fs/xfs/linux/xfs_iops.h
index 3c4529374aec..c5ce4a6ea9f9 100644
--- a/fs/xfs/linux/xfs_iops.h
+++ b/fs/xfs/linux/xfs_iops.h
@@ -65,7 +65,6 @@ extern struct file_operations linvfs_dir_operations;
extern struct address_space_operations linvfs_aops;
-extern int linvfs_revalidate_core(struct inode *, int);
extern int linvfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
#endif /* __XFS_IOPS_H__ */
diff --git a/fs/xfs/linux/xfs_linux.h b/fs/xfs/linux/xfs_linux.h
index 7def3bb302b8..49bb2095c10c 100644
--- a/fs/xfs/linux/xfs_linux.h
+++ b/fs/xfs/linux/xfs_linux.h
@@ -67,6 +67,10 @@
#define STATIC static
#endif
+#define restricted_chown xfs_params.restrict_chown
+#define irix_sgid_inherit xfs_params.sgid_inherit
+#define irix_symlink_mode xfs_params.symlink_mode
+
typedef struct xfs_dirent { /* data from readdir() */
xfs_ino_t d_ino; /* inode number of entry */
xfs_off_t d_off; /* offset of disk directory entry */
diff --git a/fs/xfs/linux/xfs_lrw.c b/fs/xfs/linux/xfs_lrw.c
index c7467e2acce3..9f4a37c46f32 100644
--- a/fs/xfs/linux/xfs_lrw.c
+++ b/fs/xfs/linux/xfs_lrw.c
@@ -43,16 +43,16 @@
<< mp->m_writeio_log)
#define XFS_STRAT_WRITE_IMAPS 2
-STATIC int xfs_iomap_read(xfs_iocore_t *, loff_t, size_t, int, pb_bmap_t *,
- int *, struct pm *);
-STATIC int xfs_iomap_write(xfs_iocore_t *, loff_t, size_t, pb_bmap_t *,
- int *, int, struct pm *);
-STATIC int xfs_iomap_write_delay(xfs_iocore_t *, loff_t, size_t, pb_bmap_t *,
+STATIC int xfs_iomap_read(xfs_iocore_t *, loff_t, size_t, int, page_buf_bmap_t *,
+ int *);
+STATIC int xfs_iomap_write(xfs_iocore_t *, loff_t, size_t, page_buf_bmap_t *,
+ int *, int);
+STATIC int xfs_iomap_write_delay(xfs_iocore_t *, loff_t, size_t, page_buf_bmap_t *,
int *, int, int);
-STATIC int xfs_iomap_write_direct(xfs_iocore_t *, loff_t, size_t, pb_bmap_t *,
+STATIC int xfs_iomap_write_direct(xfs_iocore_t *, loff_t, size_t, page_buf_bmap_t *,
int *, int, int);
STATIC int _xfs_imap_to_bmap(xfs_iocore_t *, xfs_off_t, xfs_bmbt_irec_t *,
- pb_bmap_t *, int, int);
+ page_buf_bmap_t *, int, int);
/*
@@ -136,11 +136,14 @@ xfs_read(
xfs_fsize_t n;
xfs_inode_t *ip;
xfs_mount_t *mp;
+ vnode_t *vp;
unsigned long seg;
int direct = filp->f_flags & O_DIRECT;
ip = XFS_BHVTOI(bdp);
+ vp = BHV_TO_VNODE(bdp);
mp = ip->i_mount;
+ vn_trace_entry(vp, "xfs_read", (inst_t *)__return_address);
XFS_STATS_INC(xfsstats.xs_read_calls);
@@ -194,7 +197,7 @@ xfs_read(
xfs_ilock(ip, XFS_IOLOCK_SHARED);
- if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) &&
+ if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) &&
!(filp->f_mode & FINVIS)) {
int error;
vrwlock_t locktype = VRWLOCK_READ;
@@ -230,8 +233,7 @@ xfs_zero_last_block(
xfs_iocore_t *io,
xfs_off_t offset,
xfs_fsize_t isize,
- xfs_fsize_t end_size,
- struct pm *pmp)
+ xfs_fsize_t end_size)
{
xfs_fileoff_t last_fsb;
xfs_mount_t *mp;
@@ -310,8 +312,7 @@ xfs_zero_eof(
xfs_iocore_t *io,
xfs_off_t offset, /* starting I/O offset */
xfs_fsize_t isize, /* current inode size */
- xfs_fsize_t end_size, /* terminal inode size */
- struct pm *pmp)
+ xfs_fsize_t end_size) /* terminal inode size */
{
struct inode *ip = LINVFS_GET_IP(vp);
xfs_fileoff_t start_zero_fsb;
@@ -337,7 +338,7 @@ xfs_zero_eof(
* First handle zeroing the block on which isize resides.
* We only zero a part of that block so it is handled specially.
*/
- error = xfs_zero_last_block(ip, io, offset, isize, end_size, pmp);
+ error = xfs_zero_last_block(ip, io, offset, isize, end_size);
if (error) {
ASSERT(ismrlocked(io->io_lock, MR_UPDATE));
ASSERT(ismrlocked(io->io_iolock, MR_UPDATE));
@@ -469,6 +470,7 @@ xfs_write(
XFS_STATS_INC(xfsstats.xs_write_calls);
vp = BHV_TO_VNODE(bdp);
+ vn_trace_entry(vp, "xfs_write", (inst_t *)__return_address);
xip = XFS_BHVTOI(bdp);
/* START copy & waste from filemap.c */
@@ -592,7 +594,7 @@ start:
if (!direct && (*offset > isize && isize)) {
error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, *offset,
- isize, *offset + size, NULL);
+ isize, *offset + size);
if (error) {
xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
return(-error);
@@ -755,112 +757,15 @@ retry:
return(ret);
}
-/*
- * xfs_bmap() is the same as the irix xfs_bmap from xfs_rw.c
- * execpt for slight changes to the params
- */
-int
-xfs_bmap(bhv_desc_t *bdp,
- xfs_off_t offset,
- ssize_t count,
- int flags,
- struct cred *cred,
- pb_bmap_t *pbmapp,
- int *npbmaps)
-{
- xfs_inode_t *ip;
- int error;
- int lockmode;
- int fsynced = 0;
- vnode_t *vp;
-
- ip = XFS_BHVTOI(bdp);
- ASSERT((ip->i_d.di_mode & IFMT) == IFREG);
- ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) ==
- ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0));
- ASSERT((flags & PBF_READ) || (flags & PBF_WRITE));
-
- if (XFS_FORCED_SHUTDOWN(ip->i_iocore.io_mount))
- return XFS_ERROR(EIO);
-
- if (flags & PBF_READ) {
- lockmode = xfs_ilock_map_shared(ip);
- error = xfs_iomap_read(&ip->i_iocore, offset, count,
- XFS_BMAPI_ENTIRE, pbmapp, npbmaps, NULL);
- xfs_iunlock_map_shared(ip, lockmode);
- } else { /* PBF_WRITE */
- ASSERT(flags & PBF_WRITE);
- vp = BHV_TO_VNODE(bdp);
- xfs_ilock(ip, XFS_ILOCK_EXCL);
-
- /*
- * Make sure that the dquots are there. This doesn't hold
- * the ilock across a disk read.
- */
-
- if (XFS_IS_QUOTA_ON(ip->i_mount)) {
- if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
- if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) {
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- return XFS_ERROR(error);
- }
- }
- }
-retry:
- error = xfs_iomap_write(&ip->i_iocore, offset, count,
- pbmapp, npbmaps, flags, NULL);
- /* xfs_iomap_write unlocks/locks/unlocks */
-
- if (error == ENOSPC) {
- switch (fsynced) {
- case 0:
- if (ip->i_delayed_blks) {
- filemap_fdatawrite(LINVFS_GET_IP(vp)->i_mapping);
- fsynced = 1;
- } else {
- fsynced = 2;
- flags |= PBF_SYNC;
- }
- error = 0;
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- goto retry;
- case 1:
- fsynced = 2;
- if (!(flags & PBF_SYNC)) {
- flags |= PBF_SYNC;
- error = 0;
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- goto retry;
- }
- case 2:
- sync_blockdev(vp->v_vfsp->vfs_super->s_bdev);
- xfs_log_force(ip->i_mount, (xfs_lsn_t)0,
- XFS_LOG_FORCE|XFS_LOG_SYNC);
-
- error = 0;
-/**
- delay(HZ);
-**/
- fsynced++;
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- goto retry;
- }
- }
- }
-
- return XFS_ERROR(error);
-}
int
-xfs_strategy(bhv_desc_t *bdp,
+xfs_strategy(xfs_inode_t *ip,
xfs_off_t offset,
ssize_t count,
int flags,
- struct cred *cred,
- pb_bmap_t *pbmapp,
+ page_buf_bmap_t *pbmapp,
int *npbmaps)
{
- xfs_inode_t *ip;
xfs_iocore_t *io;
xfs_mount_t *mp;
int error;
@@ -876,20 +781,16 @@ xfs_strategy(bhv_desc_t *bdp,
xfs_bmbt_irec_t imap[XFS_MAX_RW_NBMAPS];
xfs_trans_t *tp;
- ip = XFS_BHVTOI(bdp);
io = &ip->i_iocore;
mp = ip->i_mount;
/* is_xfs = IO_IS_XFS(io); */
ASSERT((ip->i_d.di_mode & IFMT) == IFREG);
ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) ==
((io->io_flags & XFS_IOCORE_RT) != 0));
- ASSERT((flags & PBF_READ) || (flags & PBF_WRITE));
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
- ASSERT(flags & PBF_WRITE);
-
offset_fsb = XFS_B_TO_FSBT(mp, offset);
nimaps = min(XFS_MAX_RW_NBMAPS, *npbmaps);
end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
@@ -1082,12 +983,110 @@ xfs_strategy(bhv_desc_t *bdp,
}
+/*
+ * xfs_bmap() is the same as the irix xfs_bmap from xfs_rw.c
+ * execpt for slight changes to the params
+ */
+int
+xfs_bmap(bhv_desc_t *bdp,
+ xfs_off_t offset,
+ ssize_t count,
+ int flags,
+ page_buf_bmap_t *pbmapp,
+ int *npbmaps)
+{
+ xfs_inode_t *ip;
+ int error;
+ int lockmode;
+ int fsynced = 0;
+ vnode_t *vp;
+
+ ip = XFS_BHVTOI(bdp);
+ ASSERT((ip->i_d.di_mode & IFMT) == IFREG);
+ ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) ==
+ ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0));
+
+ if (XFS_FORCED_SHUTDOWN(ip->i_iocore.io_mount))
+ return XFS_ERROR(EIO);
+
+ if (flags & PBF_READ) {
+ lockmode = xfs_ilock_map_shared(ip);
+ error = xfs_iomap_read(&ip->i_iocore, offset, count,
+ XFS_BMAPI_ENTIRE, pbmapp, npbmaps);
+ xfs_iunlock_map_shared(ip, lockmode);
+ } else if (flags & PBF_FILE_ALLOCATE) {
+ error = xfs_strategy(ip, offset, count, flags,
+ pbmapp, npbmaps);
+ } else { /* PBF_WRITE */
+ ASSERT(flags & PBF_WRITE);
+ vp = BHV_TO_VNODE(bdp);
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+
+ /*
+ * Make sure that the dquots are there. This doesn't hold
+ * the ilock across a disk read.
+ */
+
+ if (XFS_IS_QUOTA_ON(ip->i_mount)) {
+ if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
+ if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) {
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ return XFS_ERROR(error);
+ }
+ }
+ }
+retry:
+ error = xfs_iomap_write(&ip->i_iocore, offset, count,
+ pbmapp, npbmaps, flags);
+ /* xfs_iomap_write unlocks/locks/unlocks */
+
+ if (error == ENOSPC) {
+ switch (fsynced) {
+ case 0:
+ if (ip->i_delayed_blks) {
+ filemap_fdatawrite(LINVFS_GET_IP(vp)->i_mapping);
+ fsynced = 1;
+ } else {
+ fsynced = 2;
+ flags |= PBF_SYNC;
+ }
+ error = 0;
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+ goto retry;
+ case 1:
+ fsynced = 2;
+ if (!(flags & PBF_SYNC)) {
+ flags |= PBF_SYNC;
+ error = 0;
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+ goto retry;
+ }
+ case 2:
+ sync_blockdev(vp->v_vfsp->vfs_super->s_bdev);
+ xfs_log_force(ip->i_mount, (xfs_lsn_t)0,
+ XFS_LOG_FORCE|XFS_LOG_SYNC);
+
+ error = 0;
+/**
+ delay(HZ);
+**/
+ fsynced++;
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+ goto retry;
+ }
+ }
+ }
+
+ return XFS_ERROR(error);
+}
+
+
STATIC int
_xfs_imap_to_bmap(
xfs_iocore_t *io,
xfs_off_t offset,
xfs_bmbt_irec_t *imap,
- pb_bmap_t *pbmapp,
+ page_buf_bmap_t *pbmapp,
int imaps, /* Number of imap entries */
int pbmaps) /* Number of pbmap entries */
{
@@ -1138,9 +1137,8 @@ xfs_iomap_read(
loff_t offset,
size_t count,
int flags,
- pb_bmap_t *pbmapp,
- int *npbmaps,
- struct pm *pmp)
+ page_buf_bmap_t *pbmapp,
+ int *npbmaps)
{
xfs_fileoff_t offset_fsb;
xfs_fileoff_t end_fsb;
@@ -1191,10 +1189,9 @@ xfs_iomap_write(
xfs_iocore_t *io,
loff_t offset,
size_t count,
- pb_bmap_t *pbmapp,
+ page_buf_bmap_t *pbmapp,
int *npbmaps,
- int ioflag,
- struct pm *pmp)
+ int ioflag)
{
int maps;
int error = 0;
@@ -1211,7 +1208,7 @@ xfs_iomap_write(
*/
found = 0;
- error = xfs_iomap_read(io, offset, count, flags, pbmapp, npbmaps, NULL);
+ error = xfs_iomap_read(io, offset, count, flags, pbmapp, npbmaps);
if (error)
goto out;
@@ -1260,7 +1257,7 @@ xfs_write_bmap(
xfs_mount_t *mp,
xfs_iocore_t *io,
xfs_bmbt_irec_t *imapp,
- pb_bmap_t *pbmapp,
+ page_buf_bmap_t *pbmapp,
int iosize,
xfs_fileoff_t ioalign,
xfs_fsize_t isize)
@@ -1330,7 +1327,7 @@ xfs_iomap_write_delay(
xfs_iocore_t *io,
loff_t offset,
size_t count,
- pb_bmap_t *pbmapp,
+ page_buf_bmap_t *pbmapp,
int *npbmaps,
int ioflag,
int found)
@@ -1528,7 +1525,7 @@ xfs_iomap_write_direct(
xfs_iocore_t *io,
loff_t offset,
size_t count,
- pb_bmap_t *pbmapp,
+ page_buf_bmap_t *pbmapp,
int *npbmaps,
int ioflag,
int found)
@@ -1830,36 +1827,22 @@ XFS_log_write_unmount_ro(bhv_desc_t *bdp)
}
/*
- * In these two situations we disregard the readonly mount flag and
- * temporarily enable writes (we must, to ensure metadata integrity).
+ * If the underlying (log or data) device is readonly, there are some
+ * operations that cannot proceed.
*/
-STATIC int
-xfs_is_read_only(xfs_mount_t *mp)
+int
+xfs_dev_is_read_only(xfs_mount_t *mp, char *message)
{
if (bdev_read_only(mp->m_ddev_targp->pbr_bdev) ||
- bdev_read_only(mp->m_logdev_targp->pbr_bdev)) {
+ bdev_read_only(mp->m_logdev_targp->pbr_bdev) ||
+ (mp->m_rtdev_targp && bdev_read_only(mp->m_rtdev_targp->pbr_bdev))) {
+ cmn_err(CE_NOTE,
+ "XFS: %s required on read-only device.", message);
cmn_err(CE_NOTE,
"XFS: write access unavailable, cannot proceed.");
return EROFS;
}
- cmn_err(CE_NOTE,
- "XFS: write access will be enabled during mount.");
- XFS_MTOVFS(mp)->vfs_flag &= ~VFS_RDONLY;
- return 0;
-}
-int
-xfs_recover_read_only(xlog_t *log)
-{
- cmn_err(CE_NOTE, "XFS: WARNING: "
- "recovery required on readonly filesystem.");
- return xfs_is_read_only(log->l_mp);
+ return 0;
}
-int
-xfs_quotacheck_read_only(xfs_mount_t *mp)
-{
- cmn_err(CE_NOTE, "XFS: WARNING: "
- "quotacheck required on readonly filesystem.");
- return xfs_is_read_only(mp);
-}
diff --git a/fs/xfs/linux/xfs_lrw.h b/fs/xfs/linux/xfs_lrw.h
index 0ea2cfe9a860..3ac8eddedb23 100644
--- a/fs/xfs/linux/xfs_lrw.h
+++ b/fs/xfs/linux/xfs_lrw.h
@@ -39,13 +39,12 @@
*/
#define XFS_MAX_RW_NBMAPS 4
-extern int xfs_bmap (bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, pb_bmap_t *, int *);
-extern int xfs_strategy (bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, pb_bmap_t *, int *);
+extern int xfs_bmap (bhv_desc_t *, xfs_off_t, ssize_t, int, page_buf_bmap_t *, int *);
extern int xfsbdstrat (struct xfs_mount *, struct xfs_buf *);
extern int xfs_bdstrat_cb (struct xfs_buf *);
extern int xfs_zero_eof (vnode_t *, struct xfs_iocore *, xfs_off_t,
- xfs_fsize_t, xfs_fsize_t, struct pm *);
+ xfs_fsize_t, xfs_fsize_t);
extern ssize_t xfs_read (
struct bhv_desc *bdp,
struct file *filp,
@@ -62,8 +61,7 @@ extern ssize_t xfs_write (
loff_t *offp,
struct cred *credp);
-extern int xfs_recover_read_only (xlog_t *);
-extern int xfs_quotacheck_read_only (xfs_mount_t *);
+extern int xfs_dev_is_read_only(xfs_mount_t *, char *);
extern void XFS_log_write_unmount_ro (bhv_desc_t *);
diff --git a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c
index 2dfaf44b0f7e..27be367ec316 100644
--- a/fs/xfs/linux/xfs_super.c
+++ b/fs/xfs/linux/xfs_super.c
@@ -92,8 +92,6 @@ STATIC struct export_operations linvfs_export_ops;
#define MNTOPT_SUNIT "sunit" /* data volume stripe unit */
#define MNTOPT_SWIDTH "swidth" /* data volume stripe width */
#define MNTOPT_NORECOVERY "norecovery" /* don't run XFS recovery */
-#define MNTOPT_OSYNCISDSYNC "osyncisdsync" /* o_sync == o_dsync on this fs */
- /* (this is now the default!) */
#define MNTOPT_OSYNCISOSYNC "osyncisosync" /* o_sync is REALLY o_sync */
#define MNTOPT_QUOTA "quota" /* disk quotas */
#define MNTOPT_MRQUOTA "mrquota" /* don't turnoff if SB has quotas on */
@@ -104,7 +102,6 @@ STATIC struct export_operations linvfs_export_ops;
#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
#define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */
#define MNTOPT_NOUUID "nouuid" /* Ignore FS uuid */
-#define MNTOPT_IRIXSGID "irixsgid" /* Irix-style sgid inheritance */
#define MNTOPT_NOLOGFLUSH "nologflush" /* Don't use hard flushes in
log writing */
#define MNTOPT_MTPT "mtpt" /* filesystem mount point */
@@ -124,6 +121,9 @@ xfs_parseargs(
iosize = dsunit = dswidth = vol_dsunit = vol_dswidth = 0;
+ /* Default to 32 bit inodes on linux all the time */
+ args->flags |= XFSMNT_32BITINODES;
+
/* Copy the already-parsed mount(2) flags we're interested in */
if (flags & MS_NOATIME)
args->flags |= XFSMNT_NOATIME;
@@ -175,9 +175,6 @@ xfs_parseargs(
args->iosizelog = (uint8_t) iosize;
} else if (!strcmp(this_char, MNTOPT_WSYNC)) {
args->flags |= XFSMNT_WSYNC;
- } else if (!strcmp(this_char, MNTOPT_OSYNCISDSYNC)) {
- /* no-op, this is now the default */
-printk("XFS: osyncisdsync is now the default, and will soon be deprecated.\n");
} else if (!strcmp(this_char, MNTOPT_OSYNCISOSYNC)) {
args->flags |= XFSMNT_OSYNCISOSYNC;
} else if (!strcmp(this_char, MNTOPT_NORECOVERY)) {
@@ -212,10 +209,13 @@ printk("XFS: osyncisdsync is now the default, and will soon be deprecated.\n");
dswidth = simple_strtoul(value, &eov, 10);
} else if (!strcmp(this_char, MNTOPT_NOUUID)) {
args->flags |= XFSMNT_NOUUID;
- } else if (!strcmp(this_char, MNTOPT_IRIXSGID)) {
- args->flags |= XFSMNT_IRIXSGID;
} else if (!strcmp(this_char, MNTOPT_NOLOGFLUSH)) {
args->flags |= XFSMNT_NOLOGFLUSH;
+ } else if (!strcmp(this_char, "osyncisdsync")) {
+ /* no-op, this is now the default */
+printk("XFS: osyncisdsync is now the default, option is deprecated.\n");
+ } else if (!strcmp(this_char, "irixsgid")) {
+printk("XFS: irixsgid is now a sysctl(2) variable, option is deprecated.\n");
} else {
printk("XFS: unknown mount option [%s].\n", this_char);
return rval;
@@ -264,53 +264,72 @@ printk("XFS: osyncisdsync is now the default, and will soon be deprecated.\n");
return 0;
}
-/*
- * Convert one device special file to a dev_t.
- * Helper routine, used only by spectodevs below.
- */
STATIC int
-spectodev(
- const char *name,
- const char *id,
- dev_t *dev)
+xfs_showargs(
+ struct vfs *vfsp,
+ struct seq_file *m)
{
- struct nameidata nd;
- int error;
+ static struct proc_xfs_info {
+ int flag;
+ char *str;
+ } xfs_info[] = {
+ /* the few simple ones we can get from the mount struct */
+ { XFS_MOUNT_NOALIGN, "," MNTOPT_NOALIGN },
+ { XFS_MOUNT_NORECOVERY, "," MNTOPT_NORECOVERY },
+ { XFS_MOUNT_OSYNCISOSYNC, "," MNTOPT_OSYNCISOSYNC },
+ { XFS_MOUNT_NOUUID, "," MNTOPT_NOUUID },
+ { 0, NULL }
+ };
+ struct proc_xfs_info *xfs_infop;
+ struct xfs_mount *mp = XFS_BHVTOM(vfsp->vfs_fbhv);
- error = path_lookup(name, LOOKUP_FOLLOW, &nd);
- if (error)
- return error;
+ for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) {
+ if (mp->m_flags & xfs_infop->flag)
+ seq_puts(m, xfs_infop->str);
+ }
- *dev = kdev_t_to_nr(nd.dentry->d_inode->i_rdev);
- path_release(&nd);
- return 0;
-}
+ if (mp->m_qflags & XFS_UQUOTA_ACCT) {
+ (mp->m_qflags & XFS_UQUOTA_ENFD) ?
+ seq_puts(m, "," MNTOPT_UQUOTA) :
+ seq_puts(m, "," MNTOPT_UQUOTANOENF);
+ }
-/*
- * Convert device special files to dev_t for data, log, realtime.
- */
-int
-spectodevs(
- struct super_block *sb,
- struct xfs_mount_args *args,
- dev_t *ddevp,
- dev_t *logdevp,
- dev_t *rtdevp)
-{
- int rval = 0;
+ if (mp->m_qflags & XFS_GQUOTA_ACCT) {
+ (mp->m_qflags & XFS_GQUOTA_ENFD) ?
+ seq_puts(m, "," MNTOPT_GQUOTA) :
+ seq_puts(m, "," MNTOPT_GQUOTANOENF);
+ }
- *ddevp = sb->s_dev;
+ if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)
+ seq_printf(m, "," MNTOPT_BIOSIZE "=%d", mp->m_writeio_log);
- if (args->logname[0])
- rval = spectodev(args->logname, "log", logdevp);
- else
- *logdevp = sb->s_dev;
+ if (mp->m_logbufs > 0)
+ seq_printf(m, "," MNTOPT_LOGBUFS "=%d", mp->m_logbufs);
- if (args->rtname[0] && !rval)
- rval = spectodev(args->rtname, "realtime", rtdevp);
- else
- *rtdevp = 0;
- return rval;
+ if (mp->m_logbsize > 0)
+ seq_printf(m, "," MNTOPT_LOGBSIZE "=%d", mp->m_logbsize);
+
+ if (mp->m_ddev_targp->pbr_dev != mp->m_logdev_targp->pbr_dev)
+ seq_printf(m, "," MNTOPT_LOGDEV "=%s",
+ bdevname(mp->m_logdev_targp->pbr_bdev));
+
+ if (mp->m_rtdev_targp &&
+ mp->m_ddev_targp->pbr_dev != mp->m_rtdev_targp->pbr_dev)
+ seq_printf(m, "," MNTOPT_RTDEV "=%s",
+ bdevname(mp->m_rtdev_targp->pbr_bdev));
+
+ if (mp->m_dalign > 0)
+ seq_printf(m, "," MNTOPT_SUNIT "=%d",
+ (int)XFS_FSB_TO_BB(mp, mp->m_dalign));
+
+ if (mp->m_swidth > 0)
+ seq_printf(m, "," MNTOPT_SWIDTH "=%d",
+ (int)XFS_FSB_TO_BB(mp, mp->m_swidth));
+
+ if (vfsp->vfs_flag & VFS_DMI)
+ seq_puts(m, "," MNTOPT_DMAPI);
+
+ return 0;
}
@@ -439,7 +458,6 @@ linvfs_fill_super(
goto fail_unmount;
ip = LINVFS_GET_IP(rootvp);
- linvfs_revalidate_core(ip, ATTR_COMM);
sb->s_root = d_alloc_root(ip);
if (!sb->s_root)
@@ -493,12 +511,6 @@ linvfs_set_inode_ops(
{
vnode_t *vp = LINVFS_GET_VP(inode);
- inode->i_mode = VTTOIF(vp->v_type);
-
- /* If this isn't a new inode, nothing to do */
- if (!(inode->i_state & I_NEW))
- return;
-
if (vp->v_type == VNON) {
make_bad_inode(inode);
} else if (S_ISREG(inode->i_mode)) {
@@ -517,8 +529,6 @@ linvfs_set_inode_ops(
init_special_inode(inode, inode->i_mode,
kdev_t_to_nr(inode->i_rdev));
}
-
- unlock_new_inode(inode);
}
/*
@@ -580,7 +590,6 @@ linvfs_put_super(
struct super_block *sb)
{
int error;
- int sector_size;
vfs_t *vfsp = LINVFS_GET_VFS(sb);
VFS_DOUNMOUNT(vfsp, 0, NULL, NULL, error);
@@ -591,10 +600,6 @@ linvfs_put_super(
}
vfs_deallocate(vfsp);
-
- /* Reset device block size */
- sector_size = bdev_hardsect_size(sb->s_bdev);
- set_blocksize(sb->s_bdev, sector_size);
}
void
@@ -728,7 +733,6 @@ linvfs_get_parent(
VN_RELE(cvp);
return ERR_PTR(-EACCES);
}
- error = -linvfs_revalidate_core(ip, ATTR_COMM);
}
if (error)
return ERR_PTR(-error);
@@ -759,72 +763,9 @@ linvfs_show_options(
struct seq_file *m,
struct vfsmount *mnt)
{
- vfs_t *vfsp;
- xfs_mount_t *mp;
- static struct proc_xfs_info {
- int flag;
- char *str;
- } xfs_info[] = {
- /* the few simple ones we can get from the mount struct */
- { XFS_MOUNT_NOALIGN, ",noalign" },
- { XFS_MOUNT_NORECOVERY, ",norecovery" },
- { XFS_MOUNT_OSYNCISOSYNC, ",osyncisosync" },
- { XFS_MOUNT_NOUUID, ",nouuid" },
- { XFS_MOUNT_IRIXSGID, ",irixsgid" },
- { 0, NULL }
- };
- struct proc_xfs_info *xfs_infop;
-
- vfsp = LINVFS_GET_VFS(mnt->mnt_sb);
- mp = XFS_BHVTOM(vfsp->vfs_fbhv);
-
- for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) {
- if (mp->m_flags & xfs_infop->flag)
- seq_puts(m, xfs_infop->str);
- }
-
- if (mp->m_qflags & XFS_UQUOTA_ACCT) {
- seq_puts(m, ",uquota");
- if (!(mp->m_qflags & XFS_UQUOTA_ENFD))
- seq_puts(m, ",uqnoenforce");
- }
+ vfs_t *vfsp = LINVFS_GET_VFS(mnt->mnt_sb);
- if (mp->m_qflags & XFS_GQUOTA_ACCT) {
- seq_puts(m, ",gquota");
- if (!(mp->m_qflags & XFS_GQUOTA_ENFD))
- seq_puts(m, ",gqnoenforce");
- }
-
- if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)
- seq_printf(m, ",biosize=%d", mp->m_writeio_log);
-
- if (mp->m_logbufs > 0)
- seq_printf(m, ",logbufs=%d", mp->m_logbufs);
-
- if (mp->m_logbsize > 0)
- seq_printf(m, ",logbsize=%d", mp->m_logbsize);
-
- if (mp->m_ddev_targp->pbr_dev != mp->m_logdev_targp->pbr_dev)
- seq_printf(m, ",logdev=%s",
- bdevname(mp->m_logdev_targp->pbr_bdev));
-
- if (mp->m_rtdev_targp &&
- mp->m_ddev_targp->pbr_dev != mp->m_rtdev_targp->pbr_dev)
- seq_printf(m, ",rtdev=%s",
- bdevname(mp->m_rtdev_targp->pbr_bdev));
-
- if (mp->m_dalign > 0)
- seq_printf(m, ",sunit=%d",
- (int)XFS_FSB_TO_BB(mp, mp->m_dalign));
-
- if (mp->m_swidth > 0)
- seq_printf(m, ",swidth=%d",
- (int)XFS_FSB_TO_BB(mp, mp->m_swidth));
-
- if (vfsp->vfs_flag & VFS_DMI)
- seq_puts(m, ",dmapi");
-
- return 0;
+ return xfs_showargs(vfsp, m);
}
STATIC struct super_operations linvfs_sops = {
diff --git a/fs/xfs/linux/xfs_super.h b/fs/xfs/linux/xfs_super.h
index e783163a2300..315910498a0c 100644
--- a/fs/xfs/linux/xfs_super.h
+++ b/fs/xfs/linux/xfs_super.h
@@ -80,18 +80,8 @@
((s)->s_fs_info = vfsp)
-struct xfs_mount_args;
-
extern void
linvfs_set_inode_ops(
struct inode *inode);
-extern int
-spectodevs(
- struct super_block *sb,
- struct xfs_mount_args *args,
- dev_t *ddevp,
- dev_t *logdevp,
- dev_t *rtdevp);
-
#endif /* __XFS_SUPER_H__ */
diff --git a/fs/xfs/linux/xfs_sysctl.c b/fs/xfs/linux/xfs_sysctl.c
index 840810b33f27..4229b8975e05 100644
--- a/fs/xfs/linux/xfs_sysctl.c
+++ b/fs/xfs/linux/xfs_sysctl.c
@@ -35,30 +35,34 @@
#include <linux/proc_fs.h>
/*
- * Tunable xfs parameters
+ * Tunable XFS parameters
*/
extern struct xfsstats xfsstats;
-unsigned long xfs_min[XFS_PARAM] = { 0, 0, 0 };
-unsigned long xfs_max[XFS_PARAM] = { XFS_REFCACHE_SIZE_MAX, XFS_REFCACHE_SIZE_MAX, 1 };
+STATIC ulong xfs_min[XFS_PARAM] = { \
+ 0, 0, 0, 0, 0, 0 };
+STATIC ulong xfs_max[XFS_PARAM] = { \
+ XFS_REFCACHE_SIZE_MAX, XFS_REFCACHE_SIZE_MAX, 1, 1, 1, 1 };
-xfs_param_t xfs_params = { 128, 32, 0 };
+xfs_param_t xfs_params = { 128, 32, 0, 1, 0, 0 };
static struct ctl_table_header *xfs_table_header;
-/* proc handlers */
-extern void xfs_refcache_resize(int xfs_refcache_new_size);
+/* Custom proc handlers */
-static int
-xfs_refcache_resize_proc_handler(ctl_table *ctl, int write, struct file * filp,
- void *buffer, size_t *lenp)
+STATIC int
+xfs_refcache_resize_proc_handler(
+ ctl_table *ctl,
+ int write,
+ struct file *filp,
+ void *buffer,
+ size_t *lenp)
{
- int ret;
- int *valp = ctl->data;
- int xfs_refcache_new_size;
- int xfs_refcache_old_size = *valp;
+ int ret, *valp = ctl->data;
+ int xfs_refcache_new_size;
+ int xfs_refcache_old_size = *valp;
ret = proc_doulongvec_minmax(ctl, write, filp, buffer, lenp);
xfs_refcache_new_size = *valp;
@@ -73,12 +77,15 @@ xfs_refcache_resize_proc_handler(ctl_table *ctl, int write, struct file * filp,
return ret;
}
-static int
-xfs_stats_clear_proc_handler(ctl_table *ctl, int write, struct file * filp,
- void *buffer, size_t *lenp)
+STATIC int
+xfs_stats_clear_proc_handler(
+ ctl_table *ctl,
+ int write,
+ struct file *filp,
+ void *buffer,
+ size_t *lenp)
{
- int ret;
- int *valp = ctl->data;
+ int ret, *valp = ctl->data;
__uint32_t vn_active;
ret = proc_doulongvec_minmax(ctl, write, filp, buffer, lenp);
@@ -95,7 +102,7 @@ xfs_stats_clear_proc_handler(ctl_table *ctl, int write, struct file * filp,
return ret;
}
-static ctl_table xfs_table[] = {
+STATIC ctl_table xfs_table[] = {
{XFS_REFCACHE_SIZE, "refcache_size", &xfs_params.refcache_size,
sizeof(ulong), 0644, NULL, &xfs_refcache_resize_proc_handler,
&sysctl_intvec, NULL, &xfs_min[0], &xfs_max[0]},
@@ -108,15 +115,27 @@ static ctl_table xfs_table[] = {
sizeof(ulong), 0644, NULL, &xfs_stats_clear_proc_handler,
&sysctl_intvec, NULL, &xfs_min[2], &xfs_max[2]},
+ {XFS_RESTRICT_CHOWN, "restrict_chown", &xfs_params.restrict_chown,
+ sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax,
+ &sysctl_intvec, NULL, &xfs_min[3], &xfs_max[3]},
+
+ {XFS_SGID_INHERIT, "irix_sgid_inherit", &xfs_params.sgid_inherit,
+ sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax,
+ &sysctl_intvec, NULL, &xfs_min[4], &xfs_max[4]},
+
+ {XFS_SYMLINK_MODE, "irix_symlink_mode", &xfs_params.symlink_mode,
+ sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax,
+ &sysctl_intvec, NULL, &xfs_min[5], &xfs_max[5]},
+
{0}
};
-static ctl_table xfs_dir_table[] = {
+STATIC ctl_table xfs_dir_table[] = {
{FS_XFS, "xfs", NULL, 0, 0555, xfs_table},
{0}
};
-static ctl_table xfs_root_table[] = {
+STATIC ctl_table xfs_root_table[] = {
{CTL_FS, "fs", NULL, 0, 0555, xfs_dir_table},
{0}
};
diff --git a/fs/xfs/linux/xfs_sysctl.h b/fs/xfs/linux/xfs_sysctl.h
index 6649017ec372..4bf5749d1827 100644
--- a/fs/xfs/linux/xfs_sysctl.h
+++ b/fs/xfs/linux/xfs_sysctl.h
@@ -39,18 +39,25 @@
* Tunable xfs parameters
*/
-#define XFS_PARAM 3
+#define XFS_PARAM (sizeof(struct xfs_param) / sizeof(ulong))
typedef struct xfs_param {
- ulong refcache_size; /* Size of nfs refcache */
- ulong refcache_purge; /* # of entries to purge each time */
- ulong stats_clear; /* reset all xfs stats to 0 */
+ ulong refcache_size; /* Size of NFS reference cache. */
+ ulong refcache_purge; /* # of entries to purge each time. */
+ ulong stats_clear; /* Reset all XFS statistics to zero. */
+ ulong restrict_chown; /* Root/non-root can give away files. */
+ ulong sgid_inherit; /* Inherit ISGID bit if process' GID is */
+ /* not a member of the parent dir GID. */
+ ulong symlink_mode; /* Symlink creat mode affected by umask. */
} xfs_param_t;
enum {
XFS_REFCACHE_SIZE = 1,
XFS_REFCACHE_PURGE = 2,
XFS_STATS_CLEAR = 3,
+ XFS_RESTRICT_CHOWN = 4,
+ XFS_SGID_INHERIT = 5,
+ XFS_SYMLINK_MODE = 6,
};
extern xfs_param_t xfs_params;
diff --git a/fs/xfs/linux/xfs_vfs.h b/fs/xfs/linux/xfs_vfs.h
index 0f384eb8220f..381cb9d7c6d4 100644
--- a/fs/xfs/linux/xfs_vfs.h
+++ b/fs/xfs/linux/xfs_vfs.h
@@ -92,6 +92,8 @@ typedef struct vfsops {
/* send dmapi mount event */
int (*vfs_dmapi_fsys_vector)(bhv_desc_t *,
struct dm_fcntl_vector *);
+ void (*vfs_init_vnode)(bhv_desc_t *, struct vnode *,
+ bhv_desc_t *, int);
void (*vfs_force_shutdown)(bhv_desc_t *,
int, char *, int);
} vfsops_t;
@@ -132,6 +134,14 @@ typedef struct vfsops {
rv = (*(VFS_FOPS(vfsp)->vfs_vget))((vfsp)->vfs_fbhv, vpp, fidp); \
BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \
}
+
+#define VFS_INIT_VNODE(vfsp, vp, bhv, unlock) \
+{ \
+ BHV_READ_LOCK(&(vfsp)->vfs_bh); \
+ (*(VFS_FOPS(vfsp)->vfs_init_vnode))((vfsp)->vfs_fbhv, vp, bhv, unlock);\
+ BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \
+}
+
/* No behavior lock here */
#define VFS_FORCE_SHUTDOWN(vfsp, flags) \
(*(VFS_FOPS(vfsp)->vfs_force_shutdown))((vfsp)->vfs_fbhv, flags, __FILE__, __LINE__);
diff --git a/fs/xfs/linux/xfs_vnode.c b/fs/xfs/linux/xfs_vnode.c
index 0d4cb5ea14eb..51a855c9a4a0 100644
--- a/fs/xfs/linux/xfs_vnode.c
+++ b/fs/xfs/linux/xfs_vnode.c
@@ -179,20 +179,10 @@ vn_get(struct vnode *vp, vmap_t *vmap)
if (inode->i_state & I_FREEING)
return NULL;
- inode = iget_locked(vmap->v_vfsp->vfs_super, vmap->v_ino);
+ inode = ilookup(vmap->v_vfsp->vfs_super, vmap->v_ino);
if (inode == NULL) /* Inode not present */
return NULL;
- /* We do not want to create new inodes via vn_get,
- * returning NULL here is OK.
- */
- if (inode->i_state & I_NEW) {
- make_bad_inode(inode);
- unlock_new_inode(inode);
- iput(inode);
- return NULL;
- }
-
vn_trace_exit(vp, "vn_get", (inst_t *)__return_address);
ASSERT((vp->v_flag & VPURGE) == 0);
@@ -203,7 +193,7 @@ vn_get(struct vnode *vp, vmap_t *vmap)
* "revalidate" the linux inode.
*/
int
-vn_revalidate(struct vnode *vp, int flags)
+vn_revalidate(struct vnode *vp)
{
int error;
struct inode *inode;
@@ -215,7 +205,7 @@ vn_revalidate(struct vnode *vp, int flags)
ASSERT(vp->v_bh.bh_first != NULL);
- VOP_GETATTR(vp, &va, flags & ATTR_LAZY, NULL, error);
+ VOP_GETATTR(vp, &va, 0, NULL, error);
if (! error) {
inode = LINVFS_GET_IP(vp);
@@ -225,27 +215,12 @@ vn_revalidate(struct vnode *vp, int flags)
inode->i_nlink = va.va_nlink;
inode->i_uid = va.va_uid;
inode->i_gid = va.va_gid;
- inode->i_rdev = mk_kdev(MAJOR(va.va_rdev),
- MINOR(va.va_rdev));
- inode->i_blksize = PAGE_CACHE_SIZE;
- inode->i_generation = va.va_gencount;
- if ((flags & ATTR_COMM) ||
- S_ISREG(inode->i_mode) ||
- S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)) {
- inode->i_size = va.va_size;
- inode->i_blocks = va.va_nblocks;
- inode->i_atime = va.va_atime.tv_sec;
- inode->i_mtime = va.va_mtime.tv_sec;
- inode->i_ctime = va.va_ctime.tv_sec;
- }
- if (flags & ATTR_LAZY)
- vp->v_flag &= ~VMODIFIED;
- else
- VUNMODIFY(vp);
- } else {
- vn_trace_exit(vp, "vn_revalidate.error",
- (inst_t *)__return_address);
+ inode->i_size = va.va_size;
+ inode->i_blocks = va.va_nblocks;
+ inode->i_mtime = va.va_mtime.tv_sec;
+ inode->i_ctime = va.va_ctime.tv_sec;
+ inode->i_atime = va.va_atime.tv_sec;
+ VUNMODIFY(vp);
}
return -error;
@@ -412,8 +387,7 @@ vn_remove(struct vnode *vp)
* After the following purge the vnode
* will no longer exist.
*/
- VMAP(vp, XFS_BHVTOI(vp->v_fbhv), vmap);
-
+ VMAP(vp, vmap);
vn_purge(vp, &vmap);
}
diff --git a/fs/xfs/linux/xfs_vnode.h b/fs/xfs/linux/xfs_vnode.h
index bf6025bfe0a4..dc76f19ca268 100644
--- a/fs/xfs/linux/xfs_vnode.h
+++ b/fs/xfs/linux/xfs_vnode.h
@@ -211,8 +211,7 @@ typedef int (*vop_fid2_t)(bhv_desc_t *, struct fid *);
typedef int (*vop_release_t)(bhv_desc_t *);
typedef int (*vop_rwlock_t)(bhv_desc_t *, vrwlock_t);
typedef void (*vop_rwunlock_t)(bhv_desc_t *, vrwlock_t);
-typedef int (*vop_bmap_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, struct page_buf_bmap_s *, int *);
-typedef int (*vop_strategy_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, struct page_buf_bmap_s *, int *);
+typedef int (*vop_bmap_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, struct page_buf_bmap_s *, int *);
typedef int (*vop_reclaim_t)(bhv_desc_t *);
typedef int (*vop_attr_get_t)(bhv_desc_t *, char *, char *, int *, int,
struct cred *);
@@ -254,7 +253,6 @@ typedef struct vnodeops {
vop_rwlock_t vop_rwlock;
vop_rwunlock_t vop_rwunlock;
vop_bmap_t vop_bmap;
- vop_strategy_t vop_strategy;
vop_reclaim_t vop_reclaim;
vop_attr_get_t vop_attr_get;
vop_attr_set_t vop_attr_set;
@@ -286,16 +284,10 @@ typedef struct vnodeops {
rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,cr);\
VN_BHV_READ_UNLOCK(&(vp)->v_bh); \
}
-#define VOP_BMAP(vp,of,sz,rw,cr,b,n,rv) \
+#define VOP_BMAP(vp,of,sz,rw,b,n,rv) \
{ \
VN_BHV_READ_LOCK(&(vp)->v_bh); \
- rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,cr,b,n); \
- VN_BHV_READ_UNLOCK(&(vp)->v_bh); \
-}
-#define VOP_STRATEGY(vp,of,sz,rw,cr,b,n,rv) \
-{ \
- VN_BHV_READ_LOCK(&(vp)->v_bh); \
- rv = _VOP_(vop_strategy, vp)((vp)->v_fbhv,of,sz,rw,cr,b,n); \
+ rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n); \
VN_BHV_READ_UNLOCK(&(vp)->v_bh); \
}
#define VOP_OPEN(vp, cr, rv) \
@@ -528,14 +520,14 @@ typedef struct vattr {
mode_t va_mode; /* file access mode */
uid_t va_uid; /* owner user id */
gid_t va_gid; /* owner group id */
- dev_t va_fsid; /* file system id (dev for now) */
+ xfs_dev_t va_fsid; /* file system id (dev for now) */
xfs_ino_t va_nodeid; /* node id */
nlink_t va_nlink; /* number of references to file */
xfs_off_t va_size; /* file size in bytes */
timespec_t va_atime; /* time of last access */
timespec_t va_mtime; /* time of last modification */
timespec_t va_ctime; /* time file ``created'' */
- dev_t va_rdev; /* device the file represents */
+ xfs_dev_t va_rdev; /* device the file represents */
u_long va_blksize; /* fundamental block size */
__int64_t va_nblocks; /* # of blocks allocated */
u_long va_vcode; /* version code */
@@ -637,12 +629,13 @@ typedef struct vnode_map {
xfs_ino_t v_ino; /* inode # */
} vmap_t;
-#define VMAP(vp, ip, vmap) {(vmap).v_vfsp = (vp)->v_vfsp, \
- (vmap).v_number = (vp)->v_number, \
- (vmap).v_ino = (ip)->i_ino; }
+#define VMAP(vp, vmap) {(vmap).v_vfsp = (vp)->v_vfsp, \
+ (vmap).v_number = (vp)->v_number, \
+ (vmap).v_ino = (vp)->v_inode.i_ino; }
+
extern void vn_purge(struct vnode *, vmap_t *);
extern vnode_t *vn_get(struct vnode *, vmap_t *);
-extern int vn_revalidate(struct vnode *, int);
+extern int vn_revalidate(struct vnode *);
extern void vn_remove(struct vnode *);
static inline int vn_count(struct vnode *vp)
diff --git a/fs/xfs/pagebuf/page_buf.c b/fs/xfs/pagebuf/page_buf.c
index c98dc4637050..b066bc7878df 100644
--- a/fs/xfs/pagebuf/page_buf.c
+++ b/fs/xfs/pagebuf/page_buf.c
@@ -305,8 +305,7 @@ _pagebuf_initialize(
/*
* We don't want certain flags to appear in pb->pb_flags.
*/
- flags &= ~(PBF_LOCK|PBF_ENTER_PAGES|PBF_MAPPED);
- flags &= ~(PBF_DONT_BLOCK|PBF_READ_AHEAD);
+ flags &= ~(PBF_LOCK|PBF_MAPPED|PBF_DONT_BLOCK|PBF_READ_AHEAD);
pb_tracking_get(pb);
@@ -545,9 +544,9 @@ _pagebuf_lookup_pages(
size -= nbytes;
if (!PageUptodate(page)) {
- if ((blocksize == PAGE_CACHE_SIZE) &&
- (flags & PBF_READ)) {
- pb->pb_locked = 1;
+ if (blocksize == PAGE_CACHE_SIZE) {
+ if (flags & PBF_READ)
+ pb->pb_locked = 1;
good_pages--;
} else if (!PagePrivate(page)) {
unsigned long i, range = (offset + nbytes) >> SECTOR_SHIFT;
@@ -717,7 +716,6 @@ found:
PBF_MAPPED | \
_PBF_LOCKABLE | \
_PBF_ALL_PAGES_MAPPED | \
- _PBF_SOME_INVALID_PAGES | \
_PBF_ADDR_ALLOCATED | \
_PBF_MEM_ALLOCATED;
PB_TRACE(pb, PB_TRACE_REC(got_lk), 0);
@@ -832,19 +830,11 @@ pagebuf_lookup(
int flags)
{
page_buf_t *pb = NULL;
- int status;
flags |= _PBF_PRIVATE_BH;
pb = pagebuf_allocate(flags);
if (pb) {
_pagebuf_initialize(pb, target, ioff, isize, flags);
- if (flags & PBF_ENTER_PAGES) {
- status = _pagebuf_lookup_pages(pb, &inode->i_data, 0);
- if (status != 0) {
- pagebuf_free(pb);
- return (NULL);
- }
- }
}
return pb;
}
@@ -985,6 +975,7 @@ pagebuf_get_no_daddr(
}
/* otherwise pagebuf_free just ignores it */
pb->pb_flags |= _PBF_MEM_ALLOCATED;
+ PB_CLEAR_OWNER(pb);
up(&PBP(pb)->pb_sema); /* Return unlocked pagebuf */
PB_TRACE(pb, PB_TRACE_REC(no_daddr), rmem);
@@ -1926,14 +1917,14 @@ STATIC ctl_table pagebuf_table[] = {
sizeof(ulong), 0644, NULL, &proc_doulongvec_ms_jiffies_minmax,
&sysctl_intvec, NULL, &pagebuf_min[1], &pagebuf_max[1]},
- {PB_STATS_CLEAR, "stats_clear", &pb_params.data[3],
+ {PB_STATS_CLEAR, "stats_clear", &pb_params.data[2],
sizeof(ulong), 0644, NULL, &pb_stats_clear_handler,
- &sysctl_intvec, NULL, &pagebuf_min[3], &pagebuf_max[3]},
+ &sysctl_intvec, NULL, &pagebuf_min[2], &pagebuf_max[2]},
#ifdef PAGEBUF_TRACE
- {PB_DEBUG, "debug", &pb_params.data[4],
+ {PB_DEBUG, "debug", &pb_params.data[3],
sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax,
- &sysctl_intvec, NULL, &pagebuf_min[4], &pagebuf_max[4]},
+ &sysctl_intvec, NULL, &pagebuf_min[3], &pagebuf_max[3]},
#endif
{0}
};
diff --git a/fs/xfs/pagebuf/page_buf.h b/fs/xfs/pagebuf/page_buf.h
index 18e27035cf72..ff240fefd32c 100644
--- a/fs/xfs/pagebuf/page_buf.h
+++ b/fs/xfs/pagebuf/page_buf.h
@@ -100,35 +100,27 @@ typedef enum page_buf_flags_e { /* pb_flags values */
PBF_MAPPABLE = (1 << 9),/* use directly-addressable pages */
PBF_STALE = (1 << 10), /* buffer has been staled, do not find it */
PBF_FS_MANAGED = (1 << 11), /* filesystem controls freeing memory */
- PBF_RELEASE = (1 << 12),/* buffer to be released after I/O is done */
/* flags used only as arguments to access routines */
PBF_LOCK = (1 << 13), /* lock requested */
PBF_TRYLOCK = (1 << 14), /* lock requested, but do not wait */
- PBF_ALLOCATE = (1 << 15), /* allocate all pages (UNUSED) */
- PBF_FILE_ALLOCATE = (1 << 16), /* allocate all file space */
- PBF_DONT_BLOCK = (1 << 17), /* do not block in current thread */
- PBF_DIRECT = (1 << 18), /* direct I/O desired */
- PBF_ENTER_PAGES = (1 << 21), /* create invalid pages for all */
- /* pages in the range of the buffer */
- /* not already associated with buffer */
+ PBF_FILE_ALLOCATE = (1 << 15), /* allocate all file space */
+ PBF_DONT_BLOCK = (1 << 16), /* do not block in current thread */
+ PBF_DIRECT = (1 << 17), /* direct I/O desired */
/* flags used only internally */
_PBF_LOCKABLE = (1 << 19), /* page_buf_t may be locked */
_PBF_PRIVATE_BH = (1 << 20), /* do not use public buffer heads */
- _PBF_ALL_PAGES_MAPPED = (1 << 22),
+ _PBF_ALL_PAGES_MAPPED = (1 << 21),
/* all pages in rage are mapped */
- _PBF_SOME_INVALID_PAGES = (1 << 23),
- /* some mapped pages are not valid */
- _PBF_ADDR_ALLOCATED = (1 << 24),
+ _PBF_ADDR_ALLOCATED = (1 << 22),
/* pb_addr space was allocated */
- _PBF_MEM_ALLOCATED = (1 << 25),
+ _PBF_MEM_ALLOCATED = (1 << 23),
/* pb_mem and underlying pages allocated */
- PBF_FORCEIO = (1 << 27),
- PBF_FLUSH = (1 << 28), /* flush disk write cache */
- PBF_READ_AHEAD = (1 << 29),
- PBF_FS_RESERVED_3 = (1 << 31) /* reserved (XFS use: XFS_B_STALE) */
+ PBF_FORCEIO = (1 << 24),
+ PBF_FLUSH = (1 << 25), /* flush disk write cache */
+ PBF_READ_AHEAD = (1 << 26),
} page_buf_flags_t;
@@ -145,7 +137,6 @@ typedef struct pb_target {
struct block_device *pbr_bdev;
struct address_space *pbr_mapping;
unsigned int pbr_blocksize;
- unsigned int pbr_blocksize_bits;
} pb_target_t;
/*
@@ -303,26 +294,16 @@ extern int pagebuf_lock_value( /* return count on lock */
extern int pagebuf_lock( /* lock buffer */
page_buf_t *); /* buffer to lock */
-extern void pagebuf_lock_disable( /* disable buffer locking */
- struct pb_target *, /* inode for buffers */
- int); /* do blkdev_put? */
-
-extern struct pb_target *pagebuf_lock_enable(
- dev_t,
- int); /* do blkdev_get? */
-
-extern void pagebuf_target_blocksize(
- pb_target_t *,
- unsigned int); /* block size */
-
extern void pagebuf_target_clear(struct pb_target *);
extern void pagebuf_unlock( /* unlock buffer */
page_buf_t *); /* buffer to unlock */
/* Buffer Utility Routines */
-
-#define pagebuf_geterror(pb) ((pb)->pb_error)
+static inline int pagebuf_geterror(page_buf_t *pb)
+{
+ return (pb ? pb->pb_error : ENOMEM);
+}
extern void pagebuf_iodone( /* mark buffer I/O complete */
page_buf_t *); /* buffer to mark */
diff --git a/fs/xfs/pagebuf/page_buf_locking.c b/fs/xfs/pagebuf/page_buf_locking.c
index 6be04596ec11..ecabe0f3c2c2 100644
--- a/fs/xfs/pagebuf/page_buf_locking.c
+++ b/fs/xfs/pagebuf/page_buf_locking.c
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
- * Portions Copyright (c) 2002 Christoph Hellwig. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -58,10 +57,6 @@
#include "page_buf_internal.h"
-#ifndef EVMS_MAJOR
-#define EVMS_MAJOR 117
-#endif
-
/*
* pagebuf_cond_lock
*
@@ -126,82 +121,6 @@ pagebuf_lock(
return 0;
}
-/*
- * pagebuf_lock_disable
- *
- * pagebuf_lock_disable disables buffer object locking for an inode.
- * remove_super() does a blkdev_put for us on the data device, hence
- * the do_blkdev_put argument.
- */
-void
-pagebuf_lock_disable(
- pb_target_t *target,
- int do_blkdev_put)
-{
- pagebuf_delwri_flush(target, PBDF_WAIT, NULL);
- if (do_blkdev_put)
- blkdev_put(target->pbr_bdev, BDEV_FS);
- kfree(target);
-}
-
-/*
- * pagebuf_lock_enable
- *
- * get_sb_bdev() does a blkdev_get for us on the data device, hence
- * the do_blkdev_get argument.
- */
-pb_target_t *
-pagebuf_lock_enable(
- dev_t dev,
- int do_blkdev_get)
-{
- struct block_device *bdev;
- pb_target_t *target;
- int error = -ENOMEM;
-
- target = kmalloc(sizeof(pb_target_t), GFP_KERNEL);
- if (unlikely(!target))
- return ERR_PTR(error);
-
- bdev = bdget(dev);
- if (unlikely(!bdev))
- goto fail;
-
- if (do_blkdev_get) {
- error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_FS);
- if (unlikely(error))
- goto fail;
- }
-
- target->pbr_dev = dev;
- target->pbr_bdev = bdev;
- target->pbr_mapping = bdev->bd_inode->i_mapping;
-
- pagebuf_target_blocksize(target, PAGE_CACHE_SIZE);
-
- if ((MAJOR(dev) == MD_MAJOR) || (MAJOR(dev) == EVMS_MAJOR))
- target->pbr_flags = PBR_ALIGNED_ONLY;
- else if (MAJOR(dev) == LVM_BLK_MAJOR)
- target->pbr_flags = PBR_SECTOR_ONLY;
- else
- target->pbr_flags = 0;
-
- return target;
-
-fail:
- kfree(target);
- return ERR_PTR(error);
-}
-
-void
-pagebuf_target_blocksize(
- pb_target_t *target,
- unsigned int blocksize)
-{
- target->pbr_blocksize = blocksize;
- target->pbr_blocksize_bits = ffs(blocksize) - 1;
-}
-
void
pagebuf_target_clear(
pb_target_t *target)
diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c
index 795056094248..d6fe5d8b6983 100644
--- a/fs/xfs/support/debug.c
+++ b/fs/xfs/support/debug.c
@@ -40,6 +40,11 @@ int doass = 1;
static char message[256]; /* keep it off the stack */
static spinlock_t xfs_err_lock = SPIN_LOCK_UNLOCKED;
+/* Translate from CE_FOO to KERN_FOO, err_level(CE_FOO) == KERN_FOO */
+static char *err_level[8] = {KERN_EMERG, KERN_ALERT, KERN_CRIT,
+ KERN_ERR, KERN_WARNING, KERN_NOTICE,
+ KERN_INFO, KERN_DEBUG};
+
void
assfail(char *a, char *f, int l)
{
@@ -71,10 +76,7 @@ get_thread_id(void)
return current->pid;
}
-# define xdprintk(format...) printk(format)
-#else
-# define xdprintk(format...) do { } while (0)
-#endif
+#endif /* DEBUG */
void
cmn_err(register int level, char *fmt, ...)
@@ -86,18 +88,7 @@ cmn_err(register int level, char *fmt, ...)
va_start(ap, fmt);
if (*fmt == '!') fp++;
vsprintf(message, fp, ap);
- switch (level) {
- case CE_CONT:
- case CE_WARN:
- printk("%s", message);
- break;
- case CE_DEBUG:
- xdprintk("%s", message);
- break;
- default:
- printk("%s\n", message);
- break;
- }
+ printk("%s%s\n", err_level[level], message);
va_end(ap);
spin_unlock(&xfs_err_lock);
@@ -111,18 +102,8 @@ icmn_err(register int level, char *fmt, va_list ap)
{
spin_lock(&xfs_err_lock);
vsprintf(message, fmt, ap);
- switch (level) {
- case CE_CONT:
- case CE_WARN:
- printk("%s", message);
- break;
- case CE_DEBUG:
- xdprintk("%s", message);
- break;
- default:
- printk("cmn_err level %d ", level);
- printk("%s\n", message);
- break;
- }
spin_unlock(&xfs_err_lock);
+ printk("%s%s\n", err_level[level], message);
+ if (level == CE_PANIC)
+ BUG();
}
diff --git a/fs/xfs/support/move.c b/fs/xfs/support/move.c
index 4fc3831eed38..15dbd090c6b8 100644
--- a/fs/xfs/support/move.c
+++ b/fs/xfs/support/move.c
@@ -72,9 +72,9 @@ uiomove(void *cp, size_t n, enum uio_rw rw, struct uio *uio)
case UIO_SYSSPACE:
if (rw == UIO_READ)
- bcopy(cp, iov->iov_base, cnt);
+ memcpy(iov->iov_base, cp, cnt);
else
- bcopy(iov->iov_base, cp, cnt);
+ memcpy(cp, iov->iov_base, cnt);
break;
default:
diff --git a/fs/xfs/support/move.h b/fs/xfs/support/move.h
index e01b7b6c7a15..dd63285df2e6 100644
--- a/fs/xfs/support/move.h
+++ b/fs/xfs/support/move.h
@@ -36,11 +36,6 @@
#include <linux/uio.h>
#include <asm/uaccess.h>
-#define bzero(p,s) memset((p), 0, (s))
-#define bcopy(s,d,n) memcpy((d),(s),(n))
-#define bcmp(s1,s2,l) memcmp(s1,s2,l)
-#define ovbcopy(from,to,count) memmove(to,from,count)
-
typedef struct iovec iovec_t;
typedef struct uio {
diff --git a/fs/xfs/support/uuid.c b/fs/xfs/support/uuid.c
index f30b857a3f9a..fd98101312c1 100644
--- a/fs/xfs/support/uuid.c
+++ b/fs/xfs/support/uuid.c
@@ -109,7 +109,7 @@ uuid_getnodeuniq(uuid_t *uuid, int fsid [2])
void
uuid_create_nil(uuid_t *uuid)
{
- bzero(uuid, sizeof *uuid);
+ memset(uuid, 0, sizeof(*uuid));
}
int
@@ -129,7 +129,7 @@ uuid_is_nil(uuid_t *uuid)
int
uuid_equal(uuid_t *uuid1, uuid_t *uuid2)
{
- return bcmp(uuid1, uuid2, sizeof(uuid_t)) ? B_FALSE : B_TRUE;
+ return memcmp(uuid1, uuid2, sizeof(uuid_t)) ? B_FALSE : B_TRUE;
}
/*
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index 4489ce3a1502..5c89a956c866 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -494,13 +494,13 @@ xfs_alloc_trace_modagf(
(void *)(__psunsigned_t)INT_GET(agf->agf_seqno, ARCH_CONVERT),
(void *)(__psunsigned_t)INT_GET(agf->agf_length, ARCH_CONVERT),
(void *)(__psunsigned_t)INT_GET(agf->agf_roots[XFS_BTNUM_BNO],
- ARCH_CONVERT);
+ ARCH_CONVERT),
(void *)(__psunsigned_t)INT_GET(agf->agf_roots[XFS_BTNUM_CNT],
- ARCH_CONVERT);
+ ARCH_CONVERT),
(void *)(__psunsigned_t)INT_GET(agf->agf_levels[XFS_BTNUM_BNO],
- ARCH_CONVERT);
+ ARCH_CONVERT),
(void *)(__psunsigned_t)INT_GET(agf->agf_levels[XFS_BTNUM_CNT],
- ARCH_CONVERT);
+ ARCH_CONVERT),
(void *)(__psunsigned_t)INT_GET(agf->agf_flfirst, ARCH_CONVERT),
(void *)(__psunsigned_t)INT_GET(agf->agf_fllast, ARCH_CONVERT),
(void *)(__psunsigned_t)INT_GET(agf->agf_flcount, ARCH_CONVERT),
@@ -2597,7 +2597,7 @@ xfs_alloc_search_busy(xfs_trans_t *tp,
s = mutex_spinlock(&mp->m_perag[agno].pagb_lock);
cnt = mp->m_perag[agno].pagb_count;
- uend = bno + len;
+ uend = bno + len - 1;
/* search pagb_list for this slot, skipping open slots */
for (bsy = mp->m_perag[agno].pagb_list, n = 0;
@@ -2607,16 +2607,16 @@ xfs_alloc_search_busy(xfs_trans_t *tp,
* (start1,length1) within (start2, length2)
*/
if (bsy->busy_tp != NULL) {
- bend = bsy->busy_start + bsy->busy_length;
- if ( (bno >= bsy->busy_start && bno <= bend) ||
- (uend >= bsy->busy_start && uend <= bend) ||
- (bno <= bsy->busy_start && uend >= bsy->busy_start) ) {
+ bend = bsy->busy_start + bsy->busy_length - 1;
+ if ((bno > bend) ||
+ (uend < bsy->busy_start)) {
+ cnt--;
+ } else {
TRACE_BUSYSEARCH("xfs_alloc_search_busy",
"found1", agno, bno, len, n,
tp);
break;
}
- cnt--;
}
}
@@ -2626,7 +2626,7 @@ xfs_alloc_search_busy(xfs_trans_t *tp,
*/
if (cnt) {
TRACE_BUSYSEARCH("xfs_alloc_search_busy", "found", agno, bno, len, n, tp);
- lsn = bsy->busy_tp->t_lsn;
+ lsn = bsy->busy_tp->t_commit_lsn;
mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s);
xfs_log_force(mp, lsn, XFS_LOG_FORCE|XFS_LOG_SYNC);
} else {
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c
index 11c7618be7c7..9bb3fe79243d 100644
--- a/fs/xfs/xfs_alloc_btree.c
+++ b/fs/xfs/xfs_alloc_btree.c
@@ -132,9 +132,9 @@ xfs_alloc_delrec(
}
#endif
if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) {
- ovbcopy(&lkp[ptr], &lkp[ptr - 1],
+ memmove(&lkp[ptr - 1], &lkp[ptr],
(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lkp)); /* INT_: mem copy */
- ovbcopy(&lpp[ptr], &lpp[ptr - 1],
+ memmove(&lpp[ptr - 1], &lpp[ptr],
(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lpp)); /* INT_: mem copy */
xfs_alloc_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
xfs_alloc_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
@@ -147,7 +147,7 @@ xfs_alloc_delrec(
else {
lrp = XFS_ALLOC_REC_ADDR(block, 1, cur);
if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) {
- ovbcopy(&lrp[ptr], &lrp[ptr - 1],
+ memmove(&lrp[ptr - 1], &lrp[ptr],
(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lrp));
xfs_alloc_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
}
@@ -464,8 +464,8 @@ xfs_alloc_delrec(
return error;
}
#endif
- bcopy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp)); /* INT_: structure copy */
- bcopy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp)); /* INT_: structure copy */
+ memcpy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp)); /* INT_: structure copy */
+ memcpy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp)); /* INT_: structure copy */
xfs_alloc_log_keys(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT));
xfs_alloc_log_ptrs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
@@ -476,7 +476,7 @@ xfs_alloc_delrec(
*/
lrp = XFS_ALLOC_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur);
rrp = XFS_ALLOC_REC_ADDR(right, 1, cur);
- bcopy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp));
+ memcpy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp));
xfs_alloc_log_recs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT));
}
@@ -697,9 +697,9 @@ xfs_alloc_insrec(
return error;
}
#endif
- ovbcopy(&kp[ptr - 1], &kp[ptr],
+ memmove(&kp[ptr], &kp[ptr - 1],
(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*kp)); /* INT_: copy */
- ovbcopy(&pp[ptr - 1], &pp[ptr],
+ memmove(&pp[ptr], &pp[ptr - 1],
(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*pp)); /* INT_: copy */
#ifdef DEBUG
if ((error = xfs_btree_check_sptr(cur, *bnop, level)))
@@ -723,7 +723,7 @@ xfs_alloc_insrec(
* It's a leaf entry. Make a hole for the new record.
*/
rp = XFS_ALLOC_REC_ADDR(block, 1, cur);
- ovbcopy(&rp[ptr - 1], &rp[ptr],
+ memmove(&rp[ptr], &rp[ptr - 1],
(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*rp));
/*
* Now stuff the new record in, bump numrecs
@@ -1217,12 +1217,12 @@ xfs_alloc_lshift(
return error;
}
#endif
- ovbcopy(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
- ovbcopy(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+ memmove(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+ memmove(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
xfs_alloc_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
xfs_alloc_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
} else {
- ovbcopy(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+ memmove(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
key.ar_startblock = rrp->ar_startblock; /* INT_: direct copy */
key.ar_blockcount = rrp->ar_blockcount; /* INT_: direct copy */
@@ -1475,8 +1475,8 @@ xfs_alloc_rshift(
return error;
}
#endif
- ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
- ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+ memmove(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+ memmove(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
#ifdef DEBUG
if ((error = xfs_btree_check_sptr(cur, INT_GET(*lpp, ARCH_CONVERT), level)))
return error;
@@ -1492,7 +1492,7 @@ xfs_alloc_rshift(
lrp = XFS_ALLOC_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur);
rrp = XFS_ALLOC_REC_ADDR(right, 1, cur);
- ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+ memmove(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
*rrp = *lrp;
xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1);
key.ar_startblock = rrp->ar_startblock; /* INT_: direct copy */
@@ -1608,8 +1608,8 @@ xfs_alloc_split(
return error;
}
#endif
- bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); /* INT_: copy */
- bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));/* INT_: copy */
+ memcpy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); /* INT_: copy */
+ memcpy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); /* INT_: copy */
xfs_alloc_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
xfs_alloc_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
*keyp = *rkp;
@@ -1623,7 +1623,7 @@ xfs_alloc_split(
lrp = XFS_ALLOC_REC_ADDR(left, i, cur);
rrp = XFS_ALLOC_REC_ADDR(right, 1, cur);
- bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+ memcpy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
keyp->ar_startblock = rrp->ar_startblock; /* INT_: direct copy */
keyp->ar_blockcount = rrp->ar_blockcount; /* INT_: direct copy */
diff --git a/fs/xfs/xfs_arch.h b/fs/xfs/xfs_arch.h
index 57a28544be96..4629bc745e07 100644
--- a/fs/xfs/xfs_arch.h
+++ b/fs/xfs/xfs_arch.h
@@ -260,13 +260,13 @@
#define DIRINO_COPY_ARCH(from,to,arch) \
if ((arch) == ARCH_NOCONVERT) { \
- bcopy(from,to,sizeof(xfs_ino_t)); \
+ memcpy(to,from,sizeof(xfs_ino_t)); \
} else { \
INT_SWAP_UNALIGNED_64(from,to); \
}
#define DIRINO4_COPY_ARCH(from,to,arch) \
if ((arch) == ARCH_NOCONVERT) { \
- bcopy((((__u8*)from+4)),to,sizeof(xfs_dir2_ino4_t)); \
+ memcpy(to,(((__u8*)from+4)),sizeof(xfs_dir2_ino4_t)); \
} else { \
INT_SWAP_UNALIGNED_32(from,to); \
}
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
index 74563b62d3fc..482a20fcbfde 100644
--- a/fs/xfs/xfs_attr.c
+++ b/fs/xfs/xfs_attr.c
@@ -120,7 +120,7 @@ xfs_attr_get(bhv_desc_t *bdp, char *name, char *value, int *valuelenp,
/*
* Fill in the arg structure for this request.
*/
- bzero((char *)&args, sizeof(args));
+ memset((char *)&args, 0, sizeof(args));
args.name = name;
args.namelen = namelen;
args.value = value;
@@ -215,7 +215,7 @@ xfs_attr_set(bhv_desc_t *bdp, char *name, char *value, int valuelen, int flags,
/*
* Fill in the arg structure for this request.
*/
- bzero((char *)&args, sizeof(args));
+ memset((char *)&args, 0, sizeof(args));
args.name = name;
args.namelen = namelen;
args.value = value;
@@ -469,7 +469,7 @@ xfs_attr_remove(bhv_desc_t *bdp, char *name, int flags, struct cred *cred)
/*
* Fill in the arg structure for this request.
*/
- bzero((char *)&args, sizeof(args));
+ memset((char *)&args, 0, sizeof(args));
args.name = name;
args.namelen = namelen;
args.flags = flags;
diff --git a/fs/xfs/xfs_attr_fetch.c b/fs/xfs/xfs_attr_fetch.c
index 0c9af54eeed5..4b1a23cb21a6 100644
--- a/fs/xfs/xfs_attr_fetch.c
+++ b/fs/xfs/xfs_attr_fetch.c
@@ -43,7 +43,7 @@ xfs_attr_fetch(xfs_inode_t *ip, char *name, char *value, int valuelen)
/*
* Do the argument setup for the xfs_attr routines.
*/
- bzero((char *)&args, sizeof(args));
+ memset((char *)&args, 0, sizeof(args));
args.dp = ip;
args.flags = ATTR_ROOT;
args.whichfork = XFS_ATTR_FORK;
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
index 884da53fa54d..b1c4836d6709 100644
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -128,7 +128,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args)
sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
if (sfe->namelen != args->namelen)
continue;
- if (bcmp(args->name, sfe->nameval, args->namelen) != 0)
+ if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
continue;
if (((args->flags & ATTR_ROOT) != 0) !=
((sfe->flags & XFS_ATTR_ROOT) != 0))
@@ -145,8 +145,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args)
sfe->namelen = args->namelen;
INT_SET(sfe->valuelen, ARCH_CONVERT, args->valuelen);
sfe->flags = (args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0;
- bcopy(args->name, sfe->nameval, args->namelen);
- bcopy(args->value, &sfe->nameval[args->namelen], args->valuelen);
+ memcpy(sfe->nameval, args->name, args->namelen);
+ memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
INT_MOD(sf->hdr.count, ARCH_CONVERT, 1);
INT_MOD(sf->hdr.totsize, ARCH_CONVERT, size);
xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
@@ -178,7 +178,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
size = XFS_ATTR_SF_ENTSIZE(sfe);
if (sfe->namelen != args->namelen)
continue;
- if (bcmp(sfe->nameval, args->name, args->namelen) != 0)
+ if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
continue;
if (((args->flags & ATTR_ROOT) != 0) !=
((sfe->flags & XFS_ATTR_ROOT) != 0))
@@ -191,7 +191,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
end = base + size;
totsize = INT_GET(sf->hdr.totsize, ARCH_CONVERT);
if (end != totsize) {
- ovbcopy(&((char *)sf)[end], &((char *)sf)[base],
+ memmove(&((char *)sf)[base], &((char *)sf)[end],
totsize - end);
}
INT_MOD(sf->hdr.count, ARCH_CONVERT, -1);
@@ -222,7 +222,7 @@ xfs_attr_shortform_lookup(xfs_da_args_t *args)
sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
if (sfe->namelen != args->namelen)
continue;
- if (bcmp(args->name, sfe->nameval, args->namelen) != 0)
+ if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
continue;
if (((args->flags & ATTR_ROOT) != 0) !=
((sfe->flags & XFS_ATTR_ROOT) != 0))
@@ -250,7 +250,7 @@ xfs_attr_shortform_getvalue(xfs_da_args_t *args)
sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
if (sfe->namelen != args->namelen)
continue;
- if (bcmp(args->name, sfe->nameval, args->namelen) != 0)
+ if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
continue;
if (((args->flags & ATTR_ROOT) != 0) !=
((sfe->flags & XFS_ATTR_ROOT) != 0))
@@ -264,7 +264,7 @@ xfs_attr_shortform_getvalue(xfs_da_args_t *args)
return(XFS_ERROR(ERANGE));
}
args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);
- bcopy(&sfe->nameval[args->namelen], args->value,
+ memcpy(args->value, &sfe->nameval[args->namelen],
args->valuelen);
return(XFS_ERROR(EEXIST));
}
@@ -293,7 +293,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
size = INT_GET(sf->hdr.totsize, ARCH_CONVERT);
tmpbuffer = kmem_alloc(size, KM_SLEEP);
ASSERT(tmpbuffer != NULL);
- bcopy(ifp->if_u1.if_data, tmpbuffer, size);
+ memcpy(tmpbuffer, ifp->if_u1.if_data, size);
sf = (xfs_attr_shortform_t *)tmpbuffer;
xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
@@ -307,7 +307,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
if (error == EIO)
goto out;
xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */
- bcopy(tmpbuffer, ifp->if_u1.if_data, size); /* it back */
+ memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */
goto out;
}
@@ -319,11 +319,11 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
if (error)
goto out;
xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */
- bcopy(tmpbuffer, ifp->if_u1.if_data, size); /* it back */
+ memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */
goto out;
}
- bzero((char *)&nargs, sizeof(nargs));
+ memset((char *)&nargs, 0, sizeof(nargs));
nargs.dp = dp;
nargs.firstblock = args->firstblock;
nargs.flist = args->flist;
@@ -590,11 +590,11 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args)
ASSERT(tmpbuffer != NULL);
ASSERT(bp != NULL);
- bcopy(bp->data, tmpbuffer, XFS_LBSIZE(dp->i_mount));
+ memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount));
leaf = (xfs_attr_leafblock_t *)tmpbuffer;
ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
== XFS_ATTR_LEAF_MAGIC);
- bzero(bp->data, XFS_LBSIZE(dp->i_mount));
+ memset(bp->data, 0, XFS_LBSIZE(dp->i_mount));
/*
* Clean out the prior contents of the attribute list.
@@ -609,7 +609,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args)
/*
* Copy the attributes
*/
- bzero((char *)&nargs, sizeof(nargs));
+ memset((char *)&nargs, 0, sizeof(nargs));
nargs.dp = dp;
nargs.firstblock = args->firstblock;
nargs.flist = args->flist;
@@ -669,7 +669,7 @@ xfs_attr_leaf_to_node(xfs_da_args_t *args)
if (error)
goto out;
ASSERT(bp2 != NULL);
- bcopy(bp1->data, bp2->data, XFS_LBSIZE(dp->i_mount));
+ memcpy(bp2->data, bp1->data, XFS_LBSIZE(dp->i_mount));
xfs_da_buf_done(bp1);
bp1 = NULL;
xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1);
@@ -725,7 +725,7 @@ xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp)
return(error);
ASSERT(bp != NULL);
leaf = bp->data;
- bzero((char *)leaf, XFS_LBSIZE(dp->i_mount));
+ memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount));
hdr = &leaf->hdr;
INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_ATTR_LEAF_MAGIC);
INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount));
@@ -900,7 +900,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
if (args->index < INT_GET(hdr->count, ARCH_CONVERT)) {
tmp = INT_GET(hdr->count, ARCH_CONVERT) - args->index;
tmp *= sizeof(xfs_attr_leaf_entry_t);
- ovbcopy((char *)entry, (char *)(entry+1), tmp);
+ memmove((char *)(entry+1), (char *)entry, tmp);
xfs_da_log_buf(args->trans, bp,
XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry)));
}
@@ -955,13 +955,13 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index);
name_loc->namelen = args->namelen;
INT_SET(name_loc->valuelen, ARCH_CONVERT, args->valuelen);
- bcopy(args->name, (char *)name_loc->nameval, args->namelen);
- bcopy(args->value, (char *)&name_loc->nameval[args->namelen],
+ memcpy((char *)name_loc->nameval, args->name, args->namelen);
+ memcpy((char *)&name_loc->nameval[args->namelen], args->value,
INT_GET(name_loc->valuelen, ARCH_CONVERT));
} else {
name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index);
name_rmt->namelen = args->namelen;
- bcopy(args->name, (char *)name_rmt->name, args->namelen);
+ memcpy((char *)name_rmt->name, args->name, args->namelen);
entry->flags |= XFS_ATTR_INCOMPLETE;
/* just in case */
INT_ZERO(name_rmt->valuelen, ARCH_CONVERT);
@@ -1017,8 +1017,8 @@ xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp)
mp = trans->t_mountp;
tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP);
ASSERT(tmpbuffer != NULL);
- bcopy(bp->data, tmpbuffer, XFS_LBSIZE(mp));
- bzero(bp->data, XFS_LBSIZE(mp));
+ memcpy(tmpbuffer, bp->data, XFS_LBSIZE(mp));
+ memset(bp->data, 0, XFS_LBSIZE(mp));
/*
* Copy basic information
@@ -1390,7 +1390,7 @@ xfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action)
* path point to the block we want to drop (this one).
*/
forward = (!INT_ISZERO(info->forw, ARCH_CONVERT));
- bcopy(&state->path, &state->altpath, sizeof(state->path));
+ memcpy(&state->altpath, &state->path, sizeof(state->path));
error = xfs_da_path_shift(state, &state->altpath, forward,
0, &retval);
if (error)
@@ -1450,7 +1450,7 @@ xfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action)
* Make altpath point to the block we want to keep (the lower
* numbered block) and path point to the block we want to drop.
*/
- bcopy(&state->path, &state->altpath, sizeof(state->path));
+ memcpy(&state->altpath, &state->path, sizeof(state->path));
if (blkno < blk->blkno) {
error = xfs_da_path_shift(state, &state->altpath, forward,
0, &retval);
@@ -1585,7 +1585,7 @@ xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args)
/*
* Compress the remaining entries and zero out the removed stuff.
*/
- bzero(XFS_ATTR_LEAF_NAME(leaf, args->index), entsize);
+ memset(XFS_ATTR_LEAF_NAME(leaf, args->index), 0, entsize);
INT_MOD(hdr->usedbytes, ARCH_CONVERT, -entsize);
xfs_da_log_buf(args->trans, bp,
XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index),
@@ -1593,12 +1593,12 @@ xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args)
tmp = (INT_GET(hdr->count, ARCH_CONVERT) - args->index)
* sizeof(xfs_attr_leaf_entry_t);
- ovbcopy((char *)(entry+1), (char *)entry, tmp);
+ memmove((char *)entry, (char *)(entry+1), tmp);
INT_MOD(hdr->count, ARCH_CONVERT, -1);
xfs_da_log_buf(args->trans, bp,
XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry)));
entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)];
- bzero((char *)entry, sizeof(xfs_attr_leaf_entry_t));
+ memset((char *)entry, 0, sizeof(xfs_attr_leaf_entry_t));
/*
* If we removed the first entry, re-find the first used byte
@@ -1701,7 +1701,7 @@ xfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
*/
tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP);
ASSERT(tmpbuffer != NULL);
- bzero(tmpbuffer, state->blocksize);
+ memset(tmpbuffer, 0, state->blocksize);
tmp_leaf = (xfs_attr_leafblock_t *)tmpbuffer;
tmp_hdr = &tmp_leaf->hdr;
tmp_hdr->info = save_hdr->info; /* struct copy */
@@ -1729,7 +1729,7 @@ xfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
(int)INT_GET(drop_hdr->count, ARCH_CONVERT),
mp);
}
- bcopy((char *)tmp_leaf, (char *)save_leaf, state->blocksize);
+ memcpy((char *)save_leaf, (char *)tmp_leaf, state->blocksize);
kmem_free(tmpbuffer, state->blocksize);
}
@@ -1840,7 +1840,7 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, probe);
if (name_loc->namelen != args->namelen)
continue;
- if (bcmp(args->name, (char *)name_loc->nameval,
+ if (memcmp(args->name, (char *)name_loc->nameval,
args->namelen) != 0)
continue;
if (((args->flags & ATTR_ROOT) != 0) !=
@@ -1852,7 +1852,7 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, probe);
if (name_rmt->namelen != args->namelen)
continue;
- if (bcmp(args->name, (char *)name_rmt->name,
+ if (memcmp(args->name, (char *)name_rmt->name,
args->namelen) != 0)
continue;
if (((args->flags & ATTR_ROOT) != 0) !=
@@ -1895,7 +1895,7 @@ xfs_attr_leaf_getvalue(xfs_dabuf_t *bp, xfs_da_args_t *args)
if (entry->flags & XFS_ATTR_LOCAL) {
name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index);
ASSERT(name_loc->namelen == args->namelen);
- ASSERT(bcmp(args->name, name_loc->nameval, args->namelen) == 0);
+ ASSERT(memcmp(args->name, name_loc->nameval, args->namelen) == 0);
valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT);
if (args->flags & ATTR_KERNOVAL) {
args->valuelen = valuelen;
@@ -1906,11 +1906,11 @@ xfs_attr_leaf_getvalue(xfs_dabuf_t *bp, xfs_da_args_t *args)
return(XFS_ERROR(ERANGE));
}
args->valuelen = valuelen;
- bcopy(&name_loc->nameval[args->namelen], args->value, valuelen);
+ memcpy(args->value, &name_loc->nameval[args->namelen], valuelen);
} else {
name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index);
ASSERT(name_rmt->namelen == args->namelen);
- ASSERT(bcmp(args->name, name_rmt->name, args->namelen) == 0);
+ ASSERT(memcmp(args->name, name_rmt->name, args->namelen) == 0);
valuelen = INT_GET(name_rmt->valuelen, ARCH_CONVERT);
args->rmtblkno = INT_GET(name_rmt->valueblk, ARCH_CONVERT);
args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount, valuelen);
@@ -1983,7 +1983,7 @@ xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s,
tmp *= sizeof(xfs_attr_leaf_entry_t);
entry_s = &leaf_d->entries[start_d];
entry_d = &leaf_d->entries[start_d + count];
- ovbcopy((char *)entry_s, (char *)entry_d, tmp);
+ memmove((char *)entry_d, (char *)entry_s, tmp);
}
/*
@@ -2004,7 +2004,7 @@ xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s,
* off for 6.2, should be revisited later.
*/
if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */
- bzero(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp);
+ memset(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), 0, tmp);
INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp);
INT_MOD(hdr_s->count, ARCH_CONVERT, -1);
entry_d--; /* to compensate for ++ in loop hdr */
@@ -2021,11 +2021,11 @@ xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s,
entry_d->flags = entry_s->flags;
ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp
<= XFS_LBSIZE(mp));
- ovbcopy(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i),
- XFS_ATTR_LEAF_NAME(leaf_d, desti), tmp);
+ memmove(XFS_ATTR_LEAF_NAME(leaf_d, desti),
+ XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp);
ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp
<= XFS_LBSIZE(mp));
- bzero(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp);
+ memset(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), 0, tmp);
INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp);
INT_MOD(hdr_d->usedbytes, ARCH_CONVERT, tmp);
INT_MOD(hdr_s->count, ARCH_CONVERT, -1);
@@ -2047,7 +2047,7 @@ xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s,
entry_s = &leaf_s->entries[start_s];
ASSERT(((char *)entry_s + tmp) <=
((char *)leaf_s + XFS_LBSIZE(mp)));
- bzero((char *)entry_s, tmp);
+ memset((char *)entry_s, 0, tmp);
} else {
/*
* Move the remaining entries down to fill the hole,
@@ -2057,14 +2057,14 @@ xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s,
tmp *= sizeof(xfs_attr_leaf_entry_t);
entry_s = &leaf_s->entries[start_s + count];
entry_d = &leaf_s->entries[start_s];
- ovbcopy((char *)entry_s, (char *)entry_d, tmp);
+ memmove((char *)entry_d, (char *)entry_s, tmp);
tmp = count * sizeof(xfs_attr_leaf_entry_t);
entry_s = &leaf_s->entries[INT_GET(hdr_s->count,
ARCH_CONVERT)];
ASSERT(((char *)entry_s + tmp) <=
((char *)leaf_s + XFS_LBSIZE(mp)));
- bzero((char *)entry_s, tmp);
+ memset((char *)entry_s, 0, tmp);
}
/*
@@ -2345,7 +2345,7 @@ xfs_attr_put_listent(xfs_attr_list_context_t *context,
aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);
aep->a_valuelen = valuelen;
- bcopy(name, aep->a_name, namelen);
+ memcpy(aep->a_name, name, namelen);
aep->a_name[ namelen ] = 0;
context->alist->al_offset[ context->count++ ] = context->firstu;
context->alist->al_count = context->count;
@@ -2404,7 +2404,7 @@ xfs_attr_leaf_clearflag(xfs_da_args_t *args)
}
ASSERT(INT_GET(entry->hashval, ARCH_CONVERT) == args->hashval);
ASSERT(namelen == args->namelen);
- ASSERT(bcmp(name, args->name, namelen) == 0);
+ ASSERT(memcmp(name, args->name, namelen) == 0);
#endif /* DEBUG */
entry->flags &= ~XFS_ATTR_INCOMPLETE;
@@ -2559,7 +2559,7 @@ xfs_attr_leaf_flipflags(xfs_da_args_t *args)
}
ASSERT(INT_GET(entry1->hashval, ARCH_CONVERT) == INT_GET(entry2->hashval, ARCH_CONVERT));
ASSERT(namelen1 == namelen2);
- ASSERT(bcmp(name1, name2, namelen1) == 0);
+ ASSERT(memcmp(name1, name2, namelen1) == 0);
#endif /* DEBUG */
ASSERT(entry1->flags & XFS_ATTR_INCOMPLETE);
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 6bf9632238e7..d89a4a83d611 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -489,7 +489,7 @@ xfs_bmap_add_attrfork_local(
return 0;
if ((ip->i_d.di_mode & IFMT) == IFDIR) {
mp = ip->i_mount;
- bzero(&dargs, sizeof(dargs));
+ memset(&dargs, 0, sizeof(dargs));
dargs.dp = ip;
dargs.firstblock = firstblock;
dargs.flist = flist;
@@ -3146,7 +3146,7 @@ xfs_bmap_delete_exlist(
ASSERT(ifp->if_flags & XFS_IFEXTENTS);
base = ifp->if_u1.if_extents;
nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - count;
- ovbcopy(&base[idx + count], &base[idx],
+ memmove(&base[idx], &base[idx + count],
(nextents - idx) * sizeof(*base));
xfs_iext_realloc(ip, -count, whichfork);
}
@@ -3174,7 +3174,7 @@ xfs_bmap_extents_to_btree(
xfs_btree_cur_t *cur; /* bmap btree cursor */
xfs_bmbt_rec_t *ep; /* extent list pointer */
int error; /* error return value */
- xfs_extnum_t i; /* extent list index */
+ xfs_extnum_t i, cnt; /* extent list index */
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_bmbt_key_t *kp; /* root block key pointer */
xfs_mount_t *mp; /* mount structure */
@@ -3256,24 +3256,25 @@ xfs_bmap_extents_to_btree(
ablock = XFS_BUF_TO_BMBT_BLOCK(abp);
INT_SET(ablock->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC);
INT_ZERO(ablock->bb_level, ARCH_CONVERT);
- INT_ZERO(ablock->bb_numrecs, ARCH_CONVERT);
INT_SET(ablock->bb_leftsib, ARCH_CONVERT, NULLDFSBNO);
INT_SET(ablock->bb_rightsib, ARCH_CONVERT, NULLDFSBNO);
arp = XFS_BMAP_REC_IADDR(ablock, 1, cur);
nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
- for (ep = ifp->if_u1.if_extents, i = 0; i < nextents; i++, ep++) {
+ for (ep = ifp->if_u1.if_extents, cnt = i = 0; i < nextents; i++, ep++) {
if (!ISNULLSTARTBLOCK(xfs_bmbt_get_startblock(ep))) {
- *arp++ = *ep;
- INT_MOD(ablock->bb_numrecs, ARCH_CONVERT, +1);
+ arp->l0 = INT_GET(ep->l0, ARCH_CONVERT);
+ arp->l1 = INT_GET(ep->l1, ARCH_CONVERT);
+ arp++; cnt++;
}
}
+ INT_SET(ablock->bb_numrecs, ARCH_CONVERT, cnt);
ASSERT(INT_GET(ablock->bb_numrecs, ARCH_CONVERT) == XFS_IFORK_NEXTENTS(ip, whichfork));
/*
* Fill in the root key and pointer.
*/
kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
arp = XFS_BMAP_REC_IADDR(ablock, 1, cur);
- INT_SET(kp->br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(arp));
+ INT_SET(kp->br_startoff, ARCH_CONVERT, xfs_bmbt_disk_get_startoff(arp));
pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
INT_SET(*pp, ARCH_CONVERT, args.fsbno);
/*
@@ -3310,7 +3311,7 @@ xfs_bmap_insert_exlist(
xfs_iext_realloc(ip, count, whichfork);
base = ifp->if_u1.if_extents;
nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
- ovbcopy(&base[idx], &base[idx + count],
+ memmove(&base[idx + count], &base[idx],
(nextents - (idx + count)) * sizeof(*base));
for (to = idx; to < idx + count; to++, new++)
xfs_bmbt_set_all(&base[to], new);
@@ -3380,7 +3381,7 @@ xfs_bmap_local_to_extents(
ASSERT(args.len == 1);
*firstblock = args.fsbno;
bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
- bcopy(ifp->if_u1.if_data, (char *)XFS_BUF_PTR(bp),
+ memcpy((char *)XFS_BUF_PTR(bp), ifp->if_u1.if_data,
ifp->if_bytes);
xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
@@ -3556,7 +3557,7 @@ xfs_bmap_trace_addentry(
if (cnt == 1) {
ASSERT(r2 == NULL);
r2 = &tr2;
- bzero(&tr2, sizeof(tr2));
+ memset(&tr2, 0, sizeof(tr2));
} else
ASSERT(r2 != NULL);
ktrace_enter(xfs_bmap_trace_buf,
@@ -4332,7 +4333,7 @@ xfs_bmap_read_extents(
#ifdef XFS_BMAP_TRACE
static char fname[] = "xfs_bmap_read_extents";
#endif
- xfs_extnum_t i; /* index into the extents list */
+ xfs_extnum_t i, j; /* index into the extents list */
xfs_ifork_t *ifp; /* fork structure */
int level; /* btree level, for checking */
xfs_mount_t *mp; /* file system mount structure */
@@ -4373,28 +4374,9 @@ xfs_bmap_read_extents(
break;
pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block,
1, mp->m_bmap_dmxr[1]);
-#ifndef __KERNEL__
XFS_WANT_CORRUPTED_GOTO(
XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)),
error0);
-#else /* additional, temporary, debugging code */
- if (!(XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)))) {
- cmn_err(CE_NOTE,
- "xfs_bmap_read_extents: FSB Sanity Check:");
- if (!(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount))
- cmn_err(CE_NOTE,
- "bad AG count %d < agcount %d",
- XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)),
- mp->m_sb.sb_agcount);
- if (!(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks))
- cmn_err(CE_NOTE,
- "bad AG BNO %d < %d",
- XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)),
- mp->m_sb.sb_agblocks);
- error = XFS_ERROR(EFSCORRUPTED);
- goto error0;
- }
-#endif
bno = INT_GET(*pp, ARCH_CONVERT);
xfs_trans_brelse(tp, bp);
}
@@ -4408,7 +4390,7 @@ xfs_bmap_read_extents(
* Loop over all leaf nodes. Copy information to the extent list.
*/
for (;;) {
- xfs_bmbt_rec_t *frp;
+ xfs_bmbt_rec_t *frp, *temp;
xfs_fsblock_t nextbno;
xfs_extnum_t num_recs;
@@ -4422,35 +4404,9 @@ xfs_bmap_read_extents(
(unsigned long long) ip->i_ino);
goto error0;
}
-#ifndef __KERNEL__
XFS_WANT_CORRUPTED_GOTO(
XFS_BMAP_SANITY_CHECK(mp, block, 0),
error0);
-#else /* additional, temporary, debugging code */
- if (!(XFS_BMAP_SANITY_CHECK(mp, block, 0))) {
- cmn_err(CE_NOTE,
- "xfs_bmap_read_extents: BMAP Sanity Check:");
- if (!(INT_GET(block->bb_magic, ARCH_CONVERT) == XFS_BMAP_MAGIC))
- cmn_err(CE_NOTE,
- "bb_magic 0x%x",
- INT_GET(block->bb_magic, ARCH_CONVERT));
- if (!(INT_GET(block->bb_level, ARCH_CONVERT) == level))
- cmn_err(CE_NOTE,
- "bb_level %d",
- INT_GET(block->bb_level, ARCH_CONVERT));
- if (!(INT_GET(block->bb_numrecs, ARCH_CONVERT) > 0))
- cmn_err(CE_NOTE,
- "bb_numrecs %d",
- INT_GET(block->bb_numrecs, ARCH_CONVERT));
- if (!(INT_GET(block->bb_numrecs, ARCH_CONVERT) <= (mp)->m_bmap_dmxr[(level) != 0]))
- cmn_err(CE_NOTE,
- "bb_numrecs %d < m_bmap_dmxr[] %d",
- INT_GET(block->bb_numrecs, ARCH_CONVERT),
- (mp)->m_bmap_dmxr[(level) != 0]);
- error = XFS_ERROR(EFSCORRUPTED);
- goto error0;
- }
-#endif
/*
* Read-ahead the next leaf block, if any.
*/
@@ -4462,18 +4418,21 @@ xfs_bmap_read_extents(
*/
frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt,
block, 1, mp->m_bmap_dmxr[0]);
- bcopy(frp, trp, num_recs * sizeof(*frp));
+ temp = trp;
+ for (j = 0; j < num_recs; j++, frp++, trp++) {
+ trp->l0 = INT_GET(frp->l0, ARCH_CONVERT);
+ trp->l1 = INT_GET(frp->l1, ARCH_CONVERT);
+ }
if (exntf == XFS_EXTFMT_NOSTATE) {
/*
* Check all attribute bmap btree records and
* any "older" data bmap btree records for a
* set bit in the "extent flag" position.
*/
- if (xfs_check_nostate_extents(trp, num_recs)) {
+ if (xfs_check_nostate_extents(temp, num_recs)) {
goto error0;
}
}
- trp += num_recs;
i += num_recs;
xfs_trans_brelse(tp, bp);
bno = nextbno;
@@ -4650,11 +4609,6 @@ xfs_bmapi(
if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) {
-#ifdef __KERNEL__ /* additional, temporary, debugging code */
- cmn_err(CE_NOTE,
- "EFSCORRUPTED returned from file %s line %d",
- __FILE__, __LINE__);
-#endif
return XFS_ERROR(EFSCORRUPTED);
}
mp = ip->i_mount;
@@ -5150,11 +5104,6 @@ xfs_bmapi_single(
ifp = XFS_IFORK_PTR(ip, whichfork);
if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) {
-#ifdef __KERNEL__ /* additional, temporary, debugging code */
- cmn_err(CE_NOTE,
- "EFSCORRUPTED returned from file %s line %d",
- __FILE__, __LINE__);
-#endif
return XFS_ERROR(EFSCORRUPTED);
}
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
@@ -5228,11 +5177,6 @@ xfs_bunmapi(
ifp = XFS_IFORK_PTR(ip, whichfork);
if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) {
-#ifdef __KERNEL__ /* additional, temporary, debugging code */
- cmn_err(CE_NOTE,
- "EFSCORRUPTED returned from file %s line %d",
- __FILE__, __LINE__);
-#endif
return XFS_ERROR(EFSCORRUPTED);
}
mp = ip->i_mount;
@@ -6317,7 +6261,7 @@ xfs_bmap_count_leaves(
int b;
for ( b = 1; b <= numrecs; b++, frp++)
- *count += xfs_bmbt_get_blockcount(frp);
+ *count += xfs_bmbt_disk_get_blockcount(frp);
return 0;
}
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c
index 5b384f4f9cba..07d513d24f74 100644
--- a/fs/xfs/xfs_bmap_btree.c
+++ b/fs/xfs/xfs_bmap_btree.c
@@ -207,7 +207,7 @@ xfs_bmbt_trace_argifr(
xfs_bmbt_irec_t s;
d = (xfs_dfsbno_t)f;
- xfs_bmbt_get_all(r, &s);
+ xfs_bmbt_disk_get_all(r, &s);
o = (xfs_dfiloff_t)s.br_startoff;
b = (xfs_dfsbno_t)s.br_startblock;
c = s.br_blockcount;
@@ -381,9 +381,9 @@ xfs_bmbt_delrec(
}
#endif
if (ptr < numrecs) {
- ovbcopy(&kp[ptr], &kp[ptr - 1],
+ memmove(&kp[ptr - 1], &kp[ptr],
(numrecs - ptr) * sizeof(*kp));
- ovbcopy(&pp[ptr], &pp[ptr - 1], /* INT_: direct copy */
+ memmove(&pp[ptr - 1], &pp[ptr], /* INT_: direct copy */
(numrecs - ptr) * sizeof(*pp));
xfs_bmbt_log_ptrs(cur, bp, ptr, numrecs - 1);
xfs_bmbt_log_keys(cur, bp, ptr, numrecs - 1);
@@ -391,12 +391,12 @@ xfs_bmbt_delrec(
} else {
rp = XFS_BMAP_REC_IADDR(block, 1, cur);
if (ptr < numrecs) {
- ovbcopy(&rp[ptr], &rp[ptr - 1],
+ memmove(&rp[ptr - 1], &rp[ptr],
(numrecs - ptr) * sizeof(*rp));
xfs_bmbt_log_recs(cur, bp, ptr, numrecs - 1);
}
if (ptr == 1) {
- INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rp));
+ INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_disk_get_startoff(rp));
kp = &key;
}
}
@@ -619,14 +619,14 @@ xfs_bmbt_delrec(
}
}
#endif
- bcopy(rkp, lkp, numrrecs * sizeof(*lkp));
- bcopy(rpp, lpp, numrrecs * sizeof(*lpp));
+ memcpy(lkp, rkp, numrrecs * sizeof(*lkp));
+ memcpy(lpp, rpp, numrrecs * sizeof(*lpp));
xfs_bmbt_log_keys(cur, lbp, numlrecs + 1, numlrecs + numrrecs);
xfs_bmbt_log_ptrs(cur, lbp, numlrecs + 1, numlrecs + numrrecs);
} else {
lrp = XFS_BMAP_REC_IADDR(left, numlrecs + 1, cur);
rrp = XFS_BMAP_REC_IADDR(right, 1, cur);
- bcopy(rrp, lrp, numrrecs * sizeof(*lrp));
+ memcpy(lrp, rrp, numrrecs * sizeof(*lrp));
xfs_bmbt_log_recs(cur, lbp, numlrecs + 1, numlrecs + numrrecs);
}
INT_MOD(left->bb_numrecs, ARCH_CONVERT, numrrecs);
@@ -711,10 +711,10 @@ xfs_bmbt_get_rec(
return 0;
}
rp = XFS_BMAP_REC_IADDR(block, ptr, cur);
- *off = xfs_bmbt_get_startoff(rp);
- *bno = xfs_bmbt_get_startblock(rp);
- *len = xfs_bmbt_get_blockcount(rp);
- *state = xfs_bmbt_get_state(rp);
+ *off = xfs_bmbt_disk_get_startoff(rp);
+ *bno = xfs_bmbt_disk_get_startblock(rp);
+ *len = xfs_bmbt_disk_get_blockcount(rp);
+ *state = xfs_bmbt_disk_get_state(rp);
*stat = 1;
return 0;
}
@@ -757,7 +757,8 @@ xfs_bmbt_insrec(
XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
XFS_BMBT_TRACE_ARGIFR(cur, level, *bnop, recp);
ncur = (xfs_btree_cur_t *)0;
- INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(recp));
+ INT_SET(key.br_startoff, ARCH_CONVERT,
+ xfs_bmbt_disk_get_startoff(recp));
optr = ptr = cur->bc_ptrs[level];
if (ptr == 0) {
XFS_BMBT_TRACE_CURSOR(cur, EXIT);
@@ -835,7 +836,7 @@ xfs_bmbt_insrec(
}
#endif
ptr = cur->bc_ptrs[level];
- xfs_bmbt_set_allf(&nrec,
+ xfs_bmbt_disk_set_allf(&nrec,
nkey.br_startoff, 0, 0,
XFS_EXT_NORM);
} else {
@@ -861,9 +862,9 @@ xfs_bmbt_insrec(
}
}
#endif
- ovbcopy(&kp[ptr - 1], &kp[ptr],
+ memmove(&kp[ptr], &kp[ptr - 1],
(numrecs - ptr + 1) * sizeof(*kp));
- ovbcopy(&pp[ptr - 1], &pp[ptr], /* INT_: direct copy */
+ memmove(&pp[ptr], &pp[ptr - 1], /* INT_: direct copy */
(numrecs - ptr + 1) * sizeof(*pp));
#ifdef DEBUG
if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)*bnop,
@@ -880,7 +881,7 @@ xfs_bmbt_insrec(
xfs_bmbt_log_ptrs(cur, bp, ptr, numrecs);
} else {
rp = XFS_BMAP_REC_IADDR(block, 1, cur);
- ovbcopy(&rp[ptr - 1], &rp[ptr],
+ memmove(&rp[ptr], &rp[ptr - 1],
(numrecs - ptr + 1) * sizeof(*rp));
rp[ptr - 1] = *recp;
numrecs++;
@@ -980,7 +981,7 @@ xfs_bmbt_killroot(
ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) == INT_GET(cblock->bb_numrecs, ARCH_CONVERT));
kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur);
- bcopy(ckp, kp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*kp));
+ memcpy(kp, ckp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*kp));
pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur);
#ifdef DEBUG
@@ -991,7 +992,7 @@ xfs_bmbt_killroot(
}
}
#endif
- bcopy(cpp, pp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*pp));
+ memcpy(pp, cpp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*pp));
xfs_bmap_add_free(XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(cbp)), 1,
cur->bc_private.b.flist, cur->bc_mp);
if (!async)
@@ -1175,7 +1176,7 @@ xfs_bmbt_lookup(
startoff = INT_GET(kkp->br_startoff, ARCH_CONVERT);
} else {
krp = krbase + keyno - 1;
- startoff = xfs_bmbt_get_startoff(krp);
+ startoff = xfs_bmbt_disk_get_startoff(krp);
}
diff = (xfs_sfiloff_t)
(startoff - rp->br_startoff);
@@ -1349,14 +1350,15 @@ xfs_bmbt_lshift(
}
}
#endif
- ovbcopy(rkp + 1, rkp, rrecs * sizeof(*rkp));
- ovbcopy(rpp + 1, rpp, rrecs * sizeof(*rpp));
+ memmove(rkp, rkp + 1, rrecs * sizeof(*rkp));
+ memmove(rpp, rpp + 1, rrecs * sizeof(*rpp));
xfs_bmbt_log_keys(cur, rbp, 1, rrecs);
xfs_bmbt_log_ptrs(cur, rbp, 1, rrecs);
} else {
- ovbcopy(rrp + 1, rrp, rrecs * sizeof(*rrp));
+ memmove(rrp, rrp + 1, rrecs * sizeof(*rrp));
xfs_bmbt_log_recs(cur, rbp, 1, rrecs);
- INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rrp));
+ INT_SET(key.br_startoff, ARCH_CONVERT,
+ xfs_bmbt_disk_get_startoff(rrp));
rkp = &key;
}
if ((error = xfs_bmbt_updkey(cur, rkp, level + 1))) {
@@ -1452,8 +1454,8 @@ xfs_bmbt_rshift(
}
}
#endif
- ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
- ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+ memmove(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+ memmove(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
#ifdef DEBUG
if ((error = xfs_btree_check_lptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
@@ -1467,10 +1469,11 @@ xfs_bmbt_rshift(
} else {
lrp = XFS_BMAP_REC_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur);
rrp = XFS_BMAP_REC_IADDR(right, 1, cur);
- ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+ memmove(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
*rrp = *lrp;
xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1);
- INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rrp));
+ INT_SET(key.br_startoff, ARCH_CONVERT,
+ xfs_bmbt_disk_get_startoff(rrp));
rkp = &key;
}
INT_MOD(left->bb_numrecs, ARCH_CONVERT, -1);
@@ -1629,17 +1632,17 @@ xfs_bmbt_split(
}
}
#endif
- bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
- bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+ memcpy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+ memcpy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
xfs_bmbt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
xfs_bmbt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
keyp->br_startoff = INT_GET(rkp->br_startoff, ARCH_CONVERT);
} else {
lrp = XFS_BMAP_REC_IADDR(left, i, cur);
rrp = XFS_BMAP_REC_IADDR(right, 1, cur);
- bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+ memcpy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
- keyp->br_startoff = xfs_bmbt_get_startoff(rrp);
+ keyp->br_startoff = xfs_bmbt_disk_get_startoff(rrp);
}
INT_MOD(left->bb_numrecs, ARCH_CONVERT, -(INT_GET(right->bb_numrecs, ARCH_CONVERT)));
right->bb_rightsib = left->bb_rightsib; /* INT_: direct copy */
@@ -1748,8 +1751,8 @@ xfs_bmdr_to_bmbt(
fpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr);
tpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen);
dmxr = INT_GET(dblock->bb_numrecs, ARCH_CONVERT);
- bcopy(fkp, tkp, sizeof(*fkp) * dmxr);
- bcopy(fpp, tpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */
+ memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
+ memcpy(tpp, fpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */
}
/*
@@ -1874,17 +1877,16 @@ xfs_bmbt_delete(
* This code must be in sync with the routines xfs_bmbt_get_startoff,
* xfs_bmbt_get_startblock, xfs_bmbt_get_blockcount and xfs_bmbt_get_state.
*/
-void
-xfs_bmbt_get_all(
- xfs_bmbt_rec_t *r,
- xfs_bmbt_irec_t *s)
+
+static __inline__ void
+__xfs_bmbt_get_all(
+ __uint64_t l0,
+ __uint64_t l1,
+ xfs_bmbt_irec_t *s)
{
int ext_flag;
xfs_exntst_t st;
- __uint64_t l0, l1;
- l0 = INT_GET(r->l0, ARCH_CONVERT);
- l1 = INT_GET(r->l1, ARCH_CONVERT);
ext_flag = (int)(l0 >> (64 - BMBT_EXNTFLAG_BITLEN));
s->br_startoff = ((xfs_fileoff_t)l0 &
XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9;
@@ -1915,6 +1917,14 @@ xfs_bmbt_get_all(
s->br_state = st;
}
+void
+xfs_bmbt_get_all(
+ xfs_bmbt_rec_t *r,
+ xfs_bmbt_irec_t *s)
+{
+ __xfs_bmbt_get_all(r->l0, r->l1, s);
+}
+
/*
* Get the block pointer for the given level of the cursor.
* Fill in the buffer pointer, if applicable.
@@ -1941,23 +1951,94 @@ xfs_bmbt_get_block(
}
/*
- * Extract the blockcount field from a bmap extent record.
+ * Extract the blockcount field from an in memory bmap extent record.
*/
xfs_filblks_t
xfs_bmbt_get_blockcount(
xfs_bmbt_rec_t *r)
{
- return (xfs_filblks_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK64LO(21));
+ return (xfs_filblks_t)(r->l1 & XFS_MASK64LO(21));
}
/*
- * Extract the startblock field from a bmap extent record.
+ * Extract the startblock field from an in memory bmap extent record.
*/
xfs_fsblock_t
xfs_bmbt_get_startblock(
xfs_bmbt_rec_t *r)
{
#if XFS_BIG_FILESYSTEMS
+ return (((xfs_fsblock_t)r->l0 & XFS_MASK64LO(9)) << 43) |
+ (((xfs_fsblock_t)r->l1) >> 21);
+#else
+#ifdef DEBUG
+ xfs_dfsbno_t b;
+
+ b = (((xfs_dfsbno_t)r->l0 & XFS_MASK64LO(9)) << 43) |
+ (((xfs_dfsbno_t)r->l1) >> 21);
+ ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b));
+ return (xfs_fsblock_t)b;
+#else /* !DEBUG */
+ return (xfs_fsblock_t)(((xfs_dfsbno_t)r->l1) >> 21);
+#endif /* DEBUG */
+#endif /* XFS_BIG_FILESYSTEMS */
+}
+
+/*
+ * Extract the startoff field from an in memory bmap extent record.
+ */
+xfs_fileoff_t
+xfs_bmbt_get_startoff(
+ xfs_bmbt_rec_t *r)
+{
+ return ((xfs_fileoff_t)r->l0 &
+ XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9;
+}
+
+xfs_exntst_t
+xfs_bmbt_get_state(
+ xfs_bmbt_rec_t *r)
+{
+ int ext_flag;
+
+ ext_flag = (int)((r->l0) >> (64 - BMBT_EXNTFLAG_BITLEN));
+ return xfs_extent_state(xfs_bmbt_get_blockcount(r),
+ ext_flag);
+}
+
+#if ARCH_CONVERT != ARCH_NOCONVERT
+/* Endian flipping versions of the bmbt extraction functions */
+void
+xfs_bmbt_disk_get_all(
+ xfs_bmbt_rec_t *r,
+ xfs_bmbt_irec_t *s)
+{
+ __uint64_t l0, l1;
+
+ l0 = INT_GET(r->l0, ARCH_CONVERT);
+ l1 = INT_GET(r->l1, ARCH_CONVERT);
+
+ __xfs_bmbt_get_all(l0, l1, s);
+}
+
+/*
+ * Extract the blockcount field from an on disk bmap extent record.
+ */
+xfs_filblks_t
+xfs_bmbt_disk_get_blockcount(
+ xfs_bmbt_rec_t *r)
+{
+ return (xfs_filblks_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK64LO(21));
+}
+
+/*
+ * Extract the startblock field from an on disk bmap extent record.
+ */
+xfs_fsblock_t
+xfs_bmbt_disk_get_startblock(
+ xfs_bmbt_rec_t *r)
+{
+#if XFS_BIG_FILESYSTEMS
return (((xfs_fsblock_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) |
(((xfs_fsblock_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21);
#else
@@ -1975,10 +2056,10 @@ xfs_bmbt_get_startblock(
}
/*
- * Extract the startoff field from a bmap extent record.
+ * Extract the startoff field from a disk format bmap extent record.
*/
xfs_fileoff_t
-xfs_bmbt_get_startoff(
+xfs_bmbt_disk_get_startoff(
xfs_bmbt_rec_t *r)
{
return ((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) &
@@ -1986,15 +2067,16 @@ xfs_bmbt_get_startoff(
}
xfs_exntst_t
-xfs_bmbt_get_state(
+xfs_bmbt_disk_get_state(
xfs_bmbt_rec_t *r)
{
int ext_flag;
ext_flag = (int)((INT_GET(r->l0, ARCH_CONVERT)) >> (64 - BMBT_EXNTFLAG_BITLEN));
- return xfs_extent_state(xfs_bmbt_get_blockcount(r),
+ return xfs_extent_state(xfs_bmbt_disk_get_blockcount(r),
ext_flag);
}
+#endif
/*
@@ -2103,7 +2185,7 @@ xfs_bmbt_insert(
XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
level = 0;
nbno = NULLFSBLOCK;
- xfs_bmbt_set_all(&nrec, &cur->bc_rec.b);
+ xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b);
ncur = (xfs_btree_cur_t *)0;
pcur = cur;
do {
@@ -2333,7 +2415,7 @@ xfs_bmbt_newroot(
cur->bc_ptrs[level + 1] = 1;
kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur);
- bcopy(kp, ckp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*kp));
+ memcpy(ckp, kp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*kp));
cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur);
#ifdef DEBUG
for (i = 0; i < INT_GET(cblock->bb_numrecs, ARCH_CONVERT); i++) {
@@ -2343,7 +2425,7 @@ xfs_bmbt_newroot(
}
}
#endif
- bcopy(pp, cpp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*pp));
+ memcpy(cpp, pp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*pp));
#ifdef DEBUG
if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)args.fsbno,
level))) {
@@ -2388,6 +2470,97 @@ xfs_bmbt_set_all(
ASSERT((s->br_startblock & XFS_MASK64HI(12)) == 0);
#endif /* XFS_BIG_FILESYSTEMS */
#if XFS_BIG_FILESYSTEMS
+ r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
+ ((xfs_bmbt_rec_base_t)s->br_startoff << 9) |
+ ((xfs_bmbt_rec_base_t)s->br_startblock >> 43);
+ r->l1 = ((xfs_bmbt_rec_base_t)s->br_startblock << 21) |
+ ((xfs_bmbt_rec_base_t)s->br_blockcount &
+ (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
+#else /* !XFS_BIG_FILESYSTEMS */
+ if (ISNULLSTARTBLOCK(s->br_startblock)) {
+ r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
+ ((xfs_bmbt_rec_base_t)s->br_startoff << 9) |
+ (xfs_bmbt_rec_base_t)XFS_MASK64LO(9);
+ r->l1 = XFS_MASK64HI(11) |
+ ((xfs_bmbt_rec_base_t)s->br_startblock << 21) |
+ ((xfs_bmbt_rec_base_t)s->br_blockcount &
+ (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
+ } else {
+ r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
+ ((xfs_bmbt_rec_base_t)s->br_startoff << 9);
+ r->l1 = ((xfs_bmbt_rec_base_t)s->br_startblock << 21) |
+ ((xfs_bmbt_rec_base_t)s->br_blockcount &
+ (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
+ }
+#endif /* XFS_BIG_FILESYSTEMS */
+}
+
+/*
+ * Set all the fields in a bmap extent record from the arguments.
+ */
+void
+xfs_bmbt_set_allf(
+ xfs_bmbt_rec_t *r,
+ xfs_fileoff_t o,
+ xfs_fsblock_t b,
+ xfs_filblks_t c,
+ xfs_exntst_t v)
+{
+ int extent_flag;
+
+ ASSERT((v == XFS_EXT_NORM) || (v == XFS_EXT_UNWRITTEN));
+ extent_flag = (v == XFS_EXT_NORM) ? 0 : 1;
+ ASSERT((o & XFS_MASK64HI(64-BMBT_STARTOFF_BITLEN)) == 0);
+ ASSERT((c & XFS_MASK64HI(64-BMBT_BLOCKCOUNT_BITLEN)) == 0);
+#if XFS_BIG_FILESYSTEMS
+ ASSERT((b & XFS_MASK64HI(64-BMBT_STARTBLOCK_BITLEN)) == 0);
+#endif /* XFS_BIG_FILESYSTEMS */
+#if XFS_BIG_FILESYSTEMS
+ r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
+ ((xfs_bmbt_rec_base_t)o << 9) |
+ ((xfs_bmbt_rec_base_t)b >> 43));
+ r->l1 = ((xfs_bmbt_rec_base_t)b << 21) |
+ ((xfs_bmbt_rec_base_t)c &
+ (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)));
+#else /* !XFS_BIG_FILESYSTEMS */
+ if (ISNULLSTARTBLOCK(b)) {
+ r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
+ ((xfs_bmbt_rec_base_t)o << 9) |
+ (xfs_bmbt_rec_base_t)XFS_MASK64LO(9);
+ r->l1 = XFS_MASK64HI(11) |
+ ((xfs_bmbt_rec_base_t)b << 21) |
+ ((xfs_bmbt_rec_base_t)c &
+ (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
+ } else {
+ r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
+ ((xfs_bmbt_rec_base_t)o << 9);
+ r->l1 = ((xfs_bmbt_rec_base_t)b << 21) |
+ ((xfs_bmbt_rec_base_t)c &
+ (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
+ }
+#endif /* XFS_BIG_FILESYSTEMS */
+}
+
+#if ARCH_CONVERT != ARCH_NOCONVERT
+/*
+ * Set all the fields in a bmap extent record from the uncompressed form.
+ */
+void
+xfs_bmbt_disk_set_all(
+ xfs_bmbt_rec_t *r,
+ xfs_bmbt_irec_t *s)
+{
+ int extent_flag;
+
+ ASSERT((s->br_state == XFS_EXT_NORM) ||
+ (s->br_state == XFS_EXT_UNWRITTEN));
+ extent_flag = (s->br_state == XFS_EXT_NORM) ? 0 : 1;
+ ASSERT((s->br_startoff & XFS_MASK64HI(9)) == 0);
+ ASSERT((s->br_blockcount & XFS_MASK64HI(43)) == 0);
+#if XFS_BIG_FILESYSTEMS
+ ASSERT((s->br_startblock & XFS_MASK64HI(12)) == 0);
+#endif /* XFS_BIG_FILESYSTEMS */
+#if XFS_BIG_FILESYSTEMS
INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) |
((xfs_bmbt_rec_base_t)s->br_startoff << 9) |
((xfs_bmbt_rec_base_t)s->br_startblock >> 43));
@@ -2414,10 +2587,10 @@ xfs_bmbt_set_all(
}
/*
- * Set all the fields in a bmap extent record from the arguments.
+ * Set all the fields in a disk format bmap extent record from the arguments.
*/
void
-xfs_bmbt_set_allf(
+xfs_bmbt_disk_set_allf(
xfs_bmbt_rec_t *r,
xfs_fileoff_t o,
xfs_fsblock_t b,
@@ -2458,6 +2631,7 @@ xfs_bmbt_set_allf(
}
#endif /* XFS_BIG_FILESYSTEMS */
}
+#endif
/*
* Set the blockcount field in a bmap extent record.
@@ -2468,8 +2642,8 @@ xfs_bmbt_set_blockcount(
xfs_filblks_t v)
{
ASSERT((v & XFS_MASK64HI(43)) == 0);
- INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64HI(43)) |
- (xfs_bmbt_rec_base_t)(v & XFS_MASK64LO(21)));
+ r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)XFS_MASK64HI(43)) |
+ (xfs_bmbt_rec_base_t)(v & XFS_MASK64LO(21));
}
/*
@@ -2484,20 +2658,20 @@ xfs_bmbt_set_startblock(
ASSERT((v & XFS_MASK64HI(12)) == 0);
#endif /* XFS_BIG_FILESYSTEMS */
#if XFS_BIG_FILESYSTEMS
- INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64HI(55)) |
- (xfs_bmbt_rec_base_t)(v >> 43));
- INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)) |
- (xfs_bmbt_rec_base_t)(v << 21));
+ r->l0 = (r->l0 & (xfs_bmbt_rec_base_t)XFS_MASK64HI(55)) |
+ (xfs_bmbt_rec_base_t)(v >> 43);
+ r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)) |
+ (xfs_bmbt_rec_base_t)(v << 21);
#else /* !XFS_BIG_FILESYSTEMS */
if (ISNULLSTARTBLOCK(v)) {
- INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) | (xfs_bmbt_rec_base_t)XFS_MASK64LO(9)));
- INT_SET(r->l1, ARCH_CONVERT, (xfs_bmbt_rec_base_t)XFS_MASK64HI(11) |
+ r->l0 |= (xfs_bmbt_rec_base_t)XFS_MASK64LO(9);
+ r->l1 = (xfs_bmbt_rec_base_t)XFS_MASK64HI(11) |
((xfs_bmbt_rec_base_t)v << 21) |
- (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)));
+ (r->l1 & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
} else {
- INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & ~(xfs_bmbt_rec_base_t)XFS_MASK64LO(9)));
- INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)v << 21) |
- (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)));
+ r->l0 &= ~(xfs_bmbt_rec_base_t)XFS_MASK64LO(9);
+ r->l1 = ((xfs_bmbt_rec_base_t)v << 21) |
+ (r->l1 & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
}
#endif /* XFS_BIG_FILESYSTEMS */
}
@@ -2511,9 +2685,9 @@ xfs_bmbt_set_startoff(
xfs_fileoff_t v)
{
ASSERT((v & XFS_MASK64HI(9)) == 0);
- INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t) XFS_MASK64HI(1)) |
+ r->l0 = (r->l0 & (xfs_bmbt_rec_base_t) XFS_MASK64HI(1)) |
((xfs_bmbt_rec_base_t)v << 9) |
- (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(9)));
+ (r->l0 & (xfs_bmbt_rec_base_t)XFS_MASK64LO(9));
}
/*
@@ -2526,9 +2700,9 @@ xfs_bmbt_set_state(
{
ASSERT(v == XFS_EXT_NORM || v == XFS_EXT_UNWRITTEN);
if (v == XFS_EXT_NORM)
- INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN));
+ r->l0 &= XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN);
else
- INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) | XFS_MASK64HI(BMBT_EXNTFLAG_BITLEN));
+ r->l0 |= XFS_MASK64HI(BMBT_EXNTFLAG_BITLEN);
}
/*
@@ -2559,8 +2733,8 @@ xfs_bmbt_to_bmdr(
fpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen);
tpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr);
dmxr = INT_GET(dblock->bb_numrecs, ARCH_CONVERT);
- bcopy(fkp, tkp, sizeof(*fkp) * dmxr);
- bcopy(fpp, tpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */
+ memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
+ memcpy(tpp, fpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */
}
/*
@@ -2596,7 +2770,7 @@ xfs_bmbt_update(
#endif
ptr = cur->bc_ptrs[0];
rp = XFS_BMAP_REC_IADDR(block, ptr, cur);
- xfs_bmbt_set_allf(rp, off, bno, len, state);
+ xfs_bmbt_disk_set_allf(rp, off, bno, len, state);
xfs_bmbt_log_recs(cur, bp, ptr, ptr);
if (ptr > 1) {
XFS_BMBT_TRACE_CURSOR(cur, EXIT);
@@ -2618,13 +2792,14 @@ xfs_bmbt_update(
* Return an error condition (1) if any flags found,
* otherwise return 0.
*/
+
int
xfs_check_nostate_extents(
xfs_bmbt_rec_t *ep,
xfs_extnum_t num)
{
for (; num > 0; num--, ep++) {
- if (((INT_GET(ep->l0, ARCH_CONVERT)) >>
+ if ((ep->l0 >>
(64 - BMBT_EXNTFLAG_BITLEN)) != 0) {
ASSERT(0);
return 1;
diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h
index a9ec9c58252d..8aeefd43c967 100644
--- a/fs/xfs/xfs_bmap_btree.h
+++ b/fs/xfs/xfs_bmap_btree.h
@@ -509,6 +509,41 @@ xfs_exntst_t
xfs_bmbt_get_state(
xfs_bmbt_rec_t *r);
+#if ARCH_CONVERT != ARCH_NOCONVERT
+void
+xfs_bmbt_disk_get_all(
+ xfs_bmbt_rec_t *r,
+ xfs_bmbt_irec_t *s);
+
+xfs_exntst_t
+xfs_bmbt_disk_get_state(
+ xfs_bmbt_rec_t *r);
+
+xfs_filblks_t
+xfs_bmbt_disk_get_blockcount(
+ xfs_bmbt_rec_t *r);
+
+xfs_fsblock_t
+xfs_bmbt_disk_get_startblock(
+ xfs_bmbt_rec_t *r);
+
+xfs_fileoff_t
+xfs_bmbt_disk_get_startoff(
+ xfs_bmbt_rec_t *r);
+
+#else
+#define xfs_bmbt_disk_get_all(r, s) \
+ xfs_bmbt_get_all(r, s)
+#define xfs_bmbt_disk_get_state(r) \
+ xfs_bmbt_get_state(r)
+#define xfs_bmbt_disk_get_blockcount(r) \
+ xfs_bmbt_get_blockcount(r)
+#define xfs_bmbt_disk_get_startblock(r) \
+ xfs_bmbt_get_blockcount(r)
+#define xfs_bmbt_disk_get_startoff(r) \
+ xfs_bmbt_get_startoff(r)
+#endif
+
int
xfs_bmbt_increment(
struct xfs_btree_cur *,
@@ -607,6 +642,26 @@ xfs_bmbt_set_state(
xfs_bmbt_rec_t *r,
xfs_exntst_t v);
+#if ARCH_CONVERT != ARCH_NOCONVERT
+void
+xfs_bmbt_disk_set_all(
+ xfs_bmbt_rec_t *r,
+ xfs_bmbt_irec_t *s);
+
+void
+xfs_bmbt_disk_set_allf(
+ xfs_bmbt_rec_t *r,
+ xfs_fileoff_t o,
+ xfs_fsblock_t b,
+ xfs_filblks_t c,
+ xfs_exntst_t v);
+#else
+#define xfs_bmbt_disk_set_all(r, s) \
+ xfs_bmbt_set_all(r, s)
+#define xfs_bmbt_disk_set_allf(r, 0, b, c, v) \
+ xfs_bmbt_set_allf(r, 0, b, c, v)
+#endif
+
void
xfs_bmbt_to_bmdr(
xfs_bmbt_block_t *,
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c
index 7dcef68fb253..115b05df35ba 100644
--- a/fs/xfs/xfs_btree.c
+++ b/fs/xfs/xfs_btree.c
@@ -261,9 +261,9 @@ xfs_btree_check_rec(
r1 = ar1;
r2 = ar2;
- ASSERT(xfs_bmbt_get_startoff(r1) +
- xfs_bmbt_get_blockcount(r1) <=
- xfs_bmbt_get_startoff(r2));
+ ASSERT(xfs_bmbt_disk_get_startoff(r1) +
+ xfs_bmbt_disk_get_blockcount(r1) <=
+ xfs_bmbt_disk_get_startoff(r2));
break;
}
case XFS_BTNUM_INO: {
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index ac62646cacde..8a837fab5ad0 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -766,7 +766,7 @@ xfs_buf_item_init(
* to have logged.
*/
bip->bli_orig = (char *)kmem_alloc(XFS_BUF_COUNT(bp), KM_SLEEP);
- bcopy(XFS_BUF_PTR(bp), bip->bli_orig, XFS_BUF_COUNT(bp));
+ memcpy(bip->bli_orig, XFS_BUF_PTR(bp), XFS_BUF_COUNT(bp));
bip->bli_logged = (char *)kmem_zalloc(XFS_BUF_COUNT(bp) / NBBY, KM_SLEEP);
#endif
diff --git a/fs/xfs/xfs_clnt.h b/fs/xfs/xfs_clnt.h
index 14195151eeea..fd7d80ebe2ef 100644
--- a/fs/xfs/xfs_clnt.h
+++ b/fs/xfs/xfs_clnt.h
@@ -112,15 +112,14 @@ struct xfs_mount_args {
/* only) */
#define XFSMNT_NOTSERVER 0x00100000 /* give up being the server */
/* (remount only) */
-#define XFSMNT_DMAPI 0x00200000 /* enable dmapi/xdsm */
+#define XFSMNT_32BITINODES 0x00200000 /* restrict inodes to 32
+ * bits of address space */
#define XFSMNT_GQUOTA 0x00400000 /* group quota accounting */
#define XFSMNT_GQUOTAENF 0x00800000 /* group quota limit
* enforcement */
#define XFSMNT_NOUUID 0x01000000 /* Ignore fs uuid */
-#define XFSMNT_32BITINODES 0x02000000 /* restrict inodes to 32
- * bits of address space */
-#define XFSMNT_IRIXSGID 0x04000000 /* Irix-style sgid inheritance */
-#define XFSMNT_NOLOGFLUSH 0x08000000 /* Don't flush for log blocks */
+#define XFSMNT_DMAPI 0x02000000 /* enable dmapi/xdsm */
+#define XFSMNT_NOLOGFLUSH 0x04000000 /* Don't flush for log blocks */
/* Did we get any args for CXFS to consume? */
#define XFSARGS_FOR_CXFSARR(ap) \
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c
index 020801f897ae..06d8371730bc 100644
--- a/fs/xfs/xfs_da_btree.c
+++ b/fs/xfs/xfs_da_btree.c
@@ -360,7 +360,7 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
size = (int)((char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] -
(char *)leaf);
}
- bcopy(oldroot, node, size);
+ memcpy(node, oldroot, size);
xfs_da_log_buf(tp, bp, 0, size - 1);
xfs_da_buf_done(blk1->bp);
blk1->bp = bp;
@@ -527,7 +527,7 @@ xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
tmp *= (uint)sizeof(xfs_da_node_entry_t);
btree_s = &node2->btree[0];
btree_d = &node2->btree[count];
- ovbcopy(btree_s, btree_d, tmp);
+ memmove(btree_d, btree_s, tmp);
}
/*
@@ -538,7 +538,7 @@ xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
tmp = count * (uint)sizeof(xfs_da_node_entry_t);
btree_s = &node1->btree[INT_GET(node1->hdr.count, ARCH_CONVERT) - count];
btree_d = &node2->btree[0];
- bcopy(btree_s, btree_d, tmp);
+ memcpy(btree_d, btree_s, tmp);
INT_MOD(node1->hdr.count, ARCH_CONVERT, -(count));
} else {
@@ -550,7 +550,7 @@ xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
tmp = count * (uint)sizeof(xfs_da_node_entry_t);
btree_s = &node2->btree[0];
btree_d = &node1->btree[INT_GET(node1->hdr.count, ARCH_CONVERT)];
- bcopy(btree_s, btree_d, tmp);
+ memcpy(btree_d, btree_s, tmp);
INT_MOD(node1->hdr.count, ARCH_CONVERT, count);
xfs_da_log_buf(tp, blk1->bp,
XFS_DA_LOGRANGE(node1, btree_d, tmp));
@@ -562,7 +562,7 @@ xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
tmp *= (uint)sizeof(xfs_da_node_entry_t);
btree_s = &node2->btree[count];
btree_d = &node2->btree[0];
- ovbcopy(btree_s, btree_d, tmp);
+ memmove(btree_d, btree_s, tmp);
INT_MOD(node2->hdr.count, ARCH_CONVERT, -(count));
}
@@ -622,7 +622,7 @@ xfs_da_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
btree = &node->btree[ oldblk->index ];
if (oldblk->index < INT_GET(node->hdr.count, ARCH_CONVERT)) {
tmp = (INT_GET(node->hdr.count, ARCH_CONVERT) - oldblk->index) * (uint)sizeof(*btree);
- ovbcopy(btree, btree + 1, tmp);
+ memmove(btree + 1, btree, tmp);
}
INT_SET(btree->hashval, ARCH_CONVERT, newblk->hashval);
INT_SET(btree->before, ARCH_CONVERT, newblk->blkno);
@@ -790,7 +790,7 @@ xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk)
}
ASSERT(INT_ISZERO(blkinfo->forw, ARCH_CONVERT));
ASSERT(INT_ISZERO(blkinfo->back, ARCH_CONVERT));
- bcopy(bp->data, root_blk->bp->data, state->blocksize);
+ memcpy(root_blk->bp->data, bp->data, state->blocksize);
xfs_da_log_buf(args->trans, root_blk->bp, 0, state->blocksize - 1);
error = xfs_da_shrink_inode(args, child, bp);
return(error);
@@ -842,7 +842,7 @@ xfs_da_node_toosmall(xfs_da_state_t *state, int *action)
* path point to the block we want to drop (this one).
*/
forward = (!INT_ISZERO(info->forw, ARCH_CONVERT));
- bcopy(&state->path, &state->altpath, sizeof(state->path));
+ memcpy(&state->altpath, &state->path, sizeof(state->path));
error = xfs_da_path_shift(state, &state->altpath, forward,
0, &retval);
if (error)
@@ -898,7 +898,7 @@ xfs_da_node_toosmall(xfs_da_state_t *state, int *action)
* Make altpath point to the block we want to keep (the lower
* numbered block) and path point to the block we want to drop.
*/
- bcopy(&state->path, &state->altpath, sizeof(state->path));
+ memcpy(&state->altpath, &state->path, sizeof(state->path));
if (blkno < blk->blkno) {
error = xfs_da_path_shift(state, &state->altpath, forward,
0, &retval);
@@ -1001,12 +1001,12 @@ xfs_da_node_remove(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk)
if (drop_blk->index < (INT_GET(node->hdr.count, ARCH_CONVERT)-1)) {
tmp = INT_GET(node->hdr.count, ARCH_CONVERT) - drop_blk->index - 1;
tmp *= (uint)sizeof(xfs_da_node_entry_t);
- ovbcopy(btree + 1, btree, tmp);
+ memmove(btree, btree + 1, tmp);
xfs_da_log_buf(state->args->trans, drop_blk->bp,
XFS_DA_LOGRANGE(node, btree, tmp));
btree = &node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ];
}
- bzero((char *)btree, sizeof(xfs_da_node_entry_t));
+ memset((char *)btree, 0, sizeof(xfs_da_node_entry_t));
xfs_da_log_buf(state->args->trans, drop_blk->bp,
XFS_DA_LOGRANGE(node, btree, sizeof(*btree)));
INT_MOD(node->hdr.count, ARCH_CONVERT, -1);
@@ -1049,7 +1049,7 @@ xfs_da_node_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
{
btree = &save_node->btree[ INT_GET(drop_node->hdr.count, ARCH_CONVERT) ];
tmp = INT_GET(save_node->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_da_node_entry_t);
- ovbcopy(&save_node->btree[0], btree, tmp);
+ memmove(btree, &save_node->btree[0], tmp);
btree = &save_node->btree[0];
xfs_da_log_buf(tp, save_blk->bp,
XFS_DA_LOGRANGE(save_node, btree,
@@ -1067,7 +1067,7 @@ xfs_da_node_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
* Move all the B-tree elements from drop_blk to save_blk.
*/
tmp = INT_GET(drop_node->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_da_node_entry_t);
- bcopy(&drop_node->btree[0], btree, tmp);
+ memcpy(btree, &drop_node->btree[0], tmp);
INT_MOD(save_node->hdr.count, ARCH_CONVERT, INT_GET(drop_node->hdr.count, ARCH_CONVERT));
xfs_da_log_buf(tp, save_blk->bp,
@@ -1798,7 +1798,7 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
/*
* Copy the last block into the dead buffer and log it.
*/
- bcopy(last_buf->data, dead_buf->data, mp->m_dirblksize);
+ memcpy(dead_buf->data, last_buf->data, mp->m_dirblksize);
xfs_da_log_buf(tp, dead_buf, 0, mp->m_dirblksize - 1);
dead_info = dead_buf->data;
/*
@@ -2343,7 +2343,7 @@ xfs_da_state_free(xfs_da_state_t *state)
if (state->extravalid && state->extrablk.bp)
xfs_da_buf_done(state->extrablk.bp);
#ifdef DEBUG
- bzero((char *)state, sizeof(*state));
+ memset((char *)state, 0, sizeof(*state));
#endif /* DEBUG */
kmem_zone_free(xfs_da_state_zone, state);
}
@@ -2390,7 +2390,7 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra)
dabuf->data = kmem_alloc(BBTOB(dabuf->bbcount), KM_SLEEP);
for (i = off = 0; i < nbuf; i++, off += XFS_BUF_COUNT(bp)) {
bp = bps[i];
- bcopy(XFS_BUF_PTR(bp), (char *)dabuf->data + off,
+ memcpy((char *)dabuf->data + off, XFS_BUF_PTR(bp),
XFS_BUF_COUNT(bp));
}
}
@@ -2431,7 +2431,7 @@ xfs_da_buf_clean(xfs_dabuf_t *dabuf)
for (i = off = 0; i < dabuf->nbuf;
i++, off += XFS_BUF_COUNT(bp)) {
bp = dabuf->bps[i];
- bcopy((char *)dabuf->data + off, XFS_BUF_PTR(bp),
+ memcpy(XFS_BUF_PTR(bp), (char *)dabuf->data + off,
XFS_BUF_COUNT(bp));
}
}
@@ -2462,7 +2462,7 @@ xfs_da_buf_done(xfs_dabuf_t *dabuf)
dabuf->next->prev = dabuf->prev;
mutex_spinunlock(&xfs_dabuf_global_lock, s);
}
- bzero(dabuf, XFS_DA_BUF_SIZE(dabuf->nbuf));
+ memset(dabuf, 0, XFS_DA_BUF_SIZE(dabuf->nbuf));
#endif
if (dabuf->nbuf == 1)
kmem_zone_free(xfs_dabuf_zone, dabuf);
@@ -2532,7 +2532,7 @@ xfs_da_brelse(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
bp = dabuf->bps[0];
} else {
bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP);
- bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist));
+ memcpy(bplist, dabuf->bps, nbuf * sizeof(*bplist));
}
xfs_da_buf_done(dabuf);
for (i = 0; i < nbuf; i++)
@@ -2558,7 +2558,7 @@ xfs_da_binval(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
bp = dabuf->bps[0];
} else {
bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP);
- bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist));
+ memcpy(bplist, dabuf->bps, nbuf * sizeof(*bplist));
}
xfs_da_buf_done(dabuf);
for (i = 0; i < nbuf; i++)
diff --git a/fs/xfs/xfs_dir.c b/fs/xfs/xfs_dir.c
index ea2f5798cf70..ad3ecd88f1a6 100644
--- a/fs/xfs/xfs_dir.c
+++ b/fs/xfs/xfs_dir.c
@@ -210,7 +210,7 @@ xfs_dir_init(xfs_trans_t *trans, xfs_inode_t *dir, xfs_inode_t *parent_dir)
xfs_da_args_t args;
int error;
- bzero((char *)&args, sizeof(args));
+ memset((char *)&args, 0, sizeof(args));
args.dp = dir;
args.trans = trans;
@@ -534,7 +534,7 @@ xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, xfs_dinode_t *dp)
return 0;
}
if (INT_GET(dp->di_core.di_size, ARCH_CONVERT) < sizeof(sf->hdr)) {
- xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform size: dp 0x%p\n",
+ xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform size: dp 0x%p",
dp);
return 1;
}
@@ -546,7 +546,7 @@ xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, xfs_dinode_t *dp)
count = sf->hdr.count;
if ((count < 0) || ((count * 10) > XFS_LITINO(mp))) {
xfs_fs_cmn_err(CE_WARN, mp,
- "Invalid shortform count: dp 0x%p\n", dp);
+ "Invalid shortform count: dp 0x%p", dp);
return(1);
}
@@ -561,7 +561,7 @@ xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, xfs_dinode_t *dp)
xfs_dir_ino_validate(mp, ino);
if (sfe->namelen >= XFS_LITINO(mp)) {
xfs_fs_cmn_err(CE_WARN, mp,
- "Invalid shortform namelen: dp 0x%p\n", dp);
+ "Invalid shortform namelen: dp 0x%p", dp);
return 1;
}
namelen_sum += sfe->namelen;
@@ -569,7 +569,7 @@ xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, xfs_dinode_t *dp)
}
if (namelen_sum >= XFS_LITINO(mp)) {
xfs_fs_cmn_err(CE_WARN, mp,
- "Invalid shortform namelen: dp 0x%p\n", dp);
+ "Invalid shortform namelen: dp 0x%p", dp);
return 1;
}
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
index 1ee94f626cc1..403117dd28ff 100644
--- a/fs/xfs/xfs_dir2.c
+++ b/fs/xfs/xfs_dir2.c
@@ -147,7 +147,7 @@ xfs_dir2_init(
xfs_da_args_t args; /* operation arguments */
int error; /* error return value */
- bzero((char *)&args, sizeof(args));
+ memset((char *)&args, 0, sizeof(args));
args.dp = dp;
args.trans = tp;
ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
@@ -711,7 +711,7 @@ xfs_dir2_put_dirent64_direct(
idbp->d_off = pa->cook;
idbp->d_name[namelen] = '\0';
pa->done = 1;
- bcopy(pa->name, idbp->d_name, namelen);
+ memcpy(idbp->d_name, pa->name, namelen);
return 0;
}
@@ -743,7 +743,7 @@ xfs_dir2_put_dirent64_uio(
idbp->d_ino = pa->ino;
idbp->d_off = pa->cook;
idbp->d_name[namelen] = '\0';
- bcopy(pa->name, idbp->d_name, namelen);
+ memcpy(idbp->d_name, pa->name, namelen);
rval = uiomove((caddr_t)idbp, reclen, UIO_READ, uio);
pa->done = (rval == 0);
return rval;
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index de56814d5d25..3756923e8740 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -331,7 +331,7 @@ xfs_dir2_block_addname(
blp--;
mid++;
if (mid)
- ovbcopy(&blp[1], blp, mid * sizeof(*blp));
+ memmove(blp, &blp[1], mid * sizeof(*blp));
lfloglow = 0;
lfloghigh = mid;
}
@@ -357,7 +357,7 @@ xfs_dir2_block_addname(
(highstale == INT_GET(btp->count, ARCH_CONVERT) ||
mid - lowstale <= highstale - mid)) {
if (mid - lowstale)
- ovbcopy(&blp[lowstale + 1], &blp[lowstale],
+ memmove(&blp[lowstale], &blp[lowstale + 1],
(mid - lowstale) * sizeof(*blp));
lfloglow = MIN(lowstale, lfloglow);
lfloghigh = MAX(mid, lfloghigh);
@@ -369,7 +369,7 @@ xfs_dir2_block_addname(
ASSERT(highstale < INT_GET(btp->count, ARCH_CONVERT));
mid++;
if (highstale - mid)
- ovbcopy(&blp[mid], &blp[mid + 1],
+ memmove(&blp[mid + 1], &blp[mid],
(highstale - mid) * sizeof(*blp));
lfloglow = MIN(mid, lfloglow);
lfloghigh = MAX(highstale, lfloghigh);
@@ -397,7 +397,7 @@ xfs_dir2_block_addname(
*/
INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
dep->namelen = args->namelen;
- bcopy(args->name, dep->name, args->namelen);
+ memcpy(dep->name, args->name, args->namelen);
tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
/*
@@ -717,7 +717,7 @@ xfs_dir2_block_lookup_int(
*/
if (dep->namelen == args->namelen &&
dep->name[0] == args->name[0] &&
- bcmp(dep->name, args->name, args->namelen) == 0) {
+ memcmp(dep->name, args->name, args->namelen) == 0) {
*bpp = bp;
*entno = mid;
return 0;
@@ -1075,7 +1075,7 @@ xfs_dir2_sf_to_block(
buf_len = dp->i_df.if_bytes;
buf = kmem_alloc(dp->i_df.if_bytes, KM_SLEEP);
- bcopy(sfp, buf, dp->i_df.if_bytes);
+ memcpy(buf, sfp, dp->i_df.if_bytes);
xfs_idata_realloc(dp, -dp->i_df.if_bytes, XFS_DATA_FORK);
dp->i_d.di_size = 0;
xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
@@ -1199,7 +1199,7 @@ xfs_dir2_sf_to_block(
INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT));
dep->namelen = sfep->namelen;
- bcopy(sfep->name, dep->name, dep->namelen);
+ memcpy(dep->name, sfep->name, dep->namelen);
tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
xfs_dir2_data_log_entry(tp, bp, dep);
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c
index 7ea956729cf1..7481245193d4 100644
--- a/fs/xfs/xfs_dir2_data.c
+++ b/fs/xfs/xfs_dir2_data.c
@@ -340,7 +340,7 @@ xfs_dir2_data_freescan(
/*
* Start by clearing the table.
*/
- bzero(d->hdr.bestfree, sizeof(d->hdr.bestfree));
+ memset(d->hdr.bestfree, 0, sizeof(d->hdr.bestfree));
*loghead = 1;
/*
* Set up pointers.
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index c201111f7339..7ab474f6a3a3 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -110,7 +110,7 @@ xfs_dir2_block_to_leaf(
* Could compact these but I think we always do the conversion
* after squeezing out stale entries.
*/
- bcopy(blp, leaf->ents, INT_GET(btp->count, ARCH_CONVERT) * sizeof(xfs_dir2_leaf_entry_t));
+ memcpy(leaf->ents, blp, INT_GET(btp->count, ARCH_CONVERT) * sizeof(xfs_dir2_leaf_entry_t));
xfs_dir2_leaf_log_ents(tp, lbp, 0, INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1);
needscan = 0;
needlog = 1;
@@ -353,7 +353,7 @@ xfs_dir2_leaf_addname(
*/
if (use_block >= INT_GET(ltp->bestcount, ARCH_CONVERT)) {
bestsp--;
- ovbcopy(&bestsp[1], &bestsp[0],
+ memmove(&bestsp[0], &bestsp[1],
INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(bestsp[0]));
INT_MOD(ltp->bestcount, ARCH_CONVERT, +1);
xfs_dir2_leaf_log_tail(tp, lbp);
@@ -402,7 +402,7 @@ xfs_dir2_leaf_addname(
dep = (xfs_dir2_data_entry_t *)dup;
INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
dep->namelen = args->namelen;
- bcopy(args->name, dep->name, dep->namelen);
+ memcpy(dep->name, args->name, dep->namelen);
tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)data));
/*
@@ -434,7 +434,7 @@ xfs_dir2_leaf_addname(
* lep is still good as the index leaf entry.
*/
if (index < INT_GET(leaf->hdr.count, ARCH_CONVERT))
- ovbcopy(lep, lep + 1,
+ memmove(lep + 1, lep,
(INT_GET(leaf->hdr.count, ARCH_CONVERT) - index) * sizeof(*lep));
/*
* Record low and high logging indices for the leaf.
@@ -493,8 +493,8 @@ xfs_dir2_leaf_addname(
* and make room for the new entry.
*/
if (index - lowstale - 1 > 0)
- ovbcopy(&leaf->ents[lowstale + 1],
- &leaf->ents[lowstale],
+ memmove(&leaf->ents[lowstale],
+ &leaf->ents[lowstale + 1],
(index - lowstale - 1) * sizeof(*lep));
lep = &leaf->ents[index - 1];
lfloglow = MIN(lowstale, lfloglow);
@@ -512,8 +512,8 @@ xfs_dir2_leaf_addname(
* and make room for the new entry.
*/
if (highstale - index > 0)
- ovbcopy(&leaf->ents[index],
- &leaf->ents[index + 1],
+ memmove(&leaf->ents[index + 1],
+ &leaf->ents[index],
(highstale - index) * sizeof(*lep));
lep = &leaf->ents[index];
lfloglow = MIN(index, lfloglow);
@@ -847,7 +847,7 @@ xfs_dir2_leaf_getdents(
* the table.
*/
if (!map->br_blockcount && --map_valid)
- ovbcopy(&map[1], &map[0],
+ memmove(&map[0], &map[1],
sizeof(map[0]) *
map_valid);
i -= j;
@@ -909,8 +909,8 @@ xfs_dir2_leaf_getdents(
nmap--;
length = map_valid + nmap - i;
if (length)
- ovbcopy(&map[i + 1],
- &map[i],
+ memmove(&map[i],
+ &map[i + 1],
sizeof(map[i]) *
length);
} else {
@@ -1409,7 +1409,7 @@ xfs_dir2_leaf_lookup_int(
*/
if (dep->namelen == args->namelen &&
dep->name[0] == args->name[0] &&
- bcmp(dep->name, args->name, args->namelen) == 0) {
+ memcmp(dep->name, args->name, args->namelen) == 0) {
*dbpp = dbp;
*indexp = index;
return 0;
@@ -1544,7 +1544,7 @@ xfs_dir2_leaf_removename(
* Copy the table down so inactive entries at the
* end are removed.
*/
- ovbcopy(bestsp, &bestsp[db - i],
+ memmove(&bestsp[db - i], bestsp,
(INT_GET(ltp->bestcount, ARCH_CONVERT) - (db - i)) * sizeof(*bestsp));
INT_MOD(ltp->bestcount, ARCH_CONVERT, -(db - i));
xfs_dir2_leaf_log_tail(tp, lbp);
@@ -1728,7 +1728,7 @@ xfs_dir2_leaf_trim_data(
*/
bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT);
INT_MOD(ltp->bestcount, ARCH_CONVERT, -1);
- ovbcopy(&bestsp[0], &bestsp[1], INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(*bestsp));
+ memmove(&bestsp[1], &bestsp[0], INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(*bestsp));
xfs_dir2_leaf_log_tail(tp, lbp);
xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);
return 0;
@@ -1842,7 +1842,7 @@ xfs_dir2_node_to_leaf(
/*
* Set up the leaf bests table.
*/
- bcopy(free->bests, XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT),
+ memcpy(XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT), free->bests,
INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(leaf->bests[0]));
xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);
xfs_dir2_leaf_log_tail(tp, lbp);
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
index 99661539e595..54234b40ed6b 100644
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -239,7 +239,7 @@ xfs_dir2_leafn_add(
if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) {
lep = &leaf->ents[index];
if (index < INT_GET(leaf->hdr.count, ARCH_CONVERT))
- ovbcopy(lep, lep + 1,
+ memmove(lep + 1, lep,
(INT_GET(leaf->hdr.count, ARCH_CONVERT) - index) * sizeof(*lep));
lfloglow = index;
lfloghigh = INT_GET(leaf->hdr.count, ARCH_CONVERT);
@@ -288,8 +288,8 @@ xfs_dir2_leafn_add(
XFS_DIR2_NULL_DATAPTR);
ASSERT(index - lowstale - 1 >= 0);
if (index - lowstale - 1 > 0)
- ovbcopy(&leaf->ents[lowstale + 1],
- &leaf->ents[lowstale],
+ memmove(&leaf->ents[lowstale],
+ &leaf->ents[lowstale + 1],
(index - lowstale - 1) * sizeof(*lep));
lep = &leaf->ents[index - 1];
lfloglow = MIN(lowstale, lfloglow);
@@ -304,8 +304,8 @@ xfs_dir2_leafn_add(
XFS_DIR2_NULL_DATAPTR);
ASSERT(highstale - index >= 0);
if (highstale - index > 0)
- ovbcopy(&leaf->ents[index],
- &leaf->ents[index + 1],
+ memmove(&leaf->ents[index + 1],
+ &leaf->ents[index],
(highstale - index) * sizeof(*lep));
lep = &leaf->ents[index];
lfloglow = MIN(index, lfloglow);
@@ -564,7 +564,7 @@ xfs_dir2_leafn_lookup_int(
*/
if (dep->namelen == args->namelen &&
dep->name[0] == args->name[0] &&
- bcmp(dep->name, args->name, args->namelen) == 0) {
+ memcmp(dep->name, args->name, args->namelen) == 0) {
args->inumber = INT_GET(dep->inumber, ARCH_CONVERT);
*indexp = index;
state->extravalid = 1;
@@ -644,7 +644,7 @@ xfs_dir2_leafn_moveents(
* to hold the new entries.
*/
if (start_d < INT_GET(leaf_d->hdr.count, ARCH_CONVERT)) {
- ovbcopy(&leaf_d->ents[start_d], &leaf_d->ents[start_d + count],
+ memmove(&leaf_d->ents[start_d + count], &leaf_d->ents[start_d],
(INT_GET(leaf_d->hdr.count, ARCH_CONVERT) - start_d) *
sizeof(xfs_dir2_leaf_entry_t));
xfs_dir2_leaf_log_ents(tp, bp_d, start_d + count,
@@ -666,7 +666,7 @@ xfs_dir2_leafn_moveents(
/*
* Copy the leaf entries from source to destination.
*/
- bcopy(&leaf_s->ents[start_s], &leaf_d->ents[start_d],
+ memcpy(&leaf_d->ents[start_d], &leaf_s->ents[start_s],
count * sizeof(xfs_dir2_leaf_entry_t));
xfs_dir2_leaf_log_ents(tp, bp_d, start_d, start_d + count - 1);
/*
@@ -674,7 +674,7 @@ xfs_dir2_leafn_moveents(
* delete the ones we copied by sliding the next ones down.
*/
if (start_s + count < INT_GET(leaf_s->hdr.count, ARCH_CONVERT)) {
- ovbcopy(&leaf_s->ents[start_s + count], &leaf_s->ents[start_s],
+ memmove(&leaf_s->ents[start_s], &leaf_s->ents[start_s + count],
count * sizeof(xfs_dir2_leaf_entry_t));
xfs_dir2_leaf_log_ents(tp, bp_s, start_s, start_s + count - 1);
}
@@ -1135,7 +1135,7 @@ xfs_dir2_leafn_toosmall(
* path point to the block we want to drop (this one).
*/
forward = !INT_ISZERO(info->forw, ARCH_CONVERT);
- bcopy(&state->path, &state->altpath, sizeof(state->path));
+ memcpy(&state->altpath, &state->path, sizeof(state->path));
error = xfs_da_path_shift(state, &state->altpath, forward, 0,
&rval);
if (error)
@@ -1197,7 +1197,7 @@ xfs_dir2_leafn_toosmall(
* Make altpath point to the block we want to keep (the lower
* numbered block) and path point to the block we want to drop.
*/
- bcopy(&state->path, &state->altpath, sizeof(state->path));
+ memcpy(&state->altpath, &state->path, sizeof(state->path));
if (blkno < blk->blkno)
error = xfs_da_path_shift(state, &state->altpath, forward, 0,
&rval);
@@ -1685,7 +1685,7 @@ xfs_dir2_node_addname_int(
dep = (xfs_dir2_data_entry_t *)dup;
INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
dep->namelen = args->namelen;
- bcopy(args->name, dep->name, dep->namelen);
+ memcpy(dep->name, args->name, dep->namelen);
tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)data));
xfs_dir2_data_log_entry(tp, dbp, dep);
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c
index c1d2d3d9b2c2..aaba9972bd57 100644
--- a/fs/xfs/xfs_dir2_sf.c
+++ b/fs/xfs/xfs_dir2_sf.c
@@ -176,7 +176,7 @@ xfs_dir2_block_to_sf(
* and add local data.
*/
block = kmem_alloc(mp->m_dirblksize, KM_SLEEP);
- bcopy(bp->data, block, mp->m_dirblksize);
+ memcpy(block, bp->data, mp->m_dirblksize);
logflags = XFS_ILOG_CORE;
if ((error = xfs_dir2_shrink_inode(args, mp->m_dirdatablk, bp))) {
ASSERT(error != ENOSPC);
@@ -198,7 +198,7 @@ xfs_dir2_block_to_sf(
* Copy the header into the newly allocate local space.
*/
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- bcopy(sfhp, sfp, XFS_DIR2_SF_HDR_SIZE(sfhp->i8count));
+ memcpy(sfp, sfhp, XFS_DIR2_SF_HDR_SIZE(sfhp->i8count));
dp->i_d.di_size = size;
/*
* Set up to loop over the block's entries.
@@ -241,7 +241,7 @@ xfs_dir2_block_to_sf(
XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep,
(xfs_dir2_data_aoff_t)
((char *)dep - (char *)block), ARCH_CONVERT);
- bcopy(dep->name, sfep->name, dep->namelen);
+ memcpy(sfep->name, dep->name, dep->namelen);
temp=INT_GET(dep->inumber, ARCH_CONVERT);
XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &temp,
XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
@@ -405,7 +405,7 @@ xfs_dir2_sf_addname_easy(
*/
sfep->namelen = args->namelen;
XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT);
- bcopy(args->name, sfep->name, sfep->namelen);
+ memcpy(sfep->name, args->name, sfep->namelen);
XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber,
XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
/*
@@ -457,7 +457,7 @@ xfs_dir2_sf_addname_hard(
old_isize = (int)dp->i_d.di_size;
buf = kmem_alloc(old_isize, KM_SLEEP);
oldsfp = (xfs_dir2_sf_t *)buf;
- bcopy(sfp, oldsfp, old_isize);
+ memcpy(oldsfp, sfp, old_isize);
/*
* Loop over the old directory finding the place we're going
* to insert the new entry.
@@ -490,14 +490,14 @@ xfs_dir2_sf_addname_hard(
* Copy the first part of the directory, including the header.
*/
nbytes = (int)((char *)oldsfep - (char *)oldsfp);
- bcopy(oldsfp, sfp, nbytes);
+ memcpy(sfp, oldsfp, nbytes);
sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes);
/*
* Fill in the new entry, and update the header counts.
*/
sfep->namelen = args->namelen;
XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT);
- bcopy(args->name, sfep->name, sfep->namelen);
+ memcpy(sfep->name, args->name, sfep->namelen);
XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber,
XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
sfp->hdr.count++;
@@ -510,7 +510,7 @@ xfs_dir2_sf_addname_hard(
*/
if (!eof) {
sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
- bcopy(oldsfep, sfep, old_isize - nbytes);
+ memcpy(sfep, oldsfep, old_isize - nbytes);
}
kmem_free(buf, old_isize);
dp->i_d.di_size = new_isize;
@@ -916,7 +916,7 @@ xfs_dir2_sf_lookup(
i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
if (sfep->namelen == args->namelen &&
sfep->name[0] == args->name[0] &&
- bcmp(args->name, sfep->name, args->namelen) == 0) {
+ memcmp(args->name, sfep->name, args->namelen) == 0) {
args->inumber =
XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
@@ -971,7 +971,7 @@ xfs_dir2_sf_removename(
i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
if (sfep->namelen == args->namelen &&
sfep->name[0] == args->name[0] &&
- bcmp(sfep->name, args->name, args->namelen) == 0) {
+ memcmp(sfep->name, args->name, args->namelen) == 0) {
ASSERT(XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT) ==
args->inumber);
@@ -994,7 +994,7 @@ xfs_dir2_sf_removename(
* Copy the part if any after the removed entry, sliding it down.
*/
if (byteoff + entsize < oldsize)
- ovbcopy((char *)sfp + byteoff + entsize, (char *)sfp + byteoff,
+ memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize,
oldsize - (byteoff + entsize));
/*
* Fix up the header and file size.
@@ -1108,7 +1108,7 @@ xfs_dir2_sf_replace(
i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
if (sfep->namelen == args->namelen &&
sfep->name[0] == args->name[0] &&
- bcmp(args->name, sfep->name, args->namelen) == 0) {
+ memcmp(args->name, sfep->name, args->namelen) == 0) {
#if XFS_BIG_FILESYSTEMS || defined(DEBUG)
ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
@@ -1196,7 +1196,7 @@ xfs_dir2_sf_toino4(
buf = kmem_alloc(oldsize, KM_SLEEP);
oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
ASSERT(oldsfp->hdr.i8count == 1);
- bcopy(oldsfp, buf, oldsize);
+ memcpy(buf, oldsfp, oldsize);
/*
* Compute the new inode size.
*/
@@ -1228,7 +1228,7 @@ xfs_dir2_sf_toino4(
oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) {
sfep->namelen = oldsfep->namelen;
sfep->offset = oldsfep->offset;
- bcopy(oldsfep->name, sfep->name, sfep->namelen);
+ memcpy(sfep->name, oldsfep->name, sfep->namelen);
ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp,
XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT);
XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
@@ -1273,7 +1273,7 @@ xfs_dir2_sf_toino8(
buf = kmem_alloc(oldsize, KM_SLEEP);
oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
ASSERT(oldsfp->hdr.i8count == 0);
- bcopy(oldsfp, buf, oldsize);
+ memcpy(buf, oldsfp, oldsize);
/*
* Compute the new inode size.
*/
@@ -1305,7 +1305,7 @@ xfs_dir2_sf_toino8(
oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) {
sfep->namelen = oldsfep->namelen;
sfep->offset = oldsfep->offset;
- bcopy(oldsfep->name, sfep->name, sfep->namelen);
+ memcpy(sfep->name, oldsfep->name, sfep->namelen);
ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp,
XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT);
XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
diff --git a/fs/xfs/xfs_dir2_sf.h b/fs/xfs/xfs_dir2_sf.h
index 576c19f17c68..7ee59c6107b3 100644
--- a/fs/xfs/xfs_dir2_sf.h
+++ b/fs/xfs/xfs_dir2_sf.h
@@ -93,7 +93,7 @@ typedef struct { __uint8_t i[2]; } xfs_dir2_sf_off_t;
* be calculated on the fly.
*
* Entries are packed toward the top as tightly as possible. The header
- * and the elements must be bcopy()'d out into a work area to get correct
+ * and the elements must be memcpy'd out into a work area to get correct
* alignment for the inode number fields.
*/
typedef struct xfs_dir2_sf_hdr {
diff --git a/fs/xfs/xfs_dir2_trace.c b/fs/xfs/xfs_dir2_trace.c
index fe9280e1f427..3e517abee119 100644
--- a/fs/xfs/xfs_dir2_trace.c
+++ b/fs/xfs/xfs_dir2_trace.c
@@ -65,9 +65,9 @@ xfs_dir2_trace_enter(
ASSERT(xfs_dir2_trace_buf);
ASSERT(dp->i_dir_trace);
if (name)
- bcopy(name, n, min(sizeof(n), namelen));
+ memcpy(n, name, min(sizeof(n), namelen));
else
- bzero((char *)n, sizeof(n));
+ memset((char *)n, 0, sizeof(n));
ktrace_enter(xfs_dir2_trace_buf,
(void *)(__psunsigned_t)type, (void *)where,
(void *)a0, (void *)a1, (void *)a2, (void *)a3,
diff --git a/fs/xfs/xfs_dir_leaf.c b/fs/xfs/xfs_dir_leaf.c
index 1aceaf37693d..d689c169f6e7 100644
--- a/fs/xfs/xfs_dir_leaf.c
+++ b/fs/xfs/xfs_dir_leaf.c
@@ -105,7 +105,7 @@ xfs_dir_ino_validate(xfs_mount_t *mp, xfs_ino_t ino)
XFS_AGINO_TO_INO(mp, agno, agino) == ino;
if (XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE,
XFS_RANDOM_DIR_INO_VALIDATE)) {
- xfs_fs_cmn_err(CE_WARN, mp, "Invalid inode number 0x%Lx\n",
+ xfs_fs_cmn_err(CE_WARN, mp, "Invalid inode number 0x%Lx",
(unsigned long long) ino);
return XFS_ERROR(EFSCORRUPTED);
}
@@ -171,7 +171,7 @@ xfs_dir_shortform_addname(xfs_da_args_t *args)
for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) {
if (sfe->namelen == args->namelen &&
args->name[0] == sfe->name[0] &&
- bcmp(args->name, sfe->name, args->namelen) == 0)
+ memcmp(args->name, sfe->name, args->namelen) == 0)
return(XFS_ERROR(EEXIST));
sfe = XFS_DIR_SF_NEXTENTRY(sfe);
}
@@ -184,7 +184,7 @@ xfs_dir_shortform_addname(xfs_da_args_t *args)
XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sfe->inumber, ARCH_CONVERT);
sfe->namelen = args->namelen;
- bcopy(args->name, sfe->name, sfe->namelen);
+ memcpy(sfe->name, args->name, sfe->namelen);
INT_MOD(sf->hdr.count, ARCH_CONVERT, +1);
dp->i_d.di_size += size;
@@ -223,7 +223,7 @@ xfs_dir_shortform_removename(xfs_da_args_t *args)
size = XFS_DIR_SF_ENTSIZE_BYENTRY(sfe);
if (sfe->namelen == args->namelen &&
sfe->name[0] == args->name[0] &&
- bcmp(sfe->name, args->name, args->namelen) == 0)
+ memcmp(sfe->name, args->name, args->namelen) == 0)
break;
base += size;
sfe = XFS_DIR_SF_NEXTENTRY(sfe);
@@ -234,7 +234,7 @@ xfs_dir_shortform_removename(xfs_da_args_t *args)
}
if ((base + size) != dp->i_d.di_size) {
- ovbcopy(&((char *)sf)[base+size], &((char *)sf)[base],
+ memmove(&((char *)sf)[base], &((char *)sf)[base+size],
dp->i_d.di_size - (base+size));
}
INT_MOD(sf->hdr.count, ARCH_CONVERT, -1);
@@ -283,7 +283,7 @@ xfs_dir_shortform_lookup(xfs_da_args_t *args)
for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) {
if (sfe->namelen == args->namelen &&
sfe->name[0] == args->name[0] &&
- bcmp(args->name, sfe->name, args->namelen) == 0) {
+ memcmp(args->name, sfe->name, args->namelen) == 0) {
XFS_DIR_SF_GET_DIRINO_ARCH(&sfe->inumber, &args->inumber, ARCH_CONVERT);
return(XFS_ERROR(EEXIST));
}
@@ -324,7 +324,7 @@ xfs_dir_shortform_to_leaf(xfs_da_args_t *iargs)
tmpbuffer = kmem_alloc(size, KM_SLEEP);
ASSERT(tmpbuffer != NULL);
- bcopy(dp->i_df.if_u1.if_data, tmpbuffer, size);
+ memcpy(tmpbuffer, dp->i_df.if_u1.if_data, size);
sf = (xfs_dir_shortform_t *)tmpbuffer;
XFS_DIR_SF_GET_DIRINO_ARCH(&sf->hdr.parent, &inumber, ARCH_CONVERT);
@@ -611,8 +611,8 @@ xfs_dir_shortform_replace(xfs_da_args_t *args)
for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) {
if (sfe->namelen == args->namelen &&
sfe->name[0] == args->name[0] &&
- bcmp(args->name, sfe->name, args->namelen) == 0) {
- ASSERT(bcmp((char *)&args->inumber,
+ memcmp(args->name, sfe->name, args->namelen) == 0) {
+ ASSERT(memcmp((char *)&args->inumber,
(char *)&sfe->inumber, sizeof(xfs_ino_t)));
XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sfe->inumber, ARCH_CONVERT);
xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
@@ -650,10 +650,10 @@ xfs_dir_leaf_to_shortform(xfs_da_args_t *iargs)
if (retval)
return(retval);
ASSERT(bp != NULL);
- bcopy(bp->data, tmpbuffer, XFS_LBSIZE(dp->i_mount));
+ memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount));
leaf = (xfs_dir_leafblock_t *)tmpbuffer;
ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
- bzero(bp->data, XFS_LBSIZE(dp->i_mount));
+ memset(bp->data, 0, XFS_LBSIZE(dp->i_mount));
/*
* Find and special case the parent inode number
@@ -736,7 +736,7 @@ xfs_dir_leaf_to_node(xfs_da_args_t *args)
return(retval);
}
ASSERT(bp2 != NULL);
- bcopy(bp1->data, bp2->data, XFS_LBSIZE(dp->i_mount));
+ memcpy(bp2->data, bp1->data, XFS_LBSIZE(dp->i_mount));
xfs_da_buf_done(bp1);
xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1);
@@ -787,7 +787,7 @@ xfs_dir_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp)
return(retval);
ASSERT(bp != NULL);
leaf = bp->data;
- bzero((char *)leaf, XFS_LBSIZE(dp->i_mount));
+ memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount));
hdr = &leaf->hdr;
INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_DIR_LEAF_MAGIC);
INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount));
@@ -960,7 +960,7 @@ xfs_dir_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int index,
if (index < INT_GET(hdr->count, ARCH_CONVERT)) {
tmp = INT_GET(hdr->count, ARCH_CONVERT) - index;
tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
- ovbcopy(entry, entry + 1, tmp);
+ memmove(entry + 1, entry, tmp);
xfs_da_log_buf(args->trans, bp,
XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry)));
}
@@ -986,7 +986,7 @@ xfs_dir_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int index,
*/
namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &namest->inumber, ARCH_CONVERT);
- bcopy(args->name, namest->name, args->namelen);
+ memcpy(namest->name, args->name, args->namelen);
xfs_da_log_buf(args->trans, bp,
XFS_DA_LOGRANGE(leaf, namest, XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry)));
@@ -1029,7 +1029,7 @@ xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp, int musthave,
lbsize = XFS_LBSIZE(mp);
tmpbuffer = kmem_alloc(lbsize, KM_SLEEP);
ASSERT(tmpbuffer != NULL);
- bcopy(bp->data, tmpbuffer, lbsize);
+ memcpy(tmpbuffer, bp->data, lbsize);
/*
* Make a second copy in case xfs_dir_leaf_moveents()
@@ -1037,9 +1037,9 @@ xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp, int musthave,
*/
if (musthave || justcheck) {
tmpbuffer2 = kmem_alloc(lbsize, KM_SLEEP);
- bcopy(bp->data, tmpbuffer2, lbsize);
+ memcpy(tmpbuffer2, bp->data, lbsize);
}
- bzero(bp->data, lbsize);
+ memset(bp->data, 0, lbsize);
/*
* Copy basic information
@@ -1072,7 +1072,7 @@ xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp, int musthave,
if (justcheck || rval == ENOSPC) {
ASSERT(tmpbuffer2);
- bcopy(tmpbuffer2, bp->data, lbsize);
+ memcpy(bp->data, tmpbuffer2, lbsize);
} else {
xfs_da_log_buf(trans, bp, 0, lbsize - 1);
}
@@ -1357,7 +1357,7 @@ xfs_dir_leaf_toosmall(xfs_da_state_t *state, int *action)
* path point to the block we want to drop (this one).
*/
forward = !INT_ISZERO(info->forw, ARCH_CONVERT);
- bcopy(&state->path, &state->altpath, sizeof(state->path));
+ memcpy(&state->altpath, &state->path, sizeof(state->path));
error = xfs_da_path_shift(state, &state->altpath, forward,
0, &retval);
if (error)
@@ -1418,7 +1418,7 @@ xfs_dir_leaf_toosmall(xfs_da_state_t *state, int *action)
* Make altpath point to the block we want to keep (the lower
* numbered block) and path point to the block we want to drop.
*/
- bcopy(&state->path, &state->altpath, sizeof(state->path));
+ memcpy(&state->altpath, &state->path, sizeof(state->path));
if (blkno < blk->blkno) {
error = xfs_da_path_shift(state, &state->altpath, forward,
0, &retval);
@@ -1538,17 +1538,17 @@ xfs_dir_leaf_remove(xfs_trans_t *trans, xfs_dabuf_t *bp, int index)
* Compress the remaining entries and zero out the removed stuff.
*/
namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
- bzero((char *)namest, entsize);
+ memset((char *)namest, 0, entsize);
xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, namest, entsize));
INT_MOD(hdr->namebytes, ARCH_CONVERT, -(entry->namelen));
tmp = (INT_GET(hdr->count, ARCH_CONVERT) - index) * (uint)sizeof(xfs_dir_leaf_entry_t);
- ovbcopy(entry + 1, entry, tmp);
+ memmove(entry, entry + 1, tmp);
INT_MOD(hdr->count, ARCH_CONVERT, -1);
xfs_da_log_buf(trans, bp,
XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry)));
entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)];
- bzero((char *)entry, sizeof(xfs_dir_leaf_entry_t));
+ memset((char *)entry, 0, sizeof(xfs_dir_leaf_entry_t));
/*
* If we removed the first entry, re-find the first used byte
@@ -1642,7 +1642,7 @@ xfs_dir_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
*/
tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP);
ASSERT(tmpbuffer != NULL);
- bzero(tmpbuffer, state->blocksize);
+ memset(tmpbuffer, 0, state->blocksize);
tmp_leaf = (xfs_dir_leafblock_t *)tmpbuffer;
tmp_hdr = &tmp_leaf->hdr;
tmp_hdr->info = save_hdr->info; /* struct copy */
@@ -1664,7 +1664,7 @@ xfs_dir_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT),
(int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp);
}
- bcopy(tmp_leaf, save_leaf, state->blocksize);
+ memcpy(save_leaf, tmp_leaf, state->blocksize);
kmem_free(tmpbuffer, state->blocksize);
}
@@ -1750,7 +1750,7 @@ xfs_dir_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args, int *index)
namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
if (entry->namelen == args->namelen &&
namest->name[0] == args->name[0] &&
- bcmp(args->name, namest->name, args->namelen) == 0) {
+ memcmp(args->name, namest->name, args->namelen) == 0) {
XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &args->inumber, ARCH_CONVERT);
*index = probe;
return(XFS_ERROR(EEXIST));
@@ -1813,7 +1813,7 @@ xfs_dir_leaf_moveents(xfs_dir_leafblock_t *leaf_s, int start_s,
tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
entry_s = &leaf_d->entries[start_d];
entry_d = &leaf_d->entries[start_d + count];
- bcopy(entry_s, entry_d, tmp);
+ memcpy(entry_d, entry_s, tmp);
}
/*
@@ -1831,11 +1831,11 @@ xfs_dir_leaf_moveents(xfs_dir_leafblock_t *leaf_s, int start_s,
INT_COPY(entry_d->nameidx, hdr_d->firstused, ARCH_CONVERT);
entry_d->namelen = entry_s->namelen;
ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp));
- bcopy(XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)),
- XFS_DIR_LEAF_NAMESTRUCT(leaf_d, INT_GET(entry_d->nameidx, ARCH_CONVERT)), tmp);
+ memcpy(XFS_DIR_LEAF_NAMESTRUCT(leaf_d, INT_GET(entry_d->nameidx, ARCH_CONVERT)),
+ XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)), tmp);
ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp));
- bzero((char *)XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)),
- tmp);
+ memset((char *)XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)),
+ 0, tmp);
INT_MOD(hdr_s->namebytes, ARCH_CONVERT, -(entry_d->namelen));
INT_MOD(hdr_d->namebytes, ARCH_CONVERT, entry_d->namelen);
INT_MOD(hdr_s->count, ARCH_CONVERT, -1);
@@ -1853,7 +1853,7 @@ xfs_dir_leaf_moveents(xfs_dir_leafblock_t *leaf_s, int start_s,
tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t);
entry_s = &leaf_s->entries[start_s];
ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp));
- bzero((char *)entry_s, tmp);
+ memset((char *)entry_s, 0, tmp);
} else {
/*
* Move the remaining entries down to fill the hole,
@@ -1863,12 +1863,12 @@ xfs_dir_leaf_moveents(xfs_dir_leafblock_t *leaf_s, int start_s,
tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
entry_s = &leaf_s->entries[start_s + count];
entry_d = &leaf_s->entries[start_s];
- bcopy(entry_s, entry_d, tmp);
+ memcpy(entry_d, entry_s, tmp);
tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t);
entry_s = &leaf_s->entries[INT_GET(hdr_s->count, ARCH_CONVERT)];
ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp));
- bzero((char *)entry_s, tmp);
+ memset((char *)entry_s, 0, tmp);
}
/*
@@ -2191,7 +2191,7 @@ xfs_dir_put_dirent64_direct(xfs_dir_put_args_t *pa)
idbp->d_off = pa->cook.o;
idbp->d_name[namelen] = '\0';
pa->done = 1;
- bcopy(pa->name, idbp->d_name, namelen);
+ memcpy(idbp->d_name, pa->name, namelen);
return 0;
}
@@ -2217,7 +2217,7 @@ xfs_dir_put_dirent64_uio(xfs_dir_put_args_t *pa)
idbp->d_ino = pa->ino;
idbp->d_off = pa->cook.o;
idbp->d_name[namelen] = '\0';
- bcopy(pa->name, idbp->d_name, namelen);
+ memcpy(idbp->d_name, pa->name, namelen);
retval = uiomove((caddr_t)idbp, reclen, UIO_READ, uio);
pa->done = (retval == 0);
return retval;
diff --git a/fs/xfs/xfs_dir_sf.h b/fs/xfs/xfs_dir_sf.h
index ede171472223..10c60645f1fc 100644
--- a/fs/xfs/xfs_dir_sf.h
+++ b/fs/xfs/xfs_dir_sf.h
@@ -46,7 +46,7 @@ typedef struct { __uint8_t i[sizeof(xfs_ino_t)]; } xfs_dir_ino_t;
* be calculated on the fly.
*
* Entries are packed toward the top as tight as possible. The header
- * and the elements much be bcopy()'d out into a work area to get correct
+ * and the elements much be memcpy'd out into a work area to get correct
* alignment for the inode number fields.
*/
typedef struct xfs_dir_shortform {
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index f67497d78935..fd1ae9b156b1 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -94,7 +94,7 @@ xfs_qm_dqinit(
#endif
} else {
/*
- * Only the q_core portion was bzeroed in dqreclaim_one().
+ * Only the q_core portion was zeroed in dqreclaim_one().
* So, we need to reset others.
*/
dqp->q_nrefs = 0;
@@ -156,7 +156,7 @@ xfs_qm_dqinit_core(
xfs_dqblk_t *d)
{
/*
- * Caller has bzero'd the entire dquot 'chunk' already.
+ * Caller has zero'd the entire dquot 'chunk' already.
*/
INT_SET(d->dd_diskdq.d_magic, ARCH_CONVERT, XFS_DQUOT_MAGIC);
INT_SET(d->dd_diskdq.d_version, ARCH_CONVERT, XFS_DQUOT_VERSION);
@@ -351,7 +351,7 @@ xfs_qm_init_dquot_blk(
*/
curid = id - (id % XFS_QM_DQPERBLK(mp));
ASSERT(curid >= 0);
- bzero(d, BBTOB(XFS_QI_DQCHUNKLEN(mp)));
+ memset(d, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)));
for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++)
xfs_qm_dqinit_core(curid, type, d);
xfs_trans_dquot_buf(tp, bp,
@@ -614,7 +614,7 @@ xfs_qm_dqread(
}
/* copy everything from disk dquot to the incore dquot */
- bcopy(ddqp, &dqp->q_core, sizeof(xfs_disk_dquot_t));
+ memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));
ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id);
xfs_qm_dquot_logitem_init(dqp);
@@ -1209,7 +1209,7 @@ xfs_qm_dqflush(
}
/* This is the only portion of data that needs to persist */
- bcopy(&(dqp->q_core), ddqp, sizeof(xfs_disk_dquot_t));
+ memcpy(ddqp, &(dqp->q_core), sizeof(xfs_disk_dquot_t));
/*
* Clear the dirty field and remember the flush lsn for later use.
@@ -1475,7 +1475,7 @@ xfs_qm_dqpurge(
dqp->q_mount = NULL;;
dqp->q_hash = NULL;
dqp->dq_flags = XFS_DQ_INACTIVE;
- bzero(&dqp->q_core, sizeof(dqp->q_core));
+ memset(&dqp->q_core, 0, sizeof(dqp->q_core));
xfs_dqfunlock(dqp);
xfs_dqunlock(dqp);
XFS_DQ_HASH_UNLOCK(thishash);
@@ -1585,7 +1585,7 @@ xfs_qm_dqcheck(
*/
ASSERT(id != -1);
ASSERT(flags & XFS_QMOPT_DQREPAIR);
- bzero(ddq, sizeof(xfs_dqblk_t));
+ memset(ddq, 0, sizeof(xfs_dqblk_t));
xfs_qm_dqinit_core(id, type, (xfs_dqblk_t *)ddq);
return (errs);
}
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index b5ceb0316aba..823aa2913e75 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -69,9 +69,9 @@ char * xfs_etest_fsname[XFS_NUM_INJECT_ERROR];
void
xfs_error_test_init(void)
{
- bzero(xfs_etest, sizeof(xfs_etest));
- bzero(xfs_etest_fsid, sizeof(xfs_etest_fsid));
- bzero(xfs_etest_fsname, sizeof(xfs_etest_fsname));
+ memset(xfs_etest, 0, sizeof(xfs_etest));
+ memset(xfs_etest_fsid, 0, sizeof(xfs_etest_fsid));
+ memset(xfs_etest_fsname, 0, sizeof(xfs_etest_fsname));
}
int
@@ -84,12 +84,12 @@ xfs_error_test(int error_tag, int *fsidp, char *expression,
if (random() % randfactor)
return 0;
- bcopy(fsidp, &fsid, sizeof(fsid_t));
+ memcpy(&fsid, fsidp, sizeof(fsid_t));
for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
if (xfs_etest[i] == error_tag && xfs_etest_fsid[i] == fsid) {
cmn_err(CE_WARN,
- "Injecting error (%s) at file %s, line %d, on filesystem \"%s\"\n",
+ "Injecting error (%s) at file %s, line %d, on filesystem \"%s\"",
expression, file, line, xfs_etest_fsname[i]);
return 1;
}
@@ -105,7 +105,7 @@ xfs_errortag_add(int error_tag, xfs_mount_t *mp)
int len;
int64_t fsid;
- bcopy(mp->m_fixedfsid, &fsid, sizeof(fsid_t));
+ memcpy(&fsid, mp->m_fixedfsid, sizeof(fsid_t));
for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) {
@@ -138,7 +138,7 @@ xfs_errortag_clear(int error_tag, xfs_mount_t *mp)
int i;
int64_t fsid;
- bcopy(mp->m_fixedfsid, &fsid, sizeof(fsid_t));
+ memcpy(&fsid, mp->m_fixedfsid, sizeof(fsid_t));
for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) {
@@ -191,7 +191,7 @@ xfs_errortag_clearall(xfs_mount_t *mp)
{
int64_t fsid;
- bcopy(mp->m_fixedfsid, &fsid, sizeof(fsid_t));
+ memcpy(&fsid, mp->m_fixedfsid, sizeof(fsid_t));
return xfs_errortag_clearall_umount(fsid, mp->m_fsname, 1);
}
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
index 7984d92618fd..0311d1258076 100644
--- a/fs/xfs/xfs_fs.h
+++ b/fs/xfs/xfs_fs.h
@@ -427,9 +427,9 @@ typedef struct xfs_handle {
- (char *) &(handle)) \
+ (handle).ha_fid.xfs_fid_len)
-#define XFS_HANDLE_CMP(h1, h2) bcmp(h1, h2, sizeof (xfs_handle_t))
+#define XFS_HANDLE_CMP(h1, h2) memcmp(h1, h2, sizeof(xfs_handle_t))
-#define FSHSIZE sizeof (fsid_t)
+#define FSHSIZE sizeof(fsid_t)
/*
@@ -498,13 +498,5 @@ typedef struct xfs_handle {
#define BTOBB(bytes) (((__u64)(bytes) + BBSIZE - 1) >> BBSHIFT)
#define BTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT)
#define BBTOB(bbs) ((bbs) << BBSHIFT)
-#define OFFTOBB(bytes) (((__u64)(bytes) + BBSIZE - 1) >> BBSHIFT)
-#define OFFTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT)
-#define BBTOOFF(bbs) ((__u64)(bbs) << BBSHIFT)
-
-#define SEEKLIMIT32 0x7fffffff
-#define BBSEEKLIMIT32 BTOBBT(SEEKLIMIT32)
-#define SEEKLIMIT 0x7fffffffffffffffLL
-#define BBSEEKLIMIT OFFTOBBT(SEEKLIMIT)
#endif /* _LINUX_XFS_FS_H */
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 4cd53ed2d791..aac21b2532a6 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -149,7 +149,7 @@ xfs_growfs_data_private(
sizeof(xfs_perag_t) * nagcount,
sizeof(xfs_perag_t) * oagcount,
KM_SLEEP);
- bzero(&mp->m_perag[oagcount],
+ memset(&mp->m_perag[oagcount], 0,
(nagcount - oagcount) * sizeof(xfs_perag_t));
mp->m_flags |= XFS_MOUNT_32BITINODES;
xfs_initialize_perag(mp, nagcount);
@@ -175,7 +175,7 @@ xfs_growfs_data_private(
disk_addr,
sectbb, 0);
agf = XFS_BUF_TO_AGF(bp);
- bzero(agf, mp->m_sb.sb_sectsize);
+ memset(agf, 0, mp->m_sb.sb_sectsize);
INT_SET(agf->agf_magicnum, ARCH_CONVERT, XFS_AGF_MAGIC);
INT_SET(agf->agf_versionnum, ARCH_CONVERT, XFS_AGF_VERSION);
INT_SET(agf->agf_seqno, ARCH_CONVERT, agno);
@@ -208,7 +208,7 @@ xfs_growfs_data_private(
disk_addr,
sectbb, 0);
agi = XFS_BUF_TO_AGI(bp);
- bzero(agi, mp->m_sb.sb_sectsize);
+ memset(agi, 0, mp->m_sb.sb_sectsize);
INT_SET(agi->agi_magicnum, ARCH_CONVERT, XFS_AGI_MAGIC);
INT_SET(agi->agi_versionnum, ARCH_CONVERT, XFS_AGI_VERSION);
INT_SET(agi->agi_seqno, ARCH_CONVERT, agno);
@@ -233,7 +233,7 @@ xfs_growfs_data_private(
disk_addr,
BTOBB(bsize), 0);
block = XFS_BUF_TO_SBLOCK(bp);
- bzero(block, bsize);
+ memset(block, 0, bsize);
INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTB_MAGIC);
INT_ZERO(block->bb_level, ARCH_CONVERT);
INT_SET(block->bb_numrecs, ARCH_CONVERT, 1);
@@ -255,7 +255,7 @@ xfs_growfs_data_private(
disk_addr,
BTOBB(bsize), 0);
block = XFS_BUF_TO_SBLOCK(bp);
- bzero(block, bsize);
+ memset(block, 0, bsize);
INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTC_MAGIC);
INT_ZERO(block->bb_level, ARCH_CONVERT);
INT_SET(block->bb_numrecs, ARCH_CONVERT, 1);
@@ -278,7 +278,7 @@ xfs_growfs_data_private(
disk_addr,
BTOBB(bsize), 0);
block = XFS_BUF_TO_SBLOCK(bp);
- bzero(block, bsize);
+ memset(block, 0, bsize);
INT_SET(block->bb_magic, ARCH_CONVERT, XFS_IBT_MAGIC);
INT_ZERO(block->bb_level, ARCH_CONVERT);
INT_ZERO(block->bb_numrecs, ARCH_CONVERT);
@@ -353,7 +353,7 @@ xfs_growfs_data_private(
sectbb, 0, &bp);
if (error) {
xfs_fs_cmn_err(CE_WARN, mp,
- "error %d reading secondary superblock for ag %d\n",
+ "error %d reading secondary superblock for ag %d",
error, agno);
break;
}
@@ -368,7 +368,7 @@ xfs_growfs_data_private(
continue;
} else {
xfs_fs_cmn_err(CE_WARN, mp,
- "write error %d updating secondary superblock for ag %d\n",
+ "write error %d updating secondary superblock for ag %d",
error, agno);
break; /* no point in continuing */
}
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
index 185e62f08c70..b8f68d7c3605 100644
--- a/fs/xfs/xfs_ialloc.c
+++ b/fs/xfs/xfs_ialloc.c
@@ -263,7 +263,7 @@ xfs_ialloc_ag_alloc(
INT_ZERO(dic.di_gid, ARCH_CONVERT);
INT_ZERO(dic.di_nlink, ARCH_CONVERT);
INT_ZERO(dic.di_projid, ARCH_CONVERT);
- bzero(&(dic.di_pad[0]),sizeof(dic.di_pad));
+ memset(&(dic.di_pad[0]), 0, sizeof(dic.di_pad));
INT_SET(dic.di_atime.t_sec, ARCH_CONVERT, ztime.t_sec);
INT_SET(dic.di_atime.t_nsec, ARCH_CONVERT, ztime.t_nsec);
@@ -287,7 +287,7 @@ xfs_ialloc_ag_alloc(
for (i = 0; i < ninodes; i++) {
free = XFS_MAKE_IPTR(args.mp, fbuf, i);
- bcopy (&dic, &(free->di_core), sizeof(xfs_dinode_core_t));
+ memcpy(&(free->di_core), &dic, sizeof(xfs_dinode_core_t));
INT_SET(free->di_next_unlinked, ARCH_CONVERT, NULLAGINO);
xfs_ialloc_log_di(tp, fbuf, i,
XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED);
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c
index 0feaf85a5455..bded6cfd75f3 100644
--- a/fs/xfs/xfs_ialloc_btree.c
+++ b/fs/xfs/xfs_ialloc_btree.c
@@ -139,9 +139,9 @@ xfs_inobt_delrec(
}
#endif
if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) {
- ovbcopy(&kp[ptr], &kp[ptr - 1],
+ memmove(&kp[ptr - 1], &kp[ptr],
(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*kp));
- ovbcopy(&pp[ptr], &pp[ptr - 1],
+ memmove(&pp[ptr - 1], &pp[ptr],
(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*pp));
xfs_inobt_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
xfs_inobt_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
@@ -154,7 +154,7 @@ xfs_inobt_delrec(
else {
rp = XFS_INOBT_REC_ADDR(block, 1, cur);
if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) {
- ovbcopy(&rp[ptr], &rp[ptr - 1],
+ memmove(&rp[ptr - 1], &rp[ptr],
(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*rp));
xfs_inobt_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
}
@@ -450,8 +450,8 @@ xfs_inobt_delrec(
return error;
}
#endif
- bcopy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp));
- bcopy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp));
+ memcpy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp));
+ memcpy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp));
xfs_inobt_log_keys(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT));
xfs_inobt_log_ptrs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
@@ -462,7 +462,7 @@ xfs_inobt_delrec(
*/
lrp = XFS_INOBT_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur);
rrp = XFS_INOBT_REC_ADDR(right, 1, cur);
- bcopy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp));
+ memcpy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp));
xfs_inobt_log_recs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT));
}
@@ -690,9 +690,9 @@ xfs_inobt_insrec(
return error;
}
#endif
- ovbcopy(&kp[ptr - 1], &kp[ptr],
+ memmove(&kp[ptr], &kp[ptr - 1],
(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*kp));
- ovbcopy(&pp[ptr - 1], &pp[ptr],
+ memmove(&pp[ptr], &pp[ptr - 1],
(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*pp));
/*
* Now stuff the new data in, bump numrecs and log the new data.
@@ -711,7 +711,7 @@ xfs_inobt_insrec(
* It's a leaf entry. Make a hole for the new record.
*/
rp = XFS_INOBT_REC_ADDR(block, 1, cur);
- ovbcopy(&rp[ptr - 1], &rp[ptr],
+ memmove(&rp[ptr], &rp[ptr - 1],
(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*rp));
/*
* Now stuff the new record in, bump numrecs
@@ -1170,12 +1170,12 @@ xfs_inobt_lshift(
return error;
}
#endif
- ovbcopy(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
- ovbcopy(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+ memmove(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+ memmove(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
xfs_inobt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
xfs_inobt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
} else {
- ovbcopy(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+ memmove(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
key.ir_startino = rrp->ir_startino; /* INT_: direct copy */
rkp = &key;
@@ -1421,8 +1421,8 @@ xfs_inobt_rshift(
return error;
}
#endif
- ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
- ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+ memmove(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+ memmove(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
#ifdef DEBUG
if ((error = xfs_btree_check_sptr(cur, INT_GET(*lpp, ARCH_CONVERT), level)))
return error;
@@ -1434,7 +1434,7 @@ xfs_inobt_rshift(
} else {
lrp = XFS_INOBT_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur);
rrp = XFS_INOBT_REC_ADDR(right, 1, cur);
- ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+ memmove(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
*rrp = *lrp;
xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1);
key.ir_startino = rrp->ir_startino; /* INT_: direct copy */
@@ -1562,8 +1562,8 @@ xfs_inobt_split(
return error;
}
#endif
- bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
- bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+ memcpy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+ memcpy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
xfs_inobt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
xfs_inobt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
*keyp = *rkp;
@@ -1574,7 +1574,7 @@ xfs_inobt_split(
else {
lrp = XFS_INOBT_REC_ADDR(left, i, cur);
rrp = XFS_INOBT_REC_ADDR(right, 1, cur);
- bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+ memcpy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
keyp->ir_startino = rrp->ir_startino; /* INT_: direct copy */
}
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index 7a8b02b39557..52c1b10c2afd 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -31,6 +31,7 @@
*/
#include <xfs.h>
+#include <linux/pagemap.h>
/*
@@ -109,25 +110,36 @@ xfs_chash_free(xfs_mount_t *mp)
mp->m_chash = NULL;
}
-
-static inline void
-xfs_iget_vnode_init(
+void
+xfs_revalidate_inode(
xfs_mount_t *mp,
vnode_t *vp,
xfs_inode_t *ip)
{
- vp->v_vfsp = XFS_MTOVFS(mp);
- vp->v_type = IFTOVT(ip->i_d.di_mode);
+ struct inode *inode = LINVFS_GET_IP(vp);
- /* If we have a real type for an on-disk inode, we can set ops(&unlock)
- * now. If it's a new inode being created, xfs_ialloc will handle it.
- */
- if (vp->v_type != VNON) {
- linvfs_set_inode_ops(LINVFS_GET_IP(vp));
+ inode->i_mode = (ip->i_d.di_mode & MODEMASK) | VTTOIF(vp->v_type);
+ inode->i_nlink = ip->i_d.di_nlink;
+ inode->i_uid = ip->i_d.di_uid;
+ inode->i_gid = ip->i_d.di_gid;
+ if (((1 << vp->v_type) & ((1<<VBLK) | (1<<VCHR))) == 0) {
+ inode->i_rdev = NODEV;
+ } else {
+ xfs_dev_t dev = ip->i_df.if_u2.if_rdev;
+ inode->i_rdev = XFS_DEV_TO_KDEVT(dev);
}
+ inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_generation = ip->i_d.di_gen;
+ inode->i_size = ip->i_d.di_size;
+ inode->i_blocks =
+ XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks);
+ inode->i_atime = ip->i_d.di_atime.t_sec;
+ inode->i_mtime = ip->i_d.di_mtime.t_sec;
+ inode->i_ctime = ip->i_d.di_ctime.t_sec;
+
+ vp->v_flag &= ~VMODIFIED;
}
-
/*
* Look up an inode by number in the given file system.
* The inode is looked up in the hash table for the file system
@@ -159,7 +171,7 @@ xfs_iget_vnode_init(
* bno -- the block number starting the buffer containing the inode,
* if known (as by bulkstat), else 0.
*/
-int
+STATIC int
xfs_iget_core(
vnode_t *vp,
xfs_mount_t *mp,
@@ -205,16 +217,9 @@ again:
goto again;
}
- xfs_iget_vnode_init(mp, vp, ip);
-
vn_trace_exit(vp, "xfs_iget.alloc",
(inst_t *)__return_address);
- bhv_desc_init(&(ip->i_bhv_desc), ip, vp,
- &xfs_vnodeops);
- vn_bhv_insert_initial(VN_BHV_HEAD(vp),
- &(ip->i_bhv_desc));
-
XFS_STATS_INC(xfsstats.xs_ig_found);
read_unlock(&ih->ih_lock);
@@ -240,18 +245,12 @@ again:
cmn_err(CE_PANIC,
"xfs_iget_core: ambiguous vns: vp/0x%p, invp/0x%p",
inode_vp, vp);
- BUG();
}
read_unlock(&ih->ih_lock);
XFS_STATS_INC(xfsstats.xs_ig_found);
- /*
- * Make sure the vnode and the inode are hooked up
- */
- xfs_iget_vnode_init(mp, vp, ip);
-
finish_inode:
if (lock_flags != 0) {
xfs_ilock(ip, lock_flags);
@@ -288,19 +287,8 @@ finish_inode:
return error;
}
- /*
- * Vnode provided by vn_initialize.
- */
-
- xfs_iget_vnode_init(mp, vp, ip);
-
vn_trace_exit(vp, "xfs_iget.alloc", (inst_t *)__return_address);
- if (vp->v_fbhv == NULL) {
- bhv_desc_init(&(ip->i_bhv_desc), ip, vp, &xfs_vnodeops);
- vn_bhv_insert_initial(VN_BHV_HEAD(vp), &(ip->i_bhv_desc));
- }
-
xfs_inode_lock_init(ip, vp);
xfs_iocore_inode_init(ip);
@@ -429,8 +417,11 @@ finish_inode:
*ipp = ip;
- /* Update the linux inode */
- error = vn_revalidate(vp, ATTR_COMM|ATTR_LAZY);
+ /*
+ * If we have a real type for an on-disk inode, we can set ops(&unlock)
+ * now. If it's a new inode being created, xfs_ialloc will handle it.
+ */
+ VFS_INIT_VNODE(XFS_MTOVFS(mp), vp, XFS_ITOBHV(ip), 1);
return 0;
}
@@ -495,7 +486,6 @@ inode_allocate:
newnode = (ip->i_d.di_mode == 0);
if (newnode)
xfs_iocore_inode_reinit(ip);
- vn_revalidate(vp, ATTR_COMM|ATTR_LAZY);
XFS_STATS_INC(xfsstats.xs_ig_found);
*ipp = ip;
error = 0;
@@ -506,7 +496,6 @@ inode_allocate:
return error;
}
-
/*
* Do the setup for the various locks within the incore inode.
*/
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index f7c35e754899..bd343063b60d 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -56,8 +56,9 @@ STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int);
*/
STATIC void
xfs_validate_extents(
- xfs_bmbt_rec_32_t *ep,
+ xfs_bmbt_rec_t *ep,
int nrecs,
+ int disk,
xfs_exntfmt_t fmt)
{
xfs_bmbt_irec_t irec;
@@ -65,15 +66,18 @@ xfs_validate_extents(
xfs_bmbt_rec_t rec;
for (i = 0; i < nrecs; i++) {
- bcopy(ep, &rec, sizeof(rec));
- xfs_bmbt_get_all(&rec, &irec);
+ memcpy(&rec, ep, sizeof(rec));
+ if (disk)
+ xfs_bmbt_disk_get_all(&rec, &irec);
+ else
+ xfs_bmbt_get_all(&rec, &irec);
if (fmt == XFS_EXTFMT_NOSTATE)
ASSERT(irec.br_state == XFS_EXT_NORM);
ep++;
}
}
#else /* DEBUG */
-#define xfs_validate_extents(ep, nrecs, fmt)
+#define xfs_validate_extents(ep, nrecs, disk, fmt)
#endif /* DEBUG */
/*
@@ -551,7 +555,7 @@ xfs_iformat_local(
/*
* If the size is unreasonable, then something
* is wrong and we just bail out rather than crash in
- * kmem_alloc() or bcopy() below.
+ * kmem_alloc() or memcpy() below.
*/
if (size > XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)) {
xfs_fs_cmn_err(CE_WARN, ip->i_mount,
@@ -575,7 +579,8 @@ xfs_iformat_local(
ifp->if_bytes = size;
ifp->if_real_bytes = real_size;
if (size)
- bcopy(XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), ifp->if_u1.if_data, size);
+ memcpy(ifp->if_u1.if_data,
+ XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), size);
ifp->if_flags &= ~XFS_IFEXTENTS;
ifp->if_flags |= XFS_IFINLINE;
return 0;
@@ -597,9 +602,10 @@ xfs_iformat_extents(
int whichfork)
{
xfs_ifork_t *ifp;
- int nex;
+ int nex, i;
int real_size;
int size;
+ xfs_bmbt_rec_t *ep, *dp;
ifp = XFS_IFORK_PTR(ip, whichfork);
nex = XFS_DFORK_NEXTENTS_ARCH(dip, whichfork, ARCH_CONVERT);
@@ -608,7 +614,7 @@ xfs_iformat_extents(
/*
* If the number of extents is unreasonable, then something
* is wrong and we just bail out rather than crash in
- * kmem_alloc() or bcopy() below.
+ * kmem_alloc() or memcpy() below.
*/
if (size < 0 || size > XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)) {
xfs_fs_cmn_err(CE_WARN, ip->i_mount,
@@ -632,10 +638,18 @@ xfs_iformat_extents(
ifp->if_real_bytes = real_size;
if (size) {
xfs_validate_extents(
- (xfs_bmbt_rec_32_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT),
- nex, XFS_EXTFMT_INODE(ip));
- bcopy(XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), ifp->if_u1.if_extents,
- size);
+ (xfs_bmbt_rec_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT),
+ nex, 1, XFS_EXTFMT_INODE(ip));
+ dp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT);
+ ep = ifp->if_u1.if_extents;
+#if ARCH_CONVERT != ARCH_NOCONVERT
+ for (i = 0; i < nex; i++, ep++, dp++) {
+ ep->l0 = INT_GET(dp->l0, ARCH_CONVERT);
+ ep->l1 = INT_GET(dp->l1, ARCH_CONVERT);
+ }
+#else
+ memcpy(ep, dp, size);
+#endif
xfs_bmap_trace_exlist("xfs_iformat_extents", ip, nex,
whichfork);
if (whichfork != XFS_DATA_FORK ||
@@ -731,9 +745,9 @@ xfs_xlate_dinode_core(xfs_caddr_t buf, xfs_dinode_core_t *dip,
if (arch == ARCH_NOCONVERT) {
if (dir>0) {
- bcopy((xfs_caddr_t)buf_core, (xfs_caddr_t)mem_core, sizeof(xfs_dinode_core_t));
+ memcpy((xfs_caddr_t)mem_core, (xfs_caddr_t)buf_core, sizeof(xfs_dinode_core_t));
} else {
- bcopy((xfs_caddr_t)mem_core, (xfs_caddr_t)buf_core, sizeof(xfs_dinode_core_t));
+ memcpy((xfs_caddr_t)buf_core, (xfs_caddr_t)mem_core, sizeof(xfs_dinode_core_t));
}
return;
}
@@ -749,9 +763,9 @@ xfs_xlate_dinode_core(xfs_caddr_t buf, xfs_dinode_core_t *dip,
INT_XLATE(buf_core->di_projid, mem_core->di_projid, dir, arch);
if (dir>0) {
- bcopy(buf_core->di_pad, mem_core->di_pad, sizeof(buf_core->di_pad));
+ memcpy(mem_core->di_pad, buf_core->di_pad, sizeof(buf_core->di_pad));
} else {
- bcopy(mem_core->di_pad, buf_core->di_pad, sizeof(buf_core->di_pad));
+ memcpy(buf_core->di_pad, mem_core->di_pad, sizeof(buf_core->di_pad));
}
INT_XLATE(buf_core->di_atime.t_sec, mem_core->di_atime.t_sec, dir, arch);
@@ -978,8 +992,8 @@ xfs_iread_extents(
ifp->if_flags &= ~XFS_IFEXTENTS;
return error;
}
- xfs_validate_extents((xfs_bmbt_rec_32_t *)ifp->if_u1.if_extents,
- XFS_IFORK_NEXTENTS(ip, whichfork), XFS_EXTFMT_INODE(ip));
+ xfs_validate_extents((xfs_bmbt_rec_t *)ifp->if_u1.if_extents,
+ XFS_IFORK_NEXTENTS(ip, whichfork), 0, XFS_EXTFMT_INODE(ip));
return 0;
}
@@ -1015,7 +1029,7 @@ xfs_ialloc(
xfs_inode_t *pip,
mode_t mode,
nlink_t nlink,
- dev_t rdev,
+ xfs_dev_t rdev,
cred_t *cr,
xfs_prid_t prid,
int okalloc,
@@ -1065,10 +1079,7 @@ xfs_ialloc(
ip->i_d.di_uid = current->fsuid;
ip->i_d.di_gid = current->fsgid;
ip->i_d.di_projid = prid;
- bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad));
-
- /* now that we have a v_type we can set Linux inode ops (& unlock) */
- linvfs_set_inode_ops(LINVFS_GET_IP(XFS_ITOV(ip)));
+ memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
/*
* If the superblock version is up to where we support new format
@@ -1100,14 +1111,13 @@ xfs_ialloc(
/*
* If the group ID of the new file does not match the effective group
- * ID or one of the supplementary group IDs, the ISGID bit is
- * cleared if the "irixsgid" mount option is set.
+ * ID or one of the supplementary group IDs, the ISGID bit is cleared
+ * (and only if the irix_sgid_inherit compatibility variable is set).
*/
- if (ip->i_d.di_mode & ISGID) {
- if (!in_group_p((gid_t)ip->i_d.di_gid)
- && (ip->i_mount->m_flags & XFS_MOUNT_IRIXSGID)) {
- ip->i_d.di_mode &= ~ISGID;
- }
+ if ((irix_sgid_inherit) &&
+ (ip->i_d.di_mode & ISGID) &&
+ (!in_group_p((gid_t)ip->i_d.di_gid))) {
+ ip->i_d.di_mode &= ~ISGID;
}
ip->i_d.di_size = 0;
@@ -1128,7 +1138,7 @@ xfs_ialloc(
case IFBLK:
case IFSOCK:
ip->i_d.di_format = XFS_DINODE_FMT_DEV;
- ip->i_df.if_u2.if_rdev = IRIX_MKDEV(MAJOR(rdev), MINOR(rdev));
+ ip->i_df.if_u2.if_rdev = rdev;
ip->i_df.if_flags = 0;
flags |= XFS_ILOG_DEV;
break;
@@ -1172,6 +1182,10 @@ xfs_ialloc(
* Log the new values stuffed into the inode.
*/
xfs_trans_log_inode(tp, ip, flags);
+
+ /* now that we have a v_type we can set Linux inode ops (& unlock) */
+ VFS_INIT_VNODE(XFS_MTOVFS(tp->t_mountp), vp, XFS_ITOBHV(ip), 1);
+
*ipp = ip;
return 0;
}
@@ -1714,7 +1728,7 @@ xfs_igrow_start(
* and any blocks between the old and new file sizes.
*/
error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size, isize,
- new_size, NULL);
+ new_size);
return error;
}
@@ -2156,7 +2170,7 @@ xfs_iroot_realloc(
ifp->if_broot_bytes = (int)new_size;
ASSERT(ifp->if_broot_bytes <=
XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ);
- ovbcopy(op, np, cur_max * (uint)sizeof(xfs_dfsbno_t));
+ memmove(np, op, cur_max * (uint)sizeof(xfs_dfsbno_t));
return;
}
@@ -2178,7 +2192,7 @@ xfs_iroot_realloc(
/*
* First copy over the btree block header.
*/
- bcopy(ifp->if_broot, new_broot, sizeof(xfs_bmbt_block_t));
+ memcpy(new_broot, ifp->if_broot, sizeof(xfs_bmbt_block_t));
} else {
new_broot = NULL;
ifp->if_flags &= ~XFS_IFBROOT;
@@ -2195,7 +2209,7 @@ xfs_iroot_realloc(
ifp->if_broot_bytes);
np = (char *)XFS_BMAP_BROOT_REC_ADDR(new_broot, 1,
(int)new_size);
- bcopy(op, np, new_max * (uint)sizeof(xfs_bmbt_rec_t));
+ memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t));
/*
* Then copy the pointers.
@@ -2204,7 +2218,7 @@ xfs_iroot_realloc(
ifp->if_broot_bytes);
np = (char *)XFS_BMAP_BROOT_PTR_ADDR(new_broot, 1,
(int)new_size);
- bcopy(op, np, new_max * (uint)sizeof(xfs_dfsbno_t));
+ memcpy(np, op, new_max * (uint)sizeof(xfs_dfsbno_t));
}
kmem_free(ifp->if_broot, ifp->if_broot_bytes);
ifp->if_broot = new_broot;
@@ -2268,8 +2282,8 @@ xfs_iext_realloc(
* so the if_extents pointer is null.
*/
if (ifp->if_u1.if_extents) {
- bcopy(ifp->if_u1.if_extents,
- ifp->if_u2.if_inline_ext, new_size);
+ memcpy(ifp->if_u2.if_inline_ext,
+ ifp->if_u1.if_extents, new_size);
kmem_free(ifp->if_u1.if_extents,
ifp->if_real_bytes);
}
@@ -2286,7 +2300,7 @@ xfs_iext_realloc(
if (ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext) {
ifp->if_u1.if_extents = (xfs_bmbt_rec_t *)
kmem_alloc(rnew_size, KM_SLEEP);
- bcopy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents,
+ memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext,
sizeof(ifp->if_u2.if_inline_ext));
} else if (rnew_size != ifp->if_real_bytes) {
ifp->if_u1.if_extents = (xfs_bmbt_rec_t *)
@@ -2349,7 +2363,7 @@ xfs_idata_realloc(
ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
} else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
ASSERT(ifp->if_real_bytes != 0);
- bcopy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data,
+ memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data,
new_size);
kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes);
ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
@@ -2382,8 +2396,8 @@ xfs_idata_realloc(
} else {
ASSERT(ifp->if_real_bytes == 0);
ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
- bcopy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data,
- ifp->if_bytes);
+ memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data,
+ ifp->if_bytes);
}
}
ifp->if_real_bytes = real_size;
@@ -2610,17 +2624,17 @@ xfs_iunpin_wait(
* returns the number of bytes copied into the buffer.
*
* If there are no delayed allocation extents, then we can just
- * bcopy() the extents into the buffer. Otherwise, we need to
+ * memcpy() the extents into the buffer. Otherwise, we need to
* examine each extent in turn and skip those which are delayed.
*/
int
xfs_iextents_copy(
xfs_inode_t *ip,
- xfs_bmbt_rec_32_t *buffer,
+ xfs_bmbt_rec_t *buffer,
int whichfork)
{
int copied;
- xfs_bmbt_rec_32_t *dest_ep;
+ xfs_bmbt_rec_t *dest_ep;
xfs_bmbt_rec_t *ep;
#ifdef XFS_BMAP_TRACE
static char fname[] = "xfs_iextents_copy";
@@ -2637,28 +2651,13 @@ xfs_iextents_copy(
nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
xfs_bmap_trace_exlist(fname, ip, nrecs, whichfork);
ASSERT(nrecs > 0);
- if (nrecs == XFS_IFORK_NEXTENTS(ip, whichfork)) {
- /*
- * There are no delayed allocation extents,
- * so just copy everything.
- */
- ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
- ASSERT(ifp->if_bytes ==
- (XFS_IFORK_NEXTENTS(ip, whichfork) *
- (uint)sizeof(xfs_bmbt_rec_t)));
- bcopy(ifp->if_u1.if_extents, buffer, ifp->if_bytes);
- xfs_validate_extents(buffer, nrecs, XFS_EXTFMT_INODE(ip));
- return ifp->if_bytes;
- }
- ASSERT(whichfork == XFS_DATA_FORK);
/*
* There are some delayed allocation extents in the
* inode, so copy the extents one at a time and skip
* the delayed ones. There must be at least one
* non-delayed extent.
*/
- ASSERT(nrecs > ip->i_d.di_nextents);
ep = ifp->if_u1.if_extents;
dest_ep = buffer;
copied = 0;
@@ -2672,15 +2671,19 @@ xfs_iextents_copy(
continue;
}
- *dest_ep = *(xfs_bmbt_rec_32_t *)ep;
+#if ARCH_CONVERT != ARCH_NOCONVERT
+ /* Translate to on disk format */
+ dest_ep->l0 = INT_GET(ep->l0, ARCH_CONVERT);
+ dest_ep->l1 = INT_GET(ep->l1, ARCH_CONVERT);
+#else
+ *dest_ep = *ep;
+#endif
dest_ep++;
ep++;
copied++;
}
ASSERT(copied != 0);
- ASSERT(copied == ip->i_d.di_nextents);
- ASSERT((copied * (uint)sizeof(xfs_bmbt_rec_t)) <= XFS_IFORK_DSIZE(ip));
- xfs_validate_extents(buffer, copied, XFS_EXTFMT_INODE(ip));
+ xfs_validate_extents(buffer, copied, 1, XFS_EXTFMT_INODE(ip));
return (copied * (uint)sizeof(xfs_bmbt_rec_t));
}
@@ -2736,7 +2739,7 @@ xfs_iflush_fork(
(ifp->if_bytes > 0)) {
ASSERT(ifp->if_u1.if_data != NULL);
ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
- bcopy(ifp->if_u1.if_data, cp, ifp->if_bytes);
+ memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes);
}
if (whichfork == XFS_DATA_FORK) {
if (XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp, dip)) {
@@ -2753,7 +2756,7 @@ xfs_iflush_fork(
if ((iip->ili_format.ilf_fields & extflag[whichfork]) &&
(ifp->if_bytes > 0)) {
ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0);
- (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_32_t *)cp,
+ (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp,
whichfork);
}
break;
@@ -2781,7 +2784,7 @@ xfs_iflush_fork(
case XFS_DINODE_FMT_UUID:
if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) {
ASSERT(whichfork == XFS_DATA_FORK);
- bcopy(&ip->i_df.if_u2.if_uuid, &dip->di_u.di_muuid,
+ memcpy(&dip->di_u.di_muuid, &ip->i_df.if_u2.if_uuid,
sizeof(uuid_t));
}
break;
@@ -3208,8 +3211,8 @@ xfs_iflush_int(
INT_SET(dip->di_core.di_version, ARCH_CONVERT, XFS_DINODE_VERSION_2);
ip->i_d.di_onlink = 0;
INT_ZERO(dip->di_core.di_onlink, ARCH_CONVERT);
- bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad));
- bzero(&(dip->di_core.di_pad[0]),
+ memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
+ memset(&(dip->di_core.di_pad[0]), 0,
sizeof(dip->di_core.di_pad));
ASSERT(ip->i_d.di_projid == 0);
}
@@ -3377,7 +3380,7 @@ xfs_iflush_all(
* entry in the list anyway so we'll know below
* whether we reached the end or not.
*/
- VMAP(vp, ip, vmap);
+ VMAP(vp, vmap);
vp->v_flag |= VPURGE; /* OK for vn_purge */
XFS_MOUNT_IUNLOCK(mp);
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 308bc90d825f..38669ac946f0 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -98,7 +98,6 @@ struct xfs_inode_log_item;
struct xfs_mount;
struct xfs_trans;
struct xfs_dquot;
-struct pm;
/*
@@ -119,23 +118,6 @@ typedef struct xfs_gap {
xfs_extlen_t xg_count_fsb;
} xfs_gap_t;
-/*
- * This structure is used to hold common pieces of the buffer
- * and file for xfs_dio_write and xfs_dio_read.
- */
-typedef struct xfs_dio {
- struct xfs_buf *xd_bp;
- bhv_desc_t *xd_bdp;
- struct xfs_inode *xd_ip;
- struct xfs_iocore *xd_io;
- struct cred *xd_cr;
- struct pm *xd_pmp;
- int xd_blkalgn;
- int xd_ioflag;
- xfs_off_t xd_start;
- size_t xd_length;
-} xfs_dio_t;
-
typedef struct dm_attrs_s {
__uint32_t da_dmevmask; /* DMIG event mask */
__uint16_t da_dmstate; /* DMIG state info */
@@ -516,7 +498,7 @@ int xfs_iread(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
xfs_inode_t **, xfs_daddr_t);
int xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int);
int xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t, nlink_t,
- dev_t, struct cred *, xfs_prid_t, int,
+ xfs_dev_t, struct cred *, xfs_prid_t, int,
struct xfs_buf **, boolean_t *, xfs_inode_t **);
void xfs_xlate_dinode_core(xfs_caddr_t, struct xfs_dinode_core *, int,
xfs_arch_t);
@@ -538,7 +520,7 @@ void xfs_iext_realloc(xfs_inode_t *, int, int);
void xfs_iroot_realloc(xfs_inode_t *, int, int);
void xfs_ipin(xfs_inode_t *);
void xfs_iunpin(xfs_inode_t *);
-int xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_32_t *, int);
+int xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_t *, int);
int xfs_iflush(xfs_inode_t *, uint);
int xfs_iflush_all(struct xfs_mount *, int);
int xfs_ibusy_check(xfs_inode_t *, int);
@@ -550,7 +532,7 @@ void xfs_lock_inodes(xfs_inode_t **, int, int, uint);
#define xfs_ipincount(ip) ((unsigned int) atomic_read(&ip->i_pincount))
-
+void xfs_revalidate_inode(struct xfs_mount *, vnode_t *vp, xfs_inode_t *);
#ifdef DEBUG
void xfs_isize_check(struct xfs_mount *, xfs_inode_t *, xfs_fsize_t);
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 9beacce25dec..d23d596d7973 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -96,7 +96,7 @@ xfs_inode_item_size(
if (iip->ili_root_size > 0) {
ASSERT(iip->ili_root_size ==
ip->i_df.if_broot_bytes);
- ASSERT(bcmp(iip->ili_orig_root,
+ ASSERT(memcmp(iip->ili_orig_root,
ip->i_df.if_broot,
iip->ili_root_size) == 0);
} else {
@@ -214,7 +214,7 @@ xfs_inode_item_format(
xfs_log_iovec_t *vecp;
xfs_inode_t *ip;
size_t data_bytes;
- xfs_bmbt_rec_32_t *ext_buffer;
+ xfs_bmbt_rec_t *ext_buffer;
int nrecs;
xfs_mount_t *mp;
@@ -297,7 +297,7 @@ xfs_inode_item_format(
*/
ip->i_d.di_version = XFS_DINODE_VERSION_2;
ip->i_d.di_onlink = 0;
- bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad));
+ memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
}
}
@@ -314,6 +314,7 @@ xfs_inode_item_format(
nrecs = ip->i_df.if_bytes /
(uint)sizeof(xfs_bmbt_rec_t);
ASSERT(nrecs > 0);
+#if ARCH_CONVERT == ARCH_NOCONVERT
if (nrecs == ip->i_d.di_nextents) {
/*
* There are no delayed allocation
@@ -323,10 +324,14 @@ xfs_inode_item_format(
vecp->i_addr =
(char *)(ip->i_df.if_u1.if_extents);
vecp->i_len = ip->i_df.if_bytes;
- } else {
+ } else
+#endif
+ {
/*
* There are delayed allocation extents
- * in the inode. Use xfs_iextents_copy()
+ * in the inode, or we need to convert
+ * the extents to on disk format.
+ * Use xfs_iextents_copy()
* to copy only the real extents into
* a separate buffer. We'll free the
* buffer in the unlock routine.
@@ -336,7 +341,7 @@ xfs_inode_item_format(
iip->ili_extents_buf = ext_buffer;
vecp->i_addr = (xfs_caddr_t)ext_buffer;
vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
- XFS_DATA_FORK);
+ XFS_DATA_FORK);
}
ASSERT(vecp->i_len <= ip->i_df.if_bytes);
iip->ili_format.ilf_dsize = vecp->i_len;
@@ -428,6 +433,7 @@ xfs_inode_item_format(
ASSERT(!(iip->ili_format.ilf_fields &
(XFS_ILOG_ADATA | XFS_ILOG_ABROOT)));
if (iip->ili_format.ilf_fields & XFS_ILOG_AEXT) {
+ ASSERT(!(iip->ili_format.ilf_fields & XFS_ILOG_DEXT));
ASSERT(ip->i_afp->if_bytes > 0);
ASSERT(ip->i_afp->if_u1.if_extents != NULL);
ASSERT(ip->i_d.di_anextents > 0);
@@ -437,12 +443,25 @@ xfs_inode_item_format(
#endif
ASSERT(nrecs > 0);
ASSERT(nrecs == ip->i_d.di_anextents);
+#if ARCH_CONVERT == ARCH_NOCONVERT
/*
* There are not delayed allocation extents
* for attributes, so just point at the array.
*/
vecp->i_addr = (char *)(ip->i_afp->if_u1.if_extents);
vecp->i_len = ip->i_afp->if_bytes;
+#else
+ ASSERT(iip->ili_aextents_buf == NULL);
+ /*
+ * Need to endian flip before logging
+ */
+ ext_buffer = kmem_alloc(ip->i_df.if_bytes,
+ KM_SLEEP);
+ iip->ili_aextents_buf = ext_buffer;
+ vecp->i_addr = (xfs_caddr_t)ext_buffer;
+ vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
+ XFS_ATTR_FORK);
+#endif
iip->ili_format.ilf_asize = vecp->i_len;
vecp++;
nvecs++;
@@ -630,7 +649,6 @@ xfs_inode_item_unlock(
* If the inode needed a separate buffer with which to log
* its extents, then free it now.
*/
- /* FIXME */
if (iip->ili_extents_buf != NULL) {
ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS);
ASSERT(ip->i_d.di_nextents > 0);
@@ -639,6 +657,14 @@ xfs_inode_item_unlock(
kmem_free(iip->ili_extents_buf, ip->i_df.if_bytes);
iip->ili_extents_buf = NULL;
}
+ if (iip->ili_aextents_buf != NULL) {
+ ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS);
+ ASSERT(ip->i_d.di_anextents > 0);
+ ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_AEXT);
+ ASSERT(ip->i_afp->if_bytes > 0);
+ kmem_free(iip->ili_aextents_buf, ip->i_afp->if_bytes);
+ iip->ili_aextents_buf = NULL;
+ }
/*
* Figure out if we should unlock the inode or not.
@@ -889,7 +915,7 @@ xfs_inode_item_init(
iip->ili_inode = ip;
/*
- We have bzeroed memory. No need ...
+ We have zeroed memory. No need ...
iip->ili_extents_buf = NULL;
iip->ili_pushbuf_flag = 0;
*/
diff --git a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h
index d90407088842..4970205a5e69 100644
--- a/fs/xfs/xfs_inode_item.h
+++ b/fs/xfs/xfs_inode_item.h
@@ -141,7 +141,10 @@ typedef struct xfs_inode_log_item {
unsigned short ili_flags; /* misc flags */
unsigned short ili_logged; /* flushed logged data */
unsigned int ili_last_fields; /* fields when flushed */
- struct xfs_bmbt_rec_32 *ili_extents_buf; /* array of logged exts */
+ struct xfs_bmbt_rec_32 *ili_extents_buf; /* array of logged
+ data exts */
+ struct xfs_bmbt_rec_32 *ili_aextents_buf; /* array of logged
+ attr exts */
unsigned int ili_pushbuf_flag; /* one bit used in push_ail */
#ifdef DEBUG
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index d46f2ccf3844..8fe8097215df 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -146,7 +146,7 @@ xfs_bulkstat_one(
buf->bs_extsize = INT_GET(dic->di_extsize, arch) << mp->m_sb.sb_blocklog;
buf->bs_extents = INT_GET(dic->di_nextents, arch);
buf->bs_gen = INT_GET(dic->di_gen, arch);
- bzero(buf->bs_pad, sizeof(buf->bs_pad));
+ memset(buf->bs_pad, 0, sizeof(buf->bs_pad));
buf->bs_dmevmask = INT_GET(dic->di_dmevmask, arch);
buf->bs_dmstate = INT_GET(dic->di_dmstate, arch);
buf->bs_aextents = INT_GET(dic->di_anextents, arch);
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 942d07386d9e..d156b9cb7a7f 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -1586,8 +1586,8 @@ xlog_unalloc_log(xlog_t *log)
* 1. If first write of transaction, write start record
* 2. Write log operation header (header per region)
* 3. Find out if we can fit entire region into this iclog
- * 4. Potentially, verify destination bcopy ptr
- * 5. Bcopy (partial) region
+ * 4. Potentially, verify destination memcpy ptr
+ * 5. Memcpy (partial) region
* 6. If partial copy, release iclog; otherwise, continue
* copying more regions into current iclog
* 4. Mark want sync bit (in simulation mode)
@@ -1628,8 +1628,8 @@ xlog_write(xfs_mount_t * mp,
int start_rec_copy; /* # bytes to copy for start record */
int partial_copy; /* did we split a region? */
int partial_copy_len;/* # bytes copied if split region */
- int need_copy; /* # bytes need to bcopy this region */
- int copy_len; /* # bytes actually bcopy'ing */
+ int need_copy; /* # bytes need to memcpy this region */
+ int copy_len; /* # bytes actually memcpy'ing */
int copy_off; /* # bytes from entry start */
int contwr; /* continued write of in-core log? */
int firstwr = 0; /* first write of transaction */
@@ -1733,7 +1733,7 @@ xlog_write(xfs_mount_t * mp,
/* Partial write last time? => (partial_copy != 0)
* need_copy is the amount we'd like to copy if everything could
- * fit in the current bcopy.
+ * fit in the current memcpy.
*/
need_copy = reg[index].i_len - partial_copy_len;
@@ -1759,7 +1759,7 @@ xlog_write(xfs_mount_t * mp,
/* copy region */
ASSERT(copy_len >= 0);
- bcopy(reg[index].i_addr + copy_off, (xfs_caddr_t)ptr, copy_len);
+ memcpy((xfs_caddr_t)ptr, reg[index].i_addr + copy_off, copy_len);
xlog_write_adv_cnt(ptr, len, log_offset, copy_len);
/* make copy_len total bytes copied, including headers */
@@ -1836,7 +1836,7 @@ xlog_state_clean_log(xlog_t *log)
changed = 2;
}
INT_ZERO(iclog->ic_header.h_num_logops, ARCH_CONVERT);
- bzero(iclog->ic_header.h_cycle_data,
+ memset(iclog->ic_header.h_cycle_data, 0,
sizeof(iclog->ic_header.h_cycle_data));
INT_ZERO(iclog->ic_header.h_lsn, ARCH_CONVERT);
} else if (iclog->ic_state == XLOG_STATE_ACTIVE)
@@ -2064,7 +2064,7 @@ xlog_state_do_callback(
} while (first_iclog != iclog);
if (repeats && (repeats % 10) == 0) {
xfs_fs_cmn_err(CE_WARN, log->l_mp,
- "xlog_state_do_callback: looping %d\n", repeats);
+ "xlog_state_do_callback: looping %d", repeats);
}
} while (!ioerrors && loopdidcallbacks);
@@ -2155,20 +2155,13 @@ xlog_state_done_syncing(
iclog->ic_state = XLOG_STATE_DONE_SYNC;
}
- /*
- * Someone could be sleeping on the next iclog even though it is
- * in the ACTIVE state. We kick off one thread to force the
- * iclog buffer out.
- */
- if (iclog->ic_next->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR))
- sv_signal(&iclog->ic_next->ic_forcesema);
LOG_UNLOCK(log, s);
xlog_state_do_callback(log, aborted, iclog); /* also cleans log */
} /* xlog_state_done_syncing */
/*
- * Update counters atomically now that bcopy is done.
+ * Update counters atomically now that memcpy is done.
*/
/* ARGSUSED */
static inline void
@@ -2984,11 +2977,9 @@ xlog_state_sync(xlog_t *log,
uint flags)
{
xlog_in_core_t *iclog;
- int already_slept = 0;
SPLDECL(s);
-try_again:
s = LOG_LOCK(log);
iclog = log->l_iclog;
@@ -3009,39 +3000,12 @@ try_again:
}
if (iclog->ic_state == XLOG_STATE_ACTIVE) {
- /*
- * We sleep here if we haven't already slept (e.g.
- * this is the first time we've looked at the correct
- * iclog buf) and the buffer before us is going to
- * be sync'ed. We have to do that to ensure that the
- * log records go out in the proper order. When it's
- * done, someone waiting on this buffer will be woken up
- * (maybe us) to flush this buffer out.
- *
- * Otherwise, we mark the buffer WANT_SYNC, and bump
- * up the refcnt so we can release the log (which drops
- * the ref count). The state switch keeps new transaction
- * commits from using this buffer. When the current commits
- * finish writing into the buffer, the refcount will drop to
- * zero and the buffer will go out then.
- */
- if (!already_slept &&
- (iclog->ic_prev->ic_state & (XLOG_STATE_WANT_SYNC |
- XLOG_STATE_SYNCING))) {
- ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR));
- XFS_STATS_INC(xfsstats.xs_log_force_sleep);
- sv_wait(&iclog->ic_prev->ic_forcesema, PSWP,
- &log->l_icloglock, s);
- already_slept = 1;
- goto try_again;
- } else {
- iclog->ic_refcnt++;
- xlog_state_switch_iclogs(log, iclog, 0);
- LOG_UNLOCK(log, s);
- if (xlog_state_release_iclog(log, iclog))
- return XFS_ERROR(EIO);
- s = LOG_LOCK(log);
- }
+ iclog->ic_refcnt++;
+ xlog_state_switch_iclogs(log, iclog, 0);
+ LOG_UNLOCK(log, s);
+ if (xlog_state_release_iclog(log, iclog))
+ return XFS_ERROR(EIO);
+ s = LOG_LOCK(log);
}
if ((flags & XFS_LOG_SYNC) && /* sleep */
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 8d1676e1d157..125af631e3f2 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -476,7 +476,7 @@ xlog_find_head(xlog_t *log,
* mkfs etc write a dummy unmount record to a fresh
* log so we can store the uuid in there
*/
- xlog_warn("XFS: totally zeroed log\n");
+ xlog_warn("XFS: totally zeroed log");
}
return 0;
@@ -873,9 +873,19 @@ xlog_find_tail(xlog_t *log,
* overwrite the unmount record after a clean unmount.
*
* Do this only if we are going to recover the filesystem
+ *
+ * NOTE: This used to say "if (!readonly)"
+ * However on Linux, we can & do recover a read-only filesystem.
+ * We only skip recovery if NORECOVERY is specified on mount,
+ * in which case we would not be here.
+ *
+ * But... if the -device- itself is readonly, just skip this.
+ * We can't recover this device anyway, so it won't matter.
*/
- if (!readonly)
+
+ if (!bdev_read_only(log->l_mp->m_logdev_targp->pbr_bdev)) {
error = xlog_clear_stale_blocks(log, tail_lsn);
+ }
#endif
bread_err:
@@ -1242,7 +1252,7 @@ xlog_recover_add_to_cont_trans(xlog_recover_t *trans,
/* finish copying rest of trans header */
xlog_recover_add_item(&trans->r_itemq);
ptr = (xfs_caddr_t)&trans->r_theader+sizeof(xfs_trans_header_t)-len;
- bcopy(dp, ptr, len); /* s, d, l */
+ memcpy(ptr, dp, len); /* d, s, l */
return 0;
}
item = item->ri_prev;
@@ -1251,7 +1261,7 @@ xlog_recover_add_to_cont_trans(xlog_recover_t *trans,
old_len = item->ri_buf[item->ri_cnt-1].i_len;
ptr = kmem_realloc(old_ptr, len+old_len, old_len, 0);
- bcopy(dp , &ptr[old_len], len); /* s, d, l */
+ memcpy(&ptr[old_len], dp, len); /* d, s, l */
item->ri_buf[item->ri_cnt-1].i_len += len;
item->ri_buf[item->ri_cnt-1].i_addr = ptr;
return 0;
@@ -1282,7 +1292,7 @@ xlog_recover_add_to_trans(xlog_recover_t *trans,
if (!len)
return 0;
ptr = kmem_zalloc(len, 0);
- bcopy(dp, ptr, len);
+ memcpy(ptr, dp, len);
in_f = (xfs_inode_log_format_t *)ptr;
item = trans->r_itemq;
@@ -1290,7 +1300,7 @@ xlog_recover_add_to_trans(xlog_recover_t *trans,
ASSERT(*(uint *)dp == XFS_TRANS_HEADER_MAGIC);
if (len == sizeof(xfs_trans_header_t))
xlog_recover_add_item(&trans->r_itemq);
- bcopy(dp, &trans->r_theader, len); /* s, d, l */
+ memcpy(&trans->r_theader, dp, len); /* d, s, l */
return 0;
}
if (item->ri_prev->ri_total != 0 &&
@@ -1799,9 +1809,10 @@ xlog_recover_do_reg_buffer(xfs_mount_t *mp,
"dquot_buf_recover");
}
if (!error)
- bcopy(item->ri_buf[i].i_addr, /* source */
- xfs_buf_offset(bp, (uint)bit << XFS_BLI_SHIFT), /* dest */
- nbits<<XFS_BLI_SHIFT); /* length */
+ memcpy(xfs_buf_offset(bp,
+ (uint)bit << XFS_BLI_SHIFT), /* dest */
+ item->ri_buf[i].i_addr, /* source */
+ nbits<<XFS_BLI_SHIFT); /* length */
i++;
bit += nbits;
}
@@ -2115,9 +2126,9 @@ xlog_recover_do_inode_trans(xlog_t *log,
-1, ARCH_CONVERT);
/* the rest is in on-disk format */
if (item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t)) {
- bcopy(item->ri_buf[1].i_addr + sizeof(xfs_dinode_core_t),
- (xfs_caddr_t) dip + sizeof(xfs_dinode_core_t),
- item->ri_buf[1].i_len - sizeof(xfs_dinode_core_t));
+ memcpy((xfs_caddr_t) dip + sizeof(xfs_dinode_core_t),
+ item->ri_buf[1].i_addr + sizeof(xfs_dinode_core_t),
+ item->ri_buf[1].i_len - sizeof(xfs_dinode_core_t));
}
fields = in_f->ilf_fields;
@@ -2143,7 +2154,7 @@ xlog_recover_do_inode_trans(xlog_t *log,
switch (fields & XFS_ILOG_DFORK) {
case XFS_ILOG_DDATA:
case XFS_ILOG_DEXT:
- bcopy(src, &dip->di_u, len);
+ memcpy(&dip->di_u, src, len);
break;
case XFS_ILOG_DBROOT:
@@ -2182,7 +2193,7 @@ xlog_recover_do_inode_trans(xlog_t *log,
case XFS_ILOG_AEXT:
dest = XFS_DFORK_APTR(dip);
ASSERT(len <= XFS_DFORK_ASIZE(dip, mp));
- bcopy(src, dest, len);
+ memcpy(dest, src, len);
break;
case XFS_ILOG_ABROOT:
@@ -2341,7 +2352,7 @@ xlog_recover_do_dquot_trans(xlog_t *log,
return XFS_ERROR(EIO);
}
- bcopy(recddq, ddq, item->ri_buf[1].i_len);
+ memcpy(ddq, recddq, item->ri_buf[1].i_len);
ASSERT(dq_f->qlf_size == 2);
ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL ||
@@ -2382,7 +2393,7 @@ xlog_recover_do_efi_trans(xlog_t *log,
mp = log->l_mp;
efip = xfs_efi_init(mp, efi_formatp->efi_nextents);
- bcopy((char *)efi_formatp, (char *)&(efip->efi_format),
+ memcpy((char *)&(efip->efi_format), (char *)efi_formatp,
sizeof(xfs_efi_log_format_t) +
((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t)));
efip->efi_next_extent = efi_formatp->efi_nextents;
@@ -3131,7 +3142,7 @@ xlog_unpack_data(xlog_rec_header_t *rhead,
"XFS: Disregard message if filesystem was created with non-DEBUG kernel");
if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
cmn_err(CE_DEBUG,
- "XFS: LogR this is a LogV2 filesystem\n");
+ "XFS: LogR this is a LogV2 filesystem");
}
log->l_flags |= XLOG_CHKSUM_MISMATCH;
}
@@ -3215,7 +3226,7 @@ xlog_do_recovery_pass(xlog_t *log,
return ENOMEM;
}
- bzero(rhash, sizeof(rhash));
+ memset(rhash, 0, sizeof(rhash));
if (tail_blk <= head_blk) {
for (blk_no = tail_blk; blk_no < head_blk; ) {
if ((error = xlog_bread(log, blk_no, hblks, hbp)))
@@ -3521,17 +3532,20 @@ xlog_recover(xlog_t *log, int readonly)
* error message.
* ...but this is no longer true. Now, unless you specify
* NORECOVERY (in which case this function would never be
- * called), it enables read-write access long enough to do
- * recovery.
+ * called), we just go ahead and recover. We do this all
+ * under the vfs layer, so we can get away with it unless
+ * the device itself is read-only, in which case we fail.
*/
- if (readonly) {
#ifdef __KERNEL__
- if ((error = xfs_recover_read_only(log)))
- return error;
+ if ((error = xfs_dev_is_read_only(log->l_mp,
+ "recovery required"))) {
+ return error;
+ }
#else
+ if (readonly) {
return ENOSPC;
-#endif
}
+#endif
#ifdef __KERNEL__
#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
@@ -3548,8 +3562,6 @@ xlog_recover(xlog_t *log, int readonly)
#endif
error = xlog_do_recover(log, head_blk, tail_blk);
log->l_flags |= XLOG_RECOVERY_NEEDED;
- if (readonly)
- XFS_MTOVFS(log->l_mp)->vfs_flag |= VFS_RDONLY;
}
return error;
} /* xlog_recover */
@@ -3607,7 +3619,7 @@ xlog_recover_finish(xlog_t *log, int mfsi_flags)
log->l_flags &= ~XLOG_RECOVERY_NEEDED;
} else {
cmn_err(CE_DEBUG,
- "!Ending clean XFS mount for filesystem: %s\n",
+ "!Ending clean XFS mount for filesystem: %s",
log->l_mp->m_fsname);
}
return 0;
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 13c88ba8039e..2625226c73c7 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -31,6 +31,13 @@
*/
#include <xfs.h>
+#include <linux/major.h>
+#include <linux/namei.h>
+#include <linux/pagemap.h>
+
+#ifndef EVMS_MAJOR
+#define EVMS_MAJOR 117
+#endif
STATIC void xfs_mount_reset_sbqflags(xfs_mount_t *);
STATIC void xfs_mount_log_sbunit(xfs_mount_t *, __int64_t);
@@ -375,9 +382,9 @@ xfs_xlatesb(
size == 1 ||
xfs_sb_info[f].type == 1) {
if (dir > 0) {
- bcopy(buf_ptr + first, mem_ptr + first, size);
+ memcpy(mem_ptr + first, buf_ptr + first, size);
} else {
- bcopy(mem_ptr + first, buf_ptr + first, size);
+ memcpy(buf_ptr + first, mem_ptr + first, size);
}
} else {
switch (size) {
@@ -673,7 +680,7 @@ xfs_mountfs(
}
uuid_mounted=1;
ret64 = uuid_hash64(&sbp->sb_uuid);
- bcopy(&ret64, &vfsp->vfs_fsid, sizeof(ret64));
+ memcpy(&vfsp->vfs_fsid, &ret64, sizeof(ret64));
}
/*
@@ -904,7 +911,7 @@ xfs_mountfs(
rvp = XFS_ITOV(rip);
if ((rip->i_d.di_mode & IFMT) != IFDIR) {
cmn_err(CE_WARN, "XFS: corrupted root inode");
- VMAP(rvp, rip, vmap);
+ VMAP(rvp, vmap);
prdev("Root inode %llu is not a directory",
mp->m_dev, (unsigned long long)rip->i_ino);
rvp->v_flag |= VPURGE;
@@ -930,8 +937,7 @@ xfs_mountfs(
if (((quotaondisk && !XFS_IS_QUOTA_ON(mp)) ||
(!quotaondisk && XFS_IS_QUOTA_ON(mp))) &&
- (bdev_read_only(mp->m_ddev_targp->pbr_bdev) ||
- bdev_read_only(mp->m_logdev_targp->pbr_bdev))) {
+ xfs_dev_is_read_only(mp, "changing quota state")) {
cmn_err(CE_WARN,
"XFS: device %s is read-only, cannot change "
"quota state. Please mount with%s quota option.",
@@ -952,7 +958,7 @@ xfs_mountfs(
*/
cmn_err(CE_WARN, "XFS: failed to read RT inodes");
rvp->v_flag |= VPURGE;
- VMAP(rvp, rip, vmap);
+ VMAP(rvp, vmap);
VN_RELE(rvp);
vn_purge(rvp, &vmap);
goto error3;
@@ -1023,14 +1029,12 @@ xfs_mountfs(
if (needquotamount) {
ASSERT(mp->m_qflags == 0);
mp->m_qflags = quotaflags;
- rootqcheck = ((XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) &&
- mp->m_dev == rootdev && needquotacheck);
- if (rootqcheck && (error = xfs_quotacheck_read_only(mp)))
+ rootqcheck = (mp->m_dev == rootdev && needquotacheck);
+ if (rootqcheck && (error = xfs_dev_is_read_only(mp,
+ "quotacheck")))
goto error2;
if (xfs_qm_mount_quotas(mp))
xfs_mount_reset_sbqflags(mp);
- if (rootqcheck)
- XFS_MTOVFS(mp)->vfs_flag |= VFS_RDONLY;
}
#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
@@ -1135,7 +1139,7 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
/*
* clear all error tags on this filesystem
*/
- bcopy(&(XFS_MTOVFS(mp)->vfs_fsid), &fsid, sizeof(int64_t));
+ memcpy(&fsid, &(XFS_MTOVFS(mp)->vfs_fsid), sizeof(int64_t));
(void) xfs_errortag_clearall_umount(fsid, mp->m_fsname, 0);
#endif
@@ -1149,15 +1153,17 @@ xfs_unmountfs_close(xfs_mount_t *mp, struct cred *cr)
int have_logdev = (mp->m_logdev_targp != mp->m_ddev_targp);
if (mp->m_ddev_targp) {
- pagebuf_lock_disable(mp->m_ddev_targp, 0);
+ xfs_free_buftarg(mp->m_ddev_targp);
mp->m_ddev_targp = NULL;
}
if (mp->m_rtdev_targp) {
- pagebuf_lock_disable(mp->m_rtdev_targp, 1);
+ xfs_blkdev_put(mp->m_rtdev_targp->pbr_bdev);
+ xfs_free_buftarg(mp->m_rtdev_targp);
mp->m_rtdev_targp = NULL;
}
if (mp->m_logdev_targp && have_logdev) {
- pagebuf_lock_disable(mp->m_logdev_targp, 1);
+ xfs_blkdev_put(mp->m_logdev_targp->pbr_bdev);
+ xfs_free_buftarg(mp->m_logdev_targp);
mp->m_logdev_targp = NULL;
}
}
@@ -1725,3 +1731,71 @@ xfs_check_frozen(
if (level == XFS_FREEZE_TRANS)
atomic_inc(&mp->m_active_trans);
}
+
+int
+xfs_blkdev_get(
+ const char *name,
+ struct block_device **bdevp)
+{
+ struct nameidata nd;
+ int error = 0;
+
+ error = path_lookup(name, LOOKUP_FOLLOW, &nd);
+ if (error) {
+ printk("XFS: Invalid device [%s], error=%d\n",
+ name, error);
+ return error;
+ }
+
+ /* I think we actually want bd_acquire here.. --hch */
+ *bdevp = bdget(kdev_t_to_nr(nd.dentry->d_inode->i_rdev));
+ if (*bdevp) {
+ error = blkdev_get(*bdevp, FMODE_READ|FMODE_WRITE, 0, BDEV_FS);
+ } else {
+ error = -ENOMEM;
+ }
+
+ path_release(&nd);
+ return -error;
+}
+
+void
+xfs_blkdev_put(
+ struct block_device *bdev)
+{
+ blkdev_put(bdev, BDEV_FS);
+}
+
+void
+xfs_free_buftarg(
+ xfs_buftarg_t *btp)
+{
+ pagebuf_delwri_flush(btp, PBDF_WAIT, NULL);
+ kfree(btp);
+}
+
+xfs_buftarg_t *
+xfs_alloc_buftarg(
+ struct block_device *bdev)
+{
+ xfs_buftarg_t *btp;
+
+ btp = kmem_zalloc(sizeof(*btp), KM_SLEEP);
+
+ btp->pbr_dev = bdev->bd_dev;
+ btp->pbr_bdev = bdev;
+ btp->pbr_mapping = bdev->bd_inode->i_mapping;
+ btp->pbr_blocksize = PAGE_CACHE_SIZE;
+
+ switch (MAJOR(btp->pbr_dev)) {
+ case MD_MAJOR:
+ case EVMS_MAJOR:
+ btp->pbr_flags = PBR_ALIGNED_ONLY;
+ break;
+ case LVM_BLK_MAJOR:
+ btp->pbr_flags = PBR_SECTOR_ONLY;
+ break;
+ }
+
+ return btp;
+}
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 51c86fea20c4..7011e001b6c3 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -77,7 +77,6 @@ struct xfs_inode;
struct xfs_perag;
struct xfs_quotainfo;
struct xfs_iocore;
-struct xfs_dio;
struct xfs_bmbt_irec;
struct xfs_bmap_free;
@@ -96,24 +95,18 @@ struct xfs_bmap_free;
* minimize the number of memory indirections involved.
*/
-typedef int (*xfs_dio_write_t)(struct xfs_dio *);
-typedef int (*xfs_dio_read_t)(struct xfs_dio *);
-typedef int (*xfs_strat_write_t)(struct xfs_iocore *, struct xfs_buf *);
typedef int (*xfs_bmapi_t)(struct xfs_trans *, void *,
xfs_fileoff_t, xfs_filblks_t, int,
xfs_fsblock_t *, xfs_extlen_t,
struct xfs_bmbt_irec *, int *,
struct xfs_bmap_free *);
typedef int (*xfs_bmap_eof_t)(void *, xfs_fileoff_t, int, int *);
-typedef int (*xfs_rsync_t)(void *, int, xfs_off_t, xfs_off_t);
-typedef uint (*xfs_lck_map_shared_t)(void *);
typedef void (*xfs_lock_t)(void *, uint);
typedef void (*xfs_lock_demote_t)(void *, uint);
typedef int (*xfs_lock_nowait_t)(void *, uint);
typedef void (*xfs_unlk_t)(void *, unsigned int);
typedef void (*xfs_chgtime_t)(void *, int);
typedef xfs_fsize_t (*xfs_size_t)(void *);
-typedef xfs_fsize_t (*xfs_setsize_t)(void *, xfs_off_t);
typedef xfs_fsize_t (*xfs_lastbyte_t)(void *);
typedef struct xfs_ioops {
@@ -295,8 +288,7 @@ typedef struct xfs_mount {
#define XFS_MOUNT_NOUUID 0x00004000 /* ignore uuid during mount */
#define XFS_MOUNT_32BITINODES 0x00008000 /* do not create inodes above
* 32 bits in size */
-#define XFS_MOUNT_IRIXSGID 0x00010000 /* Irix-style sgid inheritance */
-#define XFS_MOUNT_NOLOGFLUSH 0x00020000
+#define XFS_MOUNT_NOLOGFLUSH 0x00010000
/*
* Flags for m_cxfstype
@@ -436,6 +428,11 @@ int xfs_syncsub(xfs_mount_t *, int, int, int *);
void xfs_initialize_perag(xfs_mount_t *, int);
void xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t, __int64_t);
+int xfs_blkdev_get(const char *, struct block_device **);
+void xfs_blkdev_put(struct block_device *);
+struct xfs_buftarg *xfs_alloc_buftarg(struct block_device *);
+void xfs_free_buftarg(struct xfs_buftarg *);
+
/*
* Flags for freeze operations.
*/
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index db7f44f0eb52..b728d271c7ee 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -1039,14 +1039,14 @@ xfs_qm_unmount(
vp = XFS_ITOV(XFS_QI_UQIP(mp));
VN_RELE(vp);
if (vn_count(vp) > 1)
- cmn_err(CE_WARN, "UQUOTA busy vp=0x%x count=%d\n",
+ cmn_err(CE_WARN, "UQUOTA busy vp=0x%x count=%d",
vp, vn_count(vp));
}
if (XFS_IS_GQUOTA_ON(mp)) {
vp = XFS_ITOV(XFS_QI_GQIP(mp));
VN_RELE(vp);
if (vn_count(vp) > 1)
- cmn_err(CE_WARN, "GQUOTA busy vp=0x%x count=%d\n",
+ cmn_err(CE_WARN, "GQUOTA busy vp=0x%x count=%d",
vp, vn_count(vp));
}
@@ -1427,9 +1427,9 @@ xfs_qm_qino_alloc(
xfs_trans_cancel(tp, 0);
return (error);
}
- bzero(&zerocr, sizeof(zerocr));
+ memset(&zerocr, 0, sizeof(zerocr));
- if ((error = xfs_dir_ialloc(&tp, mp->m_rootip, IFREG, 1, mp->m_dev,
+ if ((error = xfs_dir_ialloc(&tp, mp->m_rootip, IFREG, 1, 0,
&zerocr, 0, 1, ip, &committed))) {
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
XFS_TRANS_ABORT);
@@ -1998,11 +1998,16 @@ xfs_qm_init_quotainos(
int error;
__int64_t sbflags;
uint flags;
+ int readonly;
+ vfs_t *vfsp;
ASSERT(mp->m_quotainfo);
uip = gip = NULL;
+ error = 0;
sbflags = 0;
flags = 0;
+ vfsp = XFS_MTOVFS(mp);
+ readonly = vfsp->vfs_flag & VFS_RDONLY;
/*
* Get the uquota and gquota inodes
@@ -2036,36 +2041,34 @@ xfs_qm_init_quotainos(
* made above will get added to a transaction and logged in one of
* the qino_alloc calls below.
*/
+
if (XFS_IS_UQUOTA_ON(mp) && uip == NULL) {
- if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY)
- return XFS_ERROR(EROFS);
if ((error = xfs_qm_qino_alloc(mp, &uip,
sbflags | XFS_SB_UQUOTINO,
flags | XFS_QMOPT_UQUOTA)))
- return XFS_ERROR(error);
+ goto error;
flags &= ~XFS_QMOPT_SBVERSION;
}
if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) {
- if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) {
- if (uip)
- VN_RELE(XFS_ITOV(uip));
- return XFS_ERROR(EROFS);
- }
if ((error = xfs_qm_qino_alloc(mp, &gip,
sbflags | XFS_SB_GQUOTINO,
flags | XFS_QMOPT_GQUOTA))) {
if (uip)
VN_RELE(XFS_ITOV(uip));
- return XFS_ERROR(error);
+ goto error;
}
}
XFS_QI_UQIP(mp) = uip;
XFS_QI_GQIP(mp) = gip;
- return (0);
+error:
+ if (readonly)
+ vfsp->vfs_flag |= VFS_RDONLY;
+
+ return XFS_ERROR(error);
}
@@ -2414,11 +2417,11 @@ xfs_qm_dqalloc_incore(
if ((dqp = xfs_qm_dqreclaim_one())) {
XFS_STATS_INC(xfsstats.xs_qm_dqreclaims);
/*
- * Just bzero the core here. The rest will get
+ * Just zero the core here. The rest will get
* reinitialized by caller. XXX we shouldn't even
- * do this bzero ...
+ * do this zero ...
*/
- bzero(&dqp->q_core, sizeof(dqp->q_core));
+ memset(&dqp->q_core, 0, sizeof(dqp->q_core));
*O_dqpp = dqp;
return (B_FALSE);
}
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 73f22a296ec8..b3cfba7ecad0 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -550,7 +550,7 @@ xfs_qm_scall_getqstat(
uip = gip = NULL;
tempuqip = tempgqip = B_FALSE;
- bzero(out, sizeof(fs_quota_stat_t));
+ memset(out, 0, sizeof(fs_quota_stat_t));
out->qs_version = FS_QSTAT_VERSION;
if (! XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) {
@@ -885,7 +885,7 @@ xfs_qm_export_dquot(
xfs_disk_dquot_t *src,
struct fs_disk_quota *dst)
{
- bzero(dst, sizeof(*dst));
+ memset(dst, 0, sizeof(*dst));
dst->d_version = FS_DQUOT_VERSION; /* different from src->d_version */
dst->d_flags =
xfs_qm_export_qtype_flags(INT_GET(src->d_flags, ARCH_CONVERT));
@@ -1060,7 +1060,7 @@ again:
* Sample vp mapping while holding the mplock, lest
* we come across a non-existent vnode.
*/
- VMAP(vp, ip, vmap);
+ VMAP(vp, vmap);
ireclaims = mp->m_ireclaims;
topino = mp->m_inodes;
XFS_MOUNT_IUNLOCK(mp);
diff --git a/fs/xfs/xfs_quota_priv.h b/fs/xfs/xfs_quota_priv.h
index c7f8bb60e561..d016d2b6cf8a 100644
--- a/fs/xfs/xfs_quota_priv.h
+++ b/fs/xfs/xfs_quota_priv.h
@@ -181,7 +181,7 @@ for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \
vmap_t dqvmap; \
vnode_t *dqvp; \
dqvp = XFS_ITOV(ip); \
- VMAP(dqvp, ip, dqvmap); \
+ VMAP(dqvp, dqvmap); \
VN_RELE(dqvp); \
}
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index 82684350d6eb..7f5526f4417c 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -170,7 +170,7 @@ xfs_growfs_rt_alloc(
error = XFS_ERROR(EIO);
goto error_exit;
}
- bzero(XFS_BUF_PTR(bp), mp->m_sb.sb_blocksize);
+ memset(XFS_BUF_PTR(bp), 0, mp->m_sb.sb_blocksize);
xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
/*
* Commit the transaction.
@@ -2322,7 +2322,7 @@ xfs_rtmount_inodes(
vmap_t vmap; /* vmap to delete vnode */
rbmvp = XFS_ITOV(mp->m_rbmip);
- VMAP(rbmvp, mp->m_rbmip, vmap);
+ VMAP(rbmvp, vmap);
VN_RELE(rbmvp);
vn_purge(rbmvp, &vmap);
return error;
diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c
index 0076a84485e8..01dc65dc1158 100644
--- a/fs/xfs/xfs_rw.c
+++ b/fs/xfs/xfs_rw.c
@@ -230,7 +230,7 @@ xfs_ioerror_alert(
xfs_daddr_t blkno)
{
cmn_err(CE_ALERT,
- "I/O error in filesystem (\"%s\") meta-data dev 0x%x block 0x%llx\n"
+ "I/O error in filesystem (\"%s\") meta-data dev 0x%x block 0x%llx"
" (\"%s\") error %d buf count %u",
(!mp || !mp->m_fsname) ? "(fs name not set)" : mp->m_fsname,
XFS_BUF_TARGET_DEV(bp),
@@ -362,7 +362,7 @@ xfs_inval_cached_pages(
XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
isize = XFS_SIZE(mp, io);
if (offset > isize) {
- xfs_zero_eof(vp, io, offset, isize, offset, NULL);
+ xfs_zero_eof(vp, io, offset, isize, offset);
}
XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
}
diff --git a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h
index f2f4c5d88738..96bf21108a24 100644
--- a/fs/xfs/xfs_rw.h
+++ b/fs/xfs/xfs_rw.h
@@ -42,8 +42,6 @@ struct xfs_inode;
struct xfs_iocore;
struct xfs_mount;
struct xfs_trans;
-struct xfs_dio;
-struct pm;
/*
* Maximum count of bmaps used by read and write paths.
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 292ad257bc38..6e8dd532c1dc 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -788,6 +788,7 @@ shut_us_down:
commit_lsn = xfs_log_done(mp, tp->t_ticket, log_flags);
#endif
+ tp->t_commit_lsn = commit_lsn;
if (nvec > XFS_TRANS_LOGVEC_COUNT) {
kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t));
}
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 1845dd874a4b..5489e4dded40 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -378,7 +378,10 @@ typedef struct xfs_trans {
unsigned int t_rtx_res_used; /* # of resvd rt extents used */
xfs_log_ticket_t t_ticket; /* log mgr ticket */
sema_t t_sema; /* sema for commit completion */
- xfs_lsn_t t_lsn; /* log seq num of trans commit*/
+ xfs_lsn_t t_lsn; /* log seq num of start of
+ * transaction. */
+ xfs_lsn_t t_commit_lsn; /* log seq num of end of
+ * transaction. */
struct xfs_mount *t_mountp; /* ptr to fs mount struct */
struct xfs_dquot_acct *t_dqinfo; /* accting info for dquots */
xfs_trans_callback_t t_callback; /* transaction callback */
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index e6bcf374e54c..8daceb174c4f 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -472,7 +472,7 @@ shutdown_abort:
*/
#if defined(DEBUG)
if (XFS_BUF_ISSTALE(bp) && XFS_BUF_ISDELAYWRITE(bp))
- cmn_err(CE_NOTE, "about to pop assert, bp == 0x%x\n", bp);
+ cmn_err(CE_NOTE, "about to pop assert, bp == 0x%x", bp);
#endif
ASSERT((XFS_BUF_BFLAGS(bp) & (XFS_B_STALE|XFS_B_DELWRI)) !=
(XFS_B_STALE|XFS_B_DELWRI));
@@ -880,7 +880,7 @@ xfs_trans_binval(
bip->bli_flags &= ~(XFS_BLI_LOGGED | XFS_BLI_DIRTY);
bip->bli_format.blf_flags &= ~XFS_BLI_INODE_BUF;
bip->bli_format.blf_flags |= XFS_BLI_CANCEL;
- bzero((char *)(bip->bli_format.blf_data_map),
+ memset((char *)(bip->bli_format.blf_data_map), 0,
(bip->bli_format.blf_map_size * sizeof(uint)));
lidp->lid_flags |= XFS_LID_DIRTY;
tp->t_flags |= XFS_TRANS_DIRTY;
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c
index b7fbf81b00da..0df7fc3075cf 100644
--- a/fs/xfs/xfs_trans_inode.c
+++ b/fs/xfs/xfs_trans_inode.c
@@ -414,20 +414,8 @@ xfs_trans_inode_broot_debug(
iip->ili_root_size = ip->i_df.if_broot_bytes;
iip->ili_orig_root =
(char*)kmem_alloc(iip->ili_root_size, KM_SLEEP);
- bcopy((char*)(ip->i_df.if_broot), iip->ili_orig_root,
+ memcpy(iip->ili_orig_root, (char*)(ip->i_df.if_broot),
iip->ili_root_size);
}
}
#endif
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/fs/xfs/xfs_types.h b/fs/xfs/xfs_types.h
index aa6fe38dde5e..e08f8b727a65 100644
--- a/fs/xfs/xfs_types.h
+++ b/fs/xfs/xfs_types.h
@@ -308,23 +308,19 @@ extern struct xfsstats xfsstats;
#endif /* !CONFIG_PROC_FS */
-
-/* juggle IRIX device numbers - still used in ondisk structures */
-
-#ifndef __KERNEL__
-#define MKDEV(major, minor) makedev(major, minor)
-#endif
-
-#define IRIX_DEV_BITSMAJOR 14
-#define IRIX_DEV_BITSMINOR 18
-#define IRIX_DEV_MAXMAJ 0x1ff
-#define IRIX_DEV_MAXMIN 0x3ffff
-#define IRIX_DEV_MAJOR(dev) ((int)(((unsigned)(dev)>>IRIX_DEV_BITSMINOR) \
- & IRIX_DEV_MAXMAJ))
-#define IRIX_DEV_MINOR(dev) ((int)((dev)&IRIX_DEV_MAXMIN))
-#define IRIX_MKDEV(major,minor) ((xfs_dev_t)(((major)<<IRIX_DEV_BITSMINOR) \
- | (minor&IRIX_DEV_MAXMIN)))
-
-#define IRIX_DEV_TO_KDEVT(dev) MKDEV(IRIX_DEV_MAJOR(dev),IRIX_DEV_MINOR(dev))
+/*
+ * Juggle IRIX device numbers - still used in ondisk structures
+ */
+#define XFS_DEV_BITSMAJOR 14
+#define XFS_DEV_BITSMINOR 18
+#define XFS_DEV_MAXMAJ 0x1ff
+#define XFS_DEV_MAXMIN 0x3ffff
+#define XFS_DEV_MAJOR(dev) ((int)(((unsigned)(dev)>>XFS_DEV_BITSMINOR) \
+ & XFS_DEV_MAXMAJ))
+#define XFS_DEV_MINOR(dev) ((int)((dev)&XFS_DEV_MAXMIN))
+#define XFS_MKDEV(major,minor) ((xfs_dev_t)(((major)<<XFS_DEV_BITSMINOR) \
+ | (minor&XFS_DEV_MAXMIN)))
+
+#define XFS_DEV_TO_KDEVT(dev) mk_kdev(XFS_DEV_MAJOR(dev),XFS_DEV_MINOR(dev))
#endif /* !__XFS_TYPES_H */
diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c
index 9fcee5b06cdc..d82bf3a6a7be 100644
--- a/fs/xfs/xfs_utils.c
+++ b/fs/xfs/xfs_utils.c
@@ -132,7 +132,7 @@ xfs_dir_ialloc(
the inode. */
mode_t mode,
nlink_t nlink,
- dev_t rdev,
+ xfs_dev_t rdev,
cred_t *credp,
prid_t prid, /* project id */
int okalloc, /* ok to allocate new space */
@@ -345,7 +345,7 @@ xfs_bump_ino_vers2(
ip->i_d.di_version = XFS_DINODE_VERSION_2;
ip->i_d.di_onlink = 0;
- bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad));
+ memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
mp = tp->t_mountp;
if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) {
s = XFS_SB_LOCK(mp);
diff --git a/fs/xfs/xfs_utils.h b/fs/xfs/xfs_utils.h
index db4da1029291..ac8f5b92ba0f 100644
--- a/fs/xfs/xfs_utils.h
+++ b/fs/xfs/xfs_utils.h
@@ -76,7 +76,7 @@ xfs_dir_ialloc(
struct xfs_inode *dp,
mode_t mode,
nlink_t nlink,
- dev_t rdev,
+ xfs_dev_t rdev,
struct cred *credp,
prid_t prid,
int okalloc,
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
index cce4a74d5dfe..97f6f65feca6 100644
--- a/fs/xfs/xfs_vfsops.c
+++ b/fs/xfs/xfs_vfsops.c
@@ -225,7 +225,7 @@ xfs_start_flags(
(ap->logbufs < XLOG_NUM_ICLOGS ||
ap->logbufs > XLOG_MAX_ICLOGS)) {
cmn_err(CE_WARN,
- "XFS: invalid logbufs value: %d [not %d-%d]\n",
+ "XFS: invalid logbufs value: %d [not %d-%d]",
ap->logbufs, XLOG_NUM_ICLOGS, XLOG_MAX_ICLOGS);
return XFS_ERROR(EINVAL);
}
@@ -237,7 +237,7 @@ xfs_start_flags(
ap->logbufsize != 128 * 1024 &&
ap->logbufsize != 256 * 1024) {
cmn_err(CE_WARN,
- "XFS: invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]\n",
+ "XFS: invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]",
ap->logbufsize);
return XFS_ERROR(EINVAL);
}
@@ -274,13 +274,9 @@ xfs_start_flags(
if (ap->flags & XFSMNT_OSYNCISOSYNC)
mp->m_flags |= XFS_MOUNT_OSYNCISOSYNC;
- /* Default on Linux */
- if (1 || ap->flags & XFSMNT_32BITINODES)
+ if (ap->flags & XFSMNT_32BITINODES)
mp->m_flags |= XFS_MOUNT_32BITINODES;
- if (ap->flags & XFSMNT_IRIXSGID)
- mp->m_flags |= XFS_MOUNT_IRIXSGID;
-
if (ap->flags & XFSMNT_IOSIZE) {
if (ap->iosizelog > XFS_MAX_IO_LOG ||
ap->iosizelog < XFS_MIN_IO_LOG) {
@@ -392,145 +388,115 @@ xfs_finish_flags(
}
/*
- * xfs_cmountfs
+ * xfs_mount
*
- * This function is the common mount file system function for XFS.
+ * The file system configurations are:
+ * (1) device (partition) with data and internal log
+ * (2) logical volume with data and log subvolumes.
+ * (3) logical volume with data, log, and realtime subvolumes.
+ *
+ * The Linux VFS took care of finding and opening the data volume for
+ * us. We have to handle the other two (if present) here.
*/
STATIC int
-xfs_cmountfs(
+xfs_mount(
vfs_t *vfsp,
- dev_t ddev,
- dev_t logdev,
- dev_t rtdev,
- struct xfs_mount_args *ap,
- struct cred *cr)
+ struct xfs_mount_args *args,
+ cred_t *credp)
{
xfs_mount_t *mp;
+ struct block_device *ddev, *logdev, *rtdev;
int ronly = (vfsp->vfs_flag & VFS_RDONLY);
int error = 0;
- /*
- * Allocate VFS private data (xfs mount structure).
- */
- mp = xfs_mount_init();
-
- vfs_insertbhv(vfsp, &mp->m_bhv, &xfs_vfsops, mp);
+ ddev = vfsp->vfs_super->s_bdev;
+ logdev = rtdev = NULL;
/*
- * Open data, real time, and log devices now - order is important.
+ * Open real time and log devices - order is important.
*/
- mp->m_ddev_targp = pagebuf_lock_enable(ddev, 0);
- if (IS_ERR(mp->m_ddev_targp)) {
- error = PTR_ERR(mp->m_ddev_targp);
- goto error2;
+ if (args->logname[0]) {
+ error = xfs_blkdev_get(args->logname, &logdev);
+ if (error)
+ return error;
}
-
- if (rtdev != 0) {
- mp->m_rtdev_targp = pagebuf_lock_enable(rtdev, 1);
- if (IS_ERR(mp->m_rtdev_targp)) {
- error = PTR_ERR(mp->m_rtdev_targp);
- pagebuf_lock_disable(mp->m_ddev_targp, 0);
- goto error2;
+ if (args->rtname[0]) {
+ error = xfs_blkdev_get(args->rtname, &rtdev);
+ if (error) {
+ xfs_blkdev_put(logdev);
+ return error;
}
if (rtdev == ddev || rtdev == logdev) {
cmn_err(CE_WARN,
"XFS: Cannot mount filesystem with identical rtdev and ddev/logdev.");
- error = EINVAL;
- pagebuf_lock_disable(mp->m_ddev_targp, 0);
- goto error2;
+ xfs_blkdev_put(logdev);
+ xfs_blkdev_put(rtdev);
+ return EINVAL;
}
-
- /* Set the realtime device's block size */
- set_blocksize(mp->m_rtdev_targp->pbr_bdev, 512);
}
- if (logdev != ddev) {
- mp->m_logdev_targp = pagebuf_lock_enable(logdev, 1);
- if (IS_ERR(mp->m_logdev_targp)) {
- error = PTR_ERR(mp->m_logdev_targp);
- pagebuf_lock_disable(mp->m_ddev_targp, 1);
- if (mp->m_rtdev_targp)
- pagebuf_lock_disable(mp->m_rtdev_targp, 1);
- goto error2;
- }
+ /*
+ * Allocate VFS private data (xfs mount structure).
+ */
+ mp = xfs_mount_init();
- /* Set the log device's block size */
- set_blocksize(mp->m_logdev_targp->pbr_bdev, 512);
+ vfs_insertbhv(vfsp, &mp->m_bhv, &xfs_vfsops, mp);
+
+ mp->m_ddev_targp = xfs_alloc_buftarg(ddev);
+ if (rtdev != NULL) {
+ mp->m_rtdev_targp = xfs_alloc_buftarg(rtdev);
+ set_blocksize(rtdev, 512);
+ }
+ if (logdev != NULL && logdev != ddev) {
+ mp->m_logdev_targp = xfs_alloc_buftarg(logdev);
+ set_blocksize(logdev, 512);
} else {
mp->m_logdev_targp = mp->m_ddev_targp;
}
- if ((error = xfs_start_flags(ap, mp, ronly)))
- goto error3;
+ error = xfs_start_flags(args, mp, ronly);
+ if (error)
+ goto error;
- if ((error = xfs_readsb(mp)))
- goto error3;
+ error = xfs_readsb(mp);
+ if (error)
+ goto error;
- if ((error = xfs_finish_flags(ap, mp, ronly))) {
+ error = xfs_finish_flags(args, mp, ronly);
+ if (error) {
xfs_freesb(mp);
- goto error3;
+ goto error;
}
- pagebuf_target_blocksize(mp->m_ddev_targp, mp->m_sb.sb_blocksize);
- if (logdev != 0 && logdev != ddev)
- pagebuf_target_blocksize(mp->m_logdev_targp,
- mp->m_sb.sb_blocksize);
- if (rtdev != 0)
- pagebuf_target_blocksize(mp->m_rtdev_targp,
- mp->m_sb.sb_blocksize);
+ mp->m_ddev_targp->pbr_blocksize = mp->m_sb.sb_blocksize;
+ if (logdev != 0 && logdev != ddev) {
+ mp->m_logdev_targp->pbr_blocksize = mp->m_sb.sb_blocksize;
+ }
+ if (rtdev != 0) {
+ mp->m_rtdev_targp->pbr_blocksize = mp->m_sb.sb_blocksize;
+ }
mp->m_cxfstype = XFS_CXFS_NOT;
- error = xfs_mountfs(vfsp, mp, ddev, 0);
+ error = xfs_mountfs(vfsp, mp, ddev->bd_dev, 0);
if (error)
- goto error3;
+ goto error;
return 0;
- error3:
- /* It's impossible to get here before buftargs are filled */
+ error:
xfs_binval(mp->m_ddev_targp);
- pagebuf_lock_disable(mp->m_ddev_targp, 0);
- if (logdev && logdev != ddev) {
+ if (logdev != NULL && logdev != ddev) {
xfs_binval(mp->m_logdev_targp);
- pagebuf_lock_disable(mp->m_logdev_targp, 1);
}
- if (rtdev != 0) {
+ if (rtdev != NULL) {
xfs_binval(mp->m_rtdev_targp);
- pagebuf_lock_disable(mp->m_rtdev_targp, 1);
- }
- error2:
- if (error) {
- xfs_mount_free(mp, 1);
}
+ xfs_unmountfs_close(mp, NULL);
+ xfs_mount_free(mp, 1);
return error;
}
/*
- * xfs_mount
- *
- * The file system configurations are:
- * (1) device (partition) with data and internal log
- * (2) logical volume with data and log subvolumes.
- * (3) logical volume with data, log, and realtime subvolumes.
- */
-STATIC int
-xfs_mount(
- vfs_t *vfsp,
- struct xfs_mount_args *args,
- cred_t *credp)
-{
- dev_t ddev;
- dev_t logdev;
- dev_t rtdev;
- int error;
-
- error = spectodevs(vfsp->vfs_super, args, &ddev, &logdev, &rtdev);
- if (!error)
- error = xfs_cmountfs(vfsp, ddev, logdev, rtdev, args, credp);
- return (error);
-}
-
-/*
* xfs_ibusy searches for a busy inode in the mounted file system.
*
* Return 0 if there are no active inodes otherwise return 1.
@@ -1149,7 +1115,7 @@ xfs_syncsub(
* in taking a snapshot of the vnode version number
* for use in calling vn_get().
*/
- VMAP(vp, ip, vmap);
+ VMAP(vp, vmap);
IPOINTER_INSERT(ip, mp);
vp = vn_get(vp, &vmap);
@@ -1601,6 +1567,39 @@ xfs_syncsub(
return XFS_ERROR(last_error);
}
+STATIC void
+xfs_initialize_vnode(
+ bhv_desc_t *bdp,
+ vnode_t *vp,
+ bhv_desc_t *inode_bhv,
+ int unlock)
+{
+ xfs_inode_t *ip = XFS_BHVTOI(inode_bhv);
+ struct inode *inode = LINVFS_GET_IP(vp);
+
+ if (vp->v_fbhv == NULL) {
+ vp->v_vfsp = bhvtovfs(bdp);
+ bhv_desc_init(&(ip->i_bhv_desc), ip, vp, &xfs_vnodeops);
+ bhv_insert_initial(VN_BHV_HEAD(vp), &(ip->i_bhv_desc));
+ }
+
+ vp->v_type = IFTOVT(ip->i_d.di_mode);
+ /* Have we been called during the new inode create process,
+ * in which case we are too early to fill in the linux inode.
+ */
+ if (vp->v_type == VNON)
+ return;
+
+ xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);
+
+ /* For new inodes we need to set the ops vectors,
+ * and unlock the inode.
+ */
+ if (unlock && (inode->i_state & I_NEW)) {
+ linvfs_set_inode_ops(inode);
+ unlock_new_inode(inode);
+ }
+}
/*
* xfs_vget - called by DMAPI to get vnode from file handle
@@ -1653,11 +1652,6 @@ xfs_vget(
inode = LINVFS_GET_IP((*vpp));
xfs_iunlock(ip, XFS_ILOCK_SHARED);
- error = linvfs_revalidate_core(inode, ATTR_COMM);
- if (error) {
- iput(inode);
- return XFS_ERROR(error);
- }
return 0;
}
@@ -1670,6 +1664,7 @@ vfsops_t xfs_vfsops = {
.vfs_statvfs = xfs_statvfs,
.vfs_sync = xfs_sync,
.vfs_vget = xfs_vget,
+ .vfs_init_vnode = xfs_initialize_vnode,
.vfs_force_shutdown = xfs_do_force_shutdown,
#ifdef CONFIG_XFS_DMAPI
.vfs_dmapi_mount = xfs_dm_mount,
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 46c42a2cd8ed..07f1af20c108 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -208,7 +208,7 @@ xfs_getattr(
(mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog);
}
} else {
- vap->va_rdev = IRIX_DEV_TO_KDEVT(ip->i_df.if_u2.if_rdev);
+ vap->va_rdev = ip->i_df.if_u2.if_rdev;
vap->va_blksize = BLKDEV_IOSIZE;
}
@@ -1970,7 +1970,7 @@ xfs_create(
vnode_t *vp=NULL;
xfs_trans_t *tp;
xfs_mount_t *mp;
- dev_t rdev;
+ xfs_dev_t rdev;
int error;
xfs_bmap_free_t free_list;
xfs_fsblock_t first_block;
@@ -2955,8 +2955,7 @@ xfs_mkdir(
xfs_inode_t *cdp; /* inode of created dir */
vnode_t *cvp; /* vnode of created dir */
xfs_trans_t *tp;
- dev_t rdev;
- mode_t mode;
+ xfs_dev_t rdev;
xfs_mount_t *mp;
int cancel_flags;
int error;
@@ -3062,8 +3061,9 @@ xfs_mkdir(
* create the directory inode.
*/
rdev = (vap->va_mask & AT_RDEV) ? vap->va_rdev : 0;
- mode = IFDIR | (vap->va_mode & ~IFMT);
- error = xfs_dir_ialloc(&tp, dp, mode, 2, rdev, credp, prid, resblks > 0,
+ error = xfs_dir_ialloc(&tp, dp,
+ MAKEIMODE(vap->va_type,vap->va_mode), 2,
+ rdev, credp, prid, resblks > 0,
&cdp, NULL);
if (error) {
if (error == ENOSPC)
@@ -3521,7 +3521,7 @@ xfs_symlink(
xfs_inode_t *ip;
int error;
int pathlen;
- dev_t rdev;
+ xfs_dev_t rdev;
xfs_bmap_free_t free_list;
xfs_fsblock_t first_block;
boolean_t dp_joined_to_trans;
@@ -3702,7 +3702,7 @@ xfs_symlink(
*/
if (pathlen <= XFS_IFORK_DSIZE(ip)) {
xfs_idata_realloc(ip, pathlen, XFS_DATA_FORK);
- bcopy(target_path, ip->i_df.if_u1.if_data, pathlen);
+ memcpy(ip->i_df.if_u1.if_data, target_path, pathlen);
ip->i_d.di_size = pathlen;
/*
@@ -3743,7 +3743,7 @@ xfs_symlink(
}
pathlen -= byte_cnt;
- bcopy(cur_chunk, XFS_BUF_PTR(bp), byte_cnt);
+ memcpy(XFS_BUF_PTR(bp), cur_chunk, byte_cnt);
cur_chunk += byte_cnt;
xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1);
@@ -3859,10 +3859,10 @@ xfs_fid2(
xfid->fid_len = sizeof(xfs_fid2_t) - sizeof(xfid->fid_len);
xfid->fid_pad = 0;
/*
- * use bcopy because the inode is a long long and there's no
+ * use memcpy because the inode is a long long and there's no
* assurance that xfid->fid_ino is properly aligned.
*/
- bcopy(&ip->i_ino, &xfid->fid_ino, sizeof xfid->fid_ino);
+ memcpy(&xfid->fid_ino, &ip->i_ino, sizeof(xfid->fid_ino));
xfid->fid_gen = ip->i_d.di_gen;
return 0;
@@ -4504,9 +4504,9 @@ xfs_zero_remaining_bytes(
mp, bp, XFS_BUF_ADDR(bp));
break;
}
- bzero(XFS_BUF_PTR(bp) +
+ memset(XFS_BUF_PTR(bp) +
(offset - XFS_FSB_TO_B(mp, imap.br_startoff)),
- lastoffset - offset + 1);
+ 0, lastoffset - offset + 1);
XFS_BUF_UNDONE(bp);
XFS_BUF_UNREAD(bp);
XFS_BUF_WRITE(bp);
@@ -4937,7 +4937,6 @@ vnodeops_t xfs_vnodeops = {
.vop_rwlock = xfs_rwlock,
.vop_rwunlock = xfs_rwunlock,
.vop_bmap = xfs_bmap,
- .vop_strategy = xfs_strategy,
.vop_reclaim = xfs_reclaim,
.vop_attr_get = xfs_attr_get,
.vop_attr_set = xfs_attr_set,
diff --git a/fs/xfs/xfsidbg.c b/fs/xfs/xfsidbg.c
index 28ec0bd10af3..f4d1a6b4951e 100644
--- a/fs/xfs/xfsidbg.c
+++ b/fs/xfs/xfsidbg.c
@@ -53,6 +53,9 @@ static void xfsidbg_xagf(xfs_agf_t *);
static void xfsidbg_xagi(xfs_agi_t *);
static void xfsidbg_xaildump(xfs_mount_t *);
static void xfsidbg_xalloc(xfs_alloc_arg_t *);
+#ifdef DEBUG
+static void xfsidbg_xalmtrace(xfs_mount_t *);
+#endif
static void xfsidbg_xattrcontext(xfs_attr_list_context_t *);
static void xfsidbg_xattrleaf(xfs_attr_leafblock_t *);
static void xfsidbg_xattrsf(xfs_attr_shortform_t *);
@@ -196,6 +199,29 @@ static int kdbm_xfs_xalloc(
return 0;
}
+#ifdef DEBUG
+static int kdbm_xfs_xalmtrace(
+ int argc,
+ const char **argv,
+ const char **envp,
+ struct pt_regs *regs)
+{
+ unsigned long addr;
+ int nextarg = 1;
+ long offset = 0;
+ int diag;
+
+ if (argc != 1)
+ return KDB_ARGCOUNT;
+ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs);
+ if (diag)
+ return diag;
+
+ xfsidbg_xalmtrace((xfs_mount_t *) addr);
+ return 0;
+}
+#endif /* DEBUG */
+
static int kdbm_xfs_xattrcontext(
int argc,
const char **argv,
@@ -1700,18 +1726,19 @@ static int kdbm_vn(
/* pagebuf stuff */
static char *pb_flag_vals[] = {
- "READ", "WRITE", "MAPPED", "PARTIAL",
- "ASYNC", "NONE", "DELWRI", "FREED", "SYNC",
- "MAPPABLE", "STALE", "FS_MANAGED", "RELEASE",
- "LOCK", "TRYLOCK", "ALLOCATE", "FILE_ALLOCATE", "DONT_BLOCK",
- "DIRECT", "LOCKABLE", "NEXT_KEY", "ENTER_PAGES",
- "ALL_PAGES_MAPPED", "SOME_INVALID_PAGES", "ADDR_ALLOCATED",
- "MEM_ALLOCATED", "GRIO", "FORCEIO", "SHUTDOWN",
- NULL };
+/* 0 */ "READ", "WRITE", "MAPPED", "PARTIAL", "ASYNC",
+/* 5 */ "NONE", "DELWRI", "FREED", "SYNC", "MAPPABLE",
+/* 10 */ "STALE", "FS_MANAGED", "INVALID12", "LOCK", "TRYLOCK",
+/* 15 */ "FILE_ALLOCATE", "DONT_BLOCK", "DIRECT", "INVALID18", "LOCKABLE",
+/* 20 */ "PRIVATE_BH", "ALL_PAGES_MAPPED", "ADDR_ALLOCATED", "MEM_ALLOCATED",
+ "FORCEIO",
+/* 25 */ "FLUSH", "READ_AHEAD", "INVALID27", "INVALID28", "INVALID29",
+/* 30 */ "INVALID30", "INVALID31",
+ NULL };
static char *pbm_flag_vals[] = {
- "EOF", "HOLE", "DELAY", "FLUSH_OVERLAPS",
- "READAHEAD", "UNWRITTEN", "DONTALLOC", "NEW",
+ "EOF", "HOLE", "DELAY", "INVALID0x08",
+ "INVALID0x10", "UNWRITTEN", "INVALID0x40", "INVALID0x80",
NULL };
@@ -1964,7 +1991,7 @@ pb_trace_core(
if ((trace->event < EV_SIZE-1) && event_names[trace->event]) {
event = event_names[trace->event];
- } else if (trace->event == EV_SIZE) {
+ } else if (trace->event == EV_SIZE-1) {
event = (char *)trace->misc;
} else {
event = value;
@@ -2081,6 +2108,10 @@ static struct xif {
"Dump XFS AIL for a mountpoint" },
{ "xalloc", kdbm_xfs_xalloc, "<xfs_alloc_arg_t>",
"Dump XFS allocation args structure" },
+#ifdef DEBUG
+ { "xalmtrc", kdbm_xfs_xalmtrace, "<xfs_mount_t>",
+ "Dump XFS alloc mount-point trace" },
+#endif
{ "xattrcx", kdbm_xfs_xattrcontext, "<xfs_attr_list_context_t>",
"Dump XFS attr_list context struct"},
{ "xattrlf", kdbm_xfs_xattrleaf, "<xfs_attr_leafblock_t>",
@@ -2245,13 +2276,14 @@ static char *xfs_alloctype[] = {
/*
* Prototypes for static functions.
*/
+#ifdef DEBUG
+static int xfs_alloc_trace_entry(ktrace_entry_t *ktep);
+#endif
static void xfs_broot(xfs_inode_t *ip, xfs_ifork_t *f);
static void xfs_btalloc(xfs_alloc_block_t *bt, int bsz);
static void xfs_btbmap(xfs_bmbt_block_t *bt, int bsz);
static void xfs_btino(xfs_inobt_block_t *bt, int bsz);
static void xfs_buf_item_print(xfs_buf_log_item_t *blip, int summary);
-static void xfs_convert_extent(xfs_bmbt_rec_64_t *rp, xfs_dfiloff_t *op,
- xfs_dfsbno_t *sp, xfs_dfilblks_t *cp, int *fp);
static void xfs_dastate_path(xfs_da_state_path_t *p);
static void xfs_dir2data(void *addr, int size);
static void xfs_dir2leaf(xfs_dir2_leaf_t *leaf, int size);
@@ -2277,6 +2309,137 @@ static void xfs_xnode_fork(char *name, xfs_ifork_t *f);
* Static functions.
*/
+#ifdef DEBUG
+/*
+ * Print xfs alloc trace buffer entry.
+ */
+static int
+xfs_alloc_trace_entry(ktrace_entry_t *ktep)
+{
+ static char *modagf_flags[] = {
+ "magicnum",
+ "versionnum",
+ "seqno",
+ "length",
+ "roots",
+ "levels",
+ "flfirst",
+ "fllast",
+ "flcount",
+ "freeblks",
+ "longest",
+ NULL
+ };
+
+ if (((__psint_t)ktep->val[0] & 0xffff) == 0)
+ return 0;
+ switch ((long)ktep->val[0] & 0xffffL) {
+ case XFS_ALLOC_KTRACE_ALLOC:
+ kdb_printf("alloc %s[%s %d] mp 0x%p\n",
+ (char *)ktep->val[1],
+ ktep->val[2] ? (char *)ktep->val[2] : "",
+ (__psint_t)ktep->val[0] >> 16,
+ (xfs_mount_t *)ktep->val[3]);
+ kdb_printf(
+ "agno %d agbno %d minlen %d maxlen %d mod %d prod %d minleft %d\n",
+ (__psunsigned_t)ktep->val[4],
+ (__psunsigned_t)ktep->val[5],
+ (__psunsigned_t)ktep->val[6],
+ (__psunsigned_t)ktep->val[7],
+ (__psunsigned_t)ktep->val[8],
+ (__psunsigned_t)ktep->val[9],
+ (__psunsigned_t)ktep->val[10]);
+ kdb_printf("total %d alignment %d len %d type %s otype %s\n",
+ (__psunsigned_t)ktep->val[11],
+ (__psunsigned_t)ktep->val[12],
+ (__psunsigned_t)ktep->val[13],
+ xfs_alloctype[((__psint_t)ktep->val[14]) >> 16],
+ xfs_alloctype[((__psint_t)ktep->val[14]) & 0xffff]);
+ kdb_printf("wasdel %d wasfromfl %d isfl %d userdata %d\n",
+ ((__psint_t)ktep->val[15] & (1 << 3)) != 0,
+ ((__psint_t)ktep->val[15] & (1 << 2)) != 0,
+ ((__psint_t)ktep->val[15] & (1 << 1)) != 0,
+ ((__psint_t)ktep->val[15] & (1 << 0)) != 0);
+ break;
+ case XFS_ALLOC_KTRACE_FREE:
+ kdb_printf("free %s[%s %d] mp 0x%p\n",
+ (char *)ktep->val[1],
+ ktep->val[2] ? (char *)ktep->val[2] : "",
+ (__psint_t)ktep->val[0] >> 16,
+ (xfs_mount_t *)ktep->val[3]);
+ kdb_printf("agno %d agbno %d len %d isfl %d\n",
+ (__psunsigned_t)ktep->val[4],
+ (__psunsigned_t)ktep->val[5],
+ (__psunsigned_t)ktep->val[6],
+ (__psint_t)ktep->val[7]);
+ break;
+ case XFS_ALLOC_KTRACE_MODAGF:
+ kdb_printf("modagf %s[%s %d] mp 0x%p\n",
+ (char *)ktep->val[1],
+ ktep->val[2] ? (char *)ktep->val[2] : "",
+ (__psint_t)ktep->val[0] >> 16,
+ (xfs_mount_t *)ktep->val[3]);
+ printflags((__psint_t)ktep->val[4], modagf_flags, "modified");
+ kdb_printf("seqno %d length %d roots b %d c %d\n",
+ (__psunsigned_t)ktep->val[5],
+ (__psunsigned_t)ktep->val[6],
+ (__psunsigned_t)ktep->val[7],
+ (__psunsigned_t)ktep->val[8]);
+ kdb_printf("levels b %d c %d flfirst %d fllast %d flcount %d\n",
+ (__psunsigned_t)ktep->val[9],
+ (__psunsigned_t)ktep->val[10],
+ (__psunsigned_t)ktep->val[11],
+ (__psunsigned_t)ktep->val[12],
+ (__psunsigned_t)ktep->val[13]);
+ kdb_printf("freeblks %d longest %d\n",
+ (__psunsigned_t)ktep->val[14],
+ (__psunsigned_t)ktep->val[15]);
+ break;
+
+ case XFS_ALLOC_KTRACE_UNBUSY:
+ kdb_printf("unbusy %s [%s %d] mp 0x%p\n",
+ (char *)ktep->val[1],
+ ktep->val[2] ? (char *)ktep->val[2] : "",
+ (__psint_t)ktep->val[0] >> 16,
+ (xfs_mount_t *)ktep->val[3]);
+ kdb_printf(" agno %d slot %d tp 0x%x\n",
+ (__psunsigned_t)ktep->val[4],
+ (__psunsigned_t)ktep->val[7],
+ (__psunsigned_t)ktep->val[8]);
+ break;
+ case XFS_ALLOC_KTRACE_BUSY:
+ kdb_printf("busy %s [%s %d] mp 0x%p\n",
+ (char *)ktep->val[1],
+ ktep->val[2] ? (char *)ktep->val[2] : "",
+ (__psint_t)ktep->val[0] >> 16,
+ (xfs_mount_t *)ktep->val[3]);
+ kdb_printf(" agno %d agbno %d len %d slot %d tp 0x%x\n",
+ (__psunsigned_t)ktep->val[4],
+ (__psunsigned_t)ktep->val[5],
+ (__psunsigned_t)ktep->val[6],
+ (__psunsigned_t)ktep->val[7],
+ (__psunsigned_t)ktep->val[8]);
+ break;
+ case XFS_ALLOC_KTRACE_BUSYSEARCH:
+ kdb_printf("busy-search %s [%s %d] mp 0x%p\n",
+ (char *)ktep->val[1],
+ ktep->val[2] ? (char *)ktep->val[2] : "",
+ (__psint_t)ktep->val[0] >> 16,
+ (xfs_mount_t *)ktep->val[3]);
+ kdb_printf(" agno %d agbno %d len %d slot %d tp 0x%x\n",
+ (__psunsigned_t)ktep->val[4],
+ (__psunsigned_t)ktep->val[5],
+ (__psunsigned_t)ktep->val[6],
+ (__psunsigned_t)ktep->val[7],
+ (__psunsigned_t)ktep->val[8]);
+ break;
+ default:
+ kdb_printf("unknown alloc trace record\n");
+ break;
+ }
+ return 1;
+}
+#endif /* DEBUG */
/*
* Print an xfs in-inode bmap btree root.
@@ -2359,18 +2522,17 @@ xfs_btbmap(xfs_bmbt_block_t *bt, int bsz)
kdb_printf("rightsib %Lx\n", INT_GET(bt->bb_rightsib, ARCH_CONVERT));
if (INT_ISZERO(bt->bb_level, ARCH_CONVERT)) {
for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) {
- xfs_bmbt_rec_64_t *r;
- xfs_dfiloff_t o;
- xfs_dfsbno_t s;
- xfs_dfilblks_t c;
- int fl;
+ xfs_bmbt_rec_t *r;
+ xfs_bmbt_irec_t irec;
- r = (xfs_bmbt_rec_64_t *)XFS_BTREE_REC_ADDR(bsz,
+ r = (xfs_bmbt_rec_t *)XFS_BTREE_REC_ADDR(bsz,
xfs_bmbt, bt, i, 0);
- xfs_convert_extent(r, &o, &s, &c, &fl);
- kdb_printf("rec %d startoff %Ld ", i, o);
- kdb_printf("startblock %Lx ", s);
- kdb_printf("blockcount %Ld flag %d\n", c, fl);
+
+ xfs_bmbt_disk_get_all((xfs_bmbt_rec_t *)r, &irec);
+ kdb_printf("rec %d startoff %Ld startblock %Lx blockcount %Ld flag %d\n",
+ i, irec.br_startoff,
+ (__uint64_t)irec.br_startblock,
+ irec.br_blockcount, irec.br_state);
}
} else {
int mxr;
@@ -2473,31 +2635,6 @@ xfs_buf_item_print(xfs_buf_log_item_t *blip, int summary)
}
/*
- * Convert an external extent descriptor to internal form.
- */
-static void
-xfs_convert_extent(xfs_bmbt_rec_64_t *rp, xfs_dfiloff_t *op, xfs_dfsbno_t *sp,
- xfs_dfilblks_t *cp, int *fp)
-{
- xfs_dfiloff_t o;
- xfs_dfsbno_t s;
- xfs_dfilblks_t c;
- int flag;
-
- flag = (int)((INT_GET(rp->l0, ARCH_CONVERT)) >> (64 - 1 ));
- o = ((xfs_fileoff_t)INT_GET(rp->l0, ARCH_CONVERT) &
- (((__uint64_t)1 << ( 64 - 1 )) - 1) ) >> 9;
- s = (((xfs_fsblock_t)INT_GET(rp->l0, ARCH_CONVERT) & (((__uint64_t)1 << ( 9 )) - 1) ) << 43) |
- (((xfs_fsblock_t)INT_GET(rp->l1, ARCH_CONVERT)) >> 21);
- c = (xfs_filblks_t)(INT_GET(rp->l1, ARCH_CONVERT) & (((__uint64_t)1 << ( 21 )) - 1) );
- *op = o;
- *sp = s;
- *cp = c;
- *fp = flag;
-}
-
-
-/*
* Print an xfs_da_state_path structure.
*/
static void
@@ -2890,11 +3027,8 @@ static void
xfs_xexlist_fork(xfs_inode_t *ip, int whichfork)
{
int nextents, i;
- xfs_dfiloff_t o;
- xfs_dfsbno_t s;
- xfs_dfilblks_t c;
- int flag;
xfs_ifork_t *ifp;
+ xfs_bmbt_irec_t irec;
ifp = XFS_IFORK_PTR(ip, whichfork);
if (ifp->if_flags & XFS_IFEXTENTS) {
@@ -2902,12 +3036,12 @@ xfs_xexlist_fork(xfs_inode_t *ip, int whichfork)
kdb_printf("inode 0x%p %cf extents 0x%p nextents 0x%x\n",
ip, "da"[whichfork], ifp->if_u1.if_extents, nextents);
for (i = 0; i < nextents; i++) {
- xfs_convert_extent(
- (xfs_bmbt_rec_64_t *)&ifp->if_u1.if_extents[i],
- &o, &s, &c, &flag);
+ xfs_bmbt_get_all(&ifp->if_u1.if_extents[i], &irec);
kdb_printf(
"%d: startoff %Ld startblock %s blockcount %Ld flag %d\n",
- i, o, xfs_fmtfsblock(s, ip->i_mount), c, flag);
+ i, irec.br_startoff,
+ xfs_fmtfsblock(irec.br_startblock, ip->i_mount),
+ irec.br_blockcount, irec.br_state);
}
}
}
@@ -3030,7 +3164,33 @@ xfsidbg_xalloc(xfs_alloc_arg_t *args)
args->wasfromfl, args->isfl, args->userdata);
}
+#ifdef DEBUG
+/*
+ * Print out all the entries in the alloc trace buf corresponding
+ * to the given mount point.
+ */
+static void
+xfsidbg_xalmtrace(xfs_mount_t *mp)
+{
+ ktrace_entry_t *ktep;
+ ktrace_snap_t kts;
+ extern ktrace_t *xfs_alloc_trace_buf;
+
+ if (xfs_alloc_trace_buf == NULL) {
+ kdb_printf("The xfs alloc trace buffer is not initialized\n");
+ return;
+ }
+ ktep = ktrace_first(xfs_alloc_trace_buf, &kts);
+ while (ktep != NULL) {
+ if ((__psint_t)ktep->val[0] && (xfs_mount_t *)ktep->val[3] == mp) {
+ (void)xfs_alloc_trace_entry(ktep);
+ kdb_printf("\n");
+ }
+ ktep = ktrace_next(xfs_alloc_trace_buf, &kts);
+ }
+}
+#endif /* DEBUG */
/*
* Print an attr_list() context structure.
@@ -3199,14 +3359,12 @@ xfsidbg_xbmalla(xfs_bmalloca_t *a)
static void
xfsidbg_xbrec(xfs_bmbt_rec_64_t *r)
{
- xfs_dfiloff_t o;
- xfs_dfsbno_t s;
- xfs_dfilblks_t c;
- int flag;
+ xfs_bmbt_irec_t irec;
- xfs_convert_extent(r, &o, &s, &c, &flag);
+ xfs_bmbt_get_all((xfs_bmbt_rec_t *)r, &irec);
kdb_printf("startoff %Ld startblock %Lx blockcount %Ld flag %d\n",
- o, s, c, flag);
+ irec.br_startoff, (__uint64_t)irec.br_startblock,
+ irec.br_blockcount, irec.br_state);
}
/*
@@ -4412,8 +4570,7 @@ xfsidbg_xmount(xfs_mount_t *mp)
"OSYNC", /* 0x2000 */
"NOUUID", /* 0x4000 */
"32BIT", /* 0x8000 */
- "IRIXSGID", /* 0x10000 */
- "NOLOGFLUSH", /* 0x20000 */
+ "NOLOGFLUSH", /* 0x10000 */
0
};
@@ -4438,9 +4595,9 @@ xfsidbg_xmount(xfs_mount_t *mp)
mp->m_ail_gen, &mp->m_sb);
kdb_printf("sb_lock 0x%p sb_bp 0x%p dev 0x%x logdev 0x%x rtdev 0x%x\n",
&mp->m_sb_lock, mp->m_sb_bp,
- mp->m_ddev_targp->pbr_dev,
- mp->m_logdev_targp->pbr_dev,
- mp->m_rtdev_targp->pbr_dev);
+ mp->m_ddev_targp ? mp->m_ddev_targp->pbr_dev : 0,
+ mp->m_logdev_targp ? mp->m_logdev_targp->pbr_dev : 0,
+ mp->m_rtdev_targp ? mp->m_rtdev_targp->pbr_dev : 0);
kdb_printf("bsize %d agfrotor %d agirotor %d ihash 0x%p ihsize %d\n",
mp->m_bsize, mp->m_agfrotor, mp->m_agirotor,
mp->m_ihash, mp->m_ihsize);
@@ -4734,13 +4891,17 @@ xfsidbg_xperag(xfs_mount_t *mp)
if (pag->pagi_init)
kdb_printf(" i_freecount %d i_inodeok %d\n",
pag->pagi_freecount, pag->pagi_inodeok);
-
- for (busy = 0; busy < XFS_PAGB_NUM_SLOTS; busy++) {
- kdb_printf(" %04d: start %d length %d tp 0x%p\n",
- busy,
- pag->pagb_list[busy].busy_start,
- pag->pagb_list[busy].busy_length,
- pag->pagb_list[busy].busy_tp);
+ if (pag->pagf_init) {
+ for (busy = 0; busy < XFS_PAGB_NUM_SLOTS; busy++) {
+ if (pag->pagb_list[busy].busy_length != 0) {
+ kdb_printf(
+ " %04d: start %d length %d tp 0x%p\n",
+ busy,
+ pag->pagb_list[busy].busy_start,
+ pag->pagb_list[busy].busy_length,
+ pag->pagb_list[busy].busy_tp);
+ }
+ }
}
}
}
@@ -5138,8 +5299,10 @@ xfsidbg_xtp(xfs_trans_t *tp)
tp->t_log_res, tp->t_blk_res, tp->t_blk_res_used);
kdb_printf("rt res %d rt res used %d\n", tp->t_rtx_res,
tp->t_rtx_res_used);
- kdb_printf("ticket 0x%lx lsn %s\n",
- (unsigned long) tp->t_ticket, xfs_fmtlsn(&tp->t_lsn));
+ kdb_printf("ticket 0x%lx lsn %s commit_lsn %s\n",
+ (unsigned long) tp->t_ticket,
+ xfs_fmtlsn(&tp->t_lsn),
+ xfs_fmtlsn(&tp->t_commit_lsn));
kdb_printf("callback 0x%p callarg 0x%p\n",
tp->t_callback, tp->t_callarg);
kdb_printf("icount delta %ld ifree delta %ld\n",