summaryrefslogtreecommitdiffstats
path: root/extras/ganesha
ModeNameSize
-rw-r--r--Makefile.am42logstatsplain
d---------config89logstatsplain
d---------ocf159logstatsplain
d---------scripts172logstatsplain
d2=3b23f9acae02e6be192c00fc410a4d15974f5343'>api/examples/glfsxmp.c1703
-rw-r--r--api/examples/setup.py.in29
-rw-r--r--api/src/Makefile.am5
-rw-r--r--api/src/glfs-fops.c258
-rw-r--r--api/src/glfs-handleops.c1278
-rw-r--r--api/src/glfs-handles.h143
-rw-r--r--api/src/glfs-internal.h62
-rw-r--r--api/src/glfs-master.c13
-rw-r--r--api/src/glfs-mem-types.h6
-rw-r--r--api/src/glfs-mgmt.c163
-rw-r--r--api/src/glfs-resolve.c86
-rw-r--r--api/src/glfs.c96
-rw-r--r--api/src/glfs.h85
-rw-r--r--cli/src/Makefile.am5
-rw-r--r--cli/src/cli-cmd-misc.c6
-rw-r--r--cli/src/cli-cmd-parser.c1210
-rw-r--r--cli/src/cli-cmd-snapshot.c146
-rw-r--r--cli/src/cli-cmd-volume-bdevice.c270
-rw-r--r--cli/src/cli-cmd-volume.c14
-rw-r--r--cli/src/cli-cmd.c4
-rw-r--r--cli/src/cli-cmd.h5
-rw-r--r--cli/src/cli-rpc-ops.c2189
-rw-r--r--cli/src/cli-xml-output.c311
-rw-r--r--cli/src/cli.c56
-rw-r--r--cli/src/cli.h45
-rw-r--r--configure.ac76
-rw-r--r--contrib/qemu/config-host.h1
-rw-r--r--contrib/qemu/coroutine-ucontext.c225
-rw-r--r--contrib/qemu/qemu-coroutine.c2
-rw-r--r--doc/admin-guide/en-US/markdown/admin_managing_snapshots.md66
-rw-r--r--doc/features/bd.txt130
-rw-r--r--doc/gluster.823
-rw-r--r--doc/split-brain.md251
-rw-r--r--extras/Makefile.am5
-rw-r--r--extras/glusterd.vol1
-rw-r--r--extras/glusterfs-georep-logrotate18
-rwxr-xr-xextras/hook-scripts/S30samba-set.sh14
-rwxr-xr-xextras/hook-scripts/S30samba-start.sh27
-rwxr-xr-xextras/hook-scripts/S30samba-stop.sh21
-rwxr-xr-xextras/hook-scripts/S56glusterd-geo-rep-create-post.sh5
-rw-r--r--extras/logger.conf.example11
-rw-r--r--extras/systemd/glusterd.service.in3
-rw-r--r--extras/who-wrote-glusterfs/gitdm.aliases48
-rw-r--r--extras/who-wrote-glusterfs/gitdm.config8
-rw-r--r--extras/who-wrote-glusterfs/gitdm.domain-map15
-rwxr-xr-xextras/who-wrote-glusterfs/who-wrote-glusterfs.sh50
-rwxr-xr-xgeo-replication/src/gverify.sh58
-rw-r--r--geo-replication/syncdaemon/gconf.py5
-rw-r--r--geo-replication/syncdaemon/gsyncd.py23
-rw-r--r--geo-replication/syncdaemon/master.py611
-rw-r--r--geo-replication/syncdaemon/monitor.py23
-rw-r--r--geo-replication/syncdaemon/resource.py56
-rw-r--r--geo-replication/syncdaemon/syncdutils.py58
-rw-r--r--glusterfs-api.pc.in2
-rw-r--r--glusterfs.spec.in137
-rw-r--r--glusterfsd/src/glusterfsd-mem-types.h1
-rw-r--r--glusterfsd/src/glusterfsd-mgmt.c324
-rw-r--r--glusterfsd/src/glusterfsd.c247
-rw-r--r--glusterfsd/src/glusterfsd.h2
-rw-r--r--libglusterfs/src/Makefile.am15
-rw-r--r--libglusterfs/src/call-stub.c67
-rw-r--r--libglusterfs/src/call-stub.h16
-rw-r--r--libglusterfs/src/circ-buff.c30
-rw-r--r--libglusterfs/src/circ-buff.h5
-rw-r--r--libglusterfs/src/client_t.c193
-rw-r--r--libglusterfs/src/client_t.h77
-rw-r--r--libglusterfs/src/common-utils.c107
-rw-r--r--libglusterfs/src/common-utils.h4
-rw-r--r--libglusterfs/src/defaults.c33
-rw-r--r--libglusterfs/src/defaults.h18
-rw-r--r--libglusterfs/src/dict.c32
-rw-r--r--libglusterfs/src/event-history.c6
-rw-r--r--libglusterfs/src/event-history.h3
-rw-r--r--libglusterfs/src/gidcache.c15
-rw-r--r--libglusterfs/src/gidcache.h1
-rw-r--r--libglusterfs/src/globals.c58
-rw-r--r--libglusterfs/src/globals.h4
-rw-r--r--libglusterfs/src/glusterfs-acl.h81
-rw-r--r--libglusterfs/src/glusterfs.h50
-rw-r--r--libglusterfs/src/graph.c185
-rw-r--r--libglusterfs/src/graph.l4
-rw-r--r--libglusterfs/src/graph.y84
-rw-r--r--libglusterfs/src/inode.c222
-rw-r--r--libglusterfs/src/inode.h62
-rw-r--r--libglusterfs/src/list.h28
-rw-r--r--libglusterfs/src/lock-table.c133
-rw-r--r--libglusterfs/src/lock-table.h54
-rw-r--r--libglusterfs/src/logging.h4
-rw-r--r--libglusterfs/src/mem-types.h7
-rw-r--r--libglusterfs/src/run.c2
-rw-r--r--libglusterfs/src/stack.h9
-rw-r--r--libglusterfs/src/store.c33
-rw-r--r--libglusterfs/src/syncop.c191
-rw-r--r--libglusterfs/src/syncop.h80
-rw-r--r--libglusterfs/src/timer.c27
-rw-r--r--libglusterfs/src/timer.h4
-rw-r--r--libglusterfs/src/timespec.c68
-rw-r--r--libglusterfs/src/timespec.h24
-rw-r--r--libglusterfs/src/xlator.c67
-rw-r--r--libglusterfs/src/xlator.h36
-rwxr-xr-xrfc.sh2
-rw-r--r--rpc/rpc-lib/src/auth-glusterfs.c32
-rw-r--r--rpc/rpc-lib/src/auth-unix.c1
-rw-r--r--rpc/rpc-lib/src/protocol-common.h31
-rw-r--r--rpc/rpc-lib/src/rpc-clnt.c30
-rw-r--r--rpc/rpc-lib/src/rpc-drc.c63
-rw-r--r--rpc/rpc-lib/src/rpc-drc.h4
-rw-r--r--rpc/rpc-lib/src/rpc-transport.c15
-rw-r--r--rpc/rpc-lib/src/rpc-transport.h6
-rw-r--r--rpc/rpc-lib/src/rpcsvc-auth.c46
-rw-r--r--rpc/rpc-lib/src/rpcsvc-common.h16
-rw-r--r--rpc/rpc-lib/src/rpcsvc.c201
-rw-r--r--rpc/rpc-lib/src/rpcsvc.h26
-rw-r--r--rpc/rpc-transport/rdma/src/rdma.c27
-rw-r--r--rpc/rpc-transport/socket/src/socket.c30
-rw-r--r--rpc/xdr/src/cli1-xdr.c22
-rw-r--r--rpc/xdr/src/cli1-xdr.h44
-rw-r--r--rpc/xdr/src/cli1-xdr.x31
-rw-r--r--rpc/xdr/src/glusterd1-xdr.c430
-rw-r--r--rpc/xdr/src/glusterd1-xdr.h163
-rw-r--r--rpc/xdr/src/glusterd1-xdr.x91
-rw-r--r--rpc/xdr/src/glusterfs3-xdr.c41
-rw-r--r--rpc/xdr/src/glusterfs3-xdr.h29
-rw-r--r--rpc/xdr/src/glusterfs3-xdr.x17
-rwxr-xr-xrun-tests.sh29
-rw-r--r--tests/README.md (renamed from tests/README)19
-rwxr-xr-xtests/basic/bd.t76
-rwxr-xr-xtests/basic/cdc.t135
-rwxr-xr-xtests/basic/file-snapshot.t1
-rwxr-xr-xtests/basic/mgmt_v3-locks.t121
-rwxr-xr-xtests/basic/rpm.t80
-rwxr-xr-xtests/basic/volume-snapshot.t83
-rwxr-xr-xtests/bugs/bug-1002556.t25
-rw-r--r--tests/bugs/bug-1004218.t26
-rw-r--r--tests/bugs/bug-1004744.t48
-rwxr-xr-xtests/bugs/bug-1015990-rep.t81
-rwxr-xr-xtests/bugs/bug-1015990.t95
-rwxr-xr-xtests/bugs/bug-1022055.t26
-rw-r--r--tests/bugs/bug-1022905.t39
-rw-r--r--tests/bugs/bug-1030208.t35
-rw-r--r--tests/bugs/bug-1040934.t37
-rw-r--r--tests/bugs/bug-1045333.t48
-rwxr-xr-xtests/bugs/bug-1049834.t40
-rwxr-xr-xtests/bugs/bug-1064768.t20
-rwxr-xr-xtests/bugs/bug-830665.t1
-rwxr-xr-xtests/bugs/bug-853258.t6
-rw-r--r--tests/bugs/bug-857330/common.rc2
-rwxr-xr-xtests/bugs/bug-857330/normal.t6
-rwxr-xr-xtests/bugs/bug-907072.t46
-rw-r--r--tests/bugs/bug-948729/bug-948729-force.t17
-rw-r--r--tests/bugs/bug-948729/bug-948729.t3
-rwxr-xr-xtests/bugs/bug-983477.t7
-rw-r--r--tests/bugs/bug-986429.t19
-rwxr-xr-xtests/cluster.rc16
-rw-r--r--tests/include.rc5
-rwxr-xr-xtests/snapshot.rc251
-rw-r--r--tests/volume.rc58
-rw-r--r--xlators/cluster/afr/src/afr-common.c656
-rw-r--r--xlators/cluster/afr/src/afr-inode-read.c24
-rw-r--r--xlators/cluster/afr/src/afr-inode-write.c975
-rw-r--r--xlators/cluster/afr/src/afr-inode-write.h11
-rw-r--r--xlators/cluster/afr/src/afr-lk-common.c8
-rw-r--r--xlators/cluster/afr/src/afr-mem-types.h5
-rw-r--r--xlators/cluster/afr/src/afr-self-heald.c570
-rw-r--r--xlators/cluster/afr/src/afr-self-heald.h13
-rw-r--r--xlators/cluster/afr/src/afr-transaction.c4
-rw-r--r--xlators/cluster/afr/src/afr.c17
-rw-r--r--xlators/cluster/afr/src/afr.h93
-rw-r--r--xlators/cluster/dht/src/dht-common.c59
-rw-r--r--xlators/cluster/dht/src/dht-common.h41
-rw-r--r--xlators/cluster/dht/src/dht-helper.c154
-rw-r--r--xlators/cluster/dht/src/dht-inode-read.c58
-rw-r--r--xlators/cluster/dht/src/dht-inode-write.c197
-rw-r--r--xlators/cluster/dht/src/dht-layout.c35
-rw-r--r--xlators/cluster/dht/src/dht-rebalance.c78
-rw-r--r--xlators/cluster/dht/src/dht-selfheal.c33
-rw-r--r--xlators/cluster/dht/src/dht.c1
-rw-r--r--xlators/cluster/stripe/src/stripe.c244
-rw-r--r--xlators/debug/io-stats/src/io-stats.c23
-rw-r--r--xlators/debug/trace/src/trace.c2
-rw-r--r--xlators/encryption/Makefile.am2
-rw-r--r--xlators/encryption/crypt/Makefile.am3
-rw-r--r--xlators/encryption/crypt/src/Makefile.am24
-rw-r--r--xlators/encryption/crypt/src/atom.c962
-rw-r--r--xlators/encryption/crypt/src/crypt-common.h141
-rw-r--r--xlators/encryption/crypt/src/crypt-mem-types.h43
-rw-r--r--xlators/encryption/crypt/src/crypt.c4498
-rw-r--r--xlators/encryption/crypt/src/crypt.h899
-rw-r--r--xlators/encryption/crypt/src/data.c769
-rw-r--r--xlators/encryption/crypt/src/keys.c302
-rw-r--r--xlators/encryption/crypt/src/metadata.c605
-rw-r--r--xlators/encryption/crypt/src/metadata.h74
-rw-r--r--xlators/features/Makefile.am2
-rw-r--r--xlators/features/changelog/lib/src/gf-changelog.c4
-rw-r--r--xlators/features/changelog/src/changelog-encoders.c20
-rw-r--r--xlators/features/changelog/src/changelog-encoders.h2
-rw-r--r--xlators/features/changelog/src/changelog-helpers.c4
-rw-r--r--xlators/features/changelog/src/changelog.c33
-rw-r--r--xlators/features/compress/Makefile.am (renamed from xlators/storage/bd_map/Makefile.am)0
-rw-r--r--xlators/features/compress/src/Makefile.am17
-rw-r--r--xlators/features/compress/src/cdc-helper.c547
-rw-r--r--xlators/features/compress/src/cdc-mem-types.h22
-rw-r--r--xlators/features/compress/src/cdc.c342
-rw-r--r--xlators/features/compress/src/cdc.h107
-rw-r--r--xlators/features/gfid-access/src/gfid-access.c70
-rw-r--r--xlators/features/index/src/index.c317
-rw-r--r--xlators/features/index/src/index.h14
-rw-r--r--xlators/features/locks/src/Makefile.am1
-rw-r--r--xlators/features/locks/src/common.c152
-rw-r--r--xlators/features/locks/src/common.h40
-rw-r--r--xlators/features/locks/src/entrylk.c81
-rw-r--r--xlators/features/locks/src/inodelk.c75
-rw-r--r--xlators/features/locks/src/locks.h24
-rw-r--r--xlators/features/locks/src/posix.c167
-rw-r--r--xlators/features/marker/src/marker.c95
-rw-r--r--xlators/features/marker/src/marker.h5
-rw-r--r--xlators/features/qemu-block/src/Makefile.am10
-rw-r--r--xlators/features/qemu-block/src/bdrv-xlator.c43
-rw-r--r--xlators/features/qemu-block/src/coroutine-synctask.c215
-rw-r--r--xlators/features/qemu-block/src/coroutine-synctask.h51
-rw-r--r--xlators/features/qemu-block/src/qb-coroutines.c111
-rw-r--r--xlators/features/qemu-block/src/qb-coroutines.h1
-rw-r--r--xlators/features/qemu-block/src/qemu-block.c140
-rw-r--r--xlators/features/qemu-block/src/qemu-block.h10
-rw-r--r--xlators/features/quiesce/src/quiesce.c8
-rw-r--r--xlators/mgmt/glusterd/src/Makefile.am7
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-brick-ops.c120
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-geo-rep.c592
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-handler.c536
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-handshake.c249
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-locks.c637
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-locks.h51
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-log-ops.c9
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-mem-types.h4
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-mgmt-handler.c924
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-mgmt.c1893
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-mgmt.h45
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-op-sm.c1218
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-op-sm.h28
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-pmap.c12
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-rebalance.c5
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-replace-brick.c25
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-rpc-ops.c342
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-sm.h1
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-snapshot.c5590
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-store.c1207
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-store.h97
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-syncop.c515
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-syncop.h17
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.c1374
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.h74
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.c309
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.h18
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volume-ops.c360
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volume-set.c122
-rw-r--r--xlators/mgmt/glusterd/src/glusterd.c283
-rw-r--r--xlators/mgmt/glusterd/src/glusterd.h422
-rw-r--r--xlators/mount/fuse/src/fuse-bridge.c70
-rw-r--r--xlators/mount/fuse/src/fuse-bridge.h23
-rw-r--r--xlators/mount/fuse/src/fuse-helpers.c4
-rwxr-xr-xxlators/mount/fuse/utils/mount.glusterfs.in151
-rw-r--r--xlators/nfs/server/src/acl3.c165
-rw-r--r--xlators/nfs/server/src/acl3.h17
-rw-r--r--xlators/nfs/server/src/mount3.c189
-rw-r--r--xlators/nfs/server/src/mount3.h24
-rw-r--r--xlators/nfs/server/src/mount3udp_svc.c17
-rw-r--r--xlators/nfs/server/src/nfs-common.c19
-rw-r--r--xlators/nfs/server/src/nfs-common.h17
-rw-r--r--xlators/nfs/server/src/nfs-fops.c17
-rw-r--r--xlators/nfs/server/src/nfs-fops.h17
-rw-r--r--xlators/nfs/server/src/nfs-generics.c17
-rw-r--r--xlators/nfs/server/src/nfs-generics.h17
-rw-r--r--xlators/nfs/server/src/nfs-inodes.c21
-rw-r--r--xlators/nfs/server/src/nfs-inodes.h17
-rw-r--r--xlators/nfs/server/src/nfs-mem-types.h18
-rw-r--r--xlators/nfs/server/src/nfs.c523
-rw-r--r--xlators/nfs/server/src/nfs.h20
-rw-r--r--xlators/nfs/server/src/nfs3-fh.c29
-rw-r--r--xlators/nfs/server/src/nfs3-fh.h19
-rw-r--r--xlators/nfs/server/src/nfs3-helpers.c166
-rw-r--r--xlators/nfs/server/src/nfs3-helpers.h20
-rw-r--r--xlators/nfs/server/src/nfs3.c299
-rw-r--r--xlators/nfs/server/src/nfs3.h74
-rw-r--r--xlators/nfs/server/src/nlm4.c67
-rw-r--r--xlators/nfs/server/src/nlm4.h17
-rw-r--r--xlators/nfs/server/src/nlmcbk_svc.c27
-rw-r--r--xlators/performance/io-cache/src/io-cache.c26
-rw-r--r--xlators/performance/io-threads/src/io-threads.c53
-rw-r--r--xlators/performance/md-cache/src/md-cache.c48
-rw-r--r--xlators/performance/open-behind/src/open-behind.c21
-rw-r--r--xlators/performance/read-ahead/src/read-ahead.c52
-rw-r--r--xlators/protocol/auth/addr/src/addr.c17
-rw-r--r--xlators/protocol/auth/login/src/login.c17
-rw-r--r--xlators/protocol/client/src/client-handshake.c12
-rw-r--r--xlators/protocol/client/src/client-rpc-fops.c103
-rw-r--r--xlators/protocol/client/src/client.c47
-rw-r--r--xlators/protocol/client/src/client.h2
-rw-r--r--xlators/protocol/server/src/Makefile.am6
-rw-r--r--xlators/protocol/server/src/server-handshake.c32
-rw-r--r--xlators/protocol/server/src/server-helpers.c649
-rw-r--r--xlators/protocol/server/src/server-helpers.h19
-rw-r--r--xlators/protocol/server/src/server-resolve.c32
-rw-r--r--xlators/protocol/server/src/server-rpc-fops.c1356
-rw-r--r--xlators/protocol/server/src/server.c215
-rw-r--r--xlators/protocol/server/src/server.h53
-rw-r--r--xlators/storage/Makefile.am3
-rw-r--r--xlators/storage/bd/Makefile.am3
-rw-r--r--xlators/storage/bd/src/Makefile.am (renamed from xlators/storage/bd_map/src/Makefile.am)11
-rw-r--r--xlators/storage/bd/src/bd-aio.c527
-rw-r--r--xlators/storage/bd/src/bd-aio.h41
-rw-r--r--xlators/storage/bd/src/bd-helper.c783
-rw-r--r--xlators/storage/bd/src/bd.c2404
-rw-r--r--xlators/storage/bd/src/bd.h178
-rw-r--r--xlators/storage/bd_map/src/bd_map.c2580
-rw-r--r--xlators/storage/bd_map/src/bd_map.h82
-rw-r--r--xlators/storage/bd_map/src/bd_map_help.c501
-rw-r--r--xlators/storage/bd_map/src/bd_map_help.h69
-rw-r--r--xlators/storage/posix/src/posix-aio.c10
-rw-r--r--xlators/storage/posix/src/posix-helpers.c21
-rw-r--r--xlators/storage/posix/src/posix.c219
-rw-r--r--xlators/storage/posix/src/posix.h2
-rw-r--r--xlators/system/posix-acl/src/posix-acl-xattr.c4
-rw-r--r--xlators/system/posix-acl/src/posix-acl-xattr.h16
-rw-r--r--xlators/system/posix-acl/src/posix-acl.c46
-rw-r--r--xlators/system/posix-acl/src/posix-acl.h49
332 files changed, 48864 insertions, 10838 deletions
diff --git a/.gitignore b/.gitignore
index d3e1a01dd..ff253c1da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,23 +22,27 @@ Makefile
stamp-h1
# Generated files
-ufo/.tox
-ufo/test/unit/.coverage
+api/examples/__init__.py*
+api/examples/setup.py
+argp-standalone/libargp.a
contrib/uuid/uuid_types.h
-extras/init.d/glusterd.plist
extras/init.d/glusterd-Debian
extras/init.d/glusterd-Redhat
extras/init.d/glusterd-SuSE
+extras/init.d/glusterd.plist
extras/ocf/glusterd
extras/ocf/volume
-glusterfs.spec
+extras/who-wrote-glusterfs/gitdm
glusterfs-api.pc
-libtool
-xlators/mount/fuse/utils/mount.glusterfs
-xlators/mount/fuse/utils/mount_glusterfs
-argp-standalone/libargp.a
+glusterfs.spec
glusterfsd/src/glusterfsd
+libgfchangelog.pc
libglusterfs/src/spec.lex.c
libglusterfs/src/y.tab.c
libglusterfs/src/y.tab.h
-libgfchangelog.pc \ No newline at end of file
+libtool
+run-tests.sh
+ufo/.tox
+ufo/test/unit/.coverage
+xlators/mount/fuse/utils/mount.glusterfs
+xlators/mount/fuse/utils/mount_glusterfs
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 000000000..6bcd95dea
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,31 @@
+# .mailmap, see 'git short-log --help' for details
+#
+# Listing of contributors that filed patches with different email addresses.
+# Format: <name> <main-email> <alias> [<alias> ...]
+#
+
+Amar Tumballi <amarts@redhat.com> <amar@gluster.com> <amar@del.gluster.com>
+Anand Avati <avati@redhat.com> <avati@gluster.com> <avati@dev.gluster.com> <avati@amp.gluster.com> <avati@blackhole.gluster.com>
+Anush Shetty <ashetty@redhat.com> <anush@gluster.com>
+Csaba Henk <csaba@redhat.com> <csaba@gluster.com> <csaba@lowlife.hu> <csaba@zresearch.com>
+Harshavardhana <fharshav@redhat.com> <harsha@gluster.com> <harsha@zresearch.com> <harsha@dev.gluster.com> <harsha@harshavardhana.net>
+Kaleb S. KEITHLEY <kkeithle@redhat.com> <kkeithle@f16node1.kkeithle.usersys.redhat.com>
+Kaushal M <kaushal@redhat.com> <kaushal@gluster.com>
+Kaushik BV <kbudiger@redhat.com> <kaushikbv@gluster.com>
+Krishna Srinivas <ksriniva@redhat.com> <krishna@gluster.com> <krishna@zresearch.com> <krishna@guest-laptop>
+Krishnan Parthasarathi <kparthas@redhat.com> <kp@gluster.com>
+Louis Zuckerman <louiszuckerman@gmail.com> <me@louiszuckerman.com>
+M S Vishwanath Bhat <vbhat@redhat.com> <msvbhat@gmail.com> <vishwanath@gluster.com>
+Pavan Sondur <pavan@gluster.com> <pavan@dev.gluster.com>
+Pete Zaitcev <zaitcev@kotori.zaitcev.us> <zaitcev@yahoo.com>
+Pranith Kumar K <pkarampu@redhat.com> <pranithk@gluster.com>
+Raghavendra Bhat <raghavendra@redhat.com> <raghavendrabhat@gluster.com>
+Raghavendra G <rgowdapp@redhat.com> <raghavendra@gluster.com> <raghavendra@zresearch.com>
+Rahul C S <rahulcs@redhat.com> <rahulcssjce@gmail.com>
+Rajesh Amaravathi <rajesh@redhat.com> <rajesh@gluster.com> <rajesh.amaravathi@gmail.com>
+Shehjar Tikoo <shehjart@gluster.com> <shehjart@zresearch.com>
+Venky Shankar <vshankar@redhat.com> <venky@gluster.com>
+Vijay Bellur <vbellur@redhat.com> <vijay@gluster.com> <vijay@dev.gluster.com>
+Vijaykumar Koppad <vkoppad@redhat.com> <vijaykumar.koppad@gmail.com>
+Vikas Gorur <vikas@gluster.com> <vikas@zresearch.com>
+shishir gowda <sgowda@redhat.com> <shishirng@gluster.com>
diff --git a/Makefile.am b/Makefile.am
index eba8ed12d..598ebb410 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,7 +3,8 @@ EXTRA_DIST = autogen.sh \
INSTALL README AUTHORS THANKS NEWS \
glusterfs.spec glusterfs-api.pc.in libgfchangelog.pc.in \
error-codes.json gf-error-codes.h.template \
- gen-headers.py
+ gen-headers.py run-tests.sh \
+ $(shell find $(top_srcdir)/tests -type f -print)
SUBDIRS = argp-standalone libglusterfs rpc api xlators glusterfsd \
$(FUSERMOUNT_SUBDIR) doc extras cli @SYNCDAEMON_SUBDIR@
diff --git a/api/Makefile.am b/api/Makefile.am
index af437a64d..f0ad1ee97 100644
--- a/api/Makefile.am
+++ b/api/Makefile.am
@@ -1 +1 @@
-SUBDIRS = src
+SUBDIRS = src examples
diff --git a/api/examples/Makefile.am b/api/examples/Makefile.am
index 6048bb1c8..05f40ff53 100644
--- a/api/examples/Makefile.am
+++ b/api/examples/Makefile.am
@@ -1,4 +1,6 @@
-noinst_PROGRAMS = glfsxmp
+EXTRA_PROGRAMS = glfsxmp
glfsxmp_SOURCES = glfsxmp.c
glfsxmp_CFLAGS = $(GLFS_CFLAGS) -Wall
-glfsxmp_LDADD = $(GLFS_LIBS) \ No newline at end of file
+glfsxmp_LDADD = $(GLFS_LIBS) -lrt
+
+EXTRA_DIST = gfapi.py
diff --git a/api/examples/README b/api/examples/README
index 8f0bab697..4d2b521f7 100644
--- a/api/examples/README
+++ b/api/examples/README
@@ -17,3 +17,20 @@ install glusterfs-api RPM.
Make sure your LDFLAGS includes -L/path/to/lib where libgfapi.so is
installed and -I/path/to/include/glusterfs where the 'api' directory
containing the headers are available.
+
+glfsxmp.c
+=========
+
+glfsxmp.c is an example application which uses libgfapi
+
+Compilation Steps For glfsxmp.c
+===============================
+
+1. $./autogen.sh
+2. $./configure
+
+Note: Before running ./configure , as mentioned above, you need to
+ take care of #1 or #2 i.e. pkg-config path or LDFLAGS and
+ -I/<path> with correct values.
+
+3. $make glfsxmp
diff --git a/api/examples/gfapi.py b/api/examples/gfapi.py
index 8d9ed7329..3ac67f4d5 100755
--- a/api/examples/gfapi.py
+++ b/api/examples/gfapi.py
@@ -1,6 +1,7 @@
#!/usr/bin/python
from ctypes import *
+from ctypes.util import find_library
import os
import sys
import time
@@ -8,9 +9,9 @@ import types
# Looks like ctypes is having trouble with dependencies, so just force them to
# load with RTLD_GLOBAL until I figure that out.
-glfs = CDLL("libglusterfs.so",RTLD_GLOBAL)
-xdr = CDLL("libgfxdr.so",RTLD_GLOBAL)
-api = CDLL("libgfapi.so",RTLD_GLOBAL)
+glfs = CDLL(find_library("glusterfs"),RTLD_GLOBAL)
+xdr = CDLL(find_library("gfxdr"),RTLD_GLOBAL)
+api = CDLL(find_library("gfapi"),RTLD_GLOBAL)
# Wow, the Linux kernel folks really play nasty games with this structure. If
# you look at the man page for stat(2) and then at this definition you'll note
@@ -98,10 +99,12 @@ class File(object):
def write (self, data, flags=0):
return api.glfs_write(self.fd,data,len(data),flags)
- def fallocate (self, mode, offset, len):
- return api.glfs_fallocate(self.fd, mode, offset, len)
- def discard (self, offset, len):
- return api.glfs_discard(self.fd, offset, len)
+ def fallocate (self, mode, offset, len):
+ return api.glfs_fallocate(self.fd, mode, offset, len)
+
+ def discard (self, offset, len):
+ return api.glfs_discard(self.fd, offset, len)
+
class Dir(object):
@@ -381,7 +384,7 @@ if __name__ == "__main__":
test_setxattr,
test_getxattr,
test_listxattr,
- test_fallocate,
+ test_fallocate,
)
ok_to_fail = (
diff --git a/api/examples/glfsxmp.c b/api/examples/glfsxmp.c
index 644793a4b..600d72fb5 100644
--- a/api/examples/glfsxmp.c
+++ b/api/examples/glfsxmp.c
@@ -1,6 +1,8 @@
#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
#include "api/glfs.h"
+#include "api/glfs-handles.h"
#include <string.h>
#include <time.h>
@@ -8,240 +10,1589 @@
int
test_dirops (glfs_t *fs)
{
- glfs_fd_t *fd = NULL;
- char buf[512];
- struct dirent *entry = NULL;
-
- fd = glfs_opendir (fs, "/");
- if (!fd) {
- fprintf (stderr, "/: %s\n", strerror (errno));
- return -1;
- }
+ glfs_fd_t *fd = NULL;
+ char buf[512];
+ struct dirent *entry = NULL;
+
+ fd = glfs_opendir (fs, "/");
+ if (!fd) {
+ fprintf (stderr, "/: %s\n", strerror (errno));
+ return -1;
+ }
+
+ fprintf (stderr, "Entries:\n");
+ while (glfs_readdir_r (fd, (struct dirent *)buf, &entry), entry) {
+ fprintf (stderr, "%s: %lu\n", entry->d_name, glfs_telldir (fd));
+ }
+
+ glfs_closedir (fd);
+ return 0;
+}
- fprintf (stderr, "Entries:\n");
- while (glfs_readdir_r (fd, (struct dirent *)buf, &entry), entry) {
- fprintf (stderr, "%s: %lu\n", entry->d_name, glfs_telldir (fd));
- }
- glfs_closedir (fd);
- return 0;
+int
+test_xattr (glfs_t *fs)
+{
+ char *filename = "/filename2";
+ char buf[512];
+ char *ptr;
+ int ret;
+
+ ret = glfs_setxattr (fs, filename, "user.testkey", "testval", 8, 0);
+ fprintf (stderr, "setxattr(%s): %d (%s)\n", filename, ret,
+ strerror (errno));
+
+ ret = glfs_setxattr (fs, filename, "user.testkey2", "testval", 8, 0);
+ fprintf (stderr, "setxattr(%s): %d (%s)\n", filename, ret,
+ strerror (errno));
+
+ ret = glfs_listxattr (fs, filename, buf, 512);
+ fprintf (stderr, "listxattr(%s): %d (%s)\n", filename, ret,
+ strerror (errno));
+ if (ret < 0)
+ return -1;
+
+ for (ptr = buf; ptr < buf + ret; ptr++) {
+ printf ("key=%s\n", ptr);
+ ptr += strlen (ptr);
+ }
+
+ return 0;
}
int
-test_xattr (glfs_t *fs)
+test_chdir (glfs_t *fs)
+{
+ int ret = -1;
+ char *topdir = "/topdir";
+ char *linkdir = "/linkdir";
+ char *subdir = "./subdir";
+ char *respath = NULL;
+ char pathbuf[4096];
+
+ ret = glfs_mkdir (fs, topdir, 0755);
+ if (ret) {
+ fprintf (stderr, "mkdir(%s): %s\n", topdir, strerror (errno));
+ return -1;
+ }
+
+ respath = glfs_getcwd (fs, pathbuf, 4096);
+ fprintf (stdout, "getcwd() = %s\n", respath);
+
+ ret = glfs_symlink (fs, topdir, linkdir);
+ if (ret) {
+ fprintf (stderr, "symlink(%s, %s): %s\n", topdir, linkdir, strerror (errno));
+ return -1;
+ }
+
+ ret = glfs_chdir (fs, linkdir);
+ if (ret) {
+ fprintf (stderr, "chdir(%s): %s\n", linkdir, strerror (errno));
+ return -1;
+ }
+
+ respath = glfs_getcwd (fs, pathbuf, 4096);
+ fprintf (stdout, "getcwd() = %s\n", respath);
+
+ respath = glfs_realpath (fs, subdir, pathbuf);
+ if (respath) {
+ fprintf (stderr, "realpath(%s) worked unexpectedly: %s\n", subdir, respath);
+ return -1;
+ }
+
+ ret = glfs_mkdir (fs, subdir, 0755);
+ if (ret) {
+ fprintf (stderr, "mkdir(%s): %s\n", subdir, strerror (errno));
+ return -1;
+ }
+
+ respath = glfs_realpath (fs, subdir, pathbuf);
+ if (!respath) {
+ fprintf (stderr, "realpath(%s): %s\n", subdir, strerror (errno));
+ } else {
+ fprintf (stdout, "realpath(%s) = %s\n", subdir, respath);
+ }
+
+ ret = glfs_chdir (fs, subdir);
+ if (ret) {
+ fprintf (stderr, "chdir(%s): %s\n", subdir, strerror (errno));
+ return -1;
+ }
+
+ respath = glfs_getcwd (fs, pathbuf, 4096);
+ fprintf (stdout, "getcwd() = %s\n", respath);
+
+ respath = glfs_realpath (fs, "/linkdir/subdir", pathbuf);
+ if (!respath) {
+ fprintf (stderr, "realpath(/linkdir/subdir): %s\n", strerror (errno));
+ } else {
+ fprintf (stdout, "realpath(/linkdir/subdir) = %s\n", respath);
+ }
+
+ return 0;
+}
+
+#ifdef DEBUG
+static void
+peek_stat (struct stat *sb)
+{
+ printf ("Dumping stat information:\n");
+ printf ("File type: ");
+
+ switch (sb->st_mode & S_IFMT) {
+ case S_IFBLK: printf ("block device\n"); break;
+ case S_IFCHR: printf ("character device\n"); break;
+ case S_IFDIR: printf ("directory\n"); break;
+ case S_IFIFO: printf ("FIFO/pipe\n"); break;
+ case S_IFLNK: printf ("symlink\n"); break;
+ case S_IFREG: printf ("regular file\n"); break;
+ case S_IFSOCK: printf ("socket\n"); break;
+ default: printf ("unknown?\n"); break;
+ }
+
+ printf ("I-node number: %ld\n", (long) sb->st_ino);
+
+ printf ("Mode: %lo (octal)\n",
+ (unsigned long) sb->st_mode);
+
+ printf ("Link count: %ld\n", (long) sb->st_nlink);
+ printf ("Ownership: UID=%ld GID=%ld\n",
+ (long) sb->st_uid, (long) sb->st_gid);
+
+ printf ("Preferred I/O block size: %ld bytes\n",
+ (long) sb->st_blksize);
+ printf ("File size: %lld bytes\n",
+ (long long) sb->st_size);
+ printf ("Blocks allocated: %lld\n",
+ (long long) sb->st_blocks);
+
+ printf ("Last status change: %s", ctime(&sb->st_ctime));
+ printf ("Last file access: %s", ctime(&sb->st_atime));
+ printf ("Last file modification: %s", ctime(&sb->st_mtime));
+
+ return;
+}
+
+static void
+peek_handle (unsigned char *glid)
+{
+ int i;
+
+ for (i = 0; i < GFAPI_HANDLE_LENGTH; i++)
+ {
+ printf (":%02x:", glid[i]);
+ }
+ printf ("\n");
+}
+#else /* DEBUG */
+static void
+peek_stat (struct stat *sb)
+{
+ return;
+}
+
+static void
+peek_handle (unsigned char *id)
{
- char *filename = "/filename2";
- char buf[512];
- char *ptr;
- int ret;
+ return;
+}
+#endif /* DEBUG */
- ret = glfs_setxattr (fs, filename, "user.testkey", "testval", 8, 0);
- fprintf (stderr, "setxattr(%s): %d (%s)\n", filename, ret,
- strerror (errno));
+glfs_t *fs = NULL;
+char *full_parent_name = "/testdir", *parent_name = "testdir";
- ret = glfs_setxattr (fs, filename, "user.testkey2", "testval", 8, 0);
- fprintf (stderr, "setxattr(%s): %d (%s)\n", filename, ret,
- strerror (errno));
+void
+test_h_unlink (void)
+{
+ char *my_dir = "unlinkdir";
+ char *my_file = "file.txt";
+ char *my_subdir = "dir1";
+ struct glfs_object *parent = NULL, *leaf = NULL, *dir = NULL,
+ *subdir = NULL, *subleaf = NULL;
+ struct stat sb;
+ int ret;
+
+ printf ("glfs_h_unlink tests: In Progress\n");
+
+ /* Prepare tests */
+ parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb);
+ if (parent == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ full_parent_name, NULL, strerror (errno));
+ printf ("glfs_h_lookupat tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ dir = glfs_h_mkdir (fs, parent, my_dir, 0644, &sb);
+ if (dir == NULL) {
+ fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n",
+ my_dir, parent, strerror (errno));
+ printf ("glfs_h_unlink tests: FAILED\n");
+ goto out;
+ }
+
+ leaf = glfs_h_creat (fs, dir, my_file, O_CREAT, 0644, &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n",
+ my_file, dir, strerror (errno));
+ printf ("glfs_h_unlink tests: FAILED\n");
+ goto out;
+ }
+
+ subdir = glfs_h_mkdir (fs, dir, my_subdir, 0644, &sb);
+ if (subdir == NULL) {
+ fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n",
+ my_subdir, dir, strerror (errno));
+ printf ("glfs_h_unlink tests: FAILED\n");
+ goto out;
+ }
+
+ subleaf = glfs_h_creat (fs, subdir, my_file, O_CREAT, 0644, &sb);
+ if (subleaf == NULL) {
+ fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n",
+ my_file, subdir, strerror (errno));
+ printf ("glfs_h_unlink tests: FAILED\n");
+ goto out;
+ }
+
+ /* unlink non empty directory */
+ ret = glfs_h_unlink (fs, dir, my_subdir);
+ if ((ret && errno != ENOTEMPTY) || (ret == 0)) {
+ fprintf (stderr, "glfs_h_unlink: error unlinking %s: it is non empty: %s\n",
+ my_subdir, strerror (errno));
+ printf ("glfs_h_unlink tests: FAILED\n");
+ goto out;
+ }
+
+ /* unlink regular file */
+ ret = glfs_h_unlink (fs, subdir, my_file);
+ if (ret) {
+ fprintf (stderr, "glfs_h_unlink: error unlinking %s: from (%p),%s\n",
+ my_file, subdir, strerror (errno));
+ printf ("glfs_h_unlink tests: FAILED\n");
+ goto out;
+ }
+
+ /* unlink directory */
+ ret = glfs_h_unlink (fs, dir, my_subdir);
+ if (ret) {
+ fprintf (stderr, "glfs_h_unlink: error unlinking %s: from (%p),%s\n",
+ my_subdir, dir, strerror (errno));
+ printf ("glfs_h_unlink tests: FAILED\n");
+ goto out;
+ }
+
+ /* unlink regular file */
+ ret = glfs_h_unlink (fs, dir, my_file);
+ if (ret) {
+ fprintf (stderr, "glfs_h_unlink: error unlinking %s: from (%p),%s\n",
+ my_file, dir, strerror (errno));
+ printf ("glfs_h_unlink tests: FAILED\n");
+ goto out;
+ }
+
+ /* unlink non-existant regular file */
+ ret = glfs_h_unlink (fs, dir, my_file);
+ if ((ret && errno != ENOENT) || (ret == 0)) {
+ fprintf (stderr, "glfs_h_unlink: error unlinking non-existant %s: invalid errno ,%d, %s\n",
+ my_file, ret, strerror (errno));
+ printf ("glfs_h_unlink tests: FAILED\n");
+ goto out;
+ }
+
+ /* unlink non-existant directory */
+ ret = glfs_h_unlink (fs, dir, my_subdir);
+ if ((ret && errno != ENOENT) || (ret == 0)) {
+ fprintf (stderr, "glfs_h_unlink: error unlinking non-existant %s: invalid errno ,%d, %s\n",
+ my_subdir, ret, strerror (errno));
+ printf ("glfs_h_unlink tests: FAILED\n");
+ goto out;
+ }
+
+ /* unlink directory */
+ ret = glfs_h_unlink (fs, parent, my_dir);
+ if (ret) {
+ fprintf (stderr, "glfs_h_unlink: error unlinking %s: from (%p),%s\n",
+ my_dir, dir, strerror (errno));
+ printf ("glfs_h_unlink tests: FAILED\n");
+ goto out;
+ }
+
+ printf ("glfs_h_unlink tests: PASSED\n");
+
+out:
+ if (dir)
+ glfs_h_close (dir);
+ if (leaf)
+ glfs_h_close (leaf);
+ if (subdir)
+ glfs_h_close (subdir);
+ if (subleaf)
+ glfs_h_close (subleaf);
+ if (parent)
+ glfs_h_close (parent);
+
+ return;
+}
- ret = glfs_listxattr (fs, filename, buf, 512);
- fprintf (stderr, "listxattr(%s): %d (%s)\n", filename, ret,
- strerror (errno));
- if (ret < 0)
- return -1;
+void
+test_h_getsetattrs (void)
+{
+ char *my_dir = "attrdir";
+ char *my_file = "attrfile.txt";
+ struct glfs_object *parent = NULL, *leaf = NULL, *dir = NULL;
+ struct stat sb, retsb;
+ int ret, valid;
+ struct timespec timestamp;
+
+ printf("glfs_h_getattrs and setattrs tests: In Progress\n");
+
+ /* Prepare tests */
+ parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb);
+ if (parent == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ full_parent_name, NULL, strerror (errno));
+ printf ("glfs_h_lookupat tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ dir = glfs_h_mkdir (fs, parent, my_dir, 0644, &sb);
+ if (dir == NULL) {
+ fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n",
+ my_dir, parent, strerror (errno));
+ printf ("glfs_h_unlink tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ leaf = glfs_h_creat (fs, dir, my_file, O_CREAT, 0644, &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n",
+ my_file, dir, strerror (errno));
+ printf ("glfs_h_unlink tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ ret = glfs_h_getattrs (fs, dir, &retsb);
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_getattrs: error %s: from (%p),%s\n",
+ my_dir, dir, strerror (errno));
+ printf ("glfs_h_getattrs and setattrs tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&retsb);
+ /* TODO: Compare stat information */
+
+ retsb.st_mode = 00666;
+ retsb.st_uid = 1000;
+ retsb.st_gid = 1001;
+ ret = clock_gettime (CLOCK_REALTIME, &timestamp);
+ if(ret != 0) {
+ fprintf (stderr, "clock_gettime: error %s\n", strerror (errno));
+ printf ("glfs_h_getattrs and setattrs tests: FAILED\n");
+ goto out;
+ }
+ retsb.st_atim = timestamp;
+ retsb.st_mtim = timestamp;
+ valid = GFAPI_SET_ATTR_MODE | GFAPI_SET_ATTR_UID | GFAPI_SET_ATTR_GID |
+ GFAPI_SET_ATTR_ATIME | GFAPI_SET_ATTR_MTIME;
+ peek_stat (&retsb);
+
+ ret = glfs_h_setattrs (fs, dir, &retsb, valid);
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_setattrs: error %s: from (%p),%s\n",
+ my_dir, dir, strerror (errno));
+ printf ("glfs_h_getattrs and setattrs tests: FAILED\n");
+ goto out;
+ }
+
+ memset(&retsb, 0, sizeof (struct stat));
+ ret = glfs_h_stat (fs, dir, &retsb);
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_stat: error %s: from (%p),%s\n",
+ my_dir, dir, strerror (errno));
+ printf ("glfs_h_getattrs and setattrs tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&retsb);
+
+ printf ("glfs_h_getattrs and setattrs tests: PASSED\n");
+out:
+ if (parent)
+ glfs_h_close (parent);
+ if (leaf)
+ glfs_h_close (leaf);
+ if (dir)
+ glfs_h_close (dir);
+
+ return;
+}
- for (ptr = buf; ptr < buf + ret; ptr++) {
- printf ("key=%s\n", ptr);
- ptr += strlen (ptr);
- }
+void
+test_h_truncate (void)
+{
+ char *my_dir = "truncatedir";
+ char *my_file = "file.txt";
+ struct glfs_object *root = NULL, *parent = NULL, *leaf = NULL;
+ struct stat sb;
+ glfs_fd_t *fd = NULL;
+ char buf[32];
+ off_t offset = 0;
+ int ret = 0;
+
+ printf("glfs_h_truncate tests: In Progress\n");
+
+ /* Prepare tests */
+ root = glfs_h_lookupat (fs, NULL, full_parent_name, &sb);
+ if (root == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ full_parent_name, NULL, strerror (errno));
+ printf ("glfs_h_truncate tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ parent = glfs_h_mkdir (fs, root, my_dir, 0644, &sb);
+ if (parent == NULL) {
+ fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n",
+ my_dir, root, strerror (errno));
+ printf ("glfs_h_truncate tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ leaf = glfs_h_creat (fs, parent, my_file, O_CREAT, 0644, &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n",
+ my_file, parent, strerror (errno));
+ printf ("glfs_h_truncate tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ fd = glfs_h_open (fs, leaf, O_RDWR);
+ if (fd == NULL) {
+ fprintf (stderr, "glfs_h_open: error on open of %s: %s\n",
+ my_file, strerror (errno));
+ printf ("glfs_h_truncate tests: FAILED\n");
+ goto out;
+ }
+
+ memcpy (buf, "abcdefghijklmnopqrstuvwxyz012345", 32);
+ ret = glfs_write (fd, buf, 32, 0);
+
+ /* run tests */
+ /* truncate lower */
+ offset = 30;
+ ret = glfs_h_truncate (fs, leaf, offset);
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_truncate: error creating %s: from (%p),%s\n",
+ my_file, parent, strerror (errno));
+ printf ("glfs_h_truncate tests: FAILED\n");
+ goto out;
+ }
+ ret = glfs_h_getattrs (fs, leaf, &sb);
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_getattrs: error for %s (%p),%s\n",
+ my_file, leaf, strerror (errno));
+ printf ("glfs_h_truncate tests: FAILED\n");
+ goto out;
+ }
+ if (sb.st_size != offset) {
+ fprintf (stderr, "glfs_h_truncate: post size mismatch\n");
+ printf ("glfs_h_truncate tests: FAILED\n");
+ goto out;
+ }
+
+ /* truncate higher */
+ offset = 32;
+ ret = glfs_h_truncate (fs, leaf, offset);
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_truncate: error creating %s: from (%p),%s\n",
+ my_file, parent, strerror (errno));
+ printf ("glfs_h_truncate tests: FAILED\n");
+ goto out;
+ }
+ ret = glfs_h_getattrs (fs, leaf, &sb);
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_getattrs: error for %s (%p),%s\n",
+ my_file, leaf, strerror (errno));
+ printf ("glfs_h_truncate tests: FAILED\n");
+ goto out;
+ }
+ if (sb.st_size != offset) {
+ fprintf (stderr, "glfs_h_truncate: post size mismatch\n");
+ printf ("glfs_h_truncate tests: FAILED\n");
+ goto out;
+ }
+
+ /* truncate equal */
+ offset = 30;
+ ret = glfs_h_truncate (fs, leaf, offset);
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_truncate: error creating %s: from (%p),%s\n",
+ my_file, parent, strerror (errno));
+ printf ("glfs_h_truncate tests: FAILED\n");
+ goto out;
+ }
+ ret = glfs_h_getattrs (fs, leaf, &sb);
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_getattrs: error for %s (%p),%s\n",
+ my_file, leaf, strerror (errno));
+ printf ("glfs_h_truncate tests: FAILED\n");
+ goto out;
+ }
+ if (sb.st_size != offset) {
+ fprintf (stderr, "glfs_h_truncate: post size mismatch\n");
+ printf ("glfs_h_truncate tests: FAILED\n");
+ goto out;
+ }
+
+ printf ("glfs_h_truncate tests: PASSED\n");
+out:
+ if (fd)
+ glfs_close (fd);
+ if (root)
+ glfs_h_close (root);
+ if (parent)
+ glfs_h_close (parent);
+ if (leaf)
+ glfs_h_close (leaf);
+
+ return;
+}
- return 0;
+void
+test_h_links (void)
+{
+ char *my_dir = "linkdir";
+ char *my_file = "file.txt";
+ char *my_symlnk = "slnk.txt";
+ char *my_lnk = "lnk.txt";
+ char *linksrc_dir = "dir1";
+ char *linktgt_dir = "dir2";
+ struct glfs_object *root = NULL, *parent = NULL, *leaf = NULL,
+ *dirsrc = NULL, *dirtgt = NULL, *dleaf = NULL;
+ struct glfs_object *ln1 = NULL;
+ struct stat sb;
+ int ret;
+ char *buf = NULL;
+
+ printf("glfs_h_link(s) tests: In Progress\n");
+
+ /* Prepare tests */
+ root = glfs_h_lookupat (fs, NULL, full_parent_name, &sb);
+ if (root == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ full_parent_name, NULL, strerror (errno));
+ printf ("glfs_h_link(s) tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ parent = glfs_h_mkdir (fs, root, my_dir, 0644, &sb);
+ if (parent == NULL) {
+ fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n",
+ my_dir, root, strerror (errno));
+ printf ("glfs_h_link(s) tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ leaf = glfs_h_creat (fs, parent, my_file, O_CREAT, 0644, &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n",
+ my_file, parent, strerror (errno));
+ printf ("glfs_h_link(s) tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ dirsrc = glfs_h_mkdir (fs, parent, linksrc_dir, 0644, &sb);
+ if (dirsrc == NULL) {
+ fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n",
+ linksrc_dir, parent, strerror (errno));
+ printf ("glfs_h_link(s) tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ dirtgt = glfs_h_mkdir (fs, parent, linktgt_dir, 0644, &sb);
+ if (dirtgt == NULL) {
+ fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n",
+ linktgt_dir, parent, strerror (errno));
+ printf ("glfs_h_link(s) tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ dleaf = glfs_h_creat (fs, dirsrc, my_file, O_CREAT, 0644, &sb);
+ if (dleaf == NULL) {
+ fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n",
+ my_file, dirsrc, strerror (errno));
+ printf ("glfs_h_link(s) tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ /* run tests */
+ /* sym link: /testdir/linkdir/file.txt to ./slnk.txt */
+ ln1 = glfs_h_symlink (fs, parent, my_symlnk, "./file.txt", &sb);
+ if (ln1 == NULL) {
+ fprintf (stderr, "glfs_h_symlink: error creating %s: from (%p),%s\n",
+ my_symlnk, parent, strerror (errno));
+ printf ("glfs_h_link(s) tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ buf = calloc (1024, sizeof(char));
+ if (buf == NULL) {
+ fprintf (stderr, "Error allocating memory\n");
+ printf ("glfs_h_link(s) tests: FAILED\n");
+ goto out;
+ }
+
+ ret = glfs_h_readlink (fs, ln1, buf, 1024);
+ if (ret <= 0) {
+ fprintf (stderr, "glfs_h_readlink: error reading %s: from (%p),%s\n",
+ my_symlnk, ln1, strerror (errno));
+ printf ("glfs_h_link(s) tests: FAILED\n");
+ goto out;
+ }
+ if (!(strncmp (buf, my_symlnk, strlen (my_symlnk)))) {
+ fprintf (stderr, "glfs_h_readlink: error mismatch in link name: actual %s: retrieved %s\n",
+ my_symlnk, buf);
+ printf ("glfs_h_link(s) tests: FAILED\n");
+ goto out;
+ }
+
+ /* link: /testdir/linkdir/file.txt to ./lnk.txt */
+ ret = glfs_h_link (fs, leaf, parent, my_lnk);
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_link: error creating %s: from (%p),%s\n",
+ my_lnk, parent, strerror (errno));
+ printf ("glfs_h_link(s) tests: FAILED\n");
+ goto out;
+ }
+ /* TODO: Should write content to a file and read from the link */
+
+ /* link: /testdir/linkdir/dir1/file.txt to ../dir2/slnk.txt */
+ ret = glfs_h_link (fs, dleaf, dirtgt, my_lnk);
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_link: error creating %s: from (%p),%s\n",
+ my_lnk, dirtgt, strerror (errno));
+ printf ("glfs_h_link(s) tests: FAILED\n");
+ goto out;
+ }
+ /* TODO: Should write content to a file and read from the link */
+
+ printf ("glfs_h_link(s) tests: PASSED\n");
+
+out:
+ if (root)
+ glfs_h_close (root);
+ if (parent)
+ glfs_h_close (parent);
+ if (leaf)
+ glfs_h_close (leaf);
+ if (dirsrc)
+ glfs_h_close (dirsrc);
+ if (dirtgt)
+ glfs_h_close (dirtgt);
+ if (dleaf)
+ glfs_h_close (dleaf);
+ if (ln1)
+ glfs_h_close (ln1);
+ if (buf)
+ free (buf);
+
+ return;
}
+void
+test_h_rename (void)
+{
+ char *my_dir = "renamedir";
+ char *my_file = "file.txt";
+ char *src_dir = "dir1";
+ char *tgt_dir = "dir2";
+ struct glfs_object *root = NULL, *parent = NULL, *leaf = NULL,
+ *dirsrc = NULL, *dirtgt = NULL, *dleaf = NULL;
+ struct stat sb;
+ int ret;
+
+ printf("glfs_h_rename tests: In Progress\n");
+
+ /* Prepare tests */
+ root = glfs_h_lookupat (fs, NULL, full_parent_name, &sb);
+ if (root == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ full_parent_name, NULL, strerror (errno));
+ printf ("glfs_h_rename tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ parent = glfs_h_mkdir (fs, root, my_dir, 0644, &sb);
+ if (parent == NULL) {
+ fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n",
+ my_dir, root, strerror (errno));
+ printf ("glfs_h_rename tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ leaf = glfs_h_creat (fs, parent, my_file, O_CREAT, 0644, &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n",
+ my_file, parent, strerror (errno));
+ printf ("glfs_h_rename tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ dirsrc = glfs_h_mkdir (fs, parent, src_dir, 0644, &sb);
+ if (dirsrc == NULL) {
+ fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n",
+ src_dir, parent, strerror (errno));
+ printf ("glfs_h_rename tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ dirtgt = glfs_h_mkdir (fs, parent, tgt_dir, 0644, &sb);
+ if (dirtgt == NULL) {
+ fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n",
+ tgt_dir, parent, strerror (errno));
+ printf ("glfs_h_rename tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ dleaf = glfs_h_creat (fs, dirsrc, my_file, O_CREAT, 0644, &sb);
+ if (dleaf == NULL) {
+ fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n",
+ my_file, dirsrc, strerror (errno));
+ printf ("glfs_h_rename tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ /* run tests */
+ /* Rename file.txt -> file1.txt */
+ ret = glfs_h_rename (fs, parent, "file.txt", parent, "file1.txt");
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_rename: error renaming %s to %s (%s)\n",
+ "file.txt", "file1.txt", strerror (errno));
+ printf ("glfs_h_rename tests: FAILED\n");
+ goto out;
+ }
+
+ /* rename dir1/file.txt -> file.txt */
+ ret = glfs_h_rename (fs, dirsrc, "file.txt", parent, "file.txt");
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_rename: error renaming %s/%s to %s (%s)\n",
+ src_dir, "file.txt", "file.txt", strerror (errno));
+ printf ("glfs_h_rename tests: FAILED\n");
+ goto out;
+ }
+
+ /* rename file1.txt -> file.txt (exists) */
+ ret = glfs_h_rename (fs, parent, "file1.txt", parent, "file.txt");
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_rename: error renaming %s to %s (%s)\n",
+ "file.txt", "file.txt", strerror (errno));
+ printf ("glfs_h_rename tests: FAILED\n");
+ goto out;
+ }
+
+ /* rename dir1 -> dir3 */
+ ret = glfs_h_rename (fs, parent, "dir1", parent, "dir3");
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_rename: error renaming %s to %s (%s)\n",
+ "dir1", "dir3", strerror (errno));
+ printf ("glfs_h_rename tests: FAILED\n");
+ goto out;
+ }
+
+ /* rename dir2 ->dir3 (exists) */
+ ret = glfs_h_rename (fs, parent, "dir2", parent, "dir3");
+ if (ret != 0) {
+ fprintf (stderr, "glfs_h_rename: error renaming %s to %s (%s)\n",
+ "dir2", "dir3", strerror (errno));
+ printf ("glfs_h_rename tests: FAILED\n");
+ goto out;
+ }
+
+ /* rename file.txt -> dir3 (fail) */
+ ret = glfs_h_rename (fs, parent, "file.txt", parent, "dir3");
+ if (ret == 0) {
+ fprintf (stderr, "glfs_h_rename: NO error renaming %s to %s (%s)\n",
+ "file.txt", "dir3", strerror (errno));
+ printf ("glfs_h_rename tests: FAILED\n");
+ goto out;
+ }
+
+ /* rename dir3 -> file.txt (fail) */
+ ret = glfs_h_rename (fs, parent, "dir3", parent, "file.txt");
+ if (ret == 0) {
+ fprintf (stderr, "glfs_h_rename: NO error renaming %s to %s (%s)\n",
+ "dir3", "file.txt", strerror (errno));
+ printf ("glfs_h_rename tests: FAILED\n");
+ goto out;
+ }
+
+ printf ("glfs_h_rename tests: PASSED\n");
+
+out:
+ if (root)
+ glfs_h_close (root);
+ if (parent)
+ glfs_h_close (parent);
+ if (leaf)
+ glfs_h_close (leaf);
+ if (dirsrc)
+ glfs_h_close (dirsrc);
+ if (dirtgt)
+ glfs_h_close (dirtgt);
+ if (dleaf)
+ glfs_h_close (dleaf);
+
+ return;
+}
-int
-test_chdir (glfs_t *fs)
+void
+assimilatetime (struct timespec *ts, struct timespec ts_st,
+ struct timespec ts_ed)
{
- int ret = -1;
- ino_t ino = 0;
- struct stat st;
- char *topdir = "/topdir";
- char *linkdir = "/linkdir";
- char *subdir = "./subdir";
- char *respath = NULL;
- char pathbuf[4096];
-
- ret = glfs_mkdir (fs, topdir, 0755);
- if (ret) {
- fprintf (stderr, "mkdir(%s): %s\n", topdir, strerror (errno));
- return -1;
- }
-
- respath = glfs_getcwd (fs, pathbuf, 4096);
- fprintf (stdout, "getcwd() = %s\n", respath);
-
- ret = glfs_symlink (fs, topdir, linkdir);
- if (ret) {
- fprintf (stderr, "symlink(%s, %s): %s\n", topdir, linkdir, strerror (errno));
- return -1;
- }
-
- ret = glfs_chdir (fs, linkdir);
- if (ret) {
- fprintf (stderr, "chdir(%s): %s\n", linkdir, strerror (errno));
- return -1;
- }
-
- respath = glfs_getcwd (fs, pathbuf, 4096);
- fprintf (stdout, "getcwd() = %s\n", respath);
-
- respath = glfs_realpath (fs, subdir, pathbuf);
- if (respath) {
- fprintf (stderr, "realpath(%s) worked unexpectedly: %s\n", subdir, respath);
- return -1;
- }
-
- ret = glfs_mkdir (fs, subdir, 0755);
- if (ret) {
- fprintf (stderr, "mkdir(%s): %s\n", subdir, strerror (errno));
- return -1;
- }
-
- respath = glfs_realpath (fs, subdir, pathbuf);
- if (!respath) {
- fprintf (stderr, "realpath(%s): %s\n", subdir, strerror (errno));
- } else {
- fprintf (stdout, "realpath(%s) = %s\n", subdir, respath);
- }
-
- ret = glfs_chdir (fs, subdir);
- if (ret) {
- fprintf (stderr, "chdir(%s): %s\n", subdir, strerror (errno));
- return -1;
- }
-
- respath = glfs_getcwd (fs, pathbuf, 4096);
- fprintf (stdout, "getcwd() = %s\n", respath);
-
- respath = glfs_realpath (fs, "/linkdir/subdir", pathbuf);
- if (!respath) {
- fprintf (stderr, "realpath(/linkdir/subdir): %s\n", strerror (errno));
- } else {
- fprintf (stdout, "realpath(/linkdir/subdir) = %s\n", respath);
- }
-
- return 0;
+ if ((ts_ed.tv_nsec - ts_st.tv_nsec) < 0) {
+ ts->tv_sec += ts_ed.tv_sec - ts_st.tv_sec - 1;
+ ts->tv_nsec += 1000000000 + ts_ed.tv_nsec - ts_st.tv_nsec;
+ } else {
+ ts->tv_sec += ts_ed.tv_sec - ts_st.tv_sec;
+ ts->tv_nsec += ts_ed.tv_nsec - ts_st.tv_nsec;
+ }
+
+ if (ts->tv_nsec > 1000000000) {
+ ts->tv_nsec = ts->tv_nsec - 1000000000;
+ ts->tv_sec += 1;
+ }
+
+ return;
}
+#define MAX_FILES_CREATE 10
+#define MAXPATHNAME 512
+void
+test_h_performance (void)
+{
+ char *my_dir = "perftest",
+ *full_dir_path="/testdir/perftest";
+ char *my_file = "file_", my_file_name[MAXPATHNAME];
+ struct glfs_object *parent = NULL, *leaf = NULL, *dir = NULL;
+ struct stat sb;
+ int ret, i;
+ struct glfs_fd *fd;
+ struct timespec c_ts = {0, 0}, c_ts_st, c_ts_ed;
+ struct timespec o_ts = {0, 0}, o_ts_st, o_ts_ed;
+
+ printf("glfs_h_performance tests: In Progress\n");
+
+ /* Prepare tests */
+ parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb);
+ if (parent == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ full_parent_name, NULL, strerror (errno));
+ printf ("glfs_h_performance tests: FAILED\n");
+ goto out;
+ }
+
+ dir = glfs_h_mkdir (fs, parent, my_dir, 0644, &sb);
+ if (dir == NULL) {
+ fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n",
+ my_dir, parent, strerror (errno));
+ printf ("glfs_h_performance tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ /* create performance */
+ ret = clock_gettime (CLOCK_REALTIME, &o_ts_st);
+ if(ret != 0) {
+ fprintf (stderr, "clock_gettime: error %s\n", strerror (errno));
+ printf ("glfs_h_getattrs and setattrs tests: FAILED\n");
+ goto out;
+ }
+
+ for (i = 0; i < MAX_FILES_CREATE; i++) {
+ sprintf (my_file_name, "%s%d", my_file, i);
+
+ ret = clock_gettime (CLOCK_REALTIME, &c_ts_st);
+ if(ret != 0) {
+ fprintf (stderr, "clock_gettime: error %s\n",
+ strerror (errno));
+ printf ("glfs_h_getattrs and setattrs tests: FAILED\n");
+ goto out;
+ }
+
+ leaf = glfs_h_lookupat (fs, dir, my_file_name, &sb);
+ if (leaf != NULL) {
+ fprintf (stderr, "glfs_h_lookup: exists %s\n",
+ my_file_name);
+ printf ("glfs_h_performance tests: FAILED\n");
+ goto out;
+ }
+
+ leaf = glfs_h_creat (fs, dir, my_file_name, O_CREAT, 0644, &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n",
+ my_file, dir, strerror (errno));
+ printf ("glfs_h_performance tests: FAILED\n");
+ goto out;
+ }
+
+ ret = clock_gettime (CLOCK_REALTIME, &c_ts_ed);
+ if(ret != 0) {
+ fprintf (stderr, "clock_gettime: error %s\n",
+ strerror (errno));
+ printf ("glfs_h_getattrs and setattrs tests: FAILED\n");
+ goto out;
+ }
+
+ assimilatetime (&c_ts, c_ts_st, c_ts_ed);
+ glfs_h_close (leaf); leaf = NULL;
+ }
+
+ ret = clock_gettime (CLOCK_REALTIME, &o_ts_ed);
+ if(ret != 0) {
+ fprintf (stderr, "clock_gettime: error %s\n", strerror (errno));
+ printf ("glfs_h_getattrs and setattrs tests: FAILED\n");
+ goto out;
+ }
+
+ assimilatetime (&o_ts, o_ts_st, o_ts_ed);
+
+ printf ("Creation performance (handle based):\n\t# empty files:%d\n",
+ MAX_FILES_CREATE);
+ printf ("\tOverall time:\n\t\tSecs:%ld\n\t\tnSecs:%ld\n",
+ o_ts.tv_sec, o_ts.tv_nsec);
+ printf ("\tcreate call time time:\n\t\tSecs:%ld\n\t\tnSecs:%ld\n",
+ c_ts.tv_sec, c_ts.tv_nsec);
+
+ /* create using path */
+ c_ts.tv_sec = o_ts.tv_sec = 0;
+ c_ts.tv_nsec = o_ts.tv_nsec = 0;
+
+ sprintf (my_file_name, "%s1", full_dir_path);
+ ret = glfs_mkdir (fs, my_file_name, 0644);
+ if (ret != 0) {
+ fprintf (stderr, "glfs_mkdir: error creating %s: from (%p),%s\n",
+ my_dir, parent, strerror (errno));
+ printf ("glfs_h_performance tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ ret = clock_gettime (CLOCK_REALTIME, &o_ts_st);
+ if(ret != 0) {
+ fprintf (stderr, "clock_gettime: error %s\n", strerror (errno));
+ printf ("glfs_h_getattrs and setattrs tests: FAILED\n");
+ goto out;
+ }
+
+ for (i = 0; i < MAX_FILES_CREATE; i++) {
+ sprintf (my_file_name, "%s1/%sn%d", full_dir_path, my_file, i);
+
+ ret = clock_gettime (CLOCK_REALTIME, &c_ts_st);
+ if(ret != 0) {
+ fprintf (stderr, "clock_gettime: error %s\n",
+ strerror (errno));
+ printf ("glfs_h_getattrs and setattrs tests: FAILED\n");
+ goto out;
+ }
+
+ ret = glfs_stat (fs, my_file_name, &sb);
+ if (ret == 0) {
+ fprintf (stderr, "glfs_stat: exists %s\n",
+ my_file_name);
+ printf ("glfs_h_performance tests: FAILED\n");
+ goto out;
+ }
+
+ fd = glfs_creat (fs, my_file_name, O_CREAT, 0644);
+ if (fd == NULL) {
+ fprintf (stderr, "glfs_creat: error creating %s: from (%p),%s\n",
+ my_file, dir, strerror (errno));
+ printf ("glfs_h_performance tests: FAILED\n");
+ goto out;
+ }
+
+ ret = clock_gettime (CLOCK_REALTIME, &c_ts_ed);
+ if(ret != 0) {
+ fprintf (stderr, "clock_gettime: error %s\n",
+ strerror (errno));
+ printf ("glfs_h_getattrs and setattrs tests: FAILED\n");
+ goto out;
+ }
+
+ assimilatetime (&c_ts, c_ts_st, c_ts_ed);
+ glfs_close (fd);
+ }
+
+ ret = clock_gettime (CLOCK_REALTIME, &o_ts_ed);
+ if(ret != 0) {
+ fprintf (stderr, "clock_gettime: error %s\n", strerror (errno));
+ printf ("glfs_h_getattrs and setattrs tests: FAILED\n");
+ goto out;
+ }
+
+ assimilatetime (&o_ts, o_ts_st, o_ts_ed);
+
+ printf ("Creation performance (path based):\n\t# empty files:%d\n",
+ MAX_FILES_CREATE);
+ printf ("\tOverall time:\n\t\tSecs:%ld\n\t\tnSecs:%ld\n",
+ o_ts.tv_sec, o_ts.tv_nsec);
+ printf ("\tcreate call time time:\n\t\tSecs:%ld\n\t\tnSecs:%ld\n",
+ c_ts.tv_sec, c_ts.tv_nsec);
+out:
+ return;
+}
+
+int
+test_handleops (int argc, char *argv[])
+{
+ int ret = 0;
+ glfs_fd_t *fd = NULL;
+ struct stat sb = {0, };
+ struct glfs_object *root = NULL, *parent = NULL, *leaf = NULL,
+ *tmp = NULL;
+ char readbuf[32], writebuf[32];
+ unsigned char leaf_handle[GFAPI_HANDLE_LENGTH];
+
+ char *full_leaf_name = "/testdir/testfile.txt",
+ *leaf_name = "testfile.txt",
+ *relative_leaf_name = "testdir/testfile.txt";
+ char *leaf_name1 = "testfile1.txt";
+ char *full_newparent_name = "/testdir/dir1",
+ *newparent_name = "dir1";
+ char *full_newnod_name = "/testdir/nod1",
+ *newnod_name = "nod1";
+
+ /* Initialize test area */
+ ret = glfs_mkdir (fs, full_parent_name, 0644);
+ if (ret != 0 && errno != EEXIST) {
+ fprintf (stderr, "%s: (%p) %s\n", full_parent_name, fd,
+ strerror (errno));
+ printf ("Test initialization failed on volume %s\n", argv[1]);
+ goto out;
+ }
+ else if (ret != 0) {
+ printf ("Found test directory %s to be existing\n",
+ full_parent_name);
+ printf ("Cleanup test directory and restart tests\n");
+ goto out;
+ }
+
+ fd = glfs_creat (fs, full_leaf_name, O_CREAT, 0644);
+ if (fd == NULL) {
+ fprintf (stderr, "%s: (%p) %s\n", full_leaf_name, fd,
+ strerror (errno));
+ printf ("Test initialization failed on volume %s\n", argv[1]);
+ goto out;
+ }
+ glfs_close (fd);
+
+ printf ("Initialized the test area, within volume %s\n", argv[1]);
+
+ /* Handle based APIs test area */
+
+ /* glfs_lookupat test */
+ printf ("glfs_h_lookupat tests: In Progress\n");
+ /* start at root of the volume */
+ root = glfs_h_lookupat (fs, NULL, "/", &sb);
+ if (root == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ "/", NULL, strerror (errno));
+ printf ("glfs_h_lookupat tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ /* lookup a parent within root */
+ parent = glfs_h_lookupat (fs, root, parent_name, &sb);
+ if (parent == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ parent_name, root, strerror (errno));
+ printf ("glfs_h_lookupat tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ /* lookup a leaf/child within the parent */
+ leaf = glfs_h_lookupat (fs, parent, leaf_name, &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ leaf_name, parent, strerror (errno));
+ printf ("glfs_h_lookupat tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ /* reset */
+ glfs_h_close (root); root = NULL;
+ glfs_h_close (leaf); leaf = NULL;
+ glfs_h_close (parent); parent = NULL;
+
+ /* check absolute paths */
+ root = glfs_h_lookupat (fs, NULL, "/", &sb);
+ if (root == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ "/", NULL, strerror (errno));
+ printf ("glfs_h_lookupat tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb);
+ if (parent == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ full_parent_name, root, strerror (errno));
+ printf ("glfs_h_lookupat tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ leaf = glfs_h_lookupat (fs, NULL, full_leaf_name, &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ full_leaf_name, parent, strerror (errno));
+ printf ("glfs_h_lookupat tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ /* reset */
+ glfs_h_close (leaf); leaf = NULL;
+
+ /* check multiple component paths */
+ leaf = glfs_h_lookupat (fs, root, relative_leaf_name, &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ relative_leaf_name, parent, strerror (errno));
+ goto out;
+ }
+ peek_stat (&sb);
+
+ /* reset */
+ glfs_h_close (root); root = NULL;
+ glfs_h_close (parent); parent = NULL;
+
+ /* check symlinks in path */
+
+ /* TODO: -ve test cases */
+ /* parent invalid
+ * path invalid
+ * path does not exist after some components
+ * no parent, but relative path
+ * parent and full path? -ve?
+ */
+
+ printf ("glfs_h_lookupat tests: PASSED\n");
+
+ /* glfs_openat test */
+ printf ("glfs_h_open tests: In Progress\n");
+ fd = glfs_h_open (fs, leaf, O_RDWR);
+ if (fd == NULL) {
+ fprintf (stderr, "glfs_h_open: error on open of %s: %s\n",
+ full_leaf_name, strerror (errno));
+ printf ("glfs_h_open tests: FAILED\n");
+ goto out;
+ }
+
+ /* test read/write based on fd */
+ memcpy (writebuf, "abcdefghijklmnopqrstuvwxyz012345", 32);
+ ret = glfs_write (fd, writebuf, 32, 0);
+
+ glfs_lseek (fd, 0, SEEK_SET);
+
+ ret = glfs_read (fd, readbuf, 32, 0);
+ if (memcmp (readbuf, writebuf, 32)) {
+ printf ("Failed to read what I wrote: %s %s\n", readbuf,
+ writebuf);
+ glfs_close (fd);
+ printf ("glfs_h_open tests: FAILED\n");
+ goto out;
+ }
+
+ glfs_h_close (leaf); leaf = NULL;
+ glfs_close (fd);
+
+ printf ("glfs_h_open tests: PASSED\n");
+
+ /* Create tests */
+ printf ("glfs_h_creat tests: In Progress\n");
+ parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb);
+ if (parent == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ full_parent_name, root, strerror (errno));
+ printf ("glfs_h_creat tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ leaf = glfs_h_creat (fs, parent, leaf_name1, O_CREAT, 0644, &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_creat: error on create of %s: from (%p),%s\n",
+ leaf_name1, parent, strerror (errno));
+ printf ("glfs_h_creat tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ glfs_h_close (leaf); leaf = NULL;
+
+ leaf = glfs_h_creat (fs, parent, leaf_name1, O_CREAT | O_EXCL, 0644,
+ &sb);
+ if (leaf != NULL || errno != EEXIST) {
+ fprintf (stderr, "glfs_h_creat: existing file, leaf = (%p), errno = %s\n",
+ leaf, strerror (errno));
+ printf ("glfs_h_creat tests: FAILED\n");
+ if (leaf != NULL) {
+ glfs_h_close (leaf); leaf = NULL;
+ }
+ }
+
+ tmp = glfs_h_creat (fs, root, parent_name, O_CREAT, 0644, &sb);
+ if (tmp != NULL || !(errno == EISDIR || errno == EINVAL)) {
+ fprintf (stderr, "glfs_h_creat: dir create, tmp = (%p), errno = %s\n",
+ leaf, strerror (errno));
+ printf ("glfs_h_creat tests: FAILED\n");
+ if (tmp != NULL) {
+ glfs_h_close (tmp); tmp = NULL;
+ }
+ }
+
+ /* TODO: Other combinations and -ve cases as applicable */
+ printf ("glfs_h_creat tests: PASSED\n");
+
+ /* extract handle and create from handle test */
+ printf ("glfs_h_extract_handle and glfs_h_create_from_handle tests: In Progress\n");
+ /* TODO: Change the lookup to creat below for a GIFD recovery falure,
+ * that needs to be fixed */
+ leaf = glfs_h_lookupat (fs, parent, leaf_name1, &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ leaf_name1, parent, strerror (errno));
+ printf ("glfs_h_extract_handle tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ ret = glfs_h_extract_handle (leaf, leaf_handle,
+ GFAPI_HANDLE_LENGTH);
+ if (ret < 0) {
+ fprintf (stderr, "glfs_h_extract_handle: error extracting handle of %s: %s\n",
+ full_leaf_name, strerror (errno));
+ printf ("glfs_h_extract_handle tests: FAILED\n");
+ goto out;
+ }
+ peek_handle (leaf_handle);
+
+ glfs_h_close (leaf); leaf = NULL;
+
+ leaf = glfs_h_create_from_handle (fs, leaf_handle, GFAPI_HANDLE_LENGTH,
+ &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_create_from_handle: error on create of %s: from (%p),%s\n",
+ leaf_name1, leaf_handle, strerror (errno));
+ printf ("glfs_h_create_from_handle tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ fd = glfs_h_open (fs, leaf, O_RDWR);
+ if (fd == NULL) {
+ fprintf (stderr, "glfs_h_open: error on open of %s: %s\n",
+ full_leaf_name, strerror (errno));
+ printf ("glfs_h_create_from_handle tests: FAILED\n");
+ goto out;
+ }
+
+ /* test read/write based on fd */
+ memcpy (writebuf, "abcdefghijklmnopqrstuvwxyz012345", 32);
+ ret = glfs_write (fd, writebuf, 32, 0);
+
+ glfs_lseek (fd, 0, SEEK_SET);
+
+ ret = glfs_read (fd, readbuf, 32, 0);
+ if (memcmp (readbuf, writebuf, 32)) {
+ printf ("Failed to read what I wrote: %s %s\n", writebuf,
+ writebuf);
+ printf ("glfs_h_create_from_handle tests: FAILED\n");
+ glfs_close (fd);
+ goto out;
+ }
+
+ glfs_close (fd);
+ glfs_h_close (leaf); leaf = NULL;
+ glfs_h_close (parent); parent = NULL;
+
+ printf ("glfs_h_extract_handle and glfs_h_create_from_handle tests: PASSED\n");
+
+ /* Mkdir tests */
+ printf ("glfs_h_mkdir tests: In Progress\n");
+
+ ret = glfs_rmdir (fs, full_newparent_name);
+ if (ret && errno != ENOENT) {
+ fprintf (stderr, "glfs_rmdir: Failed for %s: %s\n",
+ full_newparent_name, strerror (errno));
+ printf ("glfs_h_mkdir tests: FAILED\n");
+ goto out;
+ }
+
+ parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb);
+ if (parent == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ full_parent_name, root, strerror (errno));
+ printf ("glfs_h_mkdir tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ leaf = glfs_h_mkdir (fs, parent, newparent_name, 0644, &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_mkdir: error on mkdir of %s: from (%p),%s\n",
+ newparent_name, parent, strerror (errno));
+ printf ("glfs_h_mkdir tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ glfs_h_close (leaf); leaf = NULL;
+
+ leaf = glfs_h_mkdir (fs, parent, newparent_name, 0644, &sb);
+ if (leaf != NULL || errno != EEXIST) {
+ fprintf (stderr, "glfs_h_mkdir: existing directory, leaf = (%p), errno = %s\n",
+ leaf, strerror (errno));
+ printf ("glfs_h_mkdir tests: FAILED\n");
+ if (leaf != NULL) {
+ glfs_h_close (leaf); leaf = NULL;
+ }
+ }
+
+ glfs_h_close (parent); parent = NULL;
+
+ printf ("glfs_h_mkdir tests: PASSED\n");
+
+ /* Mknod tests */
+ printf ("glfs_h_mknod tests: In Progress\n");
+ ret = glfs_unlink (fs, full_newnod_name);
+ if (ret && errno != ENOENT) {
+ fprintf (stderr, "glfs_unlink: Failed for %s: %s\n",
+ full_newnod_name, strerror (errno));
+ printf ("glfs_h_mknod tests: FAILED\n");
+ goto out;
+ }
+
+ parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb);
+ if (parent == NULL) {
+ fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n",
+ full_parent_name, root, strerror (errno));
+ printf ("glfs_h_mknod tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ leaf = glfs_h_mknod (fs, parent, newnod_name, S_IFIFO, 0, &sb);
+ if (leaf == NULL) {
+ fprintf (stderr, "glfs_h_mkdir: error on mkdir of %s: from (%p),%s\n",
+ newnod_name, parent, strerror (errno));
+ printf ("glfs_h_mknod tests: FAILED\n");
+ goto out;
+ }
+ peek_stat (&sb);
+
+ /* TODO: creat op on a FIFO node hangs, need to check and fix
+ tmp = glfs_h_creat (fs, parent, newnod_name, O_CREAT, 0644, &sb);
+ if (tmp != NULL || errno != EINVAL) {
+ fprintf (stderr, "glfs_h_creat: node create, tmp = (%p), errno = %s\n",
+ tmp, strerror (errno));
+ printf ("glfs_h_creat/mknod tests: FAILED\n");
+ if (tmp != NULL) {
+ glfs_h_close(tmp); tmp = NULL;
+ }
+ } */
+
+ glfs_h_close (leaf); leaf = NULL;
+
+ leaf = glfs_h_mknod (fs, parent, newnod_name, 0644, 0, &sb);
+ if (leaf != NULL || errno != EEXIST) {
+ fprintf (stderr, "glfs_h_mknod: existing node, leaf = (%p), errno = %s\n",
+ leaf, strerror (errno));
+ printf ("glfs_h_mknod tests: FAILED\n");
+ if (leaf != NULL) {
+ glfs_h_close (leaf); leaf = NULL;
+ }
+ }
+
+ glfs_h_close (parent); parent = NULL;
+
+ printf ("glfs_h_mknod tests: PASSED\n");
+
+ /* unlink tests */
+ test_h_unlink ();
+
+ /* TODO: opendir tests */
+
+ /* getattr tests */
+ test_h_getsetattrs ();
+
+ /* TODO: setattr tests */
+
+ /* truncate tests */
+ test_h_truncate();
+
+ /* link tests */
+ test_h_links ();
+
+ /* rename tests */
+ test_h_rename ();
+
+ /* performance tests */
+ test_h_performance ();
+
+ /* END: New APIs test area */
+
+out:
+ /* Cleanup glfs handles */
+ if (root)
+ glfs_h_close (root);
+ if (parent)
+ glfs_h_close (parent);
+ if (leaf)
+ glfs_h_close (leaf);
+
+ return ret;
+}
int
main (int argc, char *argv[])
{
- glfs_t *fs = NULL;
- glfs_t *fs2 = NULL;
- int ret = 0;
- glfs_fd_t *fd = NULL;
- glfs_fd_t *fd2 = NULL;
- struct stat sb = {0, };
- char readbuf[32];
- char writebuf[32];
+ glfs_t *fs2 = NULL;
+ int ret = 0;
+ glfs_fd_t *fd = NULL;
+ glfs_fd_t *fd2 = NULL;
+ struct stat sb = {0, };
+ char readbuf[32];
+ char writebuf[32];
+
+ char *filename = "/filename2";
- char *filename = "/filename2";
+ if (argc != 3) {
+ printf ("Expect following args\n\t%s <volname> <hostname>\n", argv[0]);
+ return -1;
+ }
- fs = glfs_new ("fsync");
- if (!fs) {
- fprintf (stderr, "glfs_new: returned NULL\n");
- return 1;
- }
+ fs = glfs_new (argv[1]);
+ if (!fs) {
+ fprintf (stderr, "glfs_new: returned NULL\n");
+ return 1;
+ }
-// ret = glfs_set_volfile (fs, "/tmp/posix.vol");
+// ret = glfs_set_volfile (fs, "/tmp/posix.vol");
- ret = glfs_set_volfile_server (fs, "tcp", "localhost", 24007);
+ ret = glfs_set_volfile_server (fs, "tcp", argv[2], 24007);
-// ret = glfs_set_volfile_server (fs, "unix", "/tmp/gluster.sock", 0);
+// ret = glfs_set_volfile_server (fs, "unix", "/tmp/gluster.sock", 0);
- ret = glfs_set_logging (fs, "/dev/stderr", 7);
+ ret = glfs_set_logging (fs, "/dev/stderr", 7);
- ret = glfs_init (fs);
+ ret = glfs_init (fs);
- fprintf (stderr, "glfs_init: returned %d\n", ret);
+ fprintf (stderr, "glfs_init: returned %d\n", ret);
- sleep (2);
+ sleep (2);
- fs2 = glfs_new ("fsync");
- if (!fs2) {
- fprintf (stderr, "glfs_new: returned NULL\n");
- return 1;
- }
+ fs2 = glfs_new (argv[1]);
+ if (!fs2) {
+ fprintf (stderr, "glfs_new: returned NULL\n");
+ return 1;
+ }
-// ret = glfs_set_volfile (fs2, "/tmp/posix.vol");
+// ret = glfs_set_volfile (fs2, "/tmp/posix.vol");
- ret = glfs_set_volfile_server (fs2, "tcp", "localhost", 24007);
+ ret = glfs_set_volfile_server (fs2, "tcp", argv[2], 24007);
- ret = glfs_set_logging (fs2, "/dev/stderr", 7);
+ ret = glfs_set_logging (fs2, "/dev/stderr", 7);
- ret = glfs_init (fs2);
+ ret = glfs_init (fs2);
- fprintf (stderr, "glfs_init: returned %d\n", ret);
+ fprintf (stderr, "glfs_init: returned %d\n", ret);
- ret = glfs_lstat (fs, filename, &sb);
- fprintf (stderr, "%s: (%d) %s\n", filename, ret, strerror (errno));
+ ret = glfs_lstat (fs, filename, &sb);
+ fprintf (stderr, "%s: (%d) %s\n", filename, ret, strerror (errno));
- fd = glfs_creat (fs, filename, O_RDWR, 0644);
- fprintf (stderr, "%s: (%p) %s\n", filename, fd, strerror (errno));
+ fd = glfs_creat (fs, filename, O_RDWR, 0644);
+ fprintf (stderr, "%s: (%p) %s\n", filename, fd, strerror (errno));
- fd2 = glfs_open (fs2, filename, O_RDWR);
- fprintf (stderr, "%s: (%p) %s\n", filename, fd, strerror (errno));
+ fd2 = glfs_open (fs2, filename, O_RDWR);
+ fprintf (stderr, "%s: (%p) %s\n", filename, fd, strerror (errno));
- sprintf (writebuf, "hi there\n");
- ret = glfs_write (fd, writebuf, 32, 0);
+ sprintf (writebuf, "hi there\n");
+ ret = glfs_write (fd, writebuf, 32, 0);
- glfs_lseek (fd2, 0, SEEK_SET);
+ glfs_lseek (fd2, 0, SEEK_SET);
- ret = glfs_read (fd2, readbuf, 32, 0);
+ ret = glfs_read (fd2, readbuf, 32, 0);
- printf ("read %d, %s", ret, readbuf);
+ printf ("read %d, %s", ret, readbuf);
- glfs_close (fd);
- glfs_close (fd2);
+ glfs_close (fd);
+ glfs_close (fd2);
- filename = "/filename3";
- ret = glfs_mknod (fs, filename, S_IFIFO, 0);
- fprintf (stderr, "%s: (%d) %s\n", filename, ret, strerror (errno));
+ filename = "/filename3";
+ ret = glfs_mknod (fs, filename, S_IFIFO, 0);
+ fprintf (stderr, "%s: (%d) %s\n", filename, ret, strerror (errno));
- ret = glfs_lstat (fs, filename, &sb);
- fprintf (stderr, "%s: (%d) %s\n", filename, ret, strerror (errno));
+ ret = glfs_lstat (fs, filename, &sb);
+ fprintf (stderr, "%s: (%d) %s\n", filename, ret, strerror (errno));
- ret = glfs_rename (fs, filename, "/filename4");
- fprintf (stderr, "rename(%s): (%d) %s\n", filename, ret,
- strerror (errno));
+ ret = glfs_rename (fs, filename, "/filename4");
+ fprintf (stderr, "rename(%s): (%d) %s\n", filename, ret,
+ strerror (errno));
- ret = glfs_unlink (fs, "/filename4");
- fprintf (stderr, "unlink(%s): (%d) %s\n", "/filename4", ret,
- strerror (errno));
+ ret = glfs_unlink (fs, "/filename4");
+ fprintf (stderr, "unlink(%s): (%d) %s\n", "/filename4", ret,
+ strerror (errno));
- filename = "/dirname2";
- ret = glfs_mkdir (fs, filename, 0);
- fprintf (stderr, "%s: (%d) %s\n", filename, ret, strerror (errno));
+ filename = "/dirname2";
+ ret = glfs_mkdir (fs, filename, 0);
+ fprintf (stderr, "%s: (%d) %s\n", filename, ret, strerror (errno));
- ret = glfs_lstat (fs, filename, &sb);
- fprintf (stderr, "lstat(%s): (%d) %s\n", filename, ret, strerror (errno));
+ ret = glfs_lstat (fs, filename, &sb);
+ fprintf (stderr, "lstat(%s): (%d) %s\n", filename, ret, strerror (errno));
- ret = glfs_rmdir (fs, filename);
- fprintf (stderr, "rmdir(%s): (%d) %s\n", filename, ret, strerror (errno));
+ ret = glfs_rmdir (fs, filename);
+ fprintf (stderr, "rmdir(%s): (%d) %s\n", filename, ret, strerror (errno));
- test_dirops (fs);
+ test_dirops (fs);
- test_xattr (fs);
+ test_xattr (fs);
- test_chdir (fs);
+ test_chdir (fs);
- // done
+ test_handleops (argc, argv);
+ // done
- glfs_fini (fs);
- glfs_fini (fs2);
+ glfs_fini (fs);
+ glfs_fini (fs2);
- return ret;
+ return ret;
}
diff --git a/api/examples/setup.py.in b/api/examples/setup.py.in
new file mode 100644
index 000000000..44b738094
--- /dev/null
+++ b/api/examples/setup.py.in
@@ -0,0 +1,29 @@
+from distutils.core import setup
+
+# generate a __init__.py for the package namespace
+fo = open('__init__.py', 'w')
+fo.write('__version__ = "@PACKAGE_VERSION@"\n')
+fo.close()
+
+DESC = """GlusterFS is a clustered file-system capable of scaling to
+several petabytes. It aggregates various storage bricks over Infiniband
+RDMA or TCP/IP interconnect into one large parallel network file system.
+GlusterFS is one of the most sophisticated file systems in terms of
+features and extensibility. It borrows a powerful concept called
+Translators from GNU Hurd kernel. Much of the code in GlusterFS is in
+user space and easily manageable.
+
+This package contains the Python interface to the libgfapi library."""
+
+setup(
+ name='glusterfs-api',
+ version='@PACKAGE_VERSION@',
+ description='Python client library for the GlusterFS libgfapi',
+ long_description=DESC,
+ author='Gluster Community',
+ author_email='gluster-devel@nongnu.org',
+ license='LGPLv3',
+ url='http://gluster.org/',
+ package_dir={'gluster':''},
+ packages=['gluster']
+)
diff --git a/api/src/Makefile.am b/api/src/Makefile.am
index 0782435e0..7c5df3e20 100644
--- a/api/src/Makefile.am
+++ b/api/src/Makefile.am
@@ -1,9 +1,10 @@
lib_LTLIBRARIES = libgfapi.la
noinst_HEADERS = glfs-mem-types.h glfs-internal.h
-libgfapi_HEADERS = glfs.h
+libgfapi_HEADERS = glfs.h glfs-handles.h
libgfapidir = $(includedir)/glusterfs/api
-libgfapi_la_SOURCES = glfs.c glfs-mgmt.c glfs-fops.c glfs-resolve.c
+libgfapi_la_SOURCES = glfs.c glfs-mgmt.c glfs-fops.c glfs-resolve.c \
+ glfs-handleops.c
libgfapi_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \
$(top_builddir)/rpc/rpc-lib/src/libgfrpc.la \
$(top_builddir)/rpc/xdr/src/libgfxdr.la \
diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c
index 3191ed700..10bb7d38b 100644
--- a/api/src/glfs-fops.c
+++ b/api/src/glfs-fops.c
@@ -13,21 +13,17 @@
#include "glfs-mem-types.h"
#include "syncop.h"
#include "glfs.h"
+#include <limits.h>
-#define DEFAULT_REVAL_COUNT 1
-
-#define ESTALE_RETRY(ret,errno,reval,loc,label) do { \
- if (ret == -1 && errno == ESTALE) { \
- if (reval < DEFAULT_REVAL_COUNT) { \
- reval++; \
- loc_wipe (loc); \
- goto label; \
- } \
- } \
- } while (0)
+#ifdef NAME_MAX
+#define GF_NAME_MAX NAME_MAX
+#else
+#define GF_NAME_MAX 255
+#endif
+#define READDIRBUF_SIZE (sizeof(struct dirent) + GF_NAME_MAX + 1)
-static int
+int
glfs_loc_link (loc_t *loc, struct iatt *iatt)
{
int ret = -1;
@@ -52,7 +48,7 @@ glfs_loc_link (loc_t *loc, struct iatt *iatt)
}
-static void
+void
glfs_iatt_to_stat (struct glfs *fs, struct iatt *iatt, struct stat *stat)
{
iatt_to_stat (iatt, stat);
@@ -60,7 +56,7 @@ glfs_iatt_to_stat (struct glfs *fs, struct iatt *iatt, struct stat *stat)
}
-static int
+int
glfs_loc_unlink (loc_t *loc)
{
inode_unlink (loc->inode, loc->parent, loc->name);
@@ -137,6 +133,7 @@ out:
glfs_fd_destroy (glfd);
glfd = NULL;
} else if (glfd) {
+ glfd->fd->flags = flags;
fd_bind (glfd->fd);
glfs_fd_bind (glfd);
}
@@ -414,6 +411,7 @@ out:
glfs_fd_destroy (glfd);
glfd = NULL;
} else if (glfd) {
+ glfd->fd->flags = flags;
fd_bind (glfd->fd);
glfs_fd_bind (glfd);
}
@@ -493,13 +491,13 @@ glfs_preadv (struct glfs_fd *glfd, const struct iovec *iovec, int iovcnt,
glfd->offset = (offset + size);
- if (iov)
- GF_FREE (iov);
- if (iobref)
- iobref_unref (iobref);
-
ret = size;
out:
+ if (iov)
+ GF_FREE (iov);
+ if (iobref)
+ iobref_unref (iobref);
+
if (fd)
fd_unref (fd);
@@ -585,10 +583,6 @@ glfs_io_async_task (void *data)
ssize_t ret = 0;
switch (gio->op) {
- case GF_FOP_READ:
- ret = glfs_preadv (gio->glfd, gio->iov, gio->count,
- gio->offset, gio->flags);
- break;
case GF_FOP_WRITE:
ret = glfs_pwritev (gio->glfd, gio->iov, gio->count,
gio->offset, gio->flags);
@@ -605,6 +599,9 @@ glfs_io_async_task (void *data)
case GF_FOP_DISCARD:
ret = glfs_discard (gio->glfd, gio->offset, gio->count);
break;
+ case GF_FOP_ZEROFILL:
+ ret = glfs_zerofill(gio->glfd, gio->offset, gio->count);
+ break;
}
return (int) ret;
@@ -612,23 +609,90 @@ glfs_io_async_task (void *data)
int
+glfs_preadv_async_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int op_ret, int op_errno, struct iovec *iovec,
+ int count, struct iatt *stbuf, struct iobref *iobref,
+ dict_t *xdata)
+{
+ struct glfs_io *gio = NULL;
+ xlator_t *subvol = NULL;
+ struct glfs *fs = NULL;
+ struct glfs_fd *glfd = NULL;
+
+
+ gio = frame->local;
+ frame->local = NULL;
+ subvol = cookie;
+ glfd = gio->glfd;
+ fs = glfd->fs;
+
+ if (op_ret <= 0)
+ goto out;
+
+ op_ret = iov_copy (gio->iov, gio->count, iovec, count);
+
+ glfd->offset = gio->offset + op_ret;
+out:
+ errno = op_errno;
+ gio->fn (gio->glfd, op_ret, gio->data);
+
+ GF_FREE (gio->iov);
+ GF_FREE (gio);
+ STACK_DESTROY (frame->root);
+ glfs_subvol_done (fs, subvol);
+
+ return 0;
+}
+
+
+int
glfs_preadv_async (struct glfs_fd *glfd, const struct iovec *iovec, int count,
off_t offset, int flags, glfs_io_cbk fn, void *data)
{
struct glfs_io *gio = NULL;
int ret = 0;
+ call_frame_t *frame = NULL;
+ xlator_t *subvol = NULL;
+ glfs_t *fs = NULL;
+ fd_t *fd = NULL;
+
+ __glfs_entry_fd (glfd);
+
+ subvol = glfs_active_subvol (glfd->fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ fd = glfs_resolve_fd (glfd->fs, subvol, glfd);
+ if (!fd) {
+ ret = -1;
+ errno = EBADFD;
+ goto out;
+ }
+
+ fs = glfd->fs;
+
+ frame = syncop_create_frame (THIS);
+ if (!frame) {
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
gio = GF_CALLOC (1, sizeof (*gio), glfs_mt_glfs_io_t);
if (!gio) {
+ ret = -1;
errno = ENOMEM;
- return -1;
+ goto out;
}
gio->iov = iov_dup (iovec, count);
if (!gio->iov) {
- GF_FREE (gio);
+ ret = -1;
errno = ENOMEM;
- return -1;
+ goto out;
}
gio->op = GF_FOP_READ;
@@ -639,15 +703,23 @@ glfs_preadv_async (struct glfs_fd *glfd, const struct iovec *iovec, int count,
gio->fn = fn;
gio->data = data;
- ret = synctask_new (glfs_from_glfd (glfd)->ctx->env,
- glfs_io_async_task, glfs_io_async_cbk,
- NULL, gio);
+ frame->local = gio;
+
+ STACK_WIND_COOKIE (frame, glfs_preadv_async_cbk, subvol, subvol,
+ subvol->fops->readv, fd, iov_length (iovec, count),
+ offset, flags, NULL);
+out:
if (ret) {
GF_FREE (gio->iov);
GF_FREE (gio);
+ STACK_DESTROY (frame->root);
+ glfs_subvol_done (fs, subvol);
}
+ if (fd)
+ fd_unref (fd);
+
return ret;
}
@@ -1804,6 +1876,38 @@ glfs_discard_async (struct glfs_fd *glfd, off_t offset, size_t len,
return ret;
}
+int
+glfs_zerofill_async (struct glfs_fd *glfd, off_t offset, size_t len,
+ glfs_io_cbk fn, void *data)
+{
+ struct glfs_io *gio = NULL;
+ int ret = 0;
+
+ gio = GF_CALLOC (1, sizeof (*gio), glfs_mt_glfs_io_t);
+ if (!gio) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ gio->op = GF_FOP_ZEROFILL;
+ gio->glfd = glfd;
+ gio->offset = offset;
+ gio->count = len;
+ gio->fn = fn;
+ gio->data = data;
+
+ ret = synctask_new (glfs_from_glfd (glfd)->ctx->env,
+ glfs_io_async_task, glfs_io_async_cbk,
+ NULL, gio);
+
+ if (ret) {
+ GF_FREE (gio->iov);
+ GF_FREE (gio);
+ }
+
+ return ret;
+}
+
void
gf_dirent_to_dirent (gf_dirent_t *gf_dirent, struct dirent *dirent)
@@ -1822,7 +1926,7 @@ gf_dirent_to_dirent (gf_dirent_t *gf_dirent, struct dirent *dirent)
dirent->d_namlen = strlen (gf_dirent->d_name);
#endif
- strncpy (dirent->d_name, gf_dirent->d_name, 256);
+ strncpy (dirent->d_name, gf_dirent->d_name, GF_NAME_MAX + 1);
}
@@ -1916,16 +2020,56 @@ glfd_entry_next (struct glfs_fd *glfd, int plus)
}
+static struct dirent *
+glfs_readdirbuf_get (struct glfs_fd *glfd)
+{
+ struct dirent *buf = NULL;
+
+ LOCK (&glfd->fd->lock);
+ {
+ buf = glfd->readdirbuf;
+ if (buf) {
+ memset (buf, 0, READDIRBUF_SIZE);
+ goto unlock;
+ }
+
+ buf = GF_CALLOC (1, READDIRBUF_SIZE, glfs_mt_readdirbuf_t);
+ if (!buf) {
+ errno = ENOMEM;
+ goto unlock;
+ }
+
+ glfd->readdirbuf = buf;
+ }
+unlock:
+ UNLOCK (&glfd->fd->lock);
+
+ return buf;
+}
+
+
int
-glfs_readdirplus_r (struct glfs_fd *glfd, struct stat *stat, struct dirent *buf,
+glfs_readdirplus_r (struct glfs_fd *glfd, struct stat *stat, struct dirent *ext,
struct dirent **res)
{
int ret = 0;
gf_dirent_t *entry = NULL;
+ struct dirent *buf = NULL;
__glfs_entry_fd (glfd);
errno = 0;
+
+ if (ext)
+ buf = ext;
+ else
+ buf = glfs_readdirbuf_get (glfd);
+
+ if (!buf) {
+ errno = ENOMEM;
+ return -1;
+ }
+
entry = glfd_entry_next (glfd, !!stat);
if (errno)
ret = -1;
@@ -1954,6 +2098,28 @@ glfs_readdir_r (struct glfs_fd *glfd, struct dirent *buf, struct dirent **res)
}
+struct dirent *
+glfs_readdirplus (struct glfs_fd *glfd, struct stat *stat)
+{
+ struct dirent *res = NULL;
+ int ret = -1;
+
+ ret = glfs_readdirplus_r (glfd, stat, NULL, &res);
+ if (ret)
+ return NULL;
+
+ return res;
+}
+
+
+
+struct dirent *
+glfs_readdir (struct glfs_fd *glfd)
+{
+ return glfs_readdirplus (glfd, NULL);
+}
+
+
int
glfs_statvfs (struct glfs *fs, const char *path, struct statvfs *buf)
{
@@ -2760,6 +2926,36 @@ out:
return ret;
}
+int
+glfs_zerofill (struct glfs_fd *glfd, off_t offset, size_t len)
+{
+ int ret = -1;
+ xlator_t *subvol = NULL;
+ fd_t *fd = NULL;
+
+ __glfs_entry_fd (glfd);
+
+ subvol = glfs_active_subvol (glfd->fs);
+ if (!subvol) {
+ errno = EIO;
+ goto out;
+ }
+
+ fd = glfs_resolve_fd (glfd->fs, subvol, glfd);
+ if (!fd) {
+ errno = EBADFD;
+ goto out;
+ }
+
+ ret = syncop_zerofill (subvol, fd, offset, len);
+out:
+ if (fd)
+ fd_unref(fd);
+
+ glfs_subvol_done (glfd->fs, subvol);
+
+ return ret;
+}
int
glfs_chdir (struct glfs *fs, const char *path)
diff --git a/api/src/glfs-handleops.c b/api/src/glfs-handleops.c
new file mode 100644
index 000000000..9c707a619
--- /dev/null
+++ b/api/src/glfs-handleops.c
@@ -0,0 +1,1278 @@
+/*
+ * Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
+ * This file is part of GlusterFS.
+ *
+ * This file is licensed to you under your choice of the GNU Lesser
+ * General Public License, version 3 or any later version (LGPLv3 or
+ * later), or the GNU General Public License, version 2 (GPLv2), in all
+ * cases as published by the Free Software Foundation.
+ */
+
+
+#include "glfs-internal.h"
+#include "glfs-mem-types.h"
+#include "syncop.h"
+#include "glfs.h"
+#include "glfs-handles.h"
+
+static void
+glfs_iatt_from_stat (struct stat *stat, int valid, struct iatt *iatt,
+ int *glvalid)
+{
+ /* validate in args */
+ if ((stat == NULL) || (iatt == NULL) || (glvalid == NULL)) {
+ errno = EINVAL;
+ return;
+ }
+
+ *glvalid = 0;
+
+ if (valid & GFAPI_SET_ATTR_MODE) {
+ iatt->ia_prot = ia_prot_from_st_mode (stat->st_mode);
+ *glvalid |= GF_SET_ATTR_MODE;
+ }
+
+ if (valid & GFAPI_SET_ATTR_UID) {
+ iatt->ia_uid = stat->st_uid;
+ *glvalid |= GF_SET_ATTR_UID;
+ }
+
+ if (valid & GFAPI_SET_ATTR_GID) {
+ iatt->ia_gid = stat->st_gid;
+ *glvalid |= GF_SET_ATTR_GID;
+ }
+
+ if (valid & GFAPI_SET_ATTR_ATIME) {
+ iatt->ia_atime = stat->st_atime;
+ iatt->ia_atime_nsec = ST_ATIM_NSEC (stat);
+ *glvalid |= GF_SET_ATTR_ATIME;
+ }
+
+ if (valid & GFAPI_SET_ATTR_MTIME) {
+ iatt->ia_mtime = stat->st_mtime;
+ iatt->ia_mtime_nsec = ST_MTIM_NSEC (stat);
+ *glvalid |= GF_SET_ATTR_MTIME;
+ }
+
+ return;
+}
+
+struct glfs_object *
+glfs_h_lookupat (struct glfs *fs, struct glfs_object *parent,
+ const char *path, struct stat *stat)
+{
+ int ret = 0;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+ struct iatt iatt = {0, };
+ struct glfs_object *object = NULL;
+ loc_t loc = {0, };
+
+ /* validate in args */
+ if ((fs == NULL) || (path == NULL)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ if (parent) {
+ inode = glfs_resolve_inode (fs, subvol, parent);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+ }
+
+ /* fop/op */
+ ret = glfs_resolve_at (fs, subvol, inode, path, &loc, &iatt,
+ 0 /*TODO: links? */, 0);
+
+ /* populate out args */
+ if (!ret) {
+ if (stat)
+ glfs_iatt_to_stat (fs, &iatt, stat);
+
+ ret = glfs_create_object (&loc, &object);
+ }
+
+out:
+ loc_wipe (&loc);
+
+ if (inode)
+ inode_unref (inode);
+
+ glfs_subvol_done (fs, subvol);
+
+ return object;
+}
+
+int
+glfs_h_stat (struct glfs *fs, struct glfs_object *object, struct stat *stat)
+{
+ int ret = -1;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+ loc_t loc = {0, };
+ struct iatt iatt = {0, };
+
+ /* validate in args */
+ if ((fs == NULL) || (object == NULL)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ inode = glfs_resolve_inode (fs, subvol, object);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ /* populate loc */
+ GLFS_LOC_FILL_INODE (inode, loc, out);
+
+ /* fop/op */
+ ret = syncop_stat (subvol, &loc, &iatt);
+
+ /* populate out args */
+ if (!ret && stat) {
+ glfs_iatt_to_stat (fs, &iatt, stat);
+ }
+out:
+ loc_wipe (&loc);
+
+ if (inode)
+ inode_unref (inode);
+
+ glfs_subvol_done (fs, subvol);
+
+ return ret;
+}
+
+int
+glfs_h_getattrs (struct glfs *fs, struct glfs_object *object, struct stat *stat)
+{
+ int ret = 0;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+ struct iatt iatt = {0, };
+
+ /* validate in args */
+ if ((fs == NULL) || (object == NULL)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ inode = glfs_resolve_inode (fs, subvol, object);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ /* fop/op */
+ ret = glfs_resolve_base (fs, subvol, inode, &iatt);
+
+ /* populate out args */
+ if (!ret && stat) {
+ glfs_iatt_to_stat (fs, &iatt, stat);
+ }
+
+out:
+ if (inode)
+ inode_unref (inode);
+
+ glfs_subvol_done (fs, subvol);
+
+ return ret;
+}
+
+int
+glfs_h_setattrs (struct glfs *fs, struct glfs_object *object, struct stat *stat,
+ int valid)
+{
+ int ret = -1;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+ loc_t loc = {0, };
+ struct iatt iatt = {0, };
+ int glvalid = 0;
+
+ /* validate in args */
+ if ((fs == NULL) || (object == NULL) || (stat == NULL)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ inode = glfs_resolve_inode (fs, subvol, object);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ /* map valid masks from in args */
+ glfs_iatt_from_stat (stat, valid, &iatt, &glvalid);
+
+ /* populate loc */
+ GLFS_LOC_FILL_INODE (inode, loc, out);
+
+ /* fop/op */
+ ret = syncop_setattr (subvol, &loc, &iatt, glvalid, 0, 0);
+out:
+ loc_wipe (&loc);
+
+ if (inode)
+ inode_unref (inode);
+
+ glfs_subvol_done (fs, subvol);
+
+ return ret;
+}
+
+struct glfs_fd *
+glfs_h_open (struct glfs *fs, struct glfs_object *object, int flags)
+{
+ int ret = -1;
+ struct glfs_fd *glfd = NULL;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+ loc_t loc = {0, };
+
+ /* validate in args */
+ if ((fs == NULL) || (object == NULL)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ inode = glfs_resolve_inode (fs, subvol, object);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ /* check types to open */
+ if (IA_ISDIR (inode->ia_type)) {
+ ret = -1;
+ errno = EISDIR;
+ goto out;
+ }
+
+ if (!IA_ISREG (inode->ia_type)) {
+ ret = -1;
+ errno = EINVAL;
+ goto out;
+ }
+
+ glfd = glfs_fd_new (fs);
+ if (!glfd) {
+ errno = ENOMEM;
+ goto out;
+ }
+
+ glfd->fd = fd_create (inode, getpid());
+ if (!glfd->fd) {
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
+
+ /* populate loc */
+ GLFS_LOC_FILL_INODE (inode, loc, out);
+
+ /* fop/op */
+ ret = syncop_open (subvol, &loc, flags, glfd->fd);
+
+out:
+ loc_wipe (&loc);
+
+ if (inode)
+ inode_unref (inode);
+
+ if (ret && glfd) {
+ glfs_fd_destroy (glfd);
+ glfd = NULL;
+ } else {
+ glfd->fd->flags = flags;
+ fd_bind (glfd->fd);
+ glfs_fd_bind (glfd);
+ }
+
+ glfs_subvol_done (fs, subvol);
+
+ return glfd;
+}
+
+struct glfs_object *
+glfs_h_creat (struct glfs *fs, struct glfs_object *parent, const char *path,
+ int flags, mode_t mode, struct stat *stat)
+{
+ int ret = -1;
+ struct glfs_fd *glfd = NULL;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+ loc_t loc = {0, };
+ struct iatt iatt = {0, };
+ uuid_t gfid;
+ dict_t *xattr_req = NULL;
+ struct glfs_object *object = NULL;
+
+ /* validate in args */
+ if ((fs == NULL) || (parent == NULL) || (path == NULL)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ inode = glfs_resolve_inode (fs, subvol, parent);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ xattr_req = dict_new ();
+ if (!xattr_req) {
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
+
+ uuid_generate (gfid);
+ ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16);
+ if (ret) {
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
+
+ GLFS_LOC_FILL_PINODE (inode, loc, ret, errno, out, path);
+
+ glfd = glfs_fd_new (fs);
+ if (!glfd)
+ goto out;
+
+ glfd->fd = fd_create (loc.inode, getpid());
+ if (!glfd->fd) {
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
+
+ /* fop/op */
+ ret = syncop_create (subvol, &loc, flags, mode, glfd->fd,
+ xattr_req, &iatt);
+
+ /* populate out args */
+ if (ret == 0) {
+ /* TODO: If the inode existed in the cache (say file already
+ exists), then the glfs_loc_link will not update the
+ loc.inode, as a result we will have a 0000 GFID that we
+ would copy out to the object, this needs to be fixed.
+ */
+ ret = glfs_loc_link (&loc, &iatt);
+ if (ret != 0) {
+ goto out;
+ }
+
+ if (stat)
+ glfs_iatt_to_stat (fs, &iatt, stat);
+
+ ret = glfs_create_object (&loc, &object);
+ }
+
+out:
+ if (ret && object != NULL) {
+ glfs_h_close (object);
+ object = NULL;
+ }
+
+ loc_wipe(&loc);
+
+ if (inode)
+ inode_unref (inode);
+
+ if (xattr_req)
+ dict_unref (xattr_req);
+
+ if (glfd) {
+ glfs_fd_destroy (glfd);
+ glfd = NULL;
+ }
+
+ glfs_subvol_done (fs, subvol);
+
+ return object;
+}
+
+struct glfs_object *
+glfs_h_mkdir (struct glfs *fs, struct glfs_object *parent, const char *path,
+ mode_t mode, struct stat *stat)
+{
+ int ret = -1;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+ loc_t loc = {0, };
+ struct iatt iatt = {0, };
+ uuid_t gfid;
+ dict_t *xattr_req = NULL;
+ struct glfs_object *object = NULL;
+
+ /* validate in args */
+ if ((fs == NULL) || (parent == NULL) || (path == NULL)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ inode = glfs_resolve_inode (fs, subvol, parent);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ xattr_req = dict_new ();
+ if (!xattr_req) {
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
+
+ uuid_generate (gfid);
+ ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16);
+ if (ret) {
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
+
+ GLFS_LOC_FILL_PINODE (inode, loc, ret, errno, out, path);
+
+ /* fop/op */
+ ret = syncop_mkdir (subvol, &loc, mode, xattr_req, &iatt);
+
+ /* populate out args */
+ if ( ret == 0 ) {
+ ret = glfs_loc_link (&loc, &iatt);
+ if (ret != 0) {
+ goto out;
+ }
+
+ if (stat)
+ glfs_iatt_to_stat (fs, &iatt, stat);
+
+ ret = glfs_create_object (&loc, &object);
+ }
+
+out:
+ if (ret && object != NULL) {
+ glfs_h_close (object);
+ object = NULL;
+ }
+
+ loc_wipe(&loc);
+
+ if (inode)
+ inode_unref (inode);
+
+ if (xattr_req)
+ dict_unref (xattr_req);
+
+ glfs_subvol_done (fs, subvol);
+
+ return object;
+}
+
+struct glfs_object *
+glfs_h_mknod (struct glfs *fs, struct glfs_object *parent, const char *path,
+ mode_t mode, dev_t dev, struct stat *stat)
+{
+ int ret = -1;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+ loc_t loc = {0, };
+ struct iatt iatt = {0, };
+ uuid_t gfid;
+ dict_t *xattr_req = NULL;
+ struct glfs_object *object = NULL;
+
+ /* validate in args */
+ if ((fs == NULL) || (parent == NULL) || (path == NULL)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ inode = glfs_resolve_inode (fs, subvol, parent);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ xattr_req = dict_new ();
+ if (!xattr_req) {
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
+
+ uuid_generate (gfid);
+ ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16);
+ if (ret) {
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
+
+ GLFS_LOC_FILL_PINODE (inode, loc, ret, errno, out, path);
+
+ /* fop/op */
+ ret = syncop_mknod (subvol, &loc, mode, dev, xattr_req, &iatt);
+
+ /* populate out args */
+ if (ret == 0) {
+ ret = glfs_loc_link (&loc, &iatt);
+ if (ret != 0) {
+ goto out;
+ }
+
+ if (stat)
+ glfs_iatt_to_stat (fs, &iatt, stat);
+
+ ret = glfs_create_object (&loc, &object);
+ }
+out:
+ if (ret && object != NULL) {
+ glfs_h_close (object);
+ object = NULL;
+ }
+
+ loc_wipe(&loc);
+
+ if (inode)
+ inode_unref (inode);
+
+ if (xattr_req)
+ dict_unref (xattr_req);
+
+ glfs_subvol_done (fs, subvol);
+
+ return object;
+}
+
+int
+glfs_h_unlink (struct glfs *fs, struct glfs_object *parent, const char *path)
+{
+ int ret = -1;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+ loc_t loc = {0, };
+
+ /* validate in args */
+ if ((fs == NULL) || (parent == NULL) || (path == NULL)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if ( !subvol ) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ inode = glfs_resolve_inode (fs, subvol, parent);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ ret = glfs_resolve_at (fs, subvol, inode, path, &loc, NULL, 0 , 0);
+ if (ret != 0) {
+ goto out;
+ }
+
+ if (!IA_ISDIR(loc.inode->ia_type)) {
+ ret = syncop_unlink (subvol, &loc);
+ if (ret != 0) {
+ goto out;
+ }
+ } else {
+ ret = syncop_rmdir (subvol, &loc);
+ if (ret != 0) {
+ goto out;
+ }
+ }
+
+ if (ret == 0)
+ ret = glfs_loc_unlink (&loc);
+
+out:
+ loc_wipe (&loc);
+
+ if (inode)
+ inode_unref (inode);
+
+ glfs_subvol_done (fs, subvol);
+
+ return ret;
+}
+
+struct glfs_fd *
+glfs_h_opendir (struct glfs *fs, struct glfs_object *object)
+{
+ int ret = -1;
+ struct glfs_fd *glfd = NULL;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+ loc_t loc = {0, };
+
+ /* validate in args */
+ if ((fs == NULL) || (object == NULL)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ inode = glfs_resolve_inode (fs, subvol, object);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ if (!IA_ISDIR (inode->ia_type)) {
+ ret = -1;
+ errno = ENOTDIR;
+ goto out;
+ }
+
+ glfd = glfs_fd_new (fs);
+ if (!glfd)
+ goto out;
+
+ INIT_LIST_HEAD (&glfd->entries);
+
+ glfd->fd = fd_create (inode, getpid());
+ if (!glfd->fd) {
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
+
+ GLFS_LOC_FILL_INODE (inode, loc, out);
+
+ /* fop/op */
+ ret = syncop_opendir (subvol, &loc, glfd->fd);
+
+out:
+ loc_wipe (&loc);
+
+ if (inode)
+ inode_unref (inode);
+
+ if (ret && glfd) {
+ glfs_fd_destroy (glfd);
+ glfd = NULL;
+ } else {
+ fd_bind (glfd->fd);
+ glfs_fd_bind (glfd);
+ }
+
+ glfs_subvol_done (fs, subvol);
+
+ return glfd;
+}
+
+ssize_t
+glfs_h_extract_handle (struct glfs_object *object, unsigned char *handle,
+ int len)
+{
+ ssize_t ret = -1;
+
+ /* validate in args */
+ if (object == NULL) {
+ errno = EINVAL;
+ goto out;
+ }
+
+ if (!handle || !len) {
+ ret = GFAPI_HANDLE_LENGTH;
+ goto out;
+ }
+
+ if (len < GFAPI_HANDLE_LENGTH)
+ {
+ errno = ERANGE;
+ goto out;
+ }
+
+ memcpy (handle, object->gfid, GFAPI_HANDLE_LENGTH);
+
+ ret = GFAPI_HANDLE_LENGTH;
+
+out:
+ return ret;
+}
+
+struct glfs_object *
+glfs_h_create_from_handle (struct glfs *fs, unsigned char *handle, int len,
+ struct stat *stat)
+{
+ loc_t loc = {0, };
+ int ret = -1;
+ struct iatt iatt = {0, };
+ inode_t *newinode = NULL;
+ xlator_t *subvol = NULL;
+ struct glfs_object *object = NULL;
+
+ /* validate in args */
+ if ((fs == NULL) || (handle == NULL) || (len != GFAPI_HANDLE_LENGTH)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ errno = EIO;
+ goto out;
+ }
+
+ memcpy (loc.gfid, handle, GFAPI_HANDLE_LENGTH);
+
+ newinode = inode_find (subvol->itable, loc.gfid);
+ if (newinode)
+ loc.inode = newinode;
+ else {
+ loc.inode = inode_new (subvol->itable);
+ if (!loc.inode) {
+ errno = ENOMEM;
+ goto out;
+ }
+ }
+
+ ret = syncop_lookup (subvol, &loc, 0, &iatt, 0, 0);
+ if (ret) {
+ gf_log (subvol->name, GF_LOG_WARNING,
+ "inode refresh of %s failed: %s",
+ uuid_utoa (loc.gfid), strerror (errno));
+ goto out;
+ }
+
+ newinode = inode_link (loc.inode, 0, 0, &iatt);
+ if (newinode)
+ inode_lookup (newinode);
+ else {
+ gf_log (subvol->name, GF_LOG_WARNING,
+ "inode linking of %s failed: %s",
+ uuid_utoa (loc.gfid), strerror (errno));
+ errno = EINVAL;
+ goto out;
+ }
+
+ /* populate stat */
+ if (stat)
+ glfs_iatt_to_stat (fs, &iatt, stat);
+
+ object = GF_CALLOC (1, sizeof(struct glfs_object),
+ glfs_mt_glfs_object_t);
+ if (object == NULL) {
+ errno = ENOMEM;
+ ret = -1;
+ goto out;
+ }
+
+ /* populate the return object */
+ object->inode = newinode;
+ uuid_copy (object->gfid, object->inode->gfid);
+
+out:
+ /* TODO: Check where the inode ref is being held? */
+ loc_wipe (&loc);
+
+ glfs_subvol_done (fs, subvol);
+
+ return object;
+}
+
+int
+glfs_h_close (struct glfs_object *object)
+{
+ /* Release the held reference */
+ inode_unref (object->inode);
+ GF_FREE (object);
+
+ return 0;
+}
+
+int
+glfs_h_truncate (struct glfs *fs, struct glfs_object *object, off_t offset)
+{
+ loc_t loc = {0, };
+ int ret = -1;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+
+ /* validate in args */
+ if ((fs == NULL) || (object == NULL)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ inode = glfs_resolve_inode (fs, subvol, object);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ GLFS_LOC_FILL_INODE (inode, loc, out);
+
+ /* fop/op */
+ ret = syncop_truncate (subvol, &loc, (off_t)offset);
+
+ /* populate out args */
+ if (ret == 0)
+ ret = glfs_loc_unlink (&loc);
+
+out:
+ loc_wipe (&loc);
+
+ if (inode)
+ inode_unref (inode);
+
+ glfs_subvol_done (fs, subvol);
+
+ return ret;
+}
+
+struct glfs_object *
+glfs_h_symlink (struct glfs *fs, struct glfs_object *parent, const char *name,
+ const char *data, struct stat *stat)
+{
+ int ret = -1;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+ loc_t loc = {0, };
+ struct iatt iatt = {0, };
+ uuid_t gfid;
+ dict_t *xattr_req = NULL;
+ struct glfs_object *object = NULL;
+
+ /* validate in args */
+ if ((fs == NULL) || (parent == NULL) || (name == NULL) ||
+ (data == NULL)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ inode = glfs_resolve_inode (fs, subvol, parent);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ xattr_req = dict_new ();
+ if (!xattr_req) {
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
+
+ uuid_generate (gfid);
+ ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16);
+ if (ret) {
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
+
+ GLFS_LOC_FILL_PINODE (inode, loc, ret, errno, out, name);
+
+ /* fop/op */
+ ret = syncop_symlink (subvol, &loc, data, xattr_req, &iatt);
+
+ /* populate out args */
+ if (ret == 0) {
+ /* TODO: If the inode existed in the cache (say file already
+ * exists), then the glfs_loc_link will not update the
+ * loc.inode, as a result we will have a 0000 GFID that we
+ * would copy out to the object, this needs to be fixed.
+ */
+ ret = glfs_loc_link (&loc, &iatt);
+ if (ret != 0) {
+ goto out;
+ }
+
+ if (stat)
+ glfs_iatt_to_stat (fs, &iatt, stat);
+
+ ret = glfs_create_object (&loc, &object);
+ }
+
+out:
+ if (ret && object != NULL) {
+ glfs_h_close (object);
+ object = NULL;
+ }
+
+ loc_wipe(&loc);
+
+ if (inode)
+ inode_unref (inode);
+
+ if (xattr_req)
+ dict_unref (xattr_req);
+
+ glfs_subvol_done (fs, subvol);
+
+ return object;
+}
+
+int
+glfs_h_readlink (struct glfs *fs, struct glfs_object *object, char *buf,
+ size_t bufsiz)
+{
+ loc_t loc = {0, };
+ int ret = -1;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+ char *linkval = NULL;
+
+ /* validate in args */
+ if ((fs == NULL) || (object == NULL) || (buf == NULL)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ inode = glfs_resolve_inode (fs, subvol, object);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ GLFS_LOC_FILL_INODE (inode, loc, out);
+
+ /* fop/op */
+ ret = syncop_readlink (subvol, &loc, &linkval, bufsiz);
+
+ /* populate out args */
+ if (ret > 0)
+ memcpy (buf, linkval, ret);
+
+out:
+ loc_wipe (&loc);
+
+ if (inode)
+ inode_unref (inode);
+
+ if (linkval)
+ GF_FREE (linkval);
+
+ glfs_subvol_done (fs, subvol);
+
+ return ret;
+}
+
+int
+glfs_h_link (struct glfs *fs, struct glfs_object *linksrc,
+ struct glfs_object *parent, const char *name)
+{
+ int ret = -1;
+ xlator_t *subvol = NULL;
+ inode_t *inode = NULL;
+ inode_t *pinode = NULL;
+ loc_t oldloc = {0, };
+ loc_t newloc = {0, };
+
+ /* validate in args */
+ if ((fs == NULL) || (linksrc == NULL) || (parent == NULL) ||
+ (name == NULL)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ inode = glfs_resolve_inode (fs, subvol, linksrc);
+ if (!inode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ if (inode->ia_type == IA_IFDIR) {
+ ret = -1;
+ errno = EISDIR;
+ goto out;
+ }
+
+ GLFS_LOC_FILL_INODE (inode, oldloc, out);
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ pinode = glfs_resolve_inode (fs, subvol, parent);
+ if (!pinode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ /* setup newloc based on parent */
+ newloc.parent = inode_ref (pinode);
+ newloc.name = name;
+ ret = glfs_loc_touchup (&newloc);
+ if (ret != 0) {
+ errno = EINVAL;
+ goto out;
+ }
+
+ /* Filling the inode of the hard link to be same as that of the
+ * original file
+ */
+ newloc.inode = inode_ref (inode);
+
+ /* fop/op */
+ ret = syncop_link (subvol, &oldloc, &newloc);
+
+ if (ret == 0)
+ /* TODO: No iatt to pass as there has been no lookup */
+ ret = glfs_loc_link (&newloc, NULL);
+out:
+ loc_wipe (&oldloc);
+ loc_wipe (&newloc);
+
+ if (inode)
+ inode_unref (inode);
+
+ if (pinode)
+ inode_unref (pinode);
+
+ glfs_subvol_done (fs, subvol);
+
+ return ret;
+}
+
+int
+glfs_h_rename (struct glfs *fs, struct glfs_object *olddir, const char *oldname,
+ struct glfs_object *newdir, const char *newname)
+{
+ int ret = -1;
+ xlator_t *subvol = NULL;
+ inode_t *oldpinode = NULL;
+ inode_t *newpinode = NULL;
+ loc_t oldloc = {0, };
+ loc_t newloc = {0, };
+ struct iatt oldiatt = {0, };
+ struct iatt newiatt = {0, };
+
+ /* validate in args */
+ if ((fs == NULL) || (olddir == NULL) || (oldname == NULL) ||
+ (newdir == NULL) || (newname == NULL)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ __glfs_entry_fs (fs);
+
+ /* get the active volume */
+ subvol = glfs_active_subvol (fs);
+ if ( !subvol ) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ oldpinode = glfs_resolve_inode (fs, subvol, olddir);
+ if (!oldpinode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ ret = glfs_resolve_at (fs, subvol, oldpinode, oldname, &oldloc,
+ &oldiatt, 0 , 0);
+ if (ret != 0) {
+ goto out;
+ }
+
+ /* get/refresh the in arg objects inode in correlation to the xlator */
+ newpinode = glfs_resolve_inode (fs, subvol, newdir);
+ if (!newpinode) {
+ errno = ESTALE;
+ goto out;
+ }
+
+ ret = glfs_resolve_at (fs, subvol, newpinode, newname, &newloc,
+ &newiatt, 0, 0);
+
+ if (ret && errno != ENOENT && newloc.parent)
+ goto out;
+
+ if (newiatt.ia_type != IA_INVAL) {
+ if ((oldiatt.ia_type == IA_IFDIR) !=
+ (newiatt.ia_type == IA_IFDIR)) {
+ /* Either both old and new must be dirs,
+ * or both must be non-dirs. Else, fail.
+ */
+ ret = -1;
+ errno = EISDIR;
+ goto out;
+ }
+ }
+
+ /* TODO: check if new or old is a prefix of the other, and fail EINVAL */
+
+ ret = syncop_rename (subvol, &oldloc, &newloc);
+
+ if (ret == 0)
+ inode_rename (oldloc.parent->table, oldloc.parent, oldloc.name,
+ newloc.parent, newloc.name, oldloc.inode,
+ &oldiatt);
+
+out:
+ loc_wipe (&oldloc);
+ loc_wipe (&newloc);
+
+ if (oldpinode)
+ inode_unref (oldpinode);
+
+ if (newpinode)
+ inode_unref (newpinode);
+
+ glfs_subvol_done (fs, subvol);
+
+ return ret;
+}
diff --git a/api/src/glfs-handles.h b/api/src/glfs-handles.h
new file mode 100644
index 000000000..437f2cbc8
--- /dev/null
+++ b/api/src/glfs-handles.h
@@ -0,0 +1,143 @@
+/*
+ Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#ifndef _GLFS_HANDLES_H
+#define _GLFS_HANDLES_H
+
+#include "glfs.h"
+
+/* GLFS OBJECT BASED OPERATIONS
+ *
+ * The following APIs are introduced to provide an API framework that can work
+ * with gluster objects (files and directories), instead of absolute paths.
+ *
+ * The following API set can be related to the POSIX *at interfaces (like
+ * openat (2)). The intention of these APIs is to be able to operate based
+ * on parent object and looking up or creating child objects within, OR to be
+ * used on the actual object thus looked up or created, and retrieve information
+ * regarding the same.
+ *
+ * The APIs also provide for generating an opaque invariant handle to the
+ * object, that can later be used to lookup the object, instead of the regular
+ * glfs_h_* variants. The APIs that provide this behaviour are,
+ * glfs_h_extract_handle and glfs_h_create_from_handle.
+ *
+ * The object handles can be transitioned to fd based operations as supported
+ * by glfs.h calls, using the glfs_h_open call. This provides a way to move
+ * from objects to fd's akin to moving from path to fd for required operations.
+ *
+ * NOTE: The opaque invariant handle is the GFID of the object in reality, but
+ * maintained as an opaque data value, for potential internal changes to the
+ * same without impacting the caller.
+ *
+ * NOTE: Currently looking up an object can create multiple object handles to
+ * the same, i.e distinct glfs_object *. Hence each such looked up or received
+ * handle from other calls, would need to be closed. In the future, for a given
+ * object these pointers would be the same, and an ease of use API to forget all
+ * instances of this bject would be provided (instead of a per lookup close).
+ * This should not change the APIs in their current form.
+ *
+ */
+
+/* Values for valid falgs to be used when using XXXsetattr, to set multiple
+ attribute values passed via the related stat structure.
+ */
+#define GFAPI_SET_ATTR_MODE 0x1
+#define GFAPI_SET_ATTR_UID 0x2
+#define GFAPI_SET_ATTR_GID 0x4
+#define GFAPI_SET_ATTR_SIZE 0x8
+#define GFAPI_SET_ATTR_ATIME 0x10
+#define GFAPI_SET_ATTR_MTIME 0x20
+
+/* Handle length for object handles returned from glfs_h_extract_handle or
+ * glfs_h_create_from_handle */
+#define GFAPI_HANDLE_LENGTH 16
+
+__BEGIN_DECLS
+
+/*
+ * Notes:
+ *
+ * The file object handle. One per looked up, created file/directory
+ *
+ * This had been introduced to facilitate gfid/inode based gfapi
+ * - a requirement introduced by nfs-ganesha
+ */
+struct glfs_object;
+typedef struct glfs_object glfs_object_t;
+
+/* Handle based operations */
+/* Operations that generate handles */
+struct glfs_object *glfs_h_lookupat (struct glfs *fs,
+ struct glfs_object *parent,
+ const char *path, struct stat *stat);
+
+struct glfs_object *glfs_h_creat (struct glfs *fs, struct glfs_object *parent,
+ const char *path, int flags, mode_t mode,
+ struct stat *sb);
+
+struct glfs_object *glfs_h_mkdir (struct glfs *fs, struct glfs_object *parent,
+ const char *path, mode_t flags,
+ struct stat *sb);
+
+struct glfs_object *glfs_h_mknod (struct glfs *fs, struct glfs_object *parent,
+ const char *path, mode_t mode, dev_t dev,
+ struct stat *sb);
+
+struct glfs_object *glfs_h_symlink (struct glfs *fs, struct glfs_object *parent,
+ const char *name, const char *data,
+ struct stat *stat);
+
+/* Operations on the actual objects */
+int glfs_h_unlink (struct glfs *fs, struct glfs_object *parent,
+ const char *path);
+
+int glfs_h_close (struct glfs_object *object);
+
+int glfs_caller_specific_init (void *uid_caller_key, void *gid_caller_key,
+ void *future);
+
+int glfs_h_truncate (struct glfs *fs, struct glfs_object *object, off_t offset);
+
+int glfs_h_stat(struct glfs *fs, struct glfs_object *object, struct stat *stat);
+
+int glfs_h_getattrs (struct glfs *fs, struct glfs_object *object,
+ struct stat *stat);
+
+int glfs_h_setattrs (struct glfs *fs, struct glfs_object *object,
+ struct stat *sb, int valid);
+
+int glfs_h_readlink (struct glfs *fs, struct glfs_object *object, char *buf,
+ size_t bufsiz);
+
+int glfs_h_link (struct glfs *fs, struct glfs_object *linktgt,
+ struct glfs_object *parent, const char *name);
+
+int glfs_h_rename (struct glfs *fs, struct glfs_object *olddir,
+ const char *oldname, struct glfs_object *newdir,
+ const char *newname);
+
+/* Operations enabling opaque invariant handle to object transitions */
+ssize_t glfs_h_extract_handle (struct glfs_object *object,
+ unsigned char *handle, int len);
+
+struct glfs_object *glfs_h_create_from_handle (struct glfs *fs,
+ unsigned char *handle, int len,
+ struct stat *stat);
+
+/* Operations enabling object handles to fd transitions */
+struct glfs_fd *glfs_h_opendir (struct glfs *fs, struct glfs_object *object);
+
+struct glfs_fd *glfs_h_open (struct glfs *fs, struct glfs_object *object,
+ int flags);
+
+__END_DECLS
+
+#endif /* !_GLFS_HANDLES_H */ \ No newline at end of file
diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h
index 30ff599f2..ec1d5579d 100644
--- a/api/src/glfs-internal.h
+++ b/api/src/glfs-internal.h
@@ -14,6 +14,46 @@
#include "xlator.h"
+#define GLFS_SYMLINK_MAX_FOLLOW 2048
+
+#define DEFAULT_REVAL_COUNT 1
+
+#define ESTALE_RETRY(ret,errno,reval,loc,label) do { \
+ if (ret == -1 && errno == ESTALE) { \
+ if (reval < DEFAULT_REVAL_COUNT) { \
+ reval++; \
+ loc_wipe (loc); \
+ goto label; \
+ } \
+ } \
+ } while (0)
+
+#define GLFS_LOC_FILL_INODE(oinode, loc, label) do { \
+ loc.inode = inode_ref (oinode); \
+ uuid_copy (loc.gfid, oinode->gfid); \
+ ret = glfs_loc_touchup (&loc); \
+ if (ret != 0) { \
+ errno = EINVAL; \
+ goto label; \
+ } \
+ } while (0)
+
+#define GLFS_LOC_FILL_PINODE(pinode, loc, ret, errno, label, path) do { \
+ loc.inode = inode_new (pinode->table); \
+ if (!loc.inode) { \
+ ret = -1; \
+ errno = ENOMEM; \
+ goto label; \
+ } \
+ loc.parent = inode_ref (pinode); \
+ loc.name = path; \
+ ret = glfs_loc_touchup (&loc); \
+ if (ret != 0) { \
+ errno = EINVAL; \
+ goto label; \
+ } \
+ } while (0)
+
struct glfs;
typedef int (*glfs_init_cbk) (struct glfs *fs, int ret);
@@ -55,6 +95,15 @@ struct glfs_fd {
fd_t *fd; /* Currently guared by @fs->mutex. TODO: per-glfd lock */
struct list_head entries;
gf_dirent_t *next;
+ struct dirent *readdirbuf;
+};
+
+/* glfs object handle introduced for the alternate gfapi implementation based
+ on glfs handles/gfid/inode
+*/
+struct glfs_object {
+ inode_t *inode;
+ uuid_t gfid;
};
#define DEFAULT_EVENT_POOL_SIZE 16384
@@ -133,6 +182,19 @@ inode_t * glfs_refresh_inode (xlator_t *subvol, inode_t *inode);
inode_t *glfs_cwd_get (struct glfs *fs);
int glfs_cwd_set (struct glfs *fs, inode_t *inode);
+inode_t *glfs_resolve_inode (struct glfs *fs, xlator_t *subvol,
+ struct glfs_object *object);
+int glfs_create_object (loc_t *loc, struct glfs_object **retobject);
int __glfs_cwd_set (struct glfs *fs, inode_t *inode);
+int glfs_resolve_base (struct glfs *fs, xlator_t *subvol, inode_t *inode,
+ struct iatt *iatt);
+int glfs_resolve_at (struct glfs *fs, xlator_t *subvol, inode_t *at,
+ const char *origpath, loc_t *loc, struct iatt *iatt,
+ int follow, int reval);
+int glfs_loc_touchup (loc_t *loc);
+void glfs_iatt_to_stat (struct glfs *fs, struct iatt *iatt, struct stat *stat);
+int glfs_loc_link (loc_t *loc, struct iatt *iatt);
+int glfs_loc_unlink (loc_t *loc);
+
#endif /* !_GLFS_INTERNAL_H */
diff --git a/api/src/glfs-master.c b/api/src/glfs-master.c
index 09a92b7f0..c02534c18 100644
--- a/api/src/glfs-master.c
+++ b/api/src/glfs-master.c
@@ -24,6 +24,7 @@
#include "glusterfs.h"
#include "glfs-internal.h"
+#include "glfs-mem-types.h"
int
@@ -114,6 +115,18 @@ notify (xlator_t *this, int event, void *data, ...)
int
mem_acct_init (xlator_t *this)
{
+ int ret = -1;
+
+ if (!this)
+ return ret;
+
+ ret = xlator_mem_acct_init (this, glfs_mt_end + 1);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to initialise "
+ "memory accounting");
+ return ret;
+ }
+
return 0;
}
diff --git a/api/src/glfs-mem-types.h b/api/src/glfs-mem-types.h
index 590acd03f..3301b3da5 100644
--- a/api/src/glfs-mem-types.h
+++ b/api/src/glfs-mem-types.h
@@ -16,14 +16,16 @@
#define GF_MEM_TYPE_START (gf_common_mt_end + 1)
enum glfs_mem_types_ {
- glfs_mt_glfs_t,
+ glfs_mt_glfs_t = GF_MEM_TYPE_START,
glfs_mt_call_pool_t,
glfs_mt_xlator_t,
glfs_mt_glfs_fd_t,
glfs_mt_glfs_io_t,
glfs_mt_volfile_t,
glfs_mt_xlator_cmdline_option_t,
- glfs_mt_end
+ glfs_mt_glfs_object_t,
+ glfs_mt_readdirbuf_t,
+ glfs_mt_end
};
#endif
diff --git a/api/src/glfs-mgmt.c b/api/src/glfs-mgmt.c
index 925029d5c..6843e9cb3 100644
--- a/api/src/glfs-mgmt.c
+++ b/api/src/glfs-mgmt.c
@@ -114,7 +114,7 @@ mgmt_cbk_event (struct rpc_clnt *rpc, void *mydata, void *data)
}
-rpcclnt_cb_actor_t gluster_cbk_actors[] = {
+rpcclnt_cb_actor_t mgmt_cbk_actors[] = {
[GF_CBK_FETCHSPEC] = {"FETCHSPEC", GF_CBK_FETCHSPEC, mgmt_cbk_spec },
[GF_CBK_EVENT_NOTIFY] = {"EVENTNOTIFY", GF_CBK_EVENT_NOTIFY,
mgmt_cbk_event},
@@ -125,7 +125,7 @@ struct rpcclnt_cb_program mgmt_cbk_prog = {
.progname = "GlusterFS Callback",
.prognum = GLUSTER_CBK_PROGRAM,
.progver = GLUSTER_CBK_VERSION,
- .actors = gluster_cbk_actors,
+ .actors = mgmt_cbk_actors,
.numactors = GF_CBK_MAXVALUE,
};
@@ -203,162 +203,6 @@ out:
static int
-xlator_equal_rec (xlator_t *xl1, xlator_t *xl2)
-{
- xlator_list_t *trav1 = NULL;
- xlator_list_t *trav2 = NULL;
- int ret = 0;
-
- if (xl1 == NULL || xl2 == NULL) {
- gf_log ("xlator", GF_LOG_DEBUG, "invalid argument");
- return -1;
- }
-
- trav1 = xl1->children;
- trav2 = xl2->children;
-
- while (trav1 && trav2) {
- ret = xlator_equal_rec (trav1->xlator, trav2->xlator);
- if (ret) {
- gf_log ("glfs-mgmt", GF_LOG_DEBUG,
- "xlators children not equal");
- goto out;
- }
-
- trav1 = trav1->next;
- trav2 = trav2->next;
- }
-
- if (trav1 || trav2) {
- ret = -1;
- goto out;
- }
-
- if (strcmp (xl1->name, xl2->name)) {
- ret = -1;
- goto out;
- }
-out :
- return ret;
-}
-
-
-static gf_boolean_t
-is_graph_topology_equal (glusterfs_graph_t *graph1,
- glusterfs_graph_t *graph2)
-{
- xlator_t *trav1 = NULL;
- xlator_t *trav2 = NULL;
- gf_boolean_t ret = _gf_true;
-
- trav1 = graph1->first;
- trav2 = graph2->first;
-
- ret = xlator_equal_rec (trav1, trav2);
-
- if (ret) {
- gf_log ("glfs-mgmt", GF_LOG_DEBUG,
- "graphs are not equal");
- ret = _gf_false;
- goto out;
- }
-
- ret = _gf_true;
- gf_log ("glfs-mgmt", GF_LOG_DEBUG,
- "graphs are equal");
-
-out:
- return ret;
-}
-
-
-/* Function has 3types of return value 0, -ve , 1
- * return 0 =======> reconfiguration of options has succeeded
- * return 1 =======> the graph has to be reconstructed and all the xlators should be inited
- * return -1(or -ve) =======> Some Internal Error occurred during the operation
- */
-static int
-glusterfs_volfile_reconfigure (struct glfs *fs, FILE *newvolfile_fp)
-{
- glusterfs_graph_t *oldvolfile_graph = NULL;
- glusterfs_graph_t *newvolfile_graph = NULL;
- FILE *oldvolfile_fp = NULL;
- glusterfs_ctx_t *ctx = NULL;
-
- int ret = -1;
-
- oldvolfile_fp = tmpfile ();
- if (!oldvolfile_fp)
- goto out;
-
- if (!fs->oldvollen) {
- ret = 1; // Has to call INIT for the whole graph
- goto out;
- }
- fwrite (fs->oldvolfile, fs->oldvollen, 1, oldvolfile_fp);
- fflush (oldvolfile_fp);
- if (ferror (oldvolfile_fp)) {
- goto out;
- }
-
- oldvolfile_graph = glusterfs_graph_construct (oldvolfile_fp);
- if (!oldvolfile_graph) {
- goto out;
- }
-
- newvolfile_graph = glusterfs_graph_construct (newvolfile_fp);
- if (!newvolfile_graph) {
- goto out;
- }
-
- if (!is_graph_topology_equal (oldvolfile_graph,
- newvolfile_graph)) {
-
- ret = 1;
- gf_log ("glfs-mgmt", GF_LOG_DEBUG,
- "Graph topology not equal(should call INIT)");
- goto out;
- }
-
- gf_log ("glfs-mgmt", GF_LOG_DEBUG,
- "Only options have changed in the new "
- "graph");
-
- ctx = fs->ctx;
-
- if (!ctx) {
- gf_log ("glfs-mgmt", GF_LOG_ERROR,
- "glusterfs_ctx_get() returned NULL");
- goto out;
- }
-
- oldvolfile_graph = ctx->active;
-
- if (!oldvolfile_graph) {
- gf_log ("glfs-mgmt", GF_LOG_ERROR,
- "glusterfs_ctx->active is NULL");
- goto out;
- }
-
- /* */
- ret = glusterfs_graph_reconfigure (oldvolfile_graph,
- newvolfile_graph);
- if (ret) {
- gf_log ("glfs-mgmt", GF_LOG_DEBUG,
- "Could not reconfigure new options in old graph");
- goto out;
- }
-
- ret = 0;
-out:
- if (oldvolfile_fp)
- fclose (oldvolfile_fp);
-
- return ret;
-}
-
-
-static int
glusterfs_oldvolfile_update (struct glfs *fs, char *volfile, ssize_t size)
{
int ret = -1;
@@ -451,7 +295,8 @@ mgmt_getspec_cbk (struct rpc_req *req, struct iovec *iov, int count,
* return -1(or -ve) =======> Some Internal Error occurred during the operation
*/
- ret = glusterfs_volfile_reconfigure (fs, tmpfp);
+ ret = glusterfs_volfile_reconfigure (fs->oldvollen, tmpfp, fs->ctx,
+ fs->oldvolfile);
if (ret == 0) {
gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
"No need to re-load volfile, reconfigure done");
diff --git a/api/src/glfs-resolve.c b/api/src/glfs-resolve.c
index ec8890b2d..4ca2eb6fc 100644
--- a/api/src/glfs-resolve.c
+++ b/api/src/glfs-resolve.c
@@ -67,6 +67,7 @@ __glfs_first_lookup (struct glfs *fs, xlator_t *subvol)
}
pthread_mutex_lock (&fs->mutex);
fs->migration_in_progress = 0;
+ pthread_cond_broadcast (&fs->cond);
return ret;
}
@@ -128,6 +129,7 @@ __glfs_refresh_inode (struct glfs *fs, xlator_t *subvol, inode_t *inode)
}
pthread_mutex_lock (&fs->mutex);
fs->migration_in_progress = 0;
+ pthread_cond_broadcast (&fs->cond);
return newinode;
}
@@ -191,7 +193,7 @@ out:
}
-void
+int
glfs_resolve_base (struct glfs *fs, xlator_t *subvol, inode_t *inode,
struct iatt *iatt)
{
@@ -210,6 +212,8 @@ glfs_resolve_base (struct glfs *fs, xlator_t *subvol, inode_t *inode,
ret = syncop_lookup (subvol, &loc, NULL, iatt, NULL, NULL);
out:
loc_wipe (&loc);
+
+ return ret;
}
@@ -337,7 +341,8 @@ glfs_resolve_at (struct glfs *fs, xlator_t *subvol, inode_t *at,
} else {
inode = inode_ref (subvol->itable->root);
- glfs_resolve_base (fs, subvol, inode, &ciatt);
+ if (strcmp (path, "/") == 0)
+ glfs_resolve_base (fs, subvol, inode, &ciatt);
}
for (component = strtok_r (path, "/", &saveptr);
@@ -356,7 +361,8 @@ glfs_resolve_at (struct glfs *fs, xlator_t *subvol, inode_t *at,
component, as the caller
wants proper iatt filled
*/
- (reval || !next_component));
+ (reval || (!next_component &&
+ iatt)));
if (!inode)
break;
@@ -368,6 +374,16 @@ glfs_resolve_at (struct glfs *fs, xlator_t *subvol, inode_t *at,
char *lpath = NULL;
loc_t sym_loc = {0,};
+ if (follow > GLFS_SYMLINK_MAX_FOLLOW) {
+ errno = ELOOP;
+ ret = -1;
+ if (inode) {
+ inode_unref (inode);
+ inode = NULL;
+ }
+ break;
+ }
+
ret = glfs_resolve_symlink (fs, subvol, inode, &lpath);
inode_unref (inode);
inode = NULL;
@@ -383,7 +399,7 @@ glfs_resolve_at (struct glfs *fs, xlator_t *subvol, inode_t *at,
/* always recurisvely follow while
following symlink
*/
- 1, reval);
+ follow + 1, reval);
if (ret == 0)
inode = inode_ref (sym_loc.inode);
loc_wipe (&sym_loc);
@@ -622,6 +638,7 @@ glfs_migrate_fd_safe (struct glfs *fs, xlator_t *newsubvol, fd_t *oldfd)
goto out;
}
+ newfd->flags = oldfd->flags;
fd_bind (newfd);
out:
if (newinode)
@@ -651,6 +668,7 @@ __glfs_migrate_fd (struct glfs *fs, xlator_t *newsubvol, struct glfs_fd *glfd)
}
pthread_mutex_lock (&fs->mutex);
fs->migration_in_progress = 0;
+ pthread_cond_broadcast (&fs->cond);
return newfd;
}
@@ -889,3 +907,63 @@ glfs_cwd_get (struct glfs *fs)
return cwd;
}
+
+inode_t *
+__glfs_resolve_inode (struct glfs *fs, xlator_t *subvol,
+ struct glfs_object *object)
+{
+ inode_t *inode = NULL;
+
+ if (object->inode->table->xl == subvol)
+ return inode_ref (object->inode);
+
+ inode = __glfs_refresh_inode (fs, fs->active_subvol,
+ object->inode);
+ if (!inode)
+ return NULL;
+
+ if (subvol == fs->active_subvol) {
+ inode_unref (object->inode);
+ object->inode = inode_ref (inode);
+ }
+
+ return inode;
+}
+
+inode_t *
+glfs_resolve_inode (struct glfs *fs, xlator_t *subvol,
+ struct glfs_object *object)
+{
+ inode_t *inode = NULL;
+
+ glfs_lock (fs);
+ {
+ inode = __glfs_resolve_inode(fs, subvol, object);
+ }
+ glfs_unlock (fs);
+
+ return inode;
+}
+
+int
+glfs_create_object (loc_t *loc, struct glfs_object **retobject)
+{
+ struct glfs_object *object = NULL;
+
+ object = GF_CALLOC (1, sizeof(struct glfs_object),
+ glfs_mt_glfs_object_t);
+ if (object == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ object->inode = loc->inode;
+ uuid_copy (object->gfid, object->inode->gfid);
+
+ /* we hold the reference */
+ loc->inode = NULL;
+
+ *retobject = object;
+
+ return 0;
+}
diff --git a/api/src/glfs.c b/api/src/glfs.c
index 2200358c6..29ed47c0c 100644
--- a/api/src/glfs.c
+++ b/api/src/glfs.c
@@ -20,7 +20,6 @@
- handle SEEK_END failure in _lseek()
- handle umask (per filesystem?)
- make itables LRU based
- - implement glfs_fini()
- 0-copy for readv/writev
- reconcile the open/creat mess
*/
@@ -51,6 +50,7 @@
#include "glfs.h"
#include "glfs-internal.h"
#include "hashfn.h"
+#include "rpc-clnt.h"
static gf_boolean_t
@@ -66,7 +66,7 @@ glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx)
call_pool_t *pool = NULL;
int ret = -1;
- xlator_mem_acct_init (THIS, glfs_mt_end);
+ xlator_mem_acct_init (THIS, glfs_mt_end + 1);
ctx->process_uuid = generate_glusterfs_ctx_id ();
if (!ctx->process_uuid) {
@@ -317,6 +317,20 @@ enomem:
return -1;
}
+int glfs_setfsuid (uid_t fsuid)
+{
+ return syncopctx_setfsuid (&fsuid);
+}
+
+int glfs_setfsgid (gid_t fsgid)
+{
+ return syncopctx_setfsgid (&fsgid);
+}
+
+int glfs_setfsgroups (size_t size, const gid_t *list)
+{
+ return syncopctx_setfsgroups(size, list);
+}
struct glfs *
glfs_from_glfd (struct glfs_fd *glfd)
@@ -370,6 +384,9 @@ glfs_fd_destroy (struct glfs_fd *glfd)
if (glfd->fd)
fd_unref (glfd->fd);
+
+ GF_FREE (glfd->readdirbuf);
+
GF_FREE (glfd);
}
@@ -475,17 +492,25 @@ int
glfs_set_logging (struct glfs *fs, const char *logfile, int loglevel)
{
int ret = 0;
+ char *tmplog = NULL;
- if (logfile) {
- /* passing ident as NULL means to use default ident for syslog */
- ret = gf_log_init (fs->ctx, logfile, NULL);
- if (ret)
- return ret;
- }
+ if (!logfile) {
+ ret = gf_set_log_file_path (&fs->ctx->cmd_args);
+ if (ret)
+ goto out;
+ tmplog = fs->ctx->cmd_args.log_file;
+ } else {
+ tmplog = (char *)logfile;
+ }
+
+ ret = gf_log_init (fs->ctx, tmplog, NULL);
+ if (ret)
+ goto out;
if (loglevel >= 0)
gf_log_set_loglevel (loglevel);
+out:
return ret;
}
@@ -551,7 +576,7 @@ glfs_init_common (struct glfs *fs)
if (ret)
return ret;
- ret = pthread_create (&fs->poller, NULL, glfs_poller, fs);
+ ret = gf_thread_create (&fs->poller, NULL, glfs_poller, fs);
if (ret)
return ret;
@@ -595,7 +620,54 @@ glfs_init (struct glfs *fs)
int
glfs_fini (struct glfs *fs)
{
- int ret = -1;
-
- return ret;
+ int ret = -1;
+ int countdown = 100;
+ xlator_t *subvol = NULL;
+ glusterfs_ctx_t *ctx = NULL;
+ call_pool_t *call_pool = NULL;
+
+ ctx = fs->ctx;
+
+ if (ctx->mgmt) {
+ rpc_clnt_disable (ctx->mgmt);
+ ctx->mgmt = NULL;
+ }
+
+ __glfs_entry_fs (fs);
+
+ call_pool = fs->ctx->pool;
+
+ while (countdown--) {
+ /* give some time for background frames to finish */
+ if (!call_pool->cnt)
+ break;
+ usleep (100000);
+ }
+ /* leaked frames may exist, we ignore */
+
+ /*We deem glfs_fini as successful if there are no pending frames in the call
+ *pool*/
+ ret = (call_pool->cnt == 0)? 0: -1;
+
+ subvol = glfs_active_subvol (fs);
+ if (subvol) {
+ /* PARENT_DOWN within glfs_subvol_done() is issued only
+ on graph switch (new graph should activiate and
+ decrement the extra @winds count taken in glfs_graph_setup()
+
+ Since we are explicitly destroying, PARENT_DOWN is necessary
+ */
+ xlator_notify (subvol, GF_EVENT_PARENT_DOWN, subvol, 0);
+ /* TBD: wait for CHILD_DOWN before exiting, in case of
+ asynchronous cleanup like graceful socket disconnection
+ in the future.
+ */
+ }
+
+ glfs_subvol_done (fs, subvol);
+
+ if (ctx->log.logfile)
+ fclose (ctx->log.logfile);
+
+ return ret;
}
diff --git a/api/src/glfs.h b/api/src/glfs.h
index 519a04036..18fda496e 100644
--- a/api/src/glfs.h
+++ b/api/src/glfs.h
@@ -176,7 +176,9 @@ int glfs_set_volfile_server (glfs_t *fs, const char *transport,
@fs: The 'virtual mount' object to be configured with the logging parameters.
@logfile: The logfile to be used for logging. Will be created if it does not
- already exist (provided system permissions allow.)
+ already exist (provided system permissions allow). If NULL, a new
+ logfile will be created in default log directory associated with
+ the glusterfs installation.
@loglevel: Numerical value specifying the degree of verbosity. Higher the
value, more verbose the logging.
@@ -218,6 +220,36 @@ int glfs_set_logging (glfs_t *fs, const char *logfile, int loglevel);
int glfs_init (glfs_t *fs);
+/*
+ SYNOPSIS
+
+ glfs_fini: Cleanup and destroy the 'virtual mount'
+
+ DESCRIPTION
+
+ This function attempts to gracefully destroy glfs_t object. An attempt is
+ made to wait for all background processing to complete before returning.
+
+ glfs_fini() must be called after all operations on glfs_t is finished.
+
+ IMPORTANT
+
+ IT IS NECESSARY TO CALL glfs_fini() ON ALL THE INITIALIZED glfs_t
+ OBJECTS BEFORE TERMINATING THE PROGRAM. THERE MAY BE CACHED AND
+ UNWRITTEN / INCOMPLETE OPERATIONS STILL IN PROGRESS EVEN THOUGH THE
+ API CALLS HAVE RETURNED. glfs_fini() WILL WAIT FOR BACKGROUND OPERATIONS
+ TO COMPLETE BEFORE RETURNING, THEREBY MAKING IT SAFE FOR THE PROGRAM TO
+ EXIT.
+
+ PARAMETERS
+
+ @fs: The 'virtual mount' object to be destroyed.
+
+ RETURN VALUES
+
+ 0 : Success.
+*/
+
int glfs_fini (glfs_t *fs);
/*
@@ -239,6 +271,32 @@ int glfs_fini (glfs_t *fs);
struct glfs_fd;
typedef struct glfs_fd glfs_fd_t;
+/*
+ * PER THREAD IDENTITY MODIFIERS
+ *
+ * The following operations enable to set a per thread identity context
+ * for the glfs APIs to perform operations as. The calls here are kept as close
+ * to POSIX equivalents as possible.
+ *
+ * NOTES:
+ *
+ * - setgroups is a per thread setting, hence this is named as fsgroups to be
+ * close in naming to the fs(u/g)id APIs
+ * - Typical mode of operation is to set the IDs as required, with the
+ * supplementary groups being optionally set, make the glfs call and post the
+ * glfs operation set them back to eu/gid or uid/gid as appropriate to the
+ * caller
+ * - The groups once set, need to be unset by setting the size to 0 (in which
+ * case the list argument is a do not care)
+ * - Once a process for a thread of operation choses to set the IDs, all glfs
+ * calls made from that thread would default to the IDs set for the thread.
+ * As a result use these APIs with care and ensure that the set IDs are
+ * reverted to global process defaults as required.
+ *
+ */
+int glfs_setfsuid (uid_t fsuid);
+int glfs_setfsgid (gid_t fsgid);
+int glfs_setfsgroups (size_t size, const gid_t *list);
/*
SYNOPSIS
@@ -410,12 +468,31 @@ int glfs_link (glfs_t *fs, const char *oldpath, const char *newpath);
glfs_fd_t *glfs_opendir (glfs_t *fs, const char *path);
+/*
+ * @glfs_readdir_r and @glfs_readdirplus_r ARE thread safe AND re-entrant,
+ * but the interface has ambiguity about the size of @dirent to be allocated
+ * before calling the APIs. 512 byte buffer (for @dirent) is sufficient for
+ * all known systems which are tested againt glusterfs/gfapi, but may be
+ * insufficient in the future.
+ */
+
int glfs_readdir_r (glfs_fd_t *fd, struct dirent *dirent,
struct dirent **result);
int glfs_readdirplus_r (glfs_fd_t *fd, struct stat *stat, struct dirent *dirent,
struct dirent **result);
+/*
+ * @glfs_readdir and @glfs_readdirplus are NEITHER thread safe NOR re-entrant
+ * when called on the same directory handle. However they ARE thread safe
+ * AND re-entrant when called on different directory handles (which may be
+ * referring to the same directory too.)
+ */
+
+struct dirent *glfs_readdir (glfs_fd_t *fd);
+
+struct dirent *glfs_readdirplus (glfs_fd_t *fd, struct stat *stat);
+
long glfs_telldir (glfs_fd_t *fd);
void glfs_seekdir (glfs_fd_t *fd, long offset);
@@ -475,9 +552,15 @@ int glfs_fallocate(glfs_fd_t *fd, int keep_size, off_t offset, size_t len);
int glfs_discard(glfs_fd_t *fd, off_t offset, size_t len);
+
int glfs_discard_async (glfs_fd_t *fd, off_t length, size_t lent,
glfs_io_cbk fn, void *data);
+int glfs_zerofill(glfs_fd_t *fd, off_t offset, size_t len);
+
+int glfs_zerofill_async (glfs_fd_t *fd, off_t length, size_t len,
+ glfs_io_cbk fn, void *data);
+
char *glfs_getcwd (glfs_t *fs, char *buf, size_t size);
int glfs_chdir (glfs_t *fs, const char *path);
diff --git a/cli/src/Makefile.am b/cli/src/Makefile.am
index ae5231026..216d1bb55 100644
--- a/cli/src/Makefile.am
+++ b/cli/src/Makefile.am
@@ -2,10 +2,7 @@ sbin_PROGRAMS = gluster
gluster_SOURCES = cli.c registry.c input.c cli-cmd.c cli-rl.c \
cli-cmd-volume.c cli-cmd-peer.c cli-rpc-ops.c cli-cmd-parser.c\
- cli-cmd-system.c cli-cmd-misc.c cli-xml-output.c
-if ENABLE_BD_XLATOR
-gluster_SOURCES += cli-cmd-volume-bdevice.c
-endif
+ cli-cmd-system.c cli-cmd-misc.c cli-xml-output.c cli-cmd-snapshot.c
gluster_LDADD = $(top_builddir)/libglusterfs/src/libglusterfs.la $(GF_LDADD)\
$(RLLIBS) $(top_builddir)/rpc/xdr/src/libgfxdr.la \
diff --git a/cli/src/cli-cmd-misc.c b/cli/src/cli-cmd-misc.c
index 5f3a77ca6..566d7c978 100644
--- a/cli/src/cli-cmd-misc.c
+++ b/cli/src/cli-cmd-misc.c
@@ -32,6 +32,7 @@ extern struct cli_cmd cli_probe_cmds[];
extern struct cli_cmd cli_log_cmds[];
extern struct cli_cmd cli_system_cmds[];
extern struct cli_cmd cli_bd_cmds[];
+extern struct cli_cmd snapshot_cmds[];
struct cli_cmd cli_misc_cmds[];
int
@@ -46,10 +47,7 @@ cli_cmd_display_help (struct cli_state *state, struct cli_cmd_word *in_word,
const char **words, int wordcount)
{
struct cli_cmd *cmd[] = {volume_cmds, cli_probe_cmds,
- cli_misc_cmds,
-#ifdef HAVE_BD_XLATOR
- cli_bd_cmds,
-#endif
+ cli_misc_cmds, snapshot_cmds,
NULL};
struct cli_cmd *cmd_ind = NULL;
int i = 0;
diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c
index 26ac6f384..5ab208b8f 100644
--- a/cli/src/cli-cmd-parser.c
+++ b/cli/src/cli-cmd-parser.c
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com>
+ Copyright (c) 2010-2013 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
@@ -26,6 +26,38 @@
#include "protocol-common.h"
#include "cli1-xdr.h"
+#define MAX_SNAP_DESCRIPTION_LEN 1024
+
+struct snap_config_opt_vals_ snap_confopt_vals[] = {
+ {.op_name = "snap-max-hard-limit",
+ .question = "Changing snapshot-max-hard-limit "
+ "will lead to deletion of snapshots "
+ "if they exceed the new limit.\n"
+ "Do you want to continue?"
+ },
+ {.op_name = "snap-max-soft-limit",
+ .question = "Changing snapshot-max-soft-limit "
+ "will lead to deletion of snapshots "
+ "if they exceed the new limit.\n"
+ "Do you want to continue?"
+ },
+ {.op_name = "both",
+ .question = "Changing snapshot-max-hard-limit & "
+ "snapshot-max-soft-limit will lead to "
+ "deletion of snapshots if they exceed "
+ "the new limit.\nDo you want to continue?"
+ },
+ {.op_name = NULL,
+ }
+};
+
+enum cli_snap_config_set_types {
+ GF_SNAP_CONFIG_SET_HARD = 0,
+ GF_SNAP_CONFIG_SET_SOFT = 1,
+ GF_SNAP_CONFIG_SET_BOTH = 2,
+};
+typedef enum cli_snap_config_set_types cli_snap_config_set_types;
+
static const char *
id_sel (void *wcon)
{
@@ -159,22 +191,17 @@ cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options
int32_t index = 0;
char *bricks = NULL;
int32_t brick_count = 0;
- char *opwords[] = { "replica", "stripe", "transport",
-#ifdef HAVE_BD_XLATOR
- "device",
-#endif
- NULL };
+ char *opwords[] = { "replica", "stripe", "transport", NULL };
char *invalid_volnames[] = {"volume", "type", "subvolumes", "option",
"end-volume", "all", "volume_not_in_ring",
- NULL};
+ "description", "force",
+ "snap-max-hard-limit",
+ "snap-max-soft-limit", NULL};
char *w = NULL;
int op_count = 0;
int32_t replica_count = 1;
int32_t stripe_count = 1;
-#ifdef HAVE_BD_XLATOR
- char *dev_type = NULL;
-#endif
gf_boolean_t is_force = _gf_false;
int wc = wordcount;
@@ -311,26 +338,7 @@ cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options
goto out;
}
index += 2;
- }
-#ifdef HAVE_BD_XLATOR
- else if ((strcmp (w, "device")) == 0) {
- if (dev_type) {
- cli_err ("'device' option given more"
- " than one time");
- goto out;
- }
- if ((strcasecmp (words[index+1], "vg") == 0)) {
- dev_type = gf_strdup ("vg");
- } else {
- gf_log ("", GF_LOG_ERROR, "incorrect"
- " device type specified");
- ret = -1;
- goto out;
- }
- index += 2;
- }
-#endif
- else {
+ } else {
GF_ASSERT (!"opword mismatch");
ret = -1;
goto out;
@@ -371,19 +379,6 @@ cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options
goto out;
}
- /* BD xlator does not support multiple bricks */
-#ifdef HAVE_BD_XLATOR
- if (brick_count > 1 && dev_type) {
- cli_err ("Block Device backend volume does not support multiple"
- " bricks");
- gf_log ("", GF_LOG_ERROR,
- "Block Device backend volume does not support multiple"
- " bricks");
- ret = -1;
- goto out;
- }
-#endif
-
if (brick_count % sub_count) {
if (type == GF_CLUSTER_TYPE_STRIPE)
cli_err ("number of bricks is not a multiple of "
@@ -417,14 +412,6 @@ cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options
if (ret)
goto out;
-#ifdef HAVE_BD_XLATOR
- if (dev_type) {
- ret = dict_set_dynstr (dict, "device", dev_type);
- if (ret)
- goto out;
- }
-#endif
-
ret = dict_set_int32 (dict, "count", brick_count);
if (ret)
goto out;
@@ -1763,7 +1750,7 @@ cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **options)
unsigned cmdi = 0;
char *opwords[] = { "create", "status", "start", "stop",
"config", "force", "delete",
- "push-pem", NULL };
+ "push-pem", "detail", NULL };
char *w = NULL;
GF_ASSERT (words);
@@ -1776,7 +1763,7 @@ cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **options)
/* new syntax:
*
* volume geo-replication $m $s create [push-pem] [force]
- * volume geo-replication [$m [$s]] status
+ * volume geo-replication [$m [$s]] status [detail]
* volume geo-replication [$m] $s config [[!]$opt [$val]]
* volume geo-replication $m $s start|stop [force]
* volume geo-replication $m $s delete
@@ -1810,6 +1797,13 @@ cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **options)
if (slavei == 3)
masteri = 2;
} else if (i <= 3) {
+ if (!strcmp ((char *)words[wordcount-1], "detail")) {
+ /* For status detail it is mandatory to provide
+ * both master and slave */
+ ret = -1;
+ goto out;
+ }
+
/* no $s, can only be status cmd
* (with either a single $m before it or nothing)
* -- these conditions imply that i <= 3 after
@@ -1873,6 +1867,21 @@ cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **options)
if (ret)
goto out;
+ if (!strcmp ((char *)words[wordcount-1], "detail")) {
+ if (strcmp ((char *)words[wordcount-2], "status")) {
+ ret = -1;
+ goto out;
+ }
+ if (!slavei || !masteri) {
+ ret = -1;
+ goto out;
+ }
+ ret = dict_set_uint32 (dict, "status-detail", _gf_true);
+ if (ret)
+ goto out;
+ cmdi++;
+ }
+
if (type != GF_GSYNC_OPTION_TYPE_CONFIG &&
(cmdi < wordcount - 1 || glob))
goto out;
@@ -2160,7 +2169,7 @@ cli_cmd_get_statusop (const char *arg)
uint32_t ret = GF_CLI_STATUS_NONE;
char *w = NULL;
char *opwords[] = {"detail", "mem", "clients", "fd",
- "inode", "callpool", NULL};
+ "inode", "callpool", "tasks", NULL};
struct {
char *opname;
uint32_t opcode;
@@ -2171,6 +2180,7 @@ cli_cmd_get_statusop (const char *arg)
{ "fd", GF_CLI_STATUS_FD },
{ "inode", GF_CLI_STATUS_INODE },
{ "callpool", GF_CLI_STATUS_CALLPOOL },
+ { "tasks", GF_CLI_STATUS_TASKS },
{ NULL }
};
@@ -2285,8 +2295,9 @@ cli_cmd_volume_status_parse (const char **words, int wordcount,
if (!strcmp (words[3], "nfs")) {
if (cmd == GF_CLI_STATUS_FD ||
- cmd == GF_CLI_STATUS_DETAIL) {
- cli_err ("Detail/FD status not available"
+ cmd == GF_CLI_STATUS_DETAIL ||
+ cmd == GF_CLI_STATUS_TASKS) {
+ cli_err ("Detail/FD/Tasks status not available"
" for NFS Servers");
ret = -1;
goto out;
@@ -2295,14 +2306,21 @@ cli_cmd_volume_status_parse (const char **words, int wordcount,
} else if (!strcmp (words[3], "shd")){
if (cmd == GF_CLI_STATUS_FD ||
cmd == GF_CLI_STATUS_CLIENTS ||
- cmd == GF_CLI_STATUS_DETAIL) {
- cli_err ("Detail/FD/Clients status not "
+ cmd == GF_CLI_STATUS_DETAIL ||
+ cmd == GF_CLI_STATUS_TASKS) {
+ cli_err ("Detail/FD/Clients/Tasks status not "
"available for Self-heal Daemons");
ret = -1;
goto out;
}
cmd |= GF_CLI_STATUS_SHD;
} else {
+ if (cmd == GF_CLI_STATUS_TASKS) {
+ cli_err ("Tasks status not available for "
+ "bricks");
+ ret = -1;
+ goto out;
+ }
cmd |= GF_CLI_STATUS_BRICK;
ret = dict_set_str (dict, "brick", (char *)words[3]);
}
@@ -2451,12 +2469,103 @@ out:
return ret;
}
+static int
+extract_hostname_path_from_token (const char *tmp_words, char **hostname,
+ char **path)
+{
+ int ret = 0;
+ char *delimiter = NULL;
+ char *tmp_host = NULL;
+ char *host_name = NULL;
+ char *words = NULL;
+
+ *hostname = NULL;
+ *path = NULL;
+
+ words = GF_CALLOC (1, strlen (tmp_words) + 1, gf_common_mt_char);
+ if (!words){
+ ret = -1;
+ goto out;
+ }
+
+ strncpy (words, tmp_words, strlen (tmp_words) + 1);
+
+ if (validate_brick_name (words)) {
+ cli_err ("Wrong brick type: %s, use <HOSTNAME>:"
+ "<export-dir-abs-path>", words);
+ ret = -1;
+ goto out;
+ } else {
+ delimiter = strrchr (words, ':');
+ ret = gf_canonicalize_path (delimiter + 1);
+ if (ret) {
+ goto out;
+ } else {
+ *path = GF_CALLOC (1, strlen (delimiter+1) +1,
+ gf_common_mt_char);
+ if (!*path) {
+ ret = -1;
+ goto out;
+
+ }
+ strncpy (*path, delimiter +1,
+ strlen(delimiter + 1) + 1);
+ }
+ }
+
+ tmp_host = gf_strdup (words);
+ if (!tmp_host) {
+ gf_log ("cli", GF_LOG_ERROR, "Out of memory");
+ ret = -1;
+ goto out;
+ }
+ get_host_name (tmp_host, &host_name);
+ if (!host_name) {
+ ret = -1;
+ gf_log("cli",GF_LOG_ERROR, "Unable to allocate "
+ "memory");
+ goto out;
+ }
+ if (!(strcmp (host_name, "localhost") &&
+ strcmp (host_name, "127.0.0.1") &&
+ strncmp (host_name, "0.", 2))) {
+ cli_err ("Please provide a valid hostname/ip other "
+ "than localhost, 127.0.0.1 or loopback "
+ "address (0.0.0.0 to 0.255.255.255).");
+ ret = -1;
+ goto out;
+ }
+ if (!valid_internet_address (host_name, _gf_false)) {
+ cli_err ("internet address '%s' does not conform to "
+ "standards", host_name);
+ ret = -1;
+ goto out;
+ }
+
+ *hostname = GF_CALLOC (1, strlen (host_name) + 1,
+ gf_common_mt_char);
+ if (!*hostname) {
+ ret = -1;
+ goto out;
+ }
+ strncpy (*hostname, host_name, strlen (host_name) + 1);
+ ret = 0;
+
+out:
+ GF_FREE (words);
+ GF_FREE (tmp_host);
+ return ret;
+}
+
+
int
cli_cmd_volume_heal_options_parse (const char **words, int wordcount,
dict_t **options)
{
int ret = 0;
dict_t *dict = NULL;
+ char *hostname = NULL;
+ char *path = NULL;
dict = dict_new ();
if (!dict)
@@ -2478,6 +2587,11 @@ cli_cmd_volume_heal_options_parse (const char **words, int wordcount,
ret = dict_set_int32 (dict, "heal-op",
GF_AFR_OP_HEAL_FULL);
goto done;
+ } else if (!strcmp (words[3], "statistics")) {
+ ret = dict_set_int32 (dict, "heal-op",
+ GF_AFR_OP_STATISTICS);
+ goto done;
+
} else if (!strcmp (words[3], "info")) {
ret = dict_set_int32 (dict, "heal-op",
GF_AFR_OP_INDEX_SUMMARY);
@@ -2488,28 +2602,66 @@ cli_cmd_volume_heal_options_parse (const char **words, int wordcount,
}
}
if (wordcount == 5) {
- if (strcmp (words[3], "info")) {
+ if (strcmp (words[3], "info") &&
+ strcmp (words[3], "statistics")) {
ret = -1;
goto out;
}
- if (!strcmp (words[4], "healed")) {
- ret = dict_set_int32 (dict, "heal-op",
- GF_AFR_OP_HEALED_FILES);
- goto done;
- }
- if (!strcmp (words[4], "heal-failed")) {
- ret = dict_set_int32 (dict, "heal-op",
- GF_AFR_OP_HEAL_FAILED_FILES);
- goto done;
+
+ if (!strcmp (words[3], "info")) {
+ if (!strcmp (words[4], "healed")) {
+ ret = dict_set_int32 (dict, "heal-op",
+ GF_AFR_OP_HEALED_FILES);
+ goto done;
+ }
+ if (!strcmp (words[4], "heal-failed")) {
+ ret = dict_set_int32 (dict, "heal-op",
+ GF_AFR_OP_HEAL_FAILED_FILES);
+ goto done;
+ }
+ if (!strcmp (words[4], "split-brain")) {
+ ret = dict_set_int32 (dict, "heal-op",
+ GF_AFR_OP_SPLIT_BRAIN_FILES);
+ goto done;
+ }
}
- if (!strcmp (words[4], "split-brain")) {
- ret = dict_set_int32 (dict, "heal-op",
- GF_AFR_OP_SPLIT_BRAIN_FILES);
- goto done;
+
+ if (!strcmp (words[3], "statistics")) {
+ if (!strcmp (words[4], "heal-count")) {
+ ret = dict_set_int32 (dict, "heal-op",
+ GF_AFR_OP_STATISTICS_HEAL_COUNT);
+ goto done;
+ }
}
ret = -1;
goto out;
}
+ if (wordcount == 7) {
+ if (!strcmp (words[3], "statistics")
+ && !strcmp (words[4], "heal-count")
+ && !strcmp (words[5], "replica")) {
+
+ ret = dict_set_int32 (dict, "heal-op",
+ GF_AFR_OP_STATISTICS_HEAL_COUNT_PER_REPLICA);
+ if (ret)
+ goto out;
+ ret = extract_hostname_path_from_token (words[6],
+ &hostname, &path);
+ if (ret)
+ goto out;
+ ret = dict_set_dynstr (dict, "per-replica-cmd-hostname",
+ hostname);
+ if (ret)
+ goto out;
+ ret = dict_set_dynstr (dict, "per-replica-cmd-path",
+ path);
+ if (ret)
+ goto out;
+ else
+ goto done;
+
+ }
+ }
ret = -1;
goto out;
done:
@@ -2614,3 +2766,917 @@ out:
return ret;
}
+
+int32_t
+cli_snap_create_desc_parse (dict_t *dict, const char **words,
+ size_t wordcount, int32_t desc_opt_loc)
+{
+ int32_t ret = -1;
+ char *desc = NULL;
+ int32_t desc_len = 0;
+
+ desc = GF_CALLOC (MAX_SNAP_DESCRIPTION_LEN + 1, sizeof(char),
+ gf_common_mt_char);
+ if (!desc) {
+ ret = -1;
+ goto out;
+ }
+
+
+ if (strlen (words[desc_opt_loc]) >= MAX_SNAP_DESCRIPTION_LEN) {
+ cli_out ("snapshot create: description truncated: "
+ "Description provided is longer than 1024 characters");
+ desc_len = MAX_SNAP_DESCRIPTION_LEN;
+ } else {
+ desc_len = strlen (words[desc_opt_loc]);
+ }
+
+ strncpy (desc, words[desc_opt_loc], desc_len);
+ desc[desc_len] = '\0';
+ /* Calculating the size of the description as given by the user */
+
+ ret = dict_set_dynstr (dict, "description", desc);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to save snap "
+ "description");
+ goto out;
+ }
+
+ ret = 0;
+out:
+ if (ret && desc)
+ GF_FREE (desc);
+
+ return ret;
+}
+
+/* Function to check whether the Volume name is repeated */
+int
+cli_check_if_volname_repeated (const char **words, unsigned int start_index,
+ uint64_t cur_index) {
+ uint64_t i = -1;
+ int ret = 0;
+
+ GF_ASSERT (words);
+
+ for (i = start_index ; i < cur_index ; i++) {
+ if (strcmp (words[i], words[cur_index]) == 0) {
+ ret = -1;
+ goto out;
+ }
+ }
+out :
+ return ret;
+}
+
+/* snapshot create <snapname> <vol-name(s)> [description <description>]
+ * [force]
+ * @arg-0, dict : Request Dictionary to be sent to server side.
+ * @arg-1, words : Contains individual words of CLI command.
+ * @arg-2, wordcount: Contains number of words present in the CLI command.
+ *
+ * return value : -1 on failure
+ * 0 on success
+ */
+int
+cli_snap_create_parse (dict_t *dict, const char **words, int wordcount) {
+ uint64_t i = 0;
+ int ret = -1;
+ uint64_t volcount = 0;
+ char key[PATH_MAX] = "";
+ char *snapname = NULL;
+ unsigned int cmdi = 2;
+ /* cmdi is command index, here cmdi is "2" (gluster snapshot create)*/
+
+ GF_ASSERT (words);
+ GF_ASSERT (dict);
+
+ if (wordcount <= cmdi + 1) {
+ cli_err ("Invalid Syntax.");
+ gf_log ("cli", GF_LOG_ERROR,
+ "Too less words for snap create command");
+ goto out;
+ }
+
+ if (strlen(words[cmdi]) >= GLUSTERD_MAX_SNAP_NAME) {
+ cli_err ("snapshot create: failed: snapname cannot exceed "
+ "255 characters.");
+ gf_log ("cli", GF_LOG_ERROR, "Snapname too long");
+
+ goto out;
+ }
+
+ snapname = (char *) words[cmdi];
+ for (i = 0 ; i < strlen (snapname); i++) {
+ /* Following volume name convention */
+ if (!isalnum (snapname[i]) && (snapname[i] != '_'
+ && (snapname[i] != '-'))) {
+ /* TODO : Is this message enough?? */
+ cli_err ("Snapname can contain only alphanumeric, "
+ "\"-\" and \"_\" characters");
+ goto out;
+ }
+ }
+
+ ret = dict_set_str (dict, "snapname", (char *)words[cmdi]);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not save snap "
+ "name");
+ goto out;
+ }
+
+ /* Filling volume name in the dictionary */
+ for (i = cmdi + 1 ; i < wordcount
+ && (strcmp (words[i], "description")) != 0
+ && (strcmp (words[i], "force") != 0); i++) {
+ volcount++;
+ /* volume index starts from 1 */
+ ret = snprintf (key, sizeof (key),"volname%ld", volcount);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_set_str (dict, key, (char *)words[i]);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not "
+ "save volume name");
+ goto out;
+ }
+
+ if (i >= cmdi + 2) {
+ ret = -1;
+ cli_err("Creating multiple volume snapshot is not "
+ "supported as of now");
+ goto out;
+ }
+ /* TODO : remove this above condition check once
+ * multiple volume snapshot is supported */
+ }
+
+ if (volcount == 0) {
+ ret = -1;
+ cli_err ("Please provide the volume name");
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+
+ ret = dict_set_int32 (dict, "volcount", volcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not save volcount");
+ goto out;
+ }
+
+ /* Verify how we got out of "for" loop,
+ * if it is by reaching wordcount limit then goto "out",
+ * because we need not parse for "description" and "force"
+ * after this.
+ */
+ if (i == wordcount) {
+ goto out;
+ }
+
+ if ((strcmp (words[i], "description")) == 0) {
+ ++i;
+ if (i > (wordcount - 1)) {
+ ret = -1;
+ cli_err ("Please provide a description");
+ gf_log ("cli", GF_LOG_ERROR,
+ "Description not provided");
+ goto out;
+ }
+
+ ret = cli_snap_create_desc_parse(dict, words, wordcount, i);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not save snap "
+ "description");
+ goto out;
+ }
+
+ if ( i == (wordcount - 1))
+ goto out;
+ i++;
+ /* point the index to next word.
+ * As description might be follwed by force option.
+ * Before that, check if wordcount limit is reached
+ */
+ }
+
+ if ((strcmp (words[i], "force") != 0)) {
+ ret = -1;
+ cli_err ("Invalid Syntax.");
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+ ret = dict_set_int8 (dict, "snap-force", 1);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not save "
+ "snap force option");
+ goto out;
+ }
+
+ /* Check if the command has anything after "force" keyword */
+ if (++i < wordcount) {
+ ret = -1;
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+
+ ret = 0;
+
+out :
+ return ret;
+}
+
+/* snapshot list [volname]
+ * @arg-0, dict : Request Dictionary to be sent to server side.
+ * @arg-1, words : Contains individual words of CLI command.
+ * @arg-2, wordcount: Contains number of words present in the CLI command.
+ *
+ * return value : -1 on failure
+ * 0 on success
+ */
+int
+cli_snap_list_parse (dict_t *dict, const char **words, int wordcount) {
+ int ret = -1;
+
+ GF_ASSERT (words);
+ GF_ASSERT (dict);
+
+ if (wordcount < 2 || wordcount > 3) {
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+
+ if (wordcount == 2) {
+ ret = 0;
+ goto out;
+ }
+
+ ret = dict_set_str (dict, "volname", (char *)words[2]);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Failed to save volname in dictionary");
+ goto out;
+ }
+out :
+ return ret;
+}
+
+/* snapshot info [(snapname | volume <volname>)]
+ * @arg-0, dict : Request Dictionary to be sent to server side.
+ * @arg-1, words : Contains individual words of CLI command.
+ * @arg-2, wordcount: Contains number of words present in the CLI command.
+ *
+ * return value : -1 on failure
+ * 0 on success
+ */
+int
+cli_snap_info_parse (dict_t *dict, const char **words, int wordcount)
+{
+
+ int ret = -1;
+ int32_t cmd = GF_SNAP_INFO_TYPE_ALL;
+ unsigned int cmdi = 2;
+ /* cmdi is command index, here cmdi is "2" (gluster snapshot info)*/
+
+ GF_ASSERT (words);
+ GF_ASSERT (dict);
+
+ if (wordcount > 4 || wordcount < cmdi) {
+ gf_log ("", GF_LOG_ERROR, "Invalid syntax");
+ goto out;
+ }
+
+ if (wordcount == cmdi) {
+ ret = 0;
+ goto out;
+ }
+
+ /* If 3rd word is not "volume", then it must
+ * be snapname.
+ */
+ if (strcmp (words[cmdi], "volume") != 0) {
+ ret = dict_set_str (dict, "snapname",
+ (char *)words[cmdi]);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to save "
+ "snapname %s", words[cmdi]);
+ goto out;
+ }
+
+ /* Once snap name is parsed, if we encounter any other
+ * word then fail it. Invalid Syntax.
+ * example : snapshot info <snapname> word
+ */
+ if ((cmdi + 1) != wordcount) {
+ ret = -1;
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+
+ cmd = GF_SNAP_INFO_TYPE_SNAP;
+ ret = 0;
+ goto out;
+ /* No need to continue the parsing once we
+ * get the snapname
+ */
+ }
+
+ /* If 3rd word is "volume", then check if next word
+ * is present. As, "snapshot info volume" is an
+ * invalid command.
+ */
+ if ((cmdi + 1) == wordcount) {
+ ret = -1;
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+
+ ret = dict_set_str (dict, "volname", (char *)words[wordcount - 1]);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Count not save "
+ "volume name %s", words[wordcount - 1]);
+ goto out;
+ }
+ cmd = GF_SNAP_INFO_TYPE_VOL;
+out :
+ if (ret == 0) {
+ ret = dict_set_int32 (dict, "cmd", cmd);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not save "
+ "type of snapshot info");
+ }
+ }
+ return ret;
+}
+
+
+
+/* snapshot restore <snapname>
+ * @arg-0, dict : Request Dictionary to be sent to server side.
+ * @arg-1, words : Contains individual words of CLI command.
+ * @arg-2, wordcount: Contains number of words present in the CLI command.
+ *
+ * return value : -1 on failure
+ * 0 on success
+ */
+int
+cli_snap_restore_parse (dict_t *dict, const char **words, int wordcount)
+{
+
+ int ret = -1;
+
+ GF_ASSERT (words);
+ GF_ASSERT (dict);
+
+ if (wordcount != 3) {
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+
+ ret = dict_set_str (dict, "snapname", (char *)words[2]);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to save snap-name %s",
+ words[2]);
+ goto out;
+ }
+out :
+ return ret;
+}
+
+/* snapshot delete <snapname>
+ * @arg-0, dict : Request Dictionary to be sent to server side.
+ * @arg-1, words : Contains individual words of CLI command.
+ * @arg-2, wordcount: Contains number of words present in the CLI command.
+ *
+ * return value : -1 on failure
+ * 0 on success
+ * 1 if user cancel the operation
+ */
+int
+cli_snap_delete_parse (dict_t *dict, const char **words, int wordcount,
+ struct cli_state *state) {
+
+ int ret = -1;
+ const char *question = NULL;
+ gf_answer_t answer = GF_ANSWER_NO;
+
+ question = "Deleting snap will erase all the information about "
+ "the snap. Do you still want to continue?";
+
+ GF_ASSERT (words);
+ GF_ASSERT (dict);
+
+ if (wordcount != 3) {
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+
+ ret = dict_set_str (dict, "snapname", (char *)words[2]);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to save snapname %s",
+ words[2]);
+ goto out;
+ }
+
+ answer = cli_cmd_get_confirmation (state, question);
+ if (GF_ANSWER_NO == answer) {
+ ret = 1;
+ gf_log ("cli", GF_LOG_DEBUG, "User cancelled "
+ "snapshot delete operation");
+ goto out;
+ }
+out :
+ return ret;
+}
+
+/* snapshot status [(snapname | volume <volname>)]
+ * @arg-0, dict : Request Dictionary to be sent to server side.
+ * @arg-1, words : Contains individual words of CLI command.
+ * @arg-2, wordcount: Contains number of words present in the CLI command.
+ *
+ * return value : -1 on failure
+ * 0 on success
+ */
+int
+cli_snap_status_parse (dict_t *dict, const char **words, int wordcount)
+{
+
+ int ret = -1;
+ int32_t cmd = GF_SNAP_STATUS_TYPE_ALL;
+ unsigned int cmdi = 2;
+ /* cmdi is command index, here cmdi is "2" (gluster snapshot status)*/
+
+ GF_ASSERT (words);
+ GF_ASSERT (dict);
+
+ if (wordcount > 4 || wordcount < cmdi) {
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+
+ if (wordcount == cmdi) {
+ ret = 0;
+ goto out;
+ }
+
+ /* if 3rd word is not "volume", then it must be "snapname"
+ */
+ if (strcmp (words[cmdi], "volume") != 0) {
+ ret = dict_set_str (dict, "snapname",
+ (char *)words[cmdi]);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Count not save "
+ "snap name %s", words[cmdi]);
+ goto out;
+ }
+
+ if ((cmdi + 1) != wordcount) {
+ ret = -1;
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+
+ ret = 0;
+ cmd = GF_SNAP_STATUS_TYPE_SNAP;
+ goto out;
+ }
+
+ /* If 3rd word is "volume", then check if next word is present.
+ * As, "snapshot info volume" is an invalid command
+ */
+ if ((cmdi + 1) == wordcount) {
+ ret = -1;
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+
+ ret = dict_set_str (dict, "volname", (char *)words [wordcount - 1]);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Count not save "
+ "volume name %s", words[wordcount - 1]);
+ goto out;
+ }
+ cmd = GF_SNAP_STATUS_TYPE_VOL;
+
+out :
+ if (ret == 0) {
+ ret = dict_set_int32 (dict, "cmd", cmd);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not save cmd "
+ "of snapshot status");
+ }
+ }
+ return ret;
+}
+
+
+int32_t
+cli_snap_config_limit_parse (const char **words, dict_t *dict,
+ unsigned int wordcount, unsigned int index,
+ char *key)
+{
+ int ret = -1;
+ int limit = 0;
+
+ GF_ASSERT (words);
+ GF_ASSERT (dict);
+ GF_ASSERT (key);
+
+ if (index >= wordcount) {
+ ret = -1;
+ cli_err ("Please provide a value for %s.",key);
+ gf_log ("cli", GF_LOG_ERROR, "Value not provided for %s", key);
+ goto out;
+ }
+
+ limit = strtol (words[index], NULL, 0);
+ if (limit <= 0) {
+ ret = -1;
+ cli_err ("%s should be greater than 0.", key);
+ goto out;
+ }
+
+ ret = dict_set_int32 (dict, key, limit);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not set "
+ "%s in dictionary", key);
+ goto out;
+ }
+
+out :
+ return ret;
+}
+
+/* function cli_snap_config_parse
+ * Config Syntax : gluster snapshot config [volname]
+ * [snap-max-hard-limit <count>]
+ * [snap-max-soft-limit <count>]
+ *
+ return value: <0 on failure
+ 1 if user cancels the operation
+ 0 on success
+
+ NOTE : snap-max-soft-limit can only be set for system.
+*/
+int32_t
+cli_snap_config_parse (const char **words, int wordcount, dict_t *dict,
+ struct cli_state *state)
+{
+ int ret = -1;
+ gf_answer_t answer = GF_ANSWER_NO;
+ gf_boolean_t vol_presence = _gf_false;
+ struct snap_config_opt_vals_ *conf_vals = NULL;
+ int8_t hard_limit = 0;
+ int8_t soft_limit = 0;
+ int8_t config_type = -1;
+ const char *question = NULL;
+ unsigned int cmdi = 2;
+ /* cmdi is command index, here cmdi is "2" (gluster snapshot config)*/
+
+ GF_ASSERT (words);
+ GF_ASSERT (dict);
+ GF_ASSERT (state);
+
+ if ((wordcount < 2) || (wordcount > 7)) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Invalid wordcount(%d)", wordcount);
+ goto out;
+ }
+
+ if (wordcount == 2) {
+ config_type = GF_SNAP_CONFIG_DISPLAY;
+ ret = 0;
+ goto set;
+ }
+
+ /* Check whether the 3rd word is volname */
+ if (strcmp (words[cmdi], "snap-max-hard-limit") != 0
+ && strcmp (words[cmdi], "snap-max-soft-limit") != 0) {
+ ret = dict_set_str (dict, "volname", (char *)words[cmdi]);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to set volname");
+ goto out;
+ }
+ cmdi++;
+ vol_presence = _gf_true;
+
+ if (cmdi == wordcount) {
+ config_type = GF_SNAP_CONFIG_DISPLAY;
+ ret = 0;
+ goto set;
+ }
+ }
+
+ config_type = GF_SNAP_CONFIG_TYPE_SET;
+
+ if (strcmp (words[cmdi], "snap-max-hard-limit") == 0) {
+ ret = cli_snap_config_limit_parse (words, dict, wordcount,
+ ++cmdi, "snap-max-hard-limit");
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to parse snap "
+ "config hard limit");
+ goto out;
+ }
+ hard_limit = 1;
+
+ if (++cmdi == wordcount) {
+ ret = 0;
+ goto set;
+ }
+ }
+
+ if (strcmp (words[cmdi], "snap-max-soft-limit") == 0) {
+ if (vol_presence == 1) {
+ ret = -1;
+ cli_err ("Soft limit cannot be set to individual "
+ "volumes.");
+ gf_log ("cli", GF_LOG_ERROR, "Soft limit cannot be "
+ "set to volumes");
+ goto out;
+ }
+
+ ret = cli_snap_config_limit_parse (words, dict, wordcount,
+ ++cmdi, "snap-max-soft-limit");
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to parse snap "
+ "config soft limit");
+ goto out;
+ }
+
+ if (++cmdi != wordcount) {
+ ret = -1;
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+ soft_limit = 1;
+ } else {
+ ret = -1;
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+ ret = 0; /* Success */
+
+set:
+ ret = dict_set_int32 (dict, "config-command", config_type);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to set "
+ "config-command");
+ goto out;
+ }
+
+ if (config_type == GF_SNAP_CONFIG_TYPE_SET) {
+ conf_vals = snap_confopt_vals;
+ if (hard_limit && soft_limit) {
+ question = conf_vals[GF_SNAP_CONFIG_SET_BOTH].question;
+ } else if (soft_limit) {
+ question = conf_vals[GF_SNAP_CONFIG_SET_SOFT].question;
+ } else if (hard_limit) {
+ question = conf_vals[GF_SNAP_CONFIG_SET_HARD].question;
+ }
+
+ answer = cli_cmd_get_confirmation (state, question);
+ if (GF_ANSWER_NO == answer) {
+ ret = 1;
+ gf_log ("cli", GF_LOG_DEBUG, "User cancelled "
+ "snapshot config operation");
+ }
+ }
+
+out:
+ return ret;
+}
+
+int
+validate_snapname (const char *snapname, char **opwords) {
+ int ret = -1;
+ int i = 0;
+
+ GF_ASSERT (snapname);
+ GF_ASSERT (opwords);
+
+ for (i = 0 ; opwords[i] != NULL; i++) {
+ if (strcmp (opwords[i], snapname) == 0) {
+ cli_out ("\"%s\" cannot be a snapname", snapname);
+ goto out;
+ }
+ }
+ ret = 0;
+out :
+ return ret;
+}
+
+int32_t
+cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options,
+ struct cli_state *state)
+{
+ int32_t ret = -1;
+ dict_t *dict = NULL;
+ gf1_cli_snapshot type = GF_SNAP_OPTION_TYPE_NONE;
+ char *w = NULL;
+ char *opwords[] = {"create", "delete", "restore", "start",
+ "stop", "list", "status", "config",
+ "info", NULL};
+ char *invalid_snapnames[] = {"description", "force",
+ "volume", NULL};
+
+ GF_ASSERT (words);
+ GF_ASSERT (options);
+ GF_ASSERT (state);
+
+ dict = dict_new ();
+ if (!dict)
+ goto out;
+
+ /* Lowest wordcount possible */
+ if (wordcount < 2) {
+ gf_log ("", GF_LOG_ERROR,
+ "Invalid command: Not enough arguments");
+ goto out;
+ }
+
+ w = str_getunamb (words[1], opwords);
+ if (!w) {
+ /* Checks if the operation is a valid operation */
+ gf_log ("", GF_LOG_ERROR, "Opword Mismatch");
+ goto out;
+ }
+
+ if (!strcmp (w, "create")) {
+ type = GF_SNAP_OPTION_TYPE_CREATE;
+ } else if (!strcmp (w, "list")) {
+ type = GF_SNAP_OPTION_TYPE_LIST;
+ } else if (!strcmp (w, "info")) {
+ type = GF_SNAP_OPTION_TYPE_INFO;
+ } else if (!strcmp (w, "delete")) {
+ type = GF_SNAP_OPTION_TYPE_DELETE;
+ } else if (!strcmp (w, "config")) {
+ type = GF_SNAP_OPTION_TYPE_CONFIG;
+ } else if (!strcmp (w, "restore")) {
+ type = GF_SNAP_OPTION_TYPE_RESTORE;
+ } else if (!strcmp (w, "status")) {
+ type = GF_SNAP_OPTION_TYPE_STATUS;
+ }
+
+ if (type != GF_SNAP_OPTION_TYPE_CONFIG) {
+ ret = dict_set_int32 (dict, "hold_snap_locks", _gf_true);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Unable to set hold-snap-locks value "
+ "as _gf_true");
+ goto out;
+ }
+ }
+
+ /* Check which op is intended */
+ switch (type) {
+ case GF_SNAP_OPTION_TYPE_CREATE:
+ {
+ /* Syntax :
+ * gluster snapshot create <snapname> <vol-name(s)>
+ * [description <description>]
+ * [force]
+ */
+
+ /* In cases where the snapname is not given then
+ * parsing fails & snapname cannot be "description",
+ * "force" and "volume", that check is made here
+ */
+ if (wordcount == 2){
+ ret = -1;
+ gf_log ("cli", GF_LOG_ERROR,
+ "Invalid Syntax");
+ goto out;
+ }
+
+ ret = validate_snapname (words[2], invalid_snapnames);
+ if (ret) {
+ goto out;
+ }
+
+ ret = cli_snap_create_parse (dict, words, wordcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "create command parsing failed.");
+ goto out;
+ }
+ break;
+ }
+ case GF_SNAP_OPTION_TYPE_INFO:
+ {
+ /* Syntax :
+ * gluster snapshot info [(snapname] | [vol <volname>)]
+ */
+ ret = cli_snap_info_parse (dict, words, wordcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to parse "
+ "snapshot info command");
+ goto out;
+ }
+ break;
+ }
+
+ case GF_SNAP_OPTION_TYPE_LIST:
+ {
+ /* Syntax :
+ * gluster snaphsot list [volname]
+ */
+
+ ret = cli_snap_list_parse (dict, words, wordcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to parse "
+ "snapshot list command");
+ goto out;
+ }
+ break;
+ }
+
+ case GF_SNAP_OPTION_TYPE_DELETE:
+ {
+ /* Syntax :
+ * gluster snapshot delete <snapname>
+ */
+ ret = cli_snap_delete_parse (dict, words, wordcount,
+ state);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to parse "
+ "snapshot delete command");
+ goto out;
+ }
+ break;
+ }
+
+ case GF_SNAP_OPTION_TYPE_CONFIG:
+ {
+ /* snapshot config [volname] [snap-max-hard-limit <count>]
+ * [snap-max-soft-limit <percent>] */
+ ret = cli_snap_config_parse (words, wordcount, dict,
+ state);
+ if (ret) {
+ if (ret < 0)
+ gf_log ("cli", GF_LOG_ERROR,
+ "config command parsing failed.");
+ goto out;
+ }
+
+ ret = dict_set_int32 (dict, "type",
+ GF_SNAP_OPTION_TYPE_CONFIG);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to set "
+ "config type");
+ ret = -1;
+ goto out;
+ }
+ break;
+ }
+ case GF_SNAP_OPTION_TYPE_STATUS:
+ {
+ /* Syntax :
+ * gluster snapshot status [(snapname |
+ * volume <volname>)]
+ */
+ ret = cli_snap_status_parse (dict, words, wordcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to parse "
+ "snapshot status command");
+ goto out;
+ }
+ break;
+ }
+
+ case GF_SNAP_OPTION_TYPE_RESTORE:
+ {
+ /* Syntax:
+ * snapshot restore <snapname>
+ */
+ ret = cli_snap_restore_parse (dict, words, wordcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to parse "
+ "restore command");
+ goto out;
+ }
+ break;
+ }
+ default:
+ gf_log ("", GF_LOG_ERROR, "Opword Mismatch");
+ goto out;
+ break;
+ }
+
+ ret = dict_set_int32 (dict, "type", type);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR,
+ "Failed to set type.");
+ goto out;
+ }
+ /* If you got so far, input is valid */
+ ret = 0;
+out:
+ if (ret) {
+ if (dict)
+ dict_destroy (dict);
+ } else
+ *options = dict;
+
+ return ret;
+}
diff --git a/cli/src/cli-cmd-snapshot.c b/cli/src/cli-cmd-snapshot.c
new file mode 100644
index 000000000..de492d683
--- /dev/null
+++ b/cli/src/cli-cmd-snapshot.c
@@ -0,0 +1,146 @@
+/*
+ Copyright (c) 2013-2014 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <pthread.h>
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "cli.h"
+#include "cli-cmd.h"
+
+extern rpc_clnt_prog_t *cli_rpc_prog;
+
+int
+cli_cmd_snapshot_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word,
+ const char **words, int wordcount);
+
+int
+cli_cmd_snapshot_cbk (struct cli_state *state, struct cli_cmd_word *word,
+ const char **words, int wordcount)
+{
+ int ret = 0;
+ int parse_err = 0;
+ dict_t *options = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ call_frame_t *frame = NULL;
+ cli_local_t *local = NULL;
+
+ proc = &cli_rpc_prog->proctable [GLUSTER_CLI_SNAP];
+ if (proc == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ frame = create_frame (THIS, THIS->ctx->pool);
+ if (frame == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ /* Parses the command entered by the user */
+ ret = cli_cmd_snapshot_parse (words, wordcount, &options, state);
+ if (ret) {
+ if (ret < 0) {
+ cli_usage_out (word->pattern);
+ parse_err = 1;
+ }
+ else {
+ /* User might have cancelled the snapshot operation */
+ ret = 0;
+ }
+ goto out;
+ }
+
+ CLI_LOCAL_INIT (local, words, frame, options);
+
+ if (proc->fn)
+ ret = proc->fn (frame, THIS, options);
+
+out:
+ if (ret && parse_err == 0)
+ cli_out ("Snapshot command failed");
+
+ CLI_STACK_DESTROY (frame);
+
+ return ret;
+}
+
+struct cli_cmd snapshot_cmds[] = {
+ { "snapshot help",
+ cli_cmd_snapshot_help_cbk,
+ "display help for snapshot commands"
+ },
+ { "snapshot create <snapname> <volname(s)> [description <description>] [force]",
+ cli_cmd_snapshot_cbk,
+ "Snapshot Create."
+ },
+ { "snapshot restore <snapname>",
+ cli_cmd_snapshot_cbk,
+ "Snapshot Restore."
+ },
+ { "snapshot status [(snapname | volume <volname>)]",
+ cli_cmd_snapshot_cbk,
+ "Snapshot Status."
+ },
+ { "snapshot info [(snapname | volume <volname>)]",
+ cli_cmd_snapshot_cbk,
+ "Snapshot Info."
+ },
+ { "snapshot list [volname]",
+ cli_cmd_snapshot_cbk,
+ "Snapshot List."
+ },
+ {"snapshot config [volname] [snap-max-hard-limit <count>] [snap-max-soft-limit <percent>]",
+ cli_cmd_snapshot_cbk,
+ "Snapshot Config."
+ },
+ {"snapshot delete <snapname>",
+ cli_cmd_snapshot_cbk,
+ "Snapshot Delete."
+ },
+ { NULL, NULL, NULL }
+};
+
+int
+cli_cmd_snapshot_help_cbk (struct cli_state *state,
+ struct cli_cmd_word *in_word,
+ const char **words,
+ int wordcount)
+{
+ struct cli_cmd *cmd = NULL;
+
+ for (cmd = snapshot_cmds; cmd->pattern; cmd++)
+ if (_gf_false == cmd->disable)
+ cli_out ("%s - %s", cmd->pattern, cmd->desc);
+
+ return 0;
+}
+
+int
+cli_cmd_snapshot_register (struct cli_state *state)
+{
+ int ret = 0;
+ struct cli_cmd *cmd = NULL;
+
+ for (cmd = snapshot_cmds; cmd->pattern; cmd++) {
+
+ ret = cli_cmd_register (&state->tree, cmd);
+ if (ret)
+ goto out;
+ }
+out:
+ return ret;
+}
diff --git a/cli/src/cli-cmd-volume-bdevice.c b/cli/src/cli-cmd-volume-bdevice.c
deleted file mode 100644
index 19325754f..000000000
--- a/cli/src/cli-cmd-volume-bdevice.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- CLI for BD translator
-
- Copyright IBM, Corp. 2012
-
- This file is part of GlusterFS.
-
- Author:
- M. Mohan Kumar <mohan@in.ibm.com>
-
- This file is licensed to you under your choice of the GNU Lesser
- General Public License, version 3 or any later version (LGPLv3 or
- later), or the GNU General Public License, version 2 (GPLv2), in all
- cases as published by the Free Software Foundation.
-*/
-
-#ifndef _CONFIG_H
-#define _CONFIG_H
-#include "config.h"
-#endif
-
-#include "cli.h"
-#include "cli-cmd.h"
-#include <string.h>
-
-extern rpc_clnt_prog_t *cli_rpc_prog;
-
-int
-cli_cmd_bd_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word,
- const char **words, int wordcount);
-
-int32_t
-cli_cmd_bd_parse (dict_t *dict, const char **words)
-{
- char *volname = NULL;
- char *buff = NULL;
- char *buffp = NULL;
- int ret = -1;
- char *save = NULL;
- char *path = NULL;
- char *size = NULL;
- char *eptr = NULL;
- gf_xl_bd_op_t bd_op = GF_BD_OP_INVALID;
- char *dest_lv = NULL;
-
-
- /* volname:/path */
- if (!strchr (words[2], ':') || !strchr (words[2], '/')) {
- cli_out ("invalid parameter %s, needs <volname:/path>",
- words[2]);
- return -1;
- }
- buff = buffp = gf_strdup (words[2]);
- volname = strtok_r (buff, ":", &save);
- path = strtok_r (NULL, ":", &save);
-
- ret = dict_set_dynstr (dict, "volname", gf_strdup (volname));
- if (ret)
- goto out;
-
- ret = dict_set_dynstr (dict, "path", gf_strdup (path));
- if (ret)
- goto out;
-
- if (!strcasecmp (words[1], "create"))
- bd_op = GF_BD_OP_NEW_BD;
- else if (!strcasecmp (words[1], "delete"))
- bd_op = GF_BD_OP_DELETE_BD;
- else if (!strcasecmp (words[1], "clone"))
- bd_op = GF_BD_OP_CLONE_BD;
- else if (!strcasecmp (words[1], "snapshot"))
- bd_op = GF_BD_OP_SNAPSHOT_BD;
- else
- return -1;
-
- ret = dict_set_int32 (dict, "bd-op", bd_op);
- if (ret)
- goto out;
-
- if (bd_op == GF_BD_OP_NEW_BD) {
- /* If no suffix given we will treat it as MB */
- strtoull (words[3], &eptr, 0);
- /* no suffix */
- if (!eptr[0])
- gf_asprintf (&size, "%sMB", words[3]);
- else
- size = gf_strdup (words[3]);
-
- ret = dict_set_dynstr (dict, "size", size);
- if (ret)
- goto out;
- } else if (bd_op == GF_BD_OP_SNAPSHOT_BD ||
- bd_op == GF_BD_OP_CLONE_BD) {
- /*
- * dest_lv should be just dest_lv, we don't support
- * cloning/snapshotting to a different volume or vg
- */
- if (strchr (words[3], ':') || strchr (words[3], '/')) {
- cli_err ("invalid parameter %s, volname/vg not needed",
- words[3]);
- ret = -1;
- goto out;
- }
- dest_lv = gf_strdup (words[3]);
- ret = dict_set_dynstr (dict, "dest_lv", dest_lv);
- if (ret)
- goto out;
-
- /* clone needs size as parameter */
- if (bd_op == GF_BD_OP_SNAPSHOT_BD) {
- ret = dict_set_dynstr (dict, "size",
- gf_strdup (words[4]));
- if (ret)
- goto out;
- }
- }
-
- ret = 0;
-out:
- GF_FREE (buffp);
- return ret;
-}
-
-/*
- * bd create <volname>:/path <size>
- * bd delete <volname>:/path
- * bd clone <volname>:/path <newbd>
- * bd snapshot <volname>:/<path> <newbd> <size>
- */
-int32_t
-cli_cmd_bd_validate (const char **words, int wordcount, dict_t **options)
-{
- dict_t *dict = NULL;
- int ret = -1;
- char *op[] = { "create", "delete", "clone", "snapshot", NULL };
- int index = 0;
-
- for (index = 0; op[index]; index++)
- if (!strcasecmp (words[1], op[index]))
- break;
-
- if (!op[index])
- return -1;
-
- dict = dict_new ();
- if (!dict)
- goto out;
-
- if (!strcasecmp (words[1], "create")) {
- if (wordcount != 4)
- goto out;
- } else if (!strcasecmp (words[1], "delete")) {
- if (wordcount != 3)
- goto out;
- } else if (!strcasecmp (words[1], "clone")) {
- if (wordcount != 4)
- goto out;
- } else if (!strcasecmp (words[1], "snapshot")) {
- if (wordcount != 5)
- goto out;
- } else {
- ret = -1;
- goto out;
- }
-
- ret = cli_cmd_bd_parse (dict, words);
- if (ret < 0)
- goto out;
-
- *options = dict;
- ret = 0;
-out:
- if (ret)
- dict_unref (dict);
- return ret;
-}
-
-int
-cli_cmd_bd_cbk (struct cli_state *state, struct cli_cmd_word *word,
- const char **words, int wordcount)
-{
- int ret = -1;
- rpc_clnt_procedure_t *proc = NULL;
- call_frame_t *frame = NULL;
- int sent = 0;
- int parse_error = 0;
- dict_t *options = NULL;
- cli_local_t *local = NULL;
-
- proc = &cli_rpc_prog->proctable[GLUSTER_CLI_BD_OP];
-
- frame = create_frame (THIS, THIS->ctx->pool);
- if (!frame)
- goto out;
-
- ret = cli_cmd_bd_validate (words, wordcount, &options);
- if (ret) {
- cli_usage_out (word->pattern);
- parse_error = 1;
- goto out;
- }
-
- CLI_LOCAL_INIT (local, words, frame, options);
- if (proc->fn) {
- ret = proc->fn (frame, THIS, options);
- }
-
-out:
- if (options)
- dict_unref (options);
-
- if (ret) {
- cli_cmd_sent_status_get (&sent);
- if ((sent == 0) && (parse_error == 0))
- cli_out ("BD op failed!");
- }
-
- CLI_STACK_DESTROY (frame);
-
- return ret;
-}
-
-struct cli_cmd cli_bd_cmds[] = {
- { "bd help",
- cli_cmd_bd_help_cbk,
- "display help for bd command"},
- { "bd create <volname>:<bd> <size>",
- cli_cmd_bd_cbk,
- "\n\tcreate a block device where size can be "
- "suffixed with KB, MB etc. Default size is in MB"},
- { "bd delete <volname>:<bd>",
- cli_cmd_bd_cbk,
- "Delete a block device"},
- { "bd clone <volname>:<bd> <newbd>",
- cli_cmd_bd_cbk,
- "clone device"},
- { "bd snapshot <volname>:<bd> <newbd> <size>",
- cli_cmd_bd_cbk,
- "\n\tsnapshot device where size can be "
- "suffixed with KB, MB etc. Default size is in MB"},
- { NULL, NULL, NULL }
-};
-
-int
-cli_cmd_bd_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word,
- const char **words, int wordcount)
-{
- struct cli_cmd *cmd = NULL;
-
- for (cmd = cli_bd_cmds; cmd->pattern; cmd++)
- if (_gf_false == cmd->disable)
- cli_out ("%s - %s", cmd->pattern, cmd->desc);
-
- return 0;
-}
-
-int
-cli_cmd_bd_register (struct cli_state *state)
-{
- int ret = 0;
- struct cli_cmd *cmd = NULL;
-
- for (cmd = cli_bd_cmds; cmd->pattern; cmd++) {
- ret = cli_cmd_register (&state->tree, cmd);
- if (ret)
- goto out;
- }
-out:
- return ret;
-}
diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c
index 8d5081586..100be0b73 100644
--- a/cli/src/cli-cmd-volume.c
+++ b/cli/src/cli-cmd-volume.c
@@ -1829,10 +1829,12 @@ struct cli_cmd volume_cmds[] = {
"list information of all volumes"},
{ "volume create <NEW-VOLNAME> [stripe <COUNT>] [replica <COUNT>] "
+ "[transport <tcp|rdma|tcp,rdma>] <NEW-BRICK>"
#ifdef HAVE_BD_XLATOR
- "[device vg] "
+ "?<vg_name>"
#endif
- "[transport <tcp|rdma|tcp,rdma>] <NEW-BRICK> ... [force]",
+ "... [force]",
+
cli_cmd_volume_create_cbk,
"create a new volume of specified type with mentioned bricks"},
@@ -1856,7 +1858,7 @@ struct cli_cmd volume_cmds[] = {
cli_cmd_volume_add_brick_cbk,
"add brick to volume <VOLNAME>"},
- { "volume remove-brick <VOLNAME> [replica <COUNT>] <BRICK> ... {start|stop|status|commit|force}",
+ { "volume remove-brick <VOLNAME> [replica <COUNT>] <BRICK> ... [start|stop|status|commit|force]",
cli_cmd_volume_remove_brick_cbk,
"remove brick from volume <VOLNAME>"},
@@ -1894,7 +1896,7 @@ struct cli_cmd volume_cmds[] = {
#if (SYNCDAEMON_COMPILE)
{"volume "GEOREP" [<VOLNAME>] [<SLAVE-URL>] {create [push-pem] [force]"
- "|start [force]|stop [force]|config|status|delete} [options...]",
+ "|start [force]|stop [force]|config|status [detail]|delete} [options...]",
cli_cmd_volume_gsync_set_cbk,
"Geo-sync operations",
cli_cmd_check_gsync_exists_cbk},
@@ -1914,11 +1916,11 @@ struct cli_cmd volume_cmds[] = {
"volume top operations"},
{ "volume status [all | <VOLNAME> [nfs|shd|<BRICK>]]"
- " [detail|clients|mem|inode|fd|callpool]",
+ " [detail|clients|mem|inode|fd|callpool|tasks]",
cli_cmd_volume_status_cbk,
"display status of all or specified volume(s)/brick"},
- { "volume heal <VOLNAME> [{full | info {healed | heal-failed | split-brain}}]",
+ { "volume heal <VOLNAME> [{full | statistics {heal-count {replica <hostname:brickname>}} |info {healed | heal-failed | split-brain}}]",
cli_cmd_volume_heal_cbk,
"self-heal commands on volume specified by <VOLNAME>"},
diff --git a/cli/src/cli-cmd.c b/cli/src/cli-cmd.c
index aa7600350..b81f75b5b 100644
--- a/cli/src/cli-cmd.c
+++ b/cli/src/cli-cmd.c
@@ -231,11 +231,9 @@ cli_cmds_register (struct cli_state *state)
if (ret)
goto out;
-#ifdef HAVE_BD_XLATOR
- ret = cli_cmd_bd_register (state);
+ ret = cli_cmd_snapshot_register (state);
if (ret)
goto out;
-#endif
out:
return ret;
}
diff --git a/cli/src/cli-cmd.h b/cli/src/cli-cmd.h
index 0ad37d498..041729276 100644
--- a/cli/src/cli-cmd.h
+++ b/cli/src/cli-cmd.h
@@ -93,6 +93,8 @@ int cli_cmd_probe_register (struct cli_state *state);
int cli_cmd_system_register (struct cli_state *state);
+int cli_cmd_snapshot_register (struct cli_state *state);
+
int cli_cmd_misc_register (struct cli_state *state);
struct cli_cmd_word *cli_cmd_nextword (struct cli_cmd_word *word,
@@ -119,7 +121,4 @@ gf_answer_t
cli_cmd_get_confirmation (struct cli_state *state, const char *question);
int cli_cmd_sent_status_get (int *status);
-#ifdef HAVE_BD_XLATOR
-int cli_cmd_bd_register (struct cli_state *state);
-#endif
#endif /* __CLI_CMD_H__ */
diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c
index ea80f9362..bfeb854ad 100644
--- a/cli/src/cli-rpc-ops.c
+++ b/cli/src/cli-rpc-ops.c
@@ -22,6 +22,8 @@
#define VOL_TOP_PERF_SPEED_WIDTH 4
#define VOL_TOP_PERF_TIME_WIDTH 26
+#define INDENT_MAIN_HEAD "%-25s %s "
+
#include "cli.h"
#include "compat-errno.h"
#include "cli-cmd.h"
@@ -58,8 +60,15 @@ char *cli_vol_status_str[] = {"Created",
"Stopped",
};
-char *cli_volume_backend[] = {"",
- "Volume Group",
+char *cli_vol_task_status_str[] = {"not started",
+ "in progress",
+ "stopped",
+ "completed",
+ "failed",
+ "fix-layout in progress",
+ "fix-layout stopped",
+ "fix-layout completed",
+ "fix-layout failed",
};
int32_t
@@ -274,7 +283,7 @@ gf_cli_output_pool_list (dict_t *dict, int count)
else
connected_str = "Disconnected";
- cli_out ("%s\t%s\t%s ", uuid_buf, hostname_buf,
+ cli_out ("%s\t%-9s\t%s ", uuid_buf, hostname_buf,
connected_str);
i++;
}
@@ -489,7 +498,11 @@ gf_cli_get_volume_cbk (struct rpc_req *req, struct iovec *iov,
char key[1024] = {0};
char err_str[2048] = {0};
gf_cli_rsp rsp = {0};
- int32_t backend = 0;
+ char *caps = NULL;
+ int k __attribute__((unused)) = 0;
+ // snap_volume variable helps in showing whether a volume is a normal
+ //volume or a volume for the snapshot
+ int32_t snap_volume = 0;
if (-1 == req->rpc_status)
goto out;
@@ -611,6 +624,11 @@ xml_output:
if (ret)
goto out;
+ snprintf (key, sizeof (key), "volume%d.snap_volume", i);
+ ret = dict_get_int32 (dict, key, &snap_volume);
+ if (ret)
+ goto out;
+
snprintf (key, 256, "volume%d.brick_count", i);
ret = dict_get_int32 (dict, key, &brick_count);
if (ret)
@@ -641,9 +659,6 @@ xml_output:
if (ret)
goto out;
- snprintf (key, 256, "volume%d.backend", i);
- ret = dict_get_int32 (dict, key, &backend);
-
vol_type = type;
// Distributed (stripe/replicate/stripe-replica) setups
@@ -654,9 +669,44 @@ xml_output:
cli_out ("Type: %s", cli_vol_type_str[vol_type]);
cli_out ("Volume ID: %s", volume_id_str);
cli_out ("Status: %s", cli_vol_status_str[status]);
+ if (snap_volume)
+ cli_out ("Snap Volume: %s", "yes");
+ else
+ cli_out ("Snap Volume: %s", "no");
- if (backend)
+#ifdef HAVE_BD_XLATOR
+ k = 0;
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "volume%d.xlator%d", i, k);
+ ret = dict_get_str (dict, key, &caps);
+ if (ret)
goto next;
+ do {
+ j = 0;
+ cli_out ("Xlator %d: %s", k + 1, caps);
+ do {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key),
+ "volume%d.xlator%d.caps%d",
+ i, k, j++);
+ ret = dict_get_str (dict, key, &caps);
+ if (ret)
+ break;
+ cli_out ("Capability %d: %s", j, caps);
+ } while (1);
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key),
+ "volume%d.xlator%d", i, ++k);
+ ret = dict_get_str (dict, key, &caps);
+ if (ret)
+ break;
+ } while (1);
+
+next:
+#else
+ caps = 0; /* Avoid compiler warnings when BD not enabled */
+#endif
if (type == GF_CLUSTER_TYPE_STRIPE_REPLICATE) {
cli_out ("Number of Bricks: %d x %d x %d = %d",
@@ -678,12 +728,6 @@ xml_output:
((transport == 0)?"tcp":
(transport == 1)?"rdma":
"tcp,rdma"));
-
-next:
- if (backend) {
- cli_out ("Backend Type: Block, %s",
- cli_volume_backend[backend]);
- }
j = 1;
GF_FREE (local->get_vol.volname);
@@ -699,6 +743,12 @@ next:
goto out;
cli_out ("Brick%d: %s", j, brick);
+#ifdef HAVE_BD_XLATOR
+ snprintf (key, 256, "volume%d.vg%d", i, j);
+ ret = dict_get_str (dict, key, &caps);
+ if (!ret)
+ cli_out ("Brick%d VG: %s", j, caps);
+#endif
j++;
}
@@ -1202,7 +1252,7 @@ gf_cli_defrag_volume_cbk (struct rpc_req *req, struct iovec *iov,
char msg[1024] = {0,};
gf_defrag_status_t status_rcd = GF_DEFRAG_STATUS_NOT_STARTED;
int32_t counter = 0;
- char *node_uuid = NULL;
+ char *node_name = NULL;
char key[256] = {0,};
int32_t i = 1;
uint64_t failures = 0;
@@ -1327,18 +1377,18 @@ gf_cli_defrag_volume_cbk (struct rpc_req *req, struct iovec *iov,
goto out;
}
- cli_out ("%40s %16s %13s %13s %13s %13s %14s %s", "Node",
+ cli_out ("%40s %16s %13s %13s %13s %13s %20s %18s", "Node",
"Rebalanced-files", "size", "scanned", "failures", "skipped",
"status", "run time in secs");
- cli_out ("%40s %16s %13s %13s %13s %13s %14s %16s", "---------",
+ cli_out ("%40s %16s %13s %13s %13s %13s %20s %18s", "---------",
"-----------", "-----------", "-----------", "-----------",
"-----------", "------------", "--------------");
do {
- snprintf (key, 256, "node-uuid-%d", i);
- ret = dict_get_str (dict, key, &node_uuid);
+ snprintf (key, 256, "node-name-%d", i);
+ ret = dict_get_str (dict, key, &node_name);
if (ret)
gf_log (frame->this->name, GF_LOG_TRACE,
- "failed to get node-uuid");
+ "failed to get node-name");
memset (key, 0, 256);
snprintf (key, 256, "files-%d", i);
@@ -1388,27 +1438,10 @@ gf_cli_defrag_volume_cbk (struct rpc_req *req, struct iovec *iov,
gf_log (frame->this->name, GF_LOG_TRACE,
"failed to get run-time");
- switch (status_rcd) {
- case GF_DEFRAG_STATUS_NOT_STARTED:
- status = "not started";
- break;
- case GF_DEFRAG_STATUS_STARTED:
- status = "in progress";
- break;
- case GF_DEFRAG_STATUS_STOPPED:
- status = "stopped";
- break;
- case GF_DEFRAG_STATUS_COMPLETE:
- status = "completed";
- break;
- case GF_DEFRAG_STATUS_FAILED:
- status = "failed";
- break;
- }
-
+ status = cli_vol_task_status_str[status_rcd];
size_str = gf_uint64_2human_readable(size);
cli_out ("%40s %16"PRIu64 " %13s" " %13"PRIu64 " %13"PRIu64
- " %13"PRIu64 " %14s %16.2f", node_uuid, files,
+ " %13"PRIu64 " %20s %18.2f", node_name, files,
size_str, lookup, failures, skipped, status, elapsed);
GF_FREE(size_str);
@@ -1417,10 +1450,18 @@ gf_cli_defrag_volume_cbk (struct rpc_req *req, struct iovec *iov,
done:
- if (rsp.op_ret)
- cli_err ("volume rebalance: %s: failed: %s", volname, msg);
- else
- cli_out ("volume rebalance: %s: success: %s", volname, msg);
+ if (global_state->mode & GLUSTER_MODE_XML)
+ cli_xml_output_str ("volRebalance", msg,
+ rsp.op_ret, rsp.op_errno,
+ rsp.op_errstr);
+ else {
+ if (rsp.op_ret)
+ cli_err ("volume rebalance: %s: failed: %s", volname,
+ msg);
+ else
+ cli_out ("volume rebalance: %s: success: %s", volname,
+ msg);
+ }
ret = rsp.op_ret;
out:
@@ -1498,7 +1539,7 @@ gf_cli_reset_volume_cbk (struct rpc_req *req, struct iovec *iov,
gf_log ("cli", GF_LOG_INFO, "Received resp to reset");
- if (rsp.op_ret && strcmp (rsp.op_errstr, ""))
+ if (strcmp (rsp.op_errstr, ""))
snprintf (msg, sizeof (msg), "%s", rsp.op_errstr);
else
snprintf (msg, sizeof (msg), "reset volume %s",
@@ -1516,7 +1557,7 @@ gf_cli_reset_volume_cbk (struct rpc_req *req, struct iovec *iov,
if (rsp.op_ret)
cli_err ("volume reset: failed: %s", msg);
else
- cli_out ("volume reset: success");
+ cli_out ("volume reset: success: %s", msg);
ret = rsp.op_ret;
@@ -1722,7 +1763,7 @@ gf_cli3_remove_brick_status_cbk (struct rpc_req *req, struct iovec *iov,
char key[256] = {0,};
int32_t i = 1;
int32_t counter = 0;
- char *node_uuid = 0;
+ char *node_name = 0;
gf_defrag_status_t status_rcd = GF_DEFRAG_STATUS_NOT_STARTED;
uint64_t failures = 0;
uint64_t skipped = 0;
@@ -1834,11 +1875,11 @@ xml_output:
"-----------","------------", "--------------");
do {
- snprintf (key, 256, "node-uuid-%d", i);
- ret = dict_get_str (dict, key, &node_uuid);
+ snprintf (key, 256, "node-name-%d", i);
+ ret = dict_get_str (dict, key, &node_name);
if (ret)
gf_log (frame->this->name, GF_LOG_TRACE,
- "failed to get node-uuid");
+ "failed to get node-name");
memset (key, 0, 256);
snprintf (key, 256, "files-%d", i);
@@ -1902,13 +1943,15 @@ xml_output:
case GF_DEFRAG_STATUS_FAILED:
status = "failed";
break;
+ default:
+ break;
}
size_str = gf_uint64_2human_readable(size);
if (strcmp (status, "not started")) {
cli_out ("%40s %16"PRIu64 " %13s" " %13"PRIu64 " %13"
- PRIu64 " %13"PRIu64 " %14s %16.2f", node_uuid,
+ PRIu64 " %13"PRIu64 " %14s %16.2f", node_name,
files, size_str, lookup, failures, skipped,
status, elapsed);
}
@@ -2928,142 +2971,6 @@ out:
return ret;
}
-#ifdef HAVE_BD_XLATOR
-int
-gf_cli_bd_op_cbk (struct rpc_req *req, struct iovec *iov,
- int count, void *myframe)
-{
- gf_cli_rsp rsp = {0,};
- int ret = -1;
- cli_local_t *local = NULL;
- dict_t *dict = NULL;
- dict_t *input_dict = NULL;
- gf_xl_bd_op_t bd_op = GF_BD_OP_INVALID;
- char *operation = NULL;
- call_frame_t *frame = NULL;
-
- if (-1 == req->rpc_status)
- goto out;
-
- frame = myframe;
-
- ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp);
- if (ret < 0) {
- gf_log (frame->this->name, GF_LOG_ERROR,
- "Failed to decode xdr response");
- goto out;
- }
-
- dict = dict_new ();
- if (!dict) {
- ret = -1;
- goto out;
- }
-
- if (frame)
- local = frame->local;
-
- if (local) {
- input_dict = local->dict;
- ret = dict_get_int32 (input_dict, "bd-op",
- (int32_t *)&bd_op);
- }
-
- switch (bd_op) {
- case GF_BD_OP_NEW_BD:
- operation = gf_strdup ("create");
- break;
- case GF_BD_OP_DELETE_BD:
- operation = gf_strdup ("delete");
- break;
- case GF_BD_OP_CLONE_BD:
- operation = gf_strdup ("clone");
- break;
- case GF_BD_OP_SNAPSHOT_BD:
- operation = gf_strdup ("snapshot");
- break;
- default:
- break;
- }
-
- ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, &dict);
- if (ret)
- goto out;
-
- gf_log ("cli", GF_LOG_INFO, "Received resp to %s bd op", operation);
-
- if (global_state->mode & GLUSTER_MODE_XML) {
- ret = cli_xml_output_dict ("BdOp", dict, rsp.op_ret,
- rsp.op_errno, rsp.op_errstr);
- if (ret)
- gf_log ("cli", GF_LOG_ERROR,
- "Error outputting to xml");
- goto out;
- }
-
- if (rsp.op_ret && strcmp (rsp.op_errstr, ""))
- cli_err ("%s", rsp.op_errstr);
- else
- cli_out ("BD %s has been %s", operation,
- (rsp.op_ret) ? "unsuccessful":
- "successful.");
- ret = rsp.op_ret;
-
-out:
- cli_cmd_broadcast_response (ret);
-
- if (dict)
- dict_unref (dict);
-
- if (operation)
- GF_FREE (operation);
-
- if (rsp.dict.dict_val)
- free (rsp.dict.dict_val);
- if (rsp.op_errstr)
- free (rsp.op_errstr);
- return ret;
-}
-
-int32_t
-gf_cli_bd_op (call_frame_t *frame, xlator_t *this,
- void *data)
-{
- gf_cli_req req = { {0,} };
- int ret = 0;
- dict_t *dict = NULL;
-
- if (!frame || !this || !data) {
- ret = -1;
- goto out;
- }
-
- dict = dict_ref ((dict_t *)data);
- if (!dict)
- goto out;
-
- ret = dict_allocate_and_serialize (dict,
- &req.dict.dict_val,
- &req.dict.dict_len);
-
-
- ret = cli_to_glusterd (&req, frame, gf_cli_bd_op_cbk,
- (xdrproc_t)xdr_gf_cli_req, dict,
- GLUSTER_CLI_BD_OP, this, cli_rpc_prog,
- NULL);
-
-out:
- if (dict)
- dict_unref (dict);
-
- if (req.dict.dict_val)
- GF_FREE (req.dict.dict_val);
-
- gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret);
- return ret;
-}
-#endif
-
int32_t
gf_cli_create_volume (call_frame_t *frame, xlator_t *this,
void *data)
@@ -3757,54 +3664,6 @@ out:
return ret;
}
-static int
-gf_cli_get_slave_volname (char *slave, char **slave_vol)
-{
- char *tmp = NULL;
- char *buf = NULL;
- char *save_ptr = NULL;
- char *slave_buf = NULL;
- int32_t ret = -1;
-
- GF_ASSERT (slave);
-
- slave_buf = gf_strdup(slave);
- if (!slave_buf) {
- gf_log ("", GF_LOG_ERROR,
- "Failed to gf_strdup");
- ret = -1;
- goto out;
- }
-
- tmp = strtok_r (slave_buf, ":", &save_ptr);
- while (tmp) {
- buf = tmp;
- tmp = strtok_r (NULL, ":", &save_ptr);
- }
-
- if (buf) {
- *slave_vol = gf_strdup (buf);
- if (!*slave_vol) {
- gf_log ("", GF_LOG_ERROR,
- "Failed to gf_strdup");
- ret = -1;
- goto out;
- }
- gf_log ("", GF_LOG_DEBUG, "Slave Vol : %s", *slave_vol);
- ret = 0;
- } else {
- gf_log ("", GF_LOG_ERROR, "Invalid slave name");
- goto out;
- }
-
-out:
- if (slave_buf)
- GF_FREE(slave_buf);
-
- gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
- return ret;
-}
-
int
gf_cli_gsync_config_command (dict_t *dict)
{
@@ -3812,7 +3671,7 @@ gf_cli_gsync_config_command (dict_t *dict)
char *subop = NULL;
char *gwd = NULL;
char *slave = NULL;
- char *slave_vol = NULL;
+ char *confpath = NULL;
char *master = NULL;
char *op_name = NULL;
int ret = -1;
@@ -3835,21 +3694,17 @@ gf_cli_gsync_config_command (dict_t *dict)
if (dict_get_str (dict, "op_name", &op_name) != 0)
op_name = NULL;
- ret = gf_cli_get_slave_volname (slave, &slave_vol);
- if (ret) {
- gf_log ("", GF_LOG_ERROR,
- "Unable to fetch slave volume name.");
- return -1;
+ ret = dict_get_str (dict, "conf_path", &confpath);
+ if (!confpath) {
+ ret = snprintf (conf_path, sizeof(conf_path) - 1,
+ "%s/"GEOREP"/gsyncd_template.conf", gwd);
+ conf_path[ret] = '\0';
+ confpath = conf_path;
}
- ret = snprintf (conf_path, sizeof(conf_path) - 1,
- "%s/"GEOREP"/%s-%s/gsyncd.conf",
- gwd, master, slave_vol);
- conf_path[ret] = '\0';
-
runinit (&runner);
runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "-c", NULL);
- runner_argprintf (&runner, "%s", conf_path);
+ runner_argprintf (&runner, "%s", confpath);
if (master)
runner_argprintf (&runner, ":%s", master);
runner_add_arg (&runner, slave);
@@ -3860,156 +3715,121 @@ gf_cli_gsync_config_command (dict_t *dict)
return runner_run (&runner);
}
-static int
-gf_cli_fetch_gsyncd_health_uptime (char *status, char **health, char **uptime)
+int
+gf_cli_fetch_gsyncd_status_values (char *status,
+ gf_cli_gsync_status_t *sts_val)
{
+ int32_t ret = -1;
char *tmp = NULL;
char *save_ptr = NULL;
- int32_t ret = -1;
char *key = NULL;
char *value = NULL;
- if (!health || !uptime || !status) {
- gf_log ("", GF_LOG_ERROR, "health or uptime or status is null");
+ if (!status || !sts_val) {
+ gf_log ("", GF_LOG_ERROR, "status or sts_val is null");
goto out;
}
tmp = strtok_r (status, "\n", &save_ptr);
if (tmp)
- *health = gf_strdup (tmp);
+ sts_val->health = gf_strdup (tmp);
while (tmp) {
key = strtok_r (tmp, "=", &value);
- if ((key) && (!strcmp(key, "Uptime"))) {
- *uptime = gf_strdup (value);
- break;
- }
- tmp = strtok_r (NULL, ";", &save_ptr);
- }
- if (*health)
- ret = 0;
+ if ((key) && (!strcmp(key, "Uptime")))
+ sts_val->uptime = gf_strdup (value);
- if (!*uptime)
- *uptime = gf_strdup ("N/A");
-out:
- gf_log ("", GF_LOG_DEBUG, "Returning %d.", ret);
- return ret;
-}
+ if ((key) && (!strcmp(key, "FilesSyncd")))
+ sts_val->files_syncd = gf_strdup (value);
-int
-gf_cli_gsync_out_status (dict_t *dict)
-{
- char mst[PATH_MAX] = {0, };
- char slv[PATH_MAX] = {0, };
- char sts[PATH_MAX] = {0, };
- char nds[PATH_MAX] = {0, };
- char errmsg[1024] = "";
- char *sts_val = NULL;
- char *master = NULL;
- char *slave = NULL;
- char **output_values = NULL;
- char **dict_values = NULL;
- char *hyphens = NULL;
- char *title_values[] = {"NODE", "MASTER", "SLAVE",
- "HEALTH", "UPTIME"};
- int gsync_count = 0;
- int i = 0;
- int j = 0;
- int dict_val_count = 0;
- int ret = 0;
- int spacing[5] = {0, 0, 0, 0, 10};
- int total_spacing = 0;
+ if ((key) && (!strcmp(key, "FilesPending")))
+ sts_val->files_pending = gf_strdup (value);
- /* Checks if any session is active or not */
- ret = dict_get_int32 (dict, "gsync-count", &gsync_count);
- if (ret) {
- ret = dict_get_str (dict, "master", &master);
+ if ((key) && (!strcmp(key, "BytesPending"))) {
+ value = gf_uint64_2human_readable(atol(value));
+ sts_val->bytes_pending = gf_strdup (value);
+ }
- ret = dict_get_str (dict, "slave", &slave);
+ if ((key) && (!strcmp(key, "DeletesPending")))
+ sts_val->deletes_pending = gf_strdup (value);
- if (master) {
- if (slave)
- snprintf (errmsg, sizeof(errmsg), "No active "
- "geo-replication sessions between %s"
- " and %s", master, slave);
- else
- snprintf (errmsg, sizeof(errmsg), "No active "
- "geo-replication sessions for %s",
- master);
- } else
- snprintf (errmsg, sizeof(errmsg), "No active "
- "geo-replication sessions");
+ tmp = strtok_r (NULL, ";", &save_ptr);
+ }
- gf_log ("cli", GF_LOG_INFO, "%s", errmsg);
- cli_out ("%s", errmsg);
+ if (sts_val->health)
ret = 0;
- goto out;
- }
- /* (gsync_count = number of nodes reporting output *
- 5 = number of fields) = total number of values to
- be fetched from dict */
- dict_values = GF_CALLOC (gsync_count * 5, sizeof (char *),
- gf_common_mt_char);
- if (!dict_values) {
- gf_log ("cli", GF_LOG_ERROR, "Out Of Memory");
- ret = -1;
- goto out;
- }
+ if (!sts_val->uptime)
+ sts_val->uptime = gf_strdup ("N/A");
- for (i = 1, j = 0; i <= gsync_count; i++) {
- snprintf (nds, sizeof(nds), "node%d", i);
- snprintf (mst, sizeof(mst), "master%d", i);
- snprintf (slv, sizeof(slv), "slave%d", i);
- snprintf (sts, sizeof(sts), "status%d", i);
+ if (!sts_val->files_syncd)
+ sts_val->files_syncd = gf_strdup ("N/A");
- /* Fetching the values from dict, and calculating
- the max length for each field */
- ret = dict_get_str (dict, nds, &dict_values[j]);
- if (ret)
- goto out;
- if (strlen (dict_values[j]) > spacing [0])
- spacing[0] = strlen (dict_values[j]);
- j++;
+ if (!sts_val->files_pending)
+ sts_val->files_pending = gf_strdup ("N/A");
- ret = dict_get_str (dict, mst, &dict_values[j]);
- if (ret)
- goto out;
- if (strlen (dict_values[j]) > spacing [1])
- spacing[1] = strlen (dict_values[j]);
- j++;
+ if (!sts_val->bytes_pending)
+ sts_val->bytes_pending = gf_strdup ("N/A");
- ret = dict_get_str (dict, slv, &dict_values[j]);
- if (ret)
- goto out;
- if (strlen (dict_values[j]) > spacing [2])
- spacing[2] = strlen (dict_values[j]);
- j++;
+ if (!sts_val->deletes_pending)
+ sts_val->deletes_pending = gf_strdup ("N/A");
- ret = dict_get_str (dict, sts, &sts_val);
- if (ret)
- goto out;
+out:
+ gf_log ("", GF_LOG_DEBUG, "Returning %d.", ret);
+ return ret;
+}
- /* Fetching health and uptime from sts_val */
- ret = gf_cli_fetch_gsyncd_health_uptime (sts_val,
- &dict_values[j],
- &dict_values[j+1]);
- if (ret)
- goto out;
+char*
+get_struct_variable (int mem_num, gf_cli_gsync_status_t *sts_val)
+{
+ switch (mem_num) {
+ case 0: return (sts_val->node);
+ case 1: return (sts_val->master);
+ case 2: return (sts_val->slave);
+ case 3: return (sts_val->health);
+ case 4: return (sts_val->uptime);
+ case 5: return (sts_val->files_syncd);
+ case 6: return (sts_val->files_pending);
+ case 7: return (sts_val->bytes_pending);
+ case 8: return (sts_val->deletes_pending);
+ default:
+ goto out;
+ }
- if (strlen (dict_values[j]) > spacing [3])
- spacing[3] = strlen (dict_values[j]);
- j++;
+out:
+ return NULL;
+}
- if (strlen (dict_values[j]) > spacing [4])
- spacing[4] = strlen (dict_values[j]);
- j++;
- }
+int
+gf_cli_print_status (char **title_values,
+ gf_cli_gsync_status_t **sts_vals,
+ int *spacing, int gsync_count,
+ int number_of_fields, int is_detail)
+{
+ int indents = 0;
+ int i = 0;
+ int j = 0;
+ int ret = 0;
+ int total_spacing = 0;
+ char **output_values = NULL;
+ char *tmp = NULL;
+ char *hyphens = NULL;
+ char heading[PATH_MAX] = {0, };
+ char indent_spaces[PATH_MAX] = {0, };
/* calculating spacing for hyphens */
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < number_of_fields; i++) {
+ /* Suppressing master and slave output for status detail */
+ if ((is_detail) && ((i == 1) || (i == 2))) {
+ total_spacing++;
+ continue;
+ } else if ((!is_detail) && (i > 4)) {
+ /* Suppressing detailed output for
+ * status */
+ continue;
+ }
spacing[i] += 3; /* Adding extra space to
distinguish between fields */
total_spacing += spacing[i];
@@ -4017,73 +3837,298 @@ gf_cli_gsync_out_status (dict_t *dict)
total_spacing += 4; /* For the spacing between the fields */
/* char pointers for each field */
- output_values = GF_CALLOC (5, sizeof (char *), gf_common_mt_char);
- if (!output_values)
+ output_values = GF_CALLOC (number_of_fields, sizeof (char *),
+ gf_common_mt_char);
+ if (!output_values) {
ret = -1;
- for (i = 0; i < 5; i++) {
+ goto out;
+ }
+ for (i = 0; i < number_of_fields; i++) {
output_values[i] = GF_CALLOC (spacing[i] + 1, sizeof (char),
gf_common_mt_char);
- if (!output_values[i])
+ if (!output_values[i]) {
ret = -1;
+ goto out;
+ }
}
hyphens = GF_CALLOC (total_spacing + 1, sizeof (char),
gf_common_mt_char);
- if (!hyphens)
+ if (!hyphens) {
ret = -1;
+ goto out;
+ }
+ ret = snprintf(heading, sizeof(heading), "MASTER: %s SLAVE: %s",
+ sts_vals[0]->master, sts_vals[0]->slave);
if (ret) {
- gf_log ("cli", GF_LOG_ERROR, "Out Of Memory");
+ if (ret < sizeof(heading))
+ heading[ret] = '\0';
+ else
+ heading[sizeof(heading) - 1] = '\0';
+ ret = 0;
+ } else {
ret = -1;
goto out;
}
+ if (is_detail) {
+ cli_out (" ");
+ if (strlen(heading) > total_spacing)
+ cli_out ("%s", heading);
+ else {
+ /* Printing the heading with centre justification */
+ indents = (total_spacing - strlen(heading)) / 2;
+ memset (indent_spaces, ' ', indents);
+ indent_spaces[indents] = '\0';
+ ret = snprintf (hyphens, total_spacing, "%s%s",
+ indent_spaces, heading);
+ if (ret) {
+ hyphens[ret] = '\0';
+ cli_out ("%s", hyphens);
+ ret = 0;
+ } else {
+ ret = -1;
+ goto out;
+ }
+ }
+ cli_out (" ");
+ }
+
/* setting the title "NODE", "MASTER", etc. from title_values[]
and printing the same */
- for (j = 0; j < 5; j++) {
+ for (j = 0; j < number_of_fields; j++) {
+ /* Suppressing master and slave output for status detail */
+ if ((is_detail) && ((j == 1) || (j == 2))) {
+ output_values[j][0] = '\0';
+ continue;
+ } else if ((!is_detail) && (j > 4)) {
+ /* Suppressing detailed output for
+ * status */
+ output_values[j][0] = '\0';
+ continue;
+ }
memset (output_values[j], ' ', spacing[j]);
memcpy (output_values[j], title_values[j],
strlen(title_values[j]));
output_values[j][spacing[j]] = '\0';
}
- cli_out ("%s %s %s %s %s", output_values[0], output_values[1],
- output_values[2], output_values[3], output_values[4]);
+ cli_out ("%s %s %s %s %s %s %s %s %s", output_values[0],
+ output_values[1], output_values[2], output_values[3],
+ output_values[4], output_values[5], output_values[6],
+ output_values[7], output_values[8]);
/* setting and printing the hyphens */
memset (hyphens, '-', total_spacing);
hyphens[total_spacing] = '\0';
cli_out ("%s", hyphens);
- for (i = 1, dict_val_count = 0; i <= gsync_count; i++) {
- /* Setting the field values for each row */
- for (j = 0; j < 5; j++) {
+ for (i = 0; i < gsync_count; i++) {
+ for (j = 0; j < number_of_fields; j++) {
+ /* Suppressing master and slave output for
+ * status detail */
+ if ((is_detail) && ((j == 1) || (j == 2))) {
+ output_values[j][0] = '\0';
+ continue;
+ } else if ((!is_detail) && (j > 4)) {
+ /* Suppressing detailed output for
+ * status */
+ output_values[j][0] = '\0';
+ continue;
+ }
+ tmp = get_struct_variable(j, sts_vals[i]);
+ if (!tmp) {
+ gf_log ("", GF_LOG_ERROR,
+ "struct member empty.");
+ ret = -1;
+ goto out;
+ }
memset (output_values[j], ' ', spacing[j]);
- memcpy (output_values[j], dict_values[dict_val_count],
- strlen(dict_values[dict_val_count]));
+ memcpy (output_values[j], tmp, strlen (tmp));
output_values[j][spacing[j]] = '\0';
- dict_val_count++;
}
- cli_out ("%s %s %s %s %s", output_values[0], output_values[1],
- output_values[2], output_values[3], output_values[4]);
+
+ cli_out ("%s %s %s %s %s %s %s %s %s", output_values[0],
+ output_values[1], output_values[2], output_values[3],
+ output_values[4], output_values[5], output_values[6],
+ output_values[7], output_values[8]);
}
+
out:
if (output_values) {
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < number_of_fields; i++) {
if (output_values[i])
GF_FREE (output_values[i]);
}
GF_FREE (output_values);
}
- if (dict_values)
- GF_FREE (dict_values);
-
if (hyphens)
GF_FREE (hyphens);
return ret;
}
+int
+gf_cli_read_status_data (dict_t *dict,
+ gf_cli_gsync_status_t **sts_vals,
+ int *spacing, int gsync_count,
+ int number_of_fields)
+{
+ int ret = 0;
+ int i = 0;
+ int j = 0;
+ char mst[PATH_MAX] = {0, };
+ char slv[PATH_MAX] = {0, };
+ char sts[PATH_MAX] = {0, };
+ char nds[PATH_MAX] = {0, };
+ char *status = NULL;
+ char *tmp = NULL;
+
+ /* Storing per node status info in each object */
+ for (i = 0; i < gsync_count; i++) {
+ snprintf (nds, sizeof(nds), "node%d", i + 1);
+ snprintf (mst, sizeof(mst), "master%d", i + 1);
+ snprintf (slv, sizeof(slv), "slave%d", i + 1);
+ snprintf (sts, sizeof(sts), "status%d", i + 1);
+
+ /* Fetching the values from dict, and calculating
+ the max length for each field */
+ ret = dict_get_str (dict, nds, &(sts_vals[i]->node));
+ if (ret)
+ goto out;
+
+ ret = dict_get_str (dict, mst, &(sts_vals[i]->master));
+ if (ret)
+ goto out;
+
+ ret = dict_get_str (dict, slv, &(sts_vals[i]->slave));
+ if (ret)
+ goto out;
+
+ ret = dict_get_str (dict, sts, &status);
+ if (ret)
+ goto out;
+
+ /* Fetching health and uptime from sts_val */
+ ret = gf_cli_fetch_gsyncd_status_values (status, sts_vals[i]);
+ if (ret)
+ goto out;
+
+ for (j = 0; j < number_of_fields; j++) {
+ tmp = get_struct_variable(j, sts_vals[i]);
+ if (!tmp) {
+ gf_log ("", GF_LOG_ERROR,
+ "struct member empty.");
+ ret = -1;
+ goto out;
+ }
+ if (strlen (tmp) > spacing[j])
+ spacing[j] = strlen (tmp);
+ }
+ }
+
+out:
+ return ret;
+}
+
+int
+gf_cli_gsync_status_output (dict_t *dict, int status_detail)
+{
+ int gsync_count = 0;
+ int i = 0;
+ int j = 0;
+ int ret = 0;
+ int spacing[10] = {0};
+ int num_of_fields = 9;
+ char errmsg[1024] = "";
+ char *master = NULL;
+ char *slave = NULL;
+ char *tmp = NULL;
+ char *title_values[] = {"NODE", "MASTER", "SLAVE",
+ "HEALTH", "UPTIME",
+ "FILES SYNCD",
+ "FILES PENDING",
+ "BYTES PENDING",
+ "DELETES PENDING"};
+ gf_cli_gsync_status_t **sts_vals = NULL;
+
+ /* Checks if any session is active or not */
+ ret = dict_get_int32 (dict, "gsync-count", &gsync_count);
+ if (ret) {
+ ret = dict_get_str (dict, "master", &master);
+
+ ret = dict_get_str (dict, "slave", &slave);
+
+ if (master) {
+ if (slave)
+ snprintf (errmsg, sizeof(errmsg), "No active "
+ "geo-replication sessions between %s"
+ " and %s", master, slave);
+ else
+ snprintf (errmsg, sizeof(errmsg), "No active "
+ "geo-replication sessions for %s",
+ master);
+ } else
+ snprintf (errmsg, sizeof(errmsg), "No active "
+ "geo-replication sessions");
+
+ gf_log ("cli", GF_LOG_INFO, "%s", errmsg);
+ cli_out ("%s", errmsg);
+ ret = 0;
+ goto out;
+ }
+
+ for (i = 0; i < num_of_fields; i++)
+ spacing[i] = strlen(title_values[i]);
+
+ /* gsync_count = number of nodes reporting output.
+ each sts_val object will store output of each
+ node */
+ sts_vals = GF_CALLOC (gsync_count, sizeof (gf_cli_gsync_status_t *),
+ gf_common_mt_char);
+ if (!sts_vals) {
+ ret = -1;
+ goto out;
+ }
+ for (i = 0; i < gsync_count; i++) {
+ sts_vals[i] = GF_CALLOC (1, sizeof (gf_cli_gsync_status_t),
+ gf_common_mt_char);
+ if (!sts_vals[i]) {
+ ret = -1;
+ goto out;
+ }
+ }
+
+ ret = gf_cli_read_status_data (dict, sts_vals, spacing,
+ gsync_count, num_of_fields);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to read status data");
+ goto out;
+ }
+
+ ret = gf_cli_print_status (title_values, sts_vals, spacing, gsync_count,
+ num_of_fields, status_detail);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to print status output");
+ goto out;
+ }
+
+out:
+ if (sts_vals) {
+ for (i = 0; i < gsync_count; i++) {
+ for (j = 3; j < num_of_fields; j++) {
+ tmp = get_struct_variable(j, sts_vals[i]);
+ if (tmp)
+ GF_FREE (tmp);
+ }
+ }
+ GF_FREE (sts_vals);
+ }
+
+ return ret;
+}
+
static int32_t
write_contents_to_common_pem_file (dict_t *dict, int output_count)
{
@@ -4318,6 +4363,8 @@ gf_cli_gsync_set_cbk (struct rpc_req *req, struct iovec *iov,
char *slave = NULL;
int32_t type = 0;
call_frame_t *frame = NULL;
+ gf_boolean_t status_detail = _gf_false;
+
if (req->rpc_status == -1) {
ret = -1;
@@ -4393,7 +4440,10 @@ gf_cli_gsync_set_cbk (struct rpc_req *req, struct iovec *iov,
break;
case GF_GSYNC_OPTION_TYPE_STATUS:
- ret = gf_cli_gsync_out_status (dict);
+ status_detail = dict_get_str_boolean (dict,
+ "status-detail",
+ _gf_false);
+ ret = gf_cli_gsync_status_output (dict, status_detail);
break;
case GF_GSYNC_OPTION_TYPE_DELETE:
@@ -6160,43 +6210,57 @@ out:
return;
}
-
static void
-cli_print_volume_tasks (dict_t *dict) {
- int ret = -1;
- int tasks = 0;
- char *op = 0;
- char *task_id_str = NULL;
- int status = 0;
- char key[1024] = {0,};
- int i = 0;
+cli_print_volume_status_tasks (dict_t *dict)
+{
+ int ret = -1;
+ int i = 0;
+ int j = 0;
+ int count = 0;
+ int task_count = 0;
+ int status = 0;
+ char *op = NULL;
+ char *task_id_str = NULL;
+ char *volname = NULL;
+ char key[1024] = {0,};
+ char task[1024] = {0,};
+ char *brick = NULL;
+ char *src_brick = NULL;
+ char *dest_brick = NULL;
- ret = dict_get_int32 (dict, "tasks", &tasks);
+ ret = dict_get_str (dict, "volname", &volname);
+ if (ret)
+ goto out;
+
+ ret = dict_get_int32 (dict, "tasks", &task_count);
if (ret) {
- gf_log ("cli", GF_LOG_ERROR,
- "Failed to get tasks count");
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get tasks count");
return;
}
- if (tasks == 0) {
+ cli_out ("Task Status of Volume %s", volname);
+ cli_print_line (CLI_BRICK_STATUS_LINE_LEN);
+
+ if (task_count == 0) {
cli_out ("There are no active volume tasks");
+ cli_out (" ");
return;
}
- cli_out ("%15s%40s%15s", "Task", "ID", "Status");
- cli_out ("%15s%40s%15s", "----", "--", "------");
- for (i = 0; i < tasks; i++) {
+ for (i = 0; i < task_count; i++) {
memset (key, 0, sizeof (key));
snprintf (key, sizeof (key), "task%d.type", i);
ret = dict_get_str(dict, key, &op);
if (ret)
return;
+ cli_out ("%-20s : %-20s", "Task", op);
memset (key, 0, sizeof (key));
snprintf (key, sizeof (key), "task%d.id", i);
ret = dict_get_str (dict, key, &task_id_str);
if (ret)
return;
+ cli_out ("%-20s : %-20s", "ID", task_id_str);
memset (key, 0, sizeof (key));
snprintf (key, sizeof (key), "task%d.status", i);
@@ -6204,9 +6268,63 @@ cli_print_volume_tasks (dict_t *dict) {
if (ret)
return;
- cli_out ("%15s%40s%15d", op, task_id_str, status);
+ snprintf (task, sizeof (task), "task%d", i);
+
+ /*
+ Replace brick only has two states - In progress and Complete
+ Ref: xlators/mgmt/glusterd/src/glusterd-replace-brick.c
+ */
+
+ if (!strcmp (op, "Replace brick")) {
+ if (status)
+ status = GF_DEFRAG_STATUS_COMPLETE;
+ else
+ status = GF_DEFRAG_STATUS_STARTED;
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.src-brick", task);
+ ret = dict_get_str (dict, key, &src_brick);
+ if (ret)
+ goto out;
+
+ cli_out ("%-20s : %-20s", "Source Brick", src_brick);
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.dst-brick", task);
+ ret = dict_get_str (dict, key, &dest_brick);
+ if (ret)
+ goto out;
+
+ cli_out ("%-20s : %-20s", "Destination Brick",
+ dest_brick);
+
+ } else if (!strcmp (op, "Remove brick")) {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.count", task);
+ ret = dict_get_int32 (dict, key, &count);
+ if (ret)
+ goto out;
+
+ cli_out ("%-20s", "Removed bricks:");
+
+ for (j = 1; j <= count; j++) {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key),"%s.brick%d",
+ task, j);
+ ret = dict_get_str (dict, key, &brick);
+ if (ret)
+ goto out;
+
+ cli_out ("%-20s", brick);
+ }
+ }
+ cli_out ("%-20s : %-20s", "Status",
+ cli_vol_task_status_str[status]);
+ cli_out (" ");
}
+out:
+ return;
}
static int
@@ -6263,10 +6381,12 @@ gf_cli_status_cbk (struct rpc_req *req, struct iovec *iov,
"status information.");
if (global_state->mode & GLUSTER_MODE_XML) {
- cli_xml_output_str ("volStatus", msg, rsp.op_ret,
- rsp.op_errno, rsp.op_errstr);
- ret = 0;
- goto out;
+ if (!local->all)
+ cli_xml_output_str ("volStatus", msg,
+ rsp.op_ret, rsp.op_errno,
+ rsp.op_errstr);
+ ret = 0;
+ goto out;
}
cli_err ("%s", msg);
@@ -6308,23 +6428,6 @@ gf_cli_status_cbk (struct rpc_req *req, struct iovec *iov,
if ((cmd & GF_CLI_STATUS_NFS) || (cmd & GF_CLI_STATUS_SHD))
notbrick = _gf_true;
- ret = dict_get_int32 (dict, "count", &count);
- if (ret)
- goto out;
- if (count == 0) {
- ret = -1;
- goto out;
- }
-
- ret = dict_get_int32 (dict, "brick-index-max", &brick_index_max);
- if (ret)
- goto out;
- ret = dict_get_int32 (dict, "other-count", &other_count);
- if (ret)
- goto out;
-
- index_max = brick_index_max + other_count;
-
if (global_state->mode & GLUSTER_MODE_XML) {
if (!local->all) {
ret = cli_xml_output_vol_status_begin (local,
@@ -6337,11 +6440,21 @@ gf_cli_status_cbk (struct rpc_req *req, struct iovec *iov,
goto out;
}
}
- ret = cli_xml_output_vol_status (local, dict);
- if (ret) {
- gf_log ("cli", GF_LOG_ERROR,
- "Error outputting to xml");
- goto out;
+ if (cmd & GF_CLI_STATUS_TASKS) {
+ ret = cli_xml_output_vol_status_tasks_detail (local,
+ dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,"Error outputting "
+ "to xml");
+ goto out;
+ }
+ } else {
+ ret = cli_xml_output_vol_status (local, dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Error outputting to xml");
+ goto out;
+ }
}
if (!local->all) {
@@ -6377,6 +6490,10 @@ gf_cli_status_cbk (struct rpc_req *req, struct iovec *iov,
cli_print_volume_status_callpool (dict, notbrick);
goto cont;
break;
+ case GF_CLI_STATUS_TASKS:
+ cli_print_volume_status_tasks (dict);
+ goto cont;
+ break;
default:
break;
}
@@ -6385,6 +6502,17 @@ gf_cli_status_cbk (struct rpc_req *req, struct iovec *iov,
if (ret)
goto out;
+ ret = dict_get_int32 (dict, "brick-index-max", &brick_index_max);
+ if (ret)
+ goto out;
+
+ ret = dict_get_int32 (dict, "other-count", &other_count);
+ if (ret)
+ goto out;
+
+ index_max = brick_index_max + other_count;
+
+
cli_out ("Status of volume: %s", volname);
if ((cmd & GF_CLI_STATUS_DETAIL) == 0) {
@@ -6458,7 +6586,7 @@ gf_cli_status_cbk (struct rpc_req *req, struct iovec *iov,
cli_out (" ");
if ((cmd & GF_CLI_STATUS_MASK) == GF_CLI_STATUS_NONE)
- cli_print_volume_tasks (dict);
+ cli_print_volume_status_tasks (dict);
cont:
ret = rsp.op_ret;
@@ -6534,12 +6662,6 @@ gf_cli_status_volume_all (call_frame_t *frame, xlator_t *this, void *data)
goto out;
}
- if (vol_count == 0) {
- cli_err ("No volumes present");
- ret = 0;
- goto out;
- }
-
/* remove the "all" flag in cmd */
cmd &= ~GF_CLI_STATUS_ALL;
cmd |= GF_CLI_STATUS_VOL;
@@ -6554,6 +6676,12 @@ gf_cli_status_volume_all (call_frame_t *frame, xlator_t *this, void *data)
}
}
+ if (vol_count == 0 && !(global_state->mode & GLUSTER_MODE_XML)) {
+ cli_err ("No volumes present");
+ ret = 0;
+ goto out;
+ }
+
for (i = 0; i < vol_count; i++) {
dict = dict_new ();
@@ -6736,6 +6864,97 @@ gf_cli_umount (call_frame_t *frame, xlator_t *this, void *data)
}
void
+cmd_heal_volume_statistics_out (dict_t *dict, int brick)
+{
+
+ uint64_t num_entries = 0;
+ int ret = 0;
+ char key[256] = {0};
+ char *hostname = NULL;
+ uint64_t i = 0;
+ uint64_t healed_count = 0;
+ uint64_t split_brain_count = 0;
+ uint64_t heal_failed_count = 0;
+ char *start_time_str = NULL;
+ char *end_time_str = NULL;
+ char *crawl_type = NULL;
+ int progress = -1;
+
+ snprintf (key, sizeof key, "%d-hostname", brick);
+ ret = dict_get_str (dict, key, &hostname);
+ if (ret)
+ goto out;
+ cli_out ("------------------------------------------------");
+ cli_out ("\nCrawl statistics for brick no %d", brick);
+ cli_out ("Hostname of brick %s", hostname);
+
+ snprintf (key, sizeof key, "statistics-%d-count", brick);
+ ret = dict_get_uint64 (dict, key, &num_entries);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < num_entries; i++)
+ {
+ snprintf (key, sizeof key, "statistics_crawl_type-%d-%"PRIu64,
+ brick, i);
+ ret = dict_get_str (dict, key, &crawl_type);
+ if (ret)
+ goto out;
+
+ snprintf (key, sizeof key, "statistics_healed_cnt-%d-%"PRIu64,
+ brick,i);
+ ret = dict_get_uint64 (dict, key, &healed_count);
+ if (ret)
+ goto out;
+
+ snprintf (key, sizeof key, "statistics_sb_cnt-%d-%"PRIu64,
+ brick, i);
+ ret = dict_get_uint64 (dict, key, &split_brain_count);
+ if (ret)
+ goto out;
+ snprintf (key, sizeof key, "statistics_heal_failed_cnt-%d-%"PRIu64,
+ brick, i);
+ ret = dict_get_uint64 (dict, key, &heal_failed_count);
+ if (ret)
+ goto out;
+ snprintf (key, sizeof key, "statistics_strt_time-%d-%"PRIu64,
+ brick, i);
+ ret = dict_get_str (dict, key, &start_time_str);
+ if (ret)
+ goto out;
+ snprintf (key, sizeof key, "statistics_end_time-%d-%"PRIu64,
+ brick, i);
+ ret = dict_get_str (dict, key, &end_time_str);
+ if (ret)
+ goto out;
+ snprintf (key, sizeof key, "statistics_inprogress-%d-%"PRIu64,
+ brick, i);
+ ret = dict_get_int32 (dict, key, &progress);
+ if (ret)
+ goto out;
+
+ cli_out ("\nStarting time of crawl: %s", start_time_str);
+ if (progress == 1)
+ cli_out ("Crawl is in progress");
+ else
+ cli_out ("Ending time of crawl: %s", end_time_str);
+
+ cli_out ("Type of crawl: %s", crawl_type);
+ cli_out ("No. of entries healed: %"PRIu64,
+ healed_count);
+ cli_out ("No. of entries in split-brain: %"PRIu64,
+ split_brain_count);
+ cli_out ("No. of heal failed entries: %"PRIu64,
+ heal_failed_count);
+
+ }
+
+
+out:
+ return;
+}
+
+void
cmd_heal_volume_brick_out (dict_t *dict, int brick)
{
uint64_t num_entries = 0;
@@ -6801,6 +7020,53 @@ out:
return;
}
+
+void
+cmd_heal_volume_statistics_heal_count_out (dict_t *dict, int brick)
+{
+ uint64_t num_entries = 0;
+ int ret = 0;
+ char key[256] = {0};
+ char *hostname = NULL;
+ char *path = NULL;
+ char *status = NULL;
+ char *shd_status = NULL;
+
+ snprintf (key, sizeof key, "%d-hostname", brick);
+ ret = dict_get_str (dict, key, &hostname);
+ if (ret)
+ goto out;
+ snprintf (key, sizeof key, "%d-path", brick);
+ ret = dict_get_str (dict, key, &path);
+ if (ret)
+ goto out;
+ cli_out ("\nBrick %s:%s", hostname, path);
+
+ snprintf (key, sizeof key, "%d-status", brick);
+ ret = dict_get_str (dict, key, &status);
+ if (status && strlen (status))
+ cli_out ("Status: %s", status);
+
+ snprintf (key, sizeof key, "%d-shd-status",brick);
+ ret = dict_get_str (dict, key, &shd_status);
+
+ if(!shd_status)
+ {
+ snprintf (key, sizeof key, "%d-hardlinks", brick);
+ ret = dict_get_uint64 (dict, key, &num_entries);
+ if (ret)
+ cli_out ("No gathered input for this brick");
+ else
+ cli_out ("Number of entries: %"PRIu64, num_entries);
+
+
+ }
+
+out:
+ return;
+}
+
+
int
gf_cli_heal_volume_cbk (struct rpc_req *req, struct iovec *iov,
int count, void *myframe)
@@ -6879,6 +7145,15 @@ gf_cli_heal_volume_cbk (struct rpc_req *req, struct iovec *iov,
case GF_AFR_OP_SPLIT_BRAIN_FILES:
heal_op_str = "list of split brain entries";
break;
+ case GF_AFR_OP_STATISTICS:
+ heal_op_str = "crawl statistics";
+ break;
+ case GF_AFR_OP_STATISTICS_HEAL_COUNT:
+ heal_op_str = "count of entries to be healed";
+ break;
+ case GF_AFR_OP_STATISTICS_HEAL_COUNT_PER_REPLICA:
+ heal_op_str = "count of entries to be healed per replica";
+ break;
case GF_AFR_OP_INVALID:
heal_op_str = "invalid heal op";
break;
@@ -6939,8 +7214,28 @@ gf_cli_heal_volume_cbk (struct rpc_req *req, struct iovec *iov,
goto out;
}
- for (i = 0; i < brick_count; i++)
- cmd_heal_volume_brick_out (dict, i);
+ switch (heal_op) {
+ case GF_AFR_OP_STATISTICS:
+ for (i = 0; i < brick_count; i++)
+ cmd_heal_volume_statistics_out (dict, i);
+ break;
+ case GF_AFR_OP_STATISTICS_HEAL_COUNT:
+ case GF_AFR_OP_STATISTICS_HEAL_COUNT_PER_REPLICA:
+ for (i = 0; i < brick_count; i++)
+ cmd_heal_volume_statistics_heal_count_out (dict,
+ i);
+ break;
+ case GF_AFR_OP_INDEX_SUMMARY:
+ case GF_AFR_OP_HEALED_FILES:
+ case GF_AFR_OP_HEAL_FAILED_FILES:
+ case GF_AFR_OP_SPLIT_BRAIN_FILES:
+ for (i = 0; i < brick_count; i++)
+ cmd_heal_volume_brick_out (dict, i);
+ break;
+ default:
+ break;
+ }
+
ret = rsp.op_ret;
out:
@@ -7237,6 +7532,1024 @@ out:
return ret;
}
+int32_t
+cli_snapshot_remove_reply (gf_cli_rsp *rsp, dict_t *dict, call_frame_t *frame)
+{
+ int32_t ret = -1;
+ char *snap_name = NULL;
+
+ GF_ASSERT (rsp);
+ GF_ASSERT (dict);
+ GF_ASSERT (frame);
+
+ if (rsp->op_ret) {
+ cli_err("snapshot delete: failed: %s",
+ rsp->op_errstr ? rsp->op_errstr :
+ "Please check log file for details");
+ ret = rsp->op_ret;
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "snapname", &snap_name);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get snapname");
+ goto out;
+ }
+
+ cli_out ("snapshot delete: %s: snap removed successfully",
+ snap_name);
+ ret = 0;
+
+out:
+ return ret;
+}
+
+int
+cli_snapshot_config_display (dict_t *dict, gf_cli_rsp *rsp)
+{
+ char buf[PATH_MAX] = "";
+ char *volname = NULL;
+ int ret = -1;
+ int config_command = 0;
+ uint64_t value = 0;
+ uint64_t hard_limit = 0;
+ uint64_t soft_limit = 0;
+ uint64_t i = 0;
+ uint64_t voldisplaycount = 0;
+
+ GF_ASSERT (dict);
+ GF_ASSERT (rsp);
+
+ if (rsp->op_ret) {
+ cli_err ("Snapshot Config : failed: %s",
+ rsp->op_errstr ? rsp->op_errstr :
+ "Please check log file for details");
+ ret = rsp->op_ret;
+ goto out;
+ }
+
+ ret = dict_get_int32 (dict, "config-command", &config_command);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch config type");
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "volname", &volname);
+ /* Ignore the error, as volname is optional */
+
+ if (!volname) {
+ volname = "System";
+ }
+
+ ret = dict_get_uint64 (dict, "snap-max-hard-limit", &hard_limit);
+ /* Ignore the error, as the key specified is optional */
+ ret = dict_get_uint64 (dict, "snap-max-soft-limit", &soft_limit);
+
+ if (!hard_limit && !soft_limit
+ && config_command != GF_SNAP_CONFIG_DISPLAY) {
+ ret = -1;
+ gf_log(THIS->name, GF_LOG_ERROR,
+ "Could not fetch config-key");
+ goto out;
+ }
+
+ switch (config_command) {
+ case GF_SNAP_CONFIG_TYPE_SET:
+ if (hard_limit && soft_limit) {
+ cli_out ("snapshot config: snap-max-hard-limit "
+ "& snap-max-soft-limit for system set "
+ "successfully");
+ } else if (hard_limit){
+ cli_out ("snapshot config: %s "
+ "for snap-max-hard-limit set successfully",
+ volname);
+ } else if (soft_limit) {
+ cli_out ("snapshot config: %s "
+ "for snap-max-soft-limit set successfully",
+ volname);
+ }
+ break;
+
+ case GF_SNAP_CONFIG_DISPLAY :
+ cli_out ("\nSnapshot System Configuration:");
+ ret = dict_get_uint64 (dict, "snap-max-hard-limit",
+ &value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch "
+ "snap_max_hard_limit for %s", volname);
+ ret = -1;
+ goto out;
+ }
+ cli_out ("snap-max-hard-limit : %"PRIu64, value);
+
+ ret = dict_get_uint64 (dict, "snap-max-soft-limit",
+ &soft_limit);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch "
+ "snap-max-soft-limit for %s", volname);
+ ret = -1;
+ goto out;
+ }
+ cli_out ("snap-max-soft-limit : %"PRIu64"%%\n",
+ soft_limit);
+
+ cli_out ("Snapshot Volume Configuration:");
+
+ ret = dict_get_uint64 (dict, "voldisplaycount",
+ &voldisplaycount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Could not fetch voldisplaycount");
+ ret = -1;
+ goto out;
+ }
+
+ for (i = 0; i < voldisplaycount; i++) {
+ snprintf (buf, sizeof(buf), "volume%ld-volname", i);
+ ret = dict_get_str (dict, buf, &volname);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch "
+ " %s", buf);
+ ret = -1;
+ goto out;
+ }
+ cli_out ("\nVolume : %s", volname);
+
+ snprintf (buf, sizeof(buf),
+ "volume%ld-snap-max-hard-limit", i);
+ ret = dict_get_uint64 (dict, buf, &value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch "
+ " %s", buf);
+ ret = -1;
+ goto out;
+ }
+ cli_out ("snap-max-hard-limit : %"PRIu64, value);
+
+ snprintf (buf, sizeof(buf),
+ "volume%ld-active-hard-limit", i);
+ ret = dict_get_uint64 (dict, buf, &value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch"
+ " effective snap_max_hard_limit for "
+ "%s", volname);
+ ret = -1;
+ goto out;
+ }
+ cli_out ("Effective snap-max-hard-limit : %"PRIu64,
+ value);
+
+ snprintf (buf, sizeof(buf),
+ "volume%ld-snap-max-soft-limit", i);
+ ret = dict_get_uint64 (dict, buf, &value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch "
+ " %s", buf);
+ ret = -1;
+ goto out;
+ }
+ cli_out ("Effective snap-max-soft-limit : %"PRIu64" "
+ "(%"PRIu64"%%)", value, soft_limit);
+ }
+ break;
+ default :
+ break;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+/* This function is used to print the volume related information
+ * of a snap.
+ *
+ * arg - 0, dict : Response Dictionary.
+ * arg - 1, prefix str : snaplist.snap{0..}.vol{0..}.*
+ */
+int
+cli_get_each_volinfo_in_snap (dict_t *dict, char *keyprefix,
+ gf_boolean_t snap_driven) {
+ char key[PATH_MAX] = "";
+ char *get_buffer = NULL;
+ int value = 0;
+ int ret = -1;
+ char indent[5] = "\t";
+ char *volname = NULL;
+
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+
+ if (snap_driven) {
+ ret = snprintf (key, sizeof (key), "%s.volname", keyprefix);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key, &get_buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get %s", key);
+ goto out;
+ }
+ cli_out ("%s" INDENT_MAIN_HEAD "%s", indent,
+ "Snap Volume Name", ":", get_buffer);
+
+ ret = snprintf (key, sizeof (key),
+ "%s.origin-volname", keyprefix);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key, &volname);
+ if (ret) {
+ gf_log ("cli", GF_LOG_WARNING, "Failed to get %s", key);
+ cli_out ("%-12s", "Origin:");
+ }
+ cli_out ("%s" INDENT_MAIN_HEAD "%s", indent,
+ "Origin Volume name", ":", volname);
+
+
+ ret = snprintf (key, sizeof (key), "%s.snapcount",
+ keyprefix);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_int32 (dict, key, &value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get %s", key);
+ goto out;
+ }
+ cli_out ("%s%s %s %s %d", indent, "Snaps taken for",
+ volname, ":", value);
+
+ ret = snprintf (key, sizeof (key), "%s.snaps-available",
+ keyprefix);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_int32 (dict, key, &value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get %s", key);
+ goto out;
+ }
+ cli_out ("%s%s %s %s %d", indent, "Snaps available for",
+ volname, ":", value);
+ }
+
+
+ ret = snprintf (key, sizeof (key), "%s.vol-status", keyprefix);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key, &get_buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get %s", key);
+ goto out;
+ }
+ cli_out ("%s" INDENT_MAIN_HEAD "%s", indent, "Status",
+ ":", get_buffer);
+out :
+ return ret;
+}
+
+/* This function is used to print snap related information
+ * arg - 0, dict : Response dictionary.
+ * arg - 1, prefix_str : snaplist.snap{0..}.*
+ */
+int
+cli_get_volinfo_in_snap (dict_t *dict, char *keyprefix) {
+
+ char key[PATH_MAX] = "";
+ int i = 0;
+ int volcount = 0;
+ int ret = -1;
+
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+
+ ret = snprintf (key, sizeof (key), "%s.vol-count", keyprefix);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_int32 (dict, key, &volcount);
+ for (i = 1 ; i <= volcount ; i++) {
+ ret = snprintf (key, sizeof (key),
+ "%s.vol%d", keyprefix, i);
+ if (ret < 0) {
+ goto out;
+ }
+ ret = cli_get_each_volinfo_in_snap (dict, key, _gf_true);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not list "
+ "details of volume in a snap");
+ goto out;
+ }
+ cli_out (" ");
+ }
+
+out :
+ return ret;
+}
+
+int
+cli_get_each_snap_info (dict_t *dict, char *prefix_str,
+ gf_boolean_t snap_driven) {
+ char key_buffer[PATH_MAX] = "";
+ char *get_buffer = NULL;
+ int ret = -1;
+ char indent[5] = "";
+
+ GF_ASSERT (dict);
+ GF_ASSERT (prefix_str);
+
+ if (!snap_driven)
+ strcat (indent, "\t");
+
+ ret = snprintf (key_buffer, sizeof (key_buffer), "%s.snapname",
+ prefix_str);
+ if (ret < 0 ) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key_buffer, &get_buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to fetch snapname %s ",
+ key_buffer);
+ goto out;
+ }
+ cli_out ("%s" INDENT_MAIN_HEAD "%s", indent, "Snapshot",
+ ":", get_buffer);
+
+ ret = snprintf (key_buffer, sizeof (key_buffer), "%s.snap-id",
+ prefix_str);
+ if (ret < 0 ) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key_buffer, &get_buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to fetch snap-id %s ",
+ key_buffer);
+ goto out;
+ }
+ cli_out ("%s" INDENT_MAIN_HEAD "%s", indent, "Snap UUID",
+ ":", get_buffer);
+
+ ret = snprintf (key_buffer, sizeof (key_buffer), "%s.snap-desc",
+ prefix_str);
+ if (ret < 0 ) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key_buffer, &get_buffer);
+ if (!ret) {
+ /* Ignore error for description */
+ cli_out ("%s" INDENT_MAIN_HEAD "%s", indent,
+ "Description", ":", get_buffer);
+ }
+
+ ret = snprintf (key_buffer, sizeof (key_buffer), "%s.snap-time",
+ prefix_str);
+ if (ret < 0 ) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key_buffer, &get_buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to fetch snap-time %s ",
+ prefix_str);
+ goto out;
+ }
+ cli_out ("%s" INDENT_MAIN_HEAD "%s", indent, "Created",
+ ":", get_buffer);
+
+ if (snap_driven) {
+ cli_out ("%-12s", "Snap Volumes:\n");
+ ret = cli_get_volinfo_in_snap (dict, prefix_str);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to list details "
+ "of the snaps");
+ goto out;
+ }
+ }
+out :
+ return ret;
+}
+
+/* This is a generic function to print snap related information.
+ * arg - 0, dict : Response Dictionary
+ */
+int
+cli_call_snapshot_info (dict_t *dict, gf_boolean_t bool_snap_driven) {
+ int snap_count = 0;
+ char key[PATH_MAX] = "";
+ int ret = -1;
+ int i = 0;
+
+ GF_ASSERT (dict);
+
+ ret = dict_get_int32 (dict, "snap-count", &snap_count);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to get snap-count");
+ goto out;
+ }
+
+ if (snap_count == 0) {
+ cli_out ("No snapshots present");
+ }
+
+ for (i = 1 ; i <= snap_count ; i++) {
+ ret = snprintf (key, sizeof (key), "snap%d", i);
+ if (ret < 0) {
+ goto out;
+ }
+ ret = cli_get_each_snap_info (dict, key, bool_snap_driven);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Unable to print snap details");
+ goto out;
+ }
+ }
+out :
+ return ret;
+}
+
+int
+cli_get_snaps_in_volume (dict_t *dict) {
+ int ret = -1;
+ int i = 0;
+ int count = 0;
+ int avail = 0;
+ char key[PATH_MAX] = "";
+ char *get_buffer = NULL;
+
+ GF_ASSERT (dict);
+
+ ret = dict_get_str (dict, "origin-volname", &get_buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch origin-volname");
+ goto out;
+ }
+ cli_out (INDENT_MAIN_HEAD "%s", "Volume Name", ":", get_buffer);
+
+ ret = dict_get_int32 (dict, "snap-count", &avail);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch snap-count");
+ goto out;
+ }
+ cli_out (INDENT_MAIN_HEAD "%d", "Snaps Taken", ":", avail);
+
+ ret = dict_get_int32 (dict, "snaps-available", &count);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch snaps-available");
+ goto out;
+ }
+ cli_out (INDENT_MAIN_HEAD "%d", "Snaps Available", ":", count);
+
+ for (i = 1 ; i <= avail ; i++) {
+ snprintf (key, sizeof (key), "snap%d", i);
+ ret = cli_get_each_snap_info (dict, key, _gf_false);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Unable to print snap details");
+ goto out;
+ }
+
+ ret = snprintf (key, sizeof (key), "snap%d.vol1", i);
+ if (ret < 0) {
+ goto out;
+ }
+ ret = cli_get_each_volinfo_in_snap (dict, key, _gf_false);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not get volume "
+ "related information");
+ goto out;
+ }
+
+ cli_out (" ");
+ }
+out :
+ return ret;
+}
+
+int
+cli_snapshot_list (dict_t *dict) {
+ int snapcount = 0;
+ char key[PATH_MAX] = "";
+ int ret = -1;
+ int i = 0;
+ char *get_buffer = NULL;
+
+ GF_ASSERT (dict);
+
+ ret = dict_get_int32 (dict, "snap-count", &snapcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch snap count");
+ goto out;
+ }
+
+ if (snapcount == 0) {
+ cli_out ("No snapshots present");
+ }
+
+ for (i = 1 ; i <= snapcount ; i++) {
+ ret = snprintf (key, sizeof (key), "snapname%d",i);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key, &get_buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not get %s ", key);
+ goto out;
+ } else {
+ cli_out ("%s", get_buffer);
+ }
+ }
+out :
+ return ret;
+}
+
+int
+cli_get_snap_volume_status (dict_t *dict, char *key_prefix)
+{
+ int ret = -1;
+ char key[PATH_MAX] = "";
+ char *buffer = NULL;
+ int brickcount = 0;
+ int i = 0;
+ int pid = 0;
+
+ GF_ASSERT (dict);
+ GF_ASSERT (key_prefix);
+
+ ret = snprintf (key, sizeof (key), "%s.brickcount", key_prefix);
+ if (ret < 0) {
+ goto out;
+ }
+ ret = dict_get_int32 (dict, key, &brickcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to fetch brickcount");
+ goto out;
+ }
+
+ for ( i = 0 ; i < brickcount ; i++ ) {
+ ret = snprintf (key, sizeof (key), "%s.brick%d.path",
+ key_prefix, i);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_INFO,
+ "Unable to get Brick Path");
+ continue;
+ }
+ cli_out ("\n\t%-17s %s %s", "Brick Path", ":", buffer);
+
+ ret = snprintf (key, sizeof (key), "%s.brick%d.vgname",
+ key_prefix, i);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_INFO,
+ "Unable to get Volume Group");
+ cli_out ("\t%-17s %s %s", "Volume Group", ":", "N/A");
+ } else
+ cli_out ("\t%-17s %s %s", "Volume Group", ":", buffer);
+
+ ret = snprintf (key, sizeof (key), "%s.brick%d.status",
+ key_prefix, i);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_INFO,
+ "Unable to get Brick Running");
+ cli_out ("\t%-17s %s %s", "Brick Running", ":", "N/A");
+ } else
+ cli_out ("\t%-17s %s %s", "Brick Running", ":", buffer);
+
+ ret = snprintf (key, sizeof (key), "%s.brick%d.pid",
+ key_prefix, i);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_int32 (dict, key, &pid);
+ if (ret) {
+ gf_log ("cli", GF_LOG_INFO,
+ "Unable to get pid");
+ cli_out ("\t%-17s %s %s", "Brick PID", ":", "N/A");
+ } else
+ cli_out ("\t%-17s %s %d", "Brick PID", ":", pid);
+
+ ret = snprintf (key, sizeof (key), "%s.brick%d.data",
+ key_prefix, i);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_INFO,
+ "Unable to get Data Percent");
+ cli_out ("\t%-17s %s %s", "Data Percentage", ":", "N/A");
+ } else
+ cli_out ("\t%-17s %s %s", "Data Percentage", ":", buffer);
+
+ ret = snprintf (key, sizeof (key), "%s.brick%d.lvsize",
+ key_prefix, i);
+ if (ret < 0) {
+ goto out;
+ }
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_INFO, "Unable to get LV Size");
+ cli_out ("\t%-17s %s %s", "LV Size", ":", "N/A");
+ } else
+ cli_out ("\t%-17s %s %s", "LV Size", ":", buffer);
+
+ }
+out :
+ return ret;
+}
+
+
+
+int
+cli_get_single_snap_status (dict_t *dict, char *keyprefix)
+{
+ int ret = -1;
+ char key[PATH_MAX] = "";
+ int i = 0;
+ int volcount = 0;
+ char *get_buffer = NULL;
+
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+
+ ret = snprintf (key, sizeof (key), "%s.snapname", keyprefix);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key, &get_buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to get snapname");
+ goto out;
+ }
+ cli_out ("\nSnap Name : %s", get_buffer);
+
+ ret = snprintf (key, sizeof (key), "%s.uuid", keyprefix);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key, &get_buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to get snap UUID");
+ goto out;
+ }
+ cli_out ("Snap UUID : %s", get_buffer);
+
+ ret = snprintf (key, sizeof (key), "%s.volcount", keyprefix);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_int32 (dict, key, &volcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to get volume count");
+ goto out;
+ }
+
+ for (i = 0 ; i < volcount ; i++) {
+ ret = snprintf (key, sizeof (key), "%s.vol%d", keyprefix, i);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = cli_get_snap_volume_status (dict, key);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Could not get snap volume status");
+ goto out;
+ }
+ }
+out :
+ return ret;
+}
+
+int
+cli_snap_status_all (dict_t *dict) {
+ int ret = -1;
+ char key[PATH_MAX] = "";
+ int snapcount = 0;
+ int i = 0;
+
+ GF_ASSERT (dict);
+
+ ret = dict_get_int32 (dict, "status.snapcount", &snapcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not get snapcount");
+ goto out;
+ }
+
+ if (snapcount == 0) {
+ cli_out ("No snapshots present");
+ }
+
+ for (i = 0 ; i < snapcount; i++) {
+ ret = snprintf (key, sizeof (key), "status.snap%d",i);
+ if (ret < 0) {
+ goto out;
+ }
+ ret = cli_get_single_snap_status (dict, key);
+ }
+out:
+ return ret;
+}
+
+
+int
+cli_snapshot_status_display (dict_t *dict, gf_cli_rsp *rsp)
+{
+ char key[PATH_MAX] = "";
+ int ret = -1;
+ int status_cmd = -1;
+
+ GF_ASSERT (dict);
+ GF_ASSERT (rsp);
+
+ if (rsp->op_ret) {
+ cli_err ("Snapshot Status : failed: %s",
+ rsp->op_errstr ? rsp->op_errstr :
+ "Please check log file for details");
+ ret = rsp->op_ret;
+ goto out;
+ }
+
+ ret = dict_get_int32 (dict, "cmd", &status_cmd);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch status type");
+ goto out;
+ }
+ switch (status_cmd) {
+ case GF_SNAP_STATUS_TYPE_ALL :
+ {
+ ret = cli_snap_status_all (dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch "
+ "status of all snap");
+ goto out;
+ }
+ break;
+ }
+
+ case GF_SNAP_STATUS_TYPE_SNAP :
+ {
+ ret = snprintf (key, sizeof (key), "status.snap0");
+ if (ret < 0) {
+ goto out;
+ }
+ ret = cli_get_single_snap_status (dict, key);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch "
+ "status of snap");
+ goto out;
+ }
+ break;
+ }
+
+ case GF_SNAP_STATUS_TYPE_VOL :
+ {
+ ret = cli_snap_status_all (dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch "
+ "status of snap in a volume");
+ goto out;
+ }
+ break;
+ }
+ default :
+ break;
+ }
+out :
+ return ret;
+}
+
+int
+gf_cli_snapshot_cbk (struct rpc_req *req, struct iovec *iov,
+ int count, void *myframe)
+{
+ int ret = -1;
+ gf_cli_rsp rsp = {0, };
+ dict_t *dict = NULL;
+ char *snap_name = NULL;
+ int32_t type = 0;
+ call_frame_t *frame = NULL;
+ gf_boolean_t snap_driven = _gf_false;
+
+ if (req->rpc_status == -1) {
+ ret = -1;
+ goto out;
+ }
+
+ frame = myframe;
+
+ ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp);
+ if (ret < 0) {
+ gf_log (frame->this->name, GF_LOG_ERROR,
+ "Failed to decode xdr response");
+ goto out;
+ }
+
+ dict = dict_new ();
+
+ if (!dict) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, &dict);
+
+ if (ret)
+ goto out;
+
+ ret = dict_get_int32 (dict, "type", &type);
+ if (ret) {
+ gf_log (frame->this->name, GF_LOG_ERROR, "failed to get type");
+ goto out;
+ }
+
+ switch (type) {
+ case GF_SNAP_OPTION_TYPE_CREATE:
+ if (rsp.op_ret) {
+ cli_err("snapshot create: failed: %s",
+ rsp.op_errstr ? rsp.op_errstr :
+ "Please check log file for details");
+ ret = rsp.op_ret;
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "snapname", &snap_name);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Failed to get snap name");
+ goto out;
+ }
+ cli_out ("snapshot create: %s: snap created successfully",
+ snap_name);
+ break;
+
+ case GF_SNAP_OPTION_TYPE_RESTORE:
+ /* TODO: Check if rsp.op_ret needs to be checked here. Or is
+ * it ok to check this in the start of the function where we
+ * get rsp.*/
+ if (rsp.op_ret) {
+ cli_err("snapshot restore: failed: %s",
+ rsp.op_errstr ? rsp.op_errstr :
+ "Please check log file for details");
+ ret = rsp.op_ret;
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "snapname", &snap_name);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Failed to get snap name");
+ goto out;
+ }
+
+ cli_out ("Snapshot restore: %s: Snap restored "
+ "successfully", snap_name);
+
+ ret = 0;
+ break;
+
+ case GF_SNAP_OPTION_TYPE_INFO:
+ if (rsp.op_ret) {
+ cli_err ("Snapshot info : failed: %s",
+ rsp.op_errstr ? rsp.op_errstr :
+ "Please check log file for details");
+ ret = rsp.op_ret;
+ goto out;
+ }
+
+ snap_driven = dict_get_str_boolean (dict, "snap-driven",
+ _gf_false);
+ if (snap_driven == _gf_true) {
+ ret = cli_call_snapshot_info (dict, snap_driven);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Snapshot info failed");
+ goto out;
+ }
+ } else if (snap_driven == _gf_false) {
+ ret = cli_get_snaps_in_volume (dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Snapshot info failed");
+ goto out;
+ }
+ }
+ break;
+
+ case GF_SNAP_OPTION_TYPE_CONFIG:
+ ret = cli_snapshot_config_display (dict, &rsp);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to display "
+ "snapshot config output.");
+ goto out;
+ }
+ break;
+
+ case GF_SNAP_OPTION_TYPE_LIST:
+ if (rsp.op_ret) {
+ cli_err ("Snapshot list : failed: %s",
+ rsp.op_errstr ? rsp.op_errstr :
+ "Please check log file for details");
+ ret = rsp.op_ret;
+ goto out;
+ }
+
+ ret = cli_snapshot_list (dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to display "
+ "snapshot list");
+ goto out;
+ }
+ break;
+
+ case GF_SNAP_OPTION_TYPE_DELETE:
+ ret = cli_snapshot_remove_reply (&rsp, dict, frame);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Failed to delete snap");
+ goto out;
+ }
+ break;
+
+ case GF_SNAP_OPTION_TYPE_STATUS:
+ ret = cli_snapshot_status_display (dict, &rsp);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to display "
+ "snapshot status output.");
+ goto out;
+ }
+ break;
+
+ default:
+ cli_err ("Unknown command executed");
+ ret = -1;
+ goto out;
+ }
+out:
+ if (dict)
+ dict_unref (dict);
+ cli_cmd_broadcast_response (ret);
+
+ free (rsp.dict.dict_val);
+ free (rsp.op_errstr);
+
+ return ret;
+}
+
+int32_t
+gf_cli_snapshot (call_frame_t *frame, xlator_t *this,
+ void *data)
+{
+ gf_cli_req req = {{0,}};
+ dict_t *options = NULL;
+ int ret = -1;
+
+ if (!frame || !this || !data)
+ goto out;
+
+ options = data;
+
+ ret = cli_to_glusterd (&req, frame, gf_cli_snapshot_cbk,
+ (xdrproc_t) xdr_gf_cli_req, options,
+ GLUSTER_CLI_SNAP, this, cli_rpc_prog,
+ NULL);
+out:
+ gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret);
+
+ GF_FREE (req.dict.dict_val);
+ return ret;
+}
+
int
cli_to_glusterd (gf_cli_req *req, call_frame_t *frame,
fop_cbk_fn_t cbkfn, xdrproc_t xdrproc, dict_t *dict,
@@ -7348,9 +8661,7 @@ struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = {
[GLUSTER_CLI_CLRLOCKS_VOLUME] = {"CLEARLOCKS_VOLUME", gf_cli_clearlocks_volume},
[GLUSTER_CLI_COPY_FILE] = {"COPY_FILE", gf_cli_copy_file},
[GLUSTER_CLI_SYS_EXEC] = {"SYS_EXEC", gf_cli_sys_exec},
-#ifdef HAVE_BD_XLATOR
- [GLUSTER_CLI_BD_OP] = {"BD_OP", gf_cli_bd_op},
-#endif
+ [GLUSTER_CLI_SNAP] = {"SNAP", gf_cli_snapshot},
};
struct rpc_clnt_program cli_prog = {
diff --git a/cli/src/cli-xml-output.c b/cli/src/cli-xml-output.c
index 6103a2cbd..d8884d44b 100644
--- a/cli/src/cli-xml-output.c
+++ b/cli/src/cli-xml-output.c
@@ -14,6 +14,12 @@
#include "compat.h"
#include "syscall.h"
+
+enum gf_task_types {
+ GF_TASK_TYPE_REBALANCE,
+ GF_TASK_TYPE_REMOVE_BRICK
+};
+
/*
* IMPORTANT NOTE:
* All exported functions in this file which use libxml need use a
@@ -1383,6 +1389,86 @@ out:
#if (HAVE_LIB_XML)
int
+cli_xml_output_remove_brick_task_params (xmlTextWriterPtr writer, dict_t *dict,
+ char *prefix)
+{
+ int ret = -1;
+ char key[1024] = {0,};
+ int count = 0;
+ int i = 0;
+ char *brick = NULL;
+
+ /* <params> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"params");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%s.count", prefix);
+ ret = dict_get_int32 (dict, key, &count);
+ if (ret)
+ goto out;
+
+ for (i = 1; i <= count; i++) {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.brick%d", prefix, i);
+ ret = dict_get_str (dict, key, &brick);
+ if (ret)
+ goto out;
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *)"brick",
+ "%s", brick);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ brick = NULL;
+ }
+
+ /* </param> */
+ ret = xmlTextWriterEndElement (writer);
+
+out:
+ gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret);
+ return ret;
+}
+
+int
+cli_xml_output_replace_brick_task_params (xmlTextWriterPtr writer, dict_t *dict,
+ char *prefix)
+{
+
+ int ret = -1;
+ char key[1024] = {0,};
+ char *brick = NULL;
+
+ /* <params> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"params");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%s.src-brick", prefix);
+ ret = dict_get_str (dict, key, &brick);
+ if (ret)
+ goto out;
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"srcBrick",
+ "%s", brick);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.dst-brick", prefix);
+ ret = dict_get_str (dict, key, &brick);
+ if (ret)
+ goto out;
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"dstBrick",
+ "%s", brick);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+
+ /* </param> */
+ ret = xmlTextWriterEndElement (writer);
+
+out:
+ gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret);
+ return ret;
+}
+
+int
cli_xml_output_vol_status_tasks (cli_local_t *local, dict_t *dict) {
int ret = -1;
char *task_type = NULL;
@@ -1436,6 +1522,36 @@ cli_xml_output_vol_status_tasks (cli_local_t *local, dict_t *dict) {
"%d", status);
XML_RET_CHECK_AND_GOTO (ret, out);
+ if (!strcmp (task_type, "Replace brick")) {
+ if (status) {
+ status = GF_DEFRAG_STATUS_COMPLETE;
+ } else {
+ status = GF_DEFRAG_STATUS_STARTED;
+ }
+ }
+
+ ret = xmlTextWriterWriteFormatElement (local->writer,
+ (xmlChar *)"statusStr",
+ "%s",
+ cli_vol_task_status_str[status]);
+
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "task%d", i);
+ if (!strcmp (task_type, "Replace brick")) {
+ ret = cli_xml_output_replace_brick_task_params
+ (local->writer, dict, key);
+ if (ret)
+ goto out;
+ } else if (!strcmp (task_type, "Remove brick")) {
+ ret = cli_xml_output_remove_brick_task_params
+ (local->writer, dict, key);
+ if (ret)
+ goto out;
+ }
+
+
/* </task> */
ret = xmlTextWriterEndElement (local->writer);
XML_RET_CHECK_AND_GOTO (ret, out);
@@ -1444,11 +1560,40 @@ cli_xml_output_vol_status_tasks (cli_local_t *local, dict_t *dict) {
/* </tasks> */
ret = xmlTextWriterEndElement (local->writer);
-
out:
gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret);
return ret;
}
+
+int
+cli_xml_output_vol_status_tasks_detail (cli_local_t *local, dict_t *dict)
+{
+ int ret = -1;
+ char *volname = NULL;
+
+ /*<volume>*/
+ ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"volume");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_str (dict, "volname", &volname);
+ if (ret)
+ goto out;
+ ret = xmlTextWriterWriteFormatElement (local->writer,
+ (xmlChar *)"volName", "%s",
+ volname);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = cli_xml_output_vol_status_tasks (local, dict);
+ if (ret)
+ goto out;
+
+ /* </volume> */
+ ret = xmlTextWriterEndElement (local->writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+out:
+ return ret;
+}
#endif
int
@@ -1568,7 +1713,6 @@ cli_xml_output_vol_status (cli_local_t *local, dict_t *dict)
goto out;
}
break;
-
default:
break;
@@ -2353,7 +2497,9 @@ cli_xml_output_vol_info (cli_local_t *local, dict_t *dict)
char key[1024] = {0,};
int i = 0;
int j = 1;
-
+ char *caps = NULL;
+ int k __attribute__((unused)) = 0;
+ char *snap_volume = NULL;
ret = dict_get_int32 (dict, "count", &count);
if (ret)
@@ -2395,6 +2541,18 @@ cli_xml_output_vol_info (cli_local_t *local, dict_t *dict)
"%d", status);
XML_RET_CHECK_AND_GOTO (ret, out);
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "volume%d.snap_volume", i);
+ ret = dict_get_str (dict, key, &snap_volume);
+ if (ret)
+ goto out;
+ if (snap_volume) {
+ ret = xmlTextWriterWriteFormatElement (local->writer,
+ (xmlChar *)"snapVol",
+ "%s", snap_volume);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ }
+
ret =xmlTextWriterWriteFormatElement
(local->writer, (xmlChar *)"statusStr", "%s",
cli_vol_status_str[status]);
@@ -2469,6 +2627,62 @@ cli_xml_output_vol_info (cli_local_t *local, dict_t *dict)
"%d", transport);
XML_RET_CHECK_AND_GOTO (ret, out);
+#ifdef HAVE_BD_XLATOR
+ /* <xlators> */
+ ret = xmlTextWriterStartElement (local->writer,
+ (xmlChar *)"xlators");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ for (k = 0; ; k++) {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key),"volume%d.xlator%d", i, k);
+ ret = dict_get_str (dict, key, &caps);
+ if (ret)
+ break;
+
+ /* <xlator> */
+ ret = xmlTextWriterStartElement (local->writer,
+ (xmlChar *)"xlator");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = xmlTextWriterWriteFormatElement
+ (local->writer, (xmlChar *)"name", "%s", caps);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* <capabilities> */
+ ret = xmlTextWriterStartElement (local->writer,
+ (xmlChar *)
+ "capabilities");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ j = 0;
+ for (j = 0; ;j++) {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key),
+ "volume%d.xlator%d.caps%d", i, k, j);
+ ret = dict_get_str (dict, key, &caps);
+ if (ret)
+ break;
+ ret = xmlTextWriterWriteFormatElement
+ (local->writer, (xmlChar *)"capability",
+ "%s", caps);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ }
+ /* </capabilities> */
+ ret = xmlTextWriterEndElement (local->writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ /* </xlator> */
+ ret = xmlTextWriterEndElement (local->writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ }
+ ret = xmlTextWriterFullEndElement (local->writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ /* </xlators> */
+#else
+ caps = 0; /* Avoid compiler warnings when BD not enabled */
+#endif
+ j = 1;
+
/* <bricks> */
ret = xmlTextWriterStartElement (local->writer,
(xmlChar *)"bricks");
@@ -2868,22 +3082,29 @@ out:
#if (HAVE_LIB_XML)
/* Used for rebalance stop/status, remove-brick status */
int
-cli_xml_output_vol_rebalance_status (xmlTextWriterPtr writer, dict_t *dict)
+cli_xml_output_vol_rebalance_status (xmlTextWriterPtr writer, dict_t *dict,
+ enum gf_task_types task_type)
{
int ret = -1;
int count = 0;
char *node_name = NULL;
+ char *node_uuid = NULL;
uint64_t files = 0;
uint64_t size = 0;
uint64_t lookups = 0;
int status_rcd = 0;
uint64_t failures = 0;
+ uint64_t skipped = 0;
uint64_t total_files = 0;
uint64_t total_size = 0;
uint64_t total_lookups = 0;
uint64_t total_failures = 0;
+ uint64_t total_skipped = 0;
char key[1024] = {0,};
int i = 0;
+ int overall_status = -1;
+ double elapsed = 0;
+ double overall_elapsed = 0;
if (!dict) {
ret = 0;
@@ -2905,13 +3126,22 @@ cli_xml_output_vol_rebalance_status (xmlTextWriterPtr writer, dict_t *dict)
XML_RET_CHECK_AND_GOTO (ret, out);
memset (key, 0, sizeof (key));
- snprintf (key, sizeof (key), "node-uuid-%d", i);
+ snprintf (key, sizeof (key), "node-name-%d", i);
ret = dict_get_str (dict, key, &node_name);
if (ret)
goto out;
ret = xmlTextWriterWriteFormatElement (writer,
(xmlChar *)"nodeName",
"%s", node_name);
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "node-uuid-%d", i);
+ ret = dict_get_str (dict, key, &node_uuid);
+ if (ret)
+ goto out;
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *)"id",
+ "%s", node_uuid);
XML_RET_CHECK_AND_GOTO (ret, out);
memset (key, 0, sizeof (key));
@@ -2958,6 +3188,27 @@ cli_xml_output_vol_rebalance_status (xmlTextWriterPtr writer, dict_t *dict)
"%"PRIu64, failures);
XML_RET_CHECK_AND_GOTO (ret, out);
+ /* skipped-%d is not available for remove brick in dict,
+ so using failures as skipped count in case of remove-brick
+ similar to logic used in CLI(non xml output) */
+ if (task_type == GF_TASK_TYPE_REBALANCE) {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "skipped-%d", i);
+ }
+ else {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "failures-%d", i);
+ }
+
+ ret = dict_get_uint64 (dict, key, &skipped);
+ if (ret)
+ goto out;
+ total_skipped += skipped;
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *)"skipped",
+ "%"PRIu64, skipped);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
memset (key, 0, sizeof (key));
snprintf (key, sizeof (key), "status-%d", i);
ret = dict_get_int32 (dict, key, &status_rcd);
@@ -2968,6 +3219,33 @@ cli_xml_output_vol_rebalance_status (xmlTextWriterPtr writer, dict_t *dict)
"%d", status_rcd);
XML_RET_CHECK_AND_GOTO (ret, out);
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *)"statusStr",
+ "%s",
+ cli_vol_task_status_str[status_rcd]);
+
+ memset (key, 0, 256);
+ snprintf (key, 256, "run-time-%d", i);
+ ret = dict_get_double (dict, key, &elapsed);
+ if (ret)
+ goto out;
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *)"runtime",
+ "%.2f", elapsed);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ if (elapsed > overall_elapsed) {
+ overall_elapsed = elapsed;
+ }
+
+ if (-1 == overall_status)
+ overall_status = status_rcd;
+ else if ((GF_DEFRAG_STATUS_COMPLETE == overall_status ||
+ status_rcd > overall_status) &&
+ (status_rcd != GF_DEFRAG_STATUS_COMPLETE))
+ overall_status = status_rcd;
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
/* </node> */
ret = xmlTextWriterEndElement (writer);
XML_RET_CHECK_AND_GOTO (ret, out);
@@ -2994,7 +3272,22 @@ cli_xml_output_vol_rebalance_status (xmlTextWriterPtr writer, dict_t *dict)
"%"PRIu64, total_failures);
XML_RET_CHECK_AND_GOTO (ret, out);
- // TODO : Aggregate status
+ ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"skipped",
+ "%"PRIu64, total_skipped);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"status",
+ "%d", overall_status);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"statusStr",
+ "%s",
+ cli_vol_task_status_str[overall_status]);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"runtime",
+ "%.2f", overall_elapsed);
+ XML_RET_CHECK_AND_GOTO (ret, out);
/* </aggregate> */
ret = xmlTextWriterEndElement (writer);
@@ -3041,7 +3334,8 @@ cli_xml_output_vol_rebalance (gf_cli_defrag_type op, dict_t *dict, int op_ret,
XML_RET_CHECK_AND_GOTO (ret, out);
if ((GF_DEFRAG_CMD_STOP == op) || (GF_DEFRAG_CMD_STATUS == op)) {
- ret = cli_xml_output_vol_rebalance_status (writer, dict);
+ ret = cli_xml_output_vol_rebalance_status (writer, dict,
+ GF_TASK_TYPE_REBALANCE);
if (ret)
goto out;
}
@@ -3092,7 +3386,8 @@ cli_xml_output_vol_remove_brick (gf_boolean_t status_op, dict_t *dict,
}
if (status_op) {
- ret = cli_xml_output_vol_rebalance_status (writer, dict);
+ ret = cli_xml_output_vol_rebalance_status (writer, dict,
+ GF_TASK_TYPE_REMOVE_BRICK);
if (ret)
goto out;
}
diff --git a/cli/src/cli.c b/cli/src/cli.c
index f87038b61..91b315ff1 100644
--- a/cli/src/cli.c
+++ b/cli/src/cli.c
@@ -353,6 +353,12 @@ cli_opt_parse (char *opt, struct cli_state *state)
return 0;
}
+ oarg = strtail (opt, "glusterd-sock=");
+ if (oarg) {
+ state->glusterd_sock = oarg;
+ return 0;
+ }
+
return -1;
}
@@ -414,7 +420,6 @@ cli_state_init (struct cli_state *state)
int ret = 0;
- state->remote_host = "localhost";
state->log_level = -1;
tree = &state->tree;
@@ -501,23 +506,46 @@ cli_rpc_init (struct cli_state *state)
if (!options)
goto out;
- ret = dict_set_str (options, "remote-host", state->remote_host);
- if (ret)
- goto out;
+ /* Connect using to glusterd using the specified method, giving
+ * preference to unix socket connection. If nothing is specified connect
+ * to the default glusterd socket
+ */
+ if (state->glusterd_sock) {
+ gf_log ("cli", GF_LOG_INFO, "Connecting to glusterd using "
+ "sockfile %s", state->glusterd_sock);
+ ret = rpc_transport_unix_options_build (&options,
+ state->glusterd_sock,
+ 0);
+ if (ret)
+ goto out;
+ } else if (state->remote_host) {
+ gf_log ("cli", GF_LOG_INFO, "Connecting to remote glusterd at "
+ "%s", state->remote_host);
+ ret = dict_set_str (options, "remote-host", state->remote_host);
+ if (ret)
+ goto out;
- if (state->remote_port)
- port = state->remote_port;
+ if (state->remote_port)
+ port = state->remote_port;
- ret = dict_set_int32 (options, "remote-port", port);
- if (ret)
- goto out;
+ ret = dict_set_int32 (options, "remote-port", port);
+ if (ret)
+ goto out;
- ret = dict_set_str (options, "transport.address-family", "inet");
- if (ret)
- goto out;
+ ret = dict_set_str (options, "transport.address-family",
+ "inet");
+ if (ret)
+ goto out;
+ } else {
+ gf_log ("cli", GF_LOG_DEBUG, "Connecting to glusterd using "
+ "default socket");
+ ret = rpc_transport_unix_options_build
+ (&options, DEFAULT_GLUSTERD_SOCKFILE, 0);
+ if (ret)
+ goto out;
+ }
rpc = rpc_clnt_new (options, this->ctx, this->name, 16);
-
if (!rpc)
goto out;
@@ -527,7 +555,7 @@ cli_rpc_init (struct cli_state *state)
goto out;
}
- rpc_clnt_start (rpc);
+ ret = rpc_clnt_start (rpc);
out:
if (ret) {
if (rpc)
diff --git a/cli/src/cli.h b/cli/src/cli.h
index 259f3bd39..8daa4b741 100644
--- a/cli/src/cli.h
+++ b/cli/src/cli.h
@@ -18,6 +18,7 @@
#include "rpc-clnt.h"
#include "glusterfs.h"
#include "protocol-common.h"
+#include "logging.h"
#include "cli1-xdr.h"
@@ -32,25 +33,10 @@
#define CLI_DEFAULT_CMD_TIMEOUT 120
#define CLI_TEN_MINUTES_TIMEOUT 600 //Longer timeout for volume top
#define DEFAULT_CLI_LOG_FILE_DIRECTORY DATADIR "/log/glusterfs"
-#define DEFAULT_LOG_FILE_DIRECTORY DATADIR "/log/glusterfs"
-#define DEFAULT_VAR_RUN_DIRECTORY DATADIR "/run/gluster"
#define CLI_VOL_STATUS_BRICK_LEN 55
#define CLI_TAB_LENGTH 8
#define CLI_BRICK_STATUS_LINE_LEN 78
-#define CLI_LOCAL_INIT(local, words, frame, dictionary) \
- do { \
- local = cli_local_get (); \
- \
- if (local) { \
- local->words = words; \
- if (dictionary) \
- local->dict = dictionary; \
- if (frame) \
- frame->local = local; \
- } \
- } while (0)
-
enum argp_option_keys {
ARGP_DEBUG_KEY = 133,
ARGP_PORT_KEY = 'p',
@@ -66,6 +52,7 @@ struct cli_cmd;
extern char *cli_vol_type_str[];
extern char *cli_vol_status_str[];
+extern char *cli_vol_task_status_str[];
typedef int (cli_cmd_cbk_t)(struct cli_state *state,
struct cli_cmd_word *word,
@@ -128,6 +115,8 @@ struct cli_state {
char *log_file;
gf_loglevel_t log_level;
+
+ char *glusterd_sock;
};
struct cli_local {
@@ -147,6 +136,18 @@ struct cli_local {
#endif
};
+struct gf_cli_gsync_detailed_status_ {
+ char *node;
+ char *master;
+ char *slave;
+ char *health;
+ char *uptime;
+ char *files_syncd;
+ char *files_pending;
+ char *bytes_pending;
+ char *deletes_pending;
+};
+
struct cli_volume_status {
int port;
int online;
@@ -165,6 +166,13 @@ struct cli_volume_status {
#endif
};
+struct snap_config_opt_vals_ {
+ char *op_name;
+ char *question;
+};
+
+typedef struct gf_cli_gsync_detailed_status_ gf_cli_gsync_status_t;
+
typedef struct cli_volume_status cli_volume_status_t;
typedef struct cli_local cli_local_t;
@@ -379,7 +387,14 @@ cli_xml_output_generic_volume (char *op, dict_t *dict, int op_ret, int op_errno,
int
cli_xml_output_vol_gsync (dict_t *dict, int op_ret, int op_errno,
char *op_errstr);
+int
+cli_xml_output_vol_status_tasks_detail (cli_local_t *local, dict_t *dict);
char *
is_server_debug_xlator (void *myframe);
+
+int32_t
+cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options,
+ struct cli_state *state);
+
#endif /* __CLI_H__ */
diff --git a/configure.ac b/configure.ac
index f81d82dcc..b3d1ed184 100644
--- a/configure.ac
+++ b/configure.ac
@@ -53,8 +53,8 @@ AC_CONFIG_FILES([Makefile
xlators/storage/Makefile
xlators/storage/posix/Makefile
xlators/storage/posix/src/Makefile
- xlators/storage/bd_map/Makefile
- xlators/storage/bd_map/src/Makefile
+ xlators/storage/bd/Makefile
+ xlators/storage/bd/src/Makefile
xlators/cluster/Makefile
xlators/cluster/afr/Makefile
xlators/cluster/afr/src/Makefile
@@ -113,6 +113,8 @@ AC_CONFIG_FILES([Makefile
xlators/features/marker/src/Makefile
xlators/features/read-only/Makefile
xlators/features/read-only/src/Makefile
+ xlators/features/compress/Makefile
+ xlators/features/compress/src/Makefile
xlators/features/mac-compat/Makefile
xlators/features/mac-compat/src/Makefile
xlators/features/quiesce/Makefile
@@ -129,6 +131,8 @@ AC_CONFIG_FILES([Makefile
xlators/encryption/Makefile
xlators/encryption/rot-13/Makefile
xlators/encryption/rot-13/src/Makefile
+ xlators/encryption/crypt/Makefile
+ xlators/encryption/crypt/src/Makefile
xlators/features/qemu-block/Makefile
xlators/features/qemu-block/src/Makefile
xlators/system/Makefile
@@ -164,6 +168,8 @@ AC_CONFIG_FILES([Makefile
libgfchangelog.pc
api/Makefile
api/src/Makefile
+ api/examples/Makefile
+ api/examples/setup.py
geo-replication/Makefile
geo-replication/src/Makefile
geo-replication/syncdaemon/Makefile
@@ -300,16 +306,15 @@ if test "x$enable_fuse_client" != "xno"; then
fi
AC_ARG_ENABLE([bd-xlator],
- AC_HELP_STRING([--enable-bd-xlator],
- [Build BD xlator]))
+ AC_HELP_STRING([--enable-bd-xlator], [Build BD xlator]))
if test "x$enable_bd_xlator" != "xno"; then
AC_CHECK_LIB([lvm2app],
- [lvm_init,lvm_lv_from_name],
- [HAVE_BD_LIB="yes"],
- [HAVE_BD_LIB="no"])
+ [lvm_init,lvm_lv_from_name],
+ [HAVE_BD_LIB="yes"],
+ [HAVE_BD_LIB="no"])
- if test "x$HAVE_BD_LIB" = "xyes"; then
+if test "x$HAVE_BD_LIB" = "xyes"; then
# lvm_lv_from_name() has been made public with lvm2-2.02.79
AC_CHECK_DECLS(
[lvm_lv_from_name],
@@ -325,10 +330,10 @@ if test "x$enable_bd_xlator" = "xyes" -a "x$HAVE_BD_LIB" = "xno"; then
fi
BUILD_BD_XLATOR=no
-if test "x${enable_bd_xlator}" != "xno" -a "x${HAVE_BD_LIB}" = "xyes"; then
+if test "x${enable-bd-xlator}" != "xno" -a "x${HAVE_BD_LIB}" = "xyes"; then
BUILD_BD_XLATOR=yes
- AC_DEFINE(HAVE_BD_XLATOR, 1, [define if lvm2app library found and bd
- xlator enabled])
+ AC_DEFINE(HAVE_BD_XLATOR, 1, [define if lvm2app library found and bd xlator
+ enabled])
if test "x$NEED_LVM_LV_FROM_NAME_DECL" = "xyes"; then
AC_DEFINE(NEED_LVM_LV_FROM_NAME_DECL, 1, [defined if lvm_lv_from_name()
was not found in the lvm2app.h header, but can be linked])
@@ -337,6 +342,26 @@ fi
AM_CONDITIONAL([ENABLE_BD_XLATOR], [test x$BUILD_BD_XLATOR = xyes])
+# start encryption/crypt section
+
+AC_CHECK_HEADERS([openssl/cmac.h], [have_cmac_h=yes], [have_cmac_h=no])
+
+AC_ARG_ENABLE([crypt-xlator],
+ AC_HELP_STRING([--enable-crypt-xlator], [Build crypt encryption xlator]))
+
+if test "x$enable_crypt_xlator" = "xyes" -a "x$have_cmac_h" = "xno"; then
+ echo "Encryption xlator requires OpenSSL with cmac.h"
+ exit 1
+fi
+
+BUILD_CRYPT_XLATOR=no
+if test "x$enable_crypt_xlator" != "xno" -a "x$have_cmac_h" = "xyes"; then
+ BUILD_CRYPT_XLATOR=yes
+ AC_DEFINE(HAVE_CRYPT_XLATOR, 1, [enable building crypt encryption xlator])
+fi
+
+AM_CONDITIONAL([ENABLE_CRYPT_XLATOR], [test x$BUILD_CRYPT_XLATOR = xyes])
+
AC_SUBST(FUSE_CLIENT_SUBDIR)
# end FUSE section
@@ -409,7 +434,7 @@ if test "x$enable_ibverbs" != "xno"; then
[ibv_get_device_list],
[HAVE_LIBIBVERBS="yes"],
[HAVE_LIBIBVERBS="no"])
- AC_CHECK_LIB([rdmacm], [rdma_create_id], [HAVE_RDMACM="yes"], [HAVE_RDMACM="no"])
+ AC_CHECK_LIB([rdmacm], [rdma_create_id], [HAVE_RDMACM="yes"], [HAVE_RDMACM="no"])
fi
if test "x$enable_ibverbs" = "xyes"; then
@@ -482,6 +507,17 @@ AC_SUBST(SYNCDAEMON_COMPILE)
AC_SUBST(SYNCDAEMON_SUBDIR)
# end SYNCDAEMON section
+# CDC xlator - check if libz is present if so enable HAVE_LIB_Z
+echo -n "checking if libz is present... "
+
+PKG_CHECK_MODULES([ZLIB], [zlib >= 1.2.0],
+ [echo "yes (features requiring zlib enabled)" AC_DEFINE(HAVE_LIB_Z, 1, [define if zlib is present])],
+ [echo "no"] )
+
+AC_SUBST(LIBZ_CFLAGS)
+AC_SUBST(LIBZ_LIBS)
+# end CDC xlator secion
+
# check for systemtap/dtrace
BUILD_SYSTEMTAP=no
AC_MSG_CHECKING([whether to include systemtap tracing support])
@@ -521,11 +557,11 @@ AC_ARG_ENABLE([xml-output],
BUILD_XML_OUTPUT="yes"
if test "x$enable_xml_output" != "xno"; then
#check if libxml is present if so enable HAVE_LIB_XML
- AM_PATH_XML2([2.6.19])
-
+ m4_ifdef([AM_PATH_XML2],[AM_PATH_XML2([2.6.19])], [no_xml=yes])
if test "x${no_xml}" = "x"; then
AC_DEFINE([HAVE_LIB_XML], [1], [Define to 1 if using libxml2.])
else
+ AC_MSG_WARN([libxml2 devel libraries not found disabling XML support])
BUILD_XML_OUTPUT="no"
fi
else
@@ -567,11 +603,15 @@ if test "x${have_linkat}" = "xyes"; then
fi
AC_SUBST(HAVE_LINKAT)
+dnl check for Monotonic clock
+AC_CHECK_FUNC([clock_gettime], [has_monotonic_clock=yes], AC_CHECK_LIB([rt], [clock_gettime], , AC_MSG_WARN([System doesn't have monotonic clock using contrib])))
+
dnl Check for argp
AC_CHECK_HEADER([argp.h], AC_DEFINE(HAVE_ARGP, 1, [have argp]))
AC_CONFIG_SUBDIRS(argp-standalone)
+
BUILD_ARGP_STANDALONE=no
-if test "x${ac_cv_header_argp_h}" = "xno"; then
+if test "x${ac_cv_header_argp_h}" = "xno"; then
BUILD_ARGP_STANDALONE=yes
ARGP_STANDALONE_CPPFLAGS='-I${top_srcdir}/argp-standalone'
ARGP_STANDALONE_LDADD='${top_builddir}/argp-standalone/libargp.a'
@@ -603,7 +643,7 @@ if test "x${have_posix_fallocate}" = "xyes"; then
fi
-# Check the distribution where you are compiling glusterfs on
+# Check the distribution where you are compiling glusterfs on
GF_DISTRIBUTION=
AC_CHECK_FILE([/etc/debian_version])
@@ -651,7 +691,6 @@ fi
case $host_os in
linux*)
- dnl GF_LINUX_HOST_OS=1
GF_HOST_OS="GF_LINUX_HOST_OS"
GF_CFLAGS="${ARGP_STANDALONE_CPPFLAGS} -O0"
GF_GLUSTERFS_CFLAGS="${GF_CFLAGS}"
@@ -843,9 +882,10 @@ echo "georeplication : $BUILD_SYNCDAEMON"
echo "Linux-AIO : $BUILD_LIBAIO"
echo "Enable Debug : $BUILD_DEBUG"
echo "systemtap : $BUILD_SYSTEMTAP"
-echo "Block Device backend : $BUILD_BD_XLATOR"
+echo "Block Device xlator : $BUILD_BD_XLATOR"
echo "glupy : $BUILD_GLUPY"
echo "Use syslog : $USE_SYSLOG"
echo "XML output : $BUILD_XML_OUTPUT"
echo "QEMU Block formats : $BUILD_QEMU_BLOCK"
+echo "Encryption xlator : $BUILD_CRYPT_XLATOR"
echo
diff --git a/contrib/qemu/config-host.h b/contrib/qemu/config-host.h
index 874b04053..46b1595a8 100644
--- a/contrib/qemu/config-host.h
+++ b/contrib/qemu/config-host.h
@@ -64,7 +64,6 @@
#define CONFIG_OPEN_BY_HANDLE 1
#define CONFIG_LINUX_MAGIC_H 1
#define CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE 1
-#define CONFIG_VALGRIND_H 1
#define CONFIG_HAS_ENVIRON 1
#define CONFIG_CPUID_H 1
#define CONFIG_INT128 1
diff --git a/contrib/qemu/coroutine-ucontext.c b/contrib/qemu/coroutine-ucontext.c
new file mode 100644
index 000000000..4bf2cde27
--- /dev/null
+++ b/contrib/qemu/coroutine-ucontext.c
@@ -0,0 +1,225 @@
+/*
+ * ucontext coroutine initialization code
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2011 Kevin Wolf <kwolf@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* XXX Is there a nicer way to disable glibc's stack check for longjmp? */
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+#include <stdlib.h>
+#include <setjmp.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <ucontext.h>
+#include "qemu-common.h"
+#include "block/coroutine_int.h"
+
+#ifdef CONFIG_VALGRIND_H
+#include <valgrind/valgrind.h>
+#endif
+
+typedef struct {
+ Coroutine base;
+ void *stack;
+ sigjmp_buf env;
+
+#ifdef CONFIG_VALGRIND_H
+ unsigned int valgrind_stack_id;
+#endif
+
+} CoroutineUContext;
+
+/**
+ * Per-thread coroutine bookkeeping
+ */
+typedef struct {
+ /** Currently executing coroutine */
+ Coroutine *current;
+
+ /** The default coroutine */
+ CoroutineUContext leader;
+} CoroutineThreadState;
+
+static pthread_key_t thread_state_key;
+
+/*
+ * va_args to makecontext() must be type 'int', so passing
+ * the pointer we need may require several int args. This
+ * union is a quick hack to let us do that
+ */
+union cc_arg {
+ void *p;
+ int i[2];
+};
+
+static CoroutineThreadState *coroutine_get_thread_state(void)
+{
+ CoroutineThreadState *s = pthread_getspecific(thread_state_key);
+
+ if (!s) {
+ s = g_malloc0(sizeof(*s));
+ s->current = &s->leader.base;
+ pthread_setspecific(thread_state_key, s);
+ }
+ return s;
+}
+
+static void qemu_coroutine_thread_cleanup(void *opaque)
+{
+ CoroutineThreadState *s = opaque;
+
+ g_free(s);
+}
+
+static void __attribute__((constructor)) coroutine_init(void)
+{
+ int ret;
+
+ ret = pthread_key_create(&thread_state_key, qemu_coroutine_thread_cleanup);
+ if (ret != 0) {
+ fprintf(stderr, "unable to create leader key: %s\n", strerror(errno));
+ abort();
+ }
+}
+
+static void coroutine_trampoline(int i0, int i1)
+{
+ union cc_arg arg;
+ CoroutineUContext *self;
+ Coroutine *co;
+
+ arg.i[0] = i0;
+ arg.i[1] = i1;
+ self = arg.p;
+ co = &self->base;
+
+ /* Initialize longjmp environment and switch back the caller */
+ if (!sigsetjmp(self->env, 0)) {
+ siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
+ }
+
+ while (true) {
+ co->entry(co->entry_arg);
+ qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
+ }
+}
+
+Coroutine *qemu_coroutine_new(void)
+{
+ const size_t stack_size = 1 << 20;
+ CoroutineUContext *co;
+ ucontext_t old_uc, uc;
+ sigjmp_buf old_env;
+ union cc_arg arg = {0};
+
+ /* The ucontext functions preserve signal masks which incurs a
+ * system call overhead. sigsetjmp(buf, 0)/siglongjmp() does not
+ * preserve signal masks but only works on the current stack.
+ * Since we need a way to create and switch to a new stack, use
+ * the ucontext functions for that but sigsetjmp()/siglongjmp() for
+ * everything else.
+ */
+
+ if (getcontext(&uc) == -1) {
+ abort();
+ }
+
+ co = g_malloc0(sizeof(*co));
+ co->stack = g_malloc(stack_size);
+ co->base.entry_arg = &old_env; /* stash away our jmp_buf */
+
+ uc.uc_link = &old_uc;
+ uc.uc_stack.ss_sp = co->stack;
+ uc.uc_stack.ss_size = stack_size;
+ uc.uc_stack.ss_flags = 0;
+
+#ifdef CONFIG_VALGRIND_H
+ co->valgrind_stack_id =
+ VALGRIND_STACK_REGISTER(co->stack, co->stack + stack_size);
+#endif
+
+ arg.p = co;
+
+ makecontext(&uc, (void (*)(void))coroutine_trampoline,
+ 2, arg.i[0], arg.i[1]);
+
+ /* swapcontext() in, siglongjmp() back out */
+ if (!sigsetjmp(old_env, 0)) {
+ swapcontext(&old_uc, &uc);
+ }
+ return &co->base;
+}
+
+#ifdef CONFIG_VALGRIND_H
+#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
+/* Work around an unused variable in the valgrind.h macro... */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#endif
+static inline void valgrind_stack_deregister(CoroutineUContext *co)
+{
+ VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id);
+}
+#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
+#pragma GCC diagnostic pop
+#endif
+#endif
+
+void qemu_coroutine_delete(Coroutine *co_)
+{
+ CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
+
+#ifdef CONFIG_VALGRIND_H
+ valgrind_stack_deregister(co);
+#endif
+
+ g_free(co->stack);
+ g_free(co);
+}
+
+CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
+ CoroutineAction action)
+{
+ CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_);
+ CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_);
+ CoroutineThreadState *s = coroutine_get_thread_state();
+ int ret;
+
+ s->current = to_;
+
+ ret = sigsetjmp(from->env, 0);
+ if (ret == 0) {
+ siglongjmp(to->env, action);
+ }
+ return ret;
+}
+
+Coroutine *qemu_coroutine_self(void)
+{
+ CoroutineThreadState *s = coroutine_get_thread_state();
+
+ return s->current;
+}
+
+bool qemu_in_coroutine(void)
+{
+ CoroutineThreadState *s = pthread_getspecific(thread_state_key);
+
+ return s && s->current->caller;
+}
diff --git a/contrib/qemu/qemu-coroutine.c b/contrib/qemu/qemu-coroutine.c
index 423430d3a..5e19307ee 100644
--- a/contrib/qemu/qemu-coroutine.c
+++ b/contrib/qemu/qemu-coroutine.c
@@ -20,7 +20,7 @@
enum {
/* Maximum free pool size prevents holding too many freed coroutines */
- POOL_MAX_SIZE = 64,
+ POOL_MAX_SIZE = 0,
};
/** Free list to speed up creation */
diff --git a/doc/admin-guide/en-US/markdown/admin_managing_snapshots.md b/doc/admin-guide/en-US/markdown/admin_managing_snapshots.md
new file mode 100644
index 000000000..e76ee9151
--- /dev/null
+++ b/doc/admin-guide/en-US/markdown/admin_managing_snapshots.md
@@ -0,0 +1,66 @@
+Managing GlusterFS Volume Snapshots
+==========================
+
+This section describes how to perform common GlusterFS volume snapshot
+management operations
+
+Pre-requisites
+=====================
+
+GlusterFS volume snapshot feature is based on thinly provisioned LVM snapshot.
+To make use of snapshot feature GlusterFS volume should fulfill following
+pre-requisites:
+
+* Each brick should be on an independent thinly provisioned LVM.
+* Brick LVM should not contain any other data other than brick.
+* None of the brick should be on a thick LVM.
+
+
+Snapshot Management
+=====================
+
+
+**Snapshot creation**
+
+*gluster snapshot create \<vol-name\> \[-n \<snap-name\>\] \[-d \<description\>\]*
+
+This command will create a snapshot of a GlusterFS volume. User can provide a snap-name and a description to identify the snap. The description cannot be more than 1024 characters.
+
+Volume should be present and it should be in started state.
+
+**Restoring snaps**
+
+*gluster snapshot restore -v \<vol-name\> \<snap-name\>*
+
+This command restores an already taken snapshot of a GlusterFS volume. Snapshot restore is an offline activity therefore if the volume is online then the restore operation will fail.
+
+Once the snapshot is restored it will be deleted from the list of snapshot.
+
+**Deleting snaps**
+
+*gluster snapshot delete \<volname\>\ -s \<snap-name\> \[force\]*
+
+This command will delete the specified snapshot.
+
+**Listing of available snaps**
+
+*gluster snapshot list \[\<volname\> \[-s \<snap-name>\]\]*
+
+This command is used to list all snapshots taken, or for a specified volume. If snap-name is provided then it will list the details of that snap.
+
+**Configuring the snapshot behavior**
+
+*gluster snapshot config \[\<vol-name | all\>\]*
+
+This command will display existing config values for a volume. If volume name is not provided then config values of all the volume is displayed. System config is displayed irrespective of volume name.
+
+*gluster snapshot config \<vol-name | all\> \[\<snap-max-hard-limit\> \<count\>\] \[\<snap-max-soft-limit\> \<percentage\>\]*
+
+The above command can be used to change the existing config values. If vol-name is provided then config value of that volume is changed, else it will set/change the system limit.
+
+The system limit is the default value of the config for all the volume. Volume specific limit cannot cross the system limit. If a volume specific limit is not provided then system limit will be considered.
+
+If any of this limit is decreased and the current snap count of the system/volume is more than the limit then the command will fail. If user still want to decrease the limit then force option should be used.
+
+
+
diff --git a/doc/features/bd.txt b/doc/features/bd.txt
deleted file mode 100644
index c1ba006ef..000000000
--- a/doc/features/bd.txt
+++ /dev/null
@@ -1,130 +0,0 @@
-Sections
-1. Introduction
-2. Advantages
-3. Creating BD backend volume
-4. BD volume file
-5. Using BD backend gluster volume
-6. Limitations
-7. TODO
-
-1. Introduction
-===============
-Block Device translator(BD xlator) represented as storage/bd_map in
-volume file adds a new backend 'block' to GlusterFS. It enables
-GlusterFS to export block devices as regular files to the client.
-Currently BD xlator supports exporting of 'Volume Group(VG)' as
-directory and Logical Volumes(LV) within that VG as regular files to the
-client.
-
-The eventual goal of this work is to support thin provisioning,
-snapshot, copy etc of VM images seamlessly in GlusterFS storage
-environment
-
-The immediate goal of this translator is to use LVs to store
-VM images and expose them as files to QEMU/KVM. Given VG is represented
-as directory and its logical volumes as files.
-
-BD xlator uses lvm2-devel APIs for getting the list of VGs and LVs in
-the system and lvm binaries (such as lvcreate, lvresize etc) to perform
-the required LV operations.
-
-2. Advantages
-=============
-By exporting LVs as regular files, it becomes possible to:
-* Associate each VM to a LV so that there is no file system overhead.
-* Use file system commands like cp to take copy of VM images
-* Create linked clones of VM by doing LV snapshot at server
-side
-* Implement thin provisioning by developing a qcow2 translator
-
-3. Creating BD backend volume
-=============================
-New parameter "device vg" in volume create command is used to create BD
-backend gluster volumes.
-
-For example
- $ gluster volume create my-volume device vg hostname:/my-vg
-
-creates gluster volume 'my-volume' with BD backend which uses the VG
-'my-vg' to store data. VG 'my-vg' should exist before creating this
-gluster volume.
-
-4. BD volume file
-=================
-BD backend volume file specifies which VG to export to the client. The
-section in the volume file that describes BD xlator looks like this.
-
-volume my-volume-bd_map
-type storage/bd_map
-option device vg
-option export volume-group
-end-volume
-
-option device=vg specifies that it should use VG as block backend. option
-export=volume-group specifies that it should export VG "volume-group"
-to the client.
-
-5. Using BD backend gluster volume
-==================================
-Mount
------
- $ mount -t glusterfs hostname:/my-volume /media/bd
- $ cd /media/bd
-
-From the mount point:
---------------------
-* Creating a new file (ie LV) involves two steps
- $ touch lv1
- $ truncate -s <size> lv1
- or
- $ qemu-img create -f <format> gluster:/hostname/my-volume/path-to-image <size>
-
-* Cloning an LV
- $ ln lv1 lv2
-
-* Snapshotting an LV
- $ ln -s lv1 lv1-ss
-
-* Passing it to QEMU as one of the drives
- $ qemu -drive file=<mount>/<file>,if=<if-type>
-
-* GlusterFS is one of the supported QEMU block drivers, the URI format
- is
- gluster[+transport]://[server[:port]]/my-volume/image[?socket=...]
- ie
- $ qemu -drive file=gluster:/hostname/my-volume/path-to-image,if=<if-type>
-
-Using Gluster CLI:
------------------
-* To create a new image of required size
- $ gluster bd create my-volume:/path-to-image <size>
-
-* To delete an existing image
- $ gluster bd delete my-volume:/path-to-image
-
-* To clone (full clone) an image
- $ gluster bd clone my-volume:/path-to-image new-image
-
-* To take a snapshot of an image
- $ gluster bd snapshot my-volume:/path-to-image snapshot-image <size>
-
-All gluster BD commands need size to specified in terms of KB, MB, etc.
-
-6. Limitations
-==============
-* No support to create multiple bricks
-* Image creation should be used with truncate to get proper size or use
- qemu-img create
-* cp command can't be used to copy images, instead use ln command or
- gluster bd clone command
-* ln -s command throws an error even if snapshot is successful
-* When ln command used on BD volumes, target file's inode is different
- from target's
-* Creation/deletion of directories, xattr operations, mknod and readlink
- operations are not supported.
-
-7. TODO
-=======
-Add support for exporting LUNs also as a regular files.
-Add support for xattr and multi brick support
-Include support for device mapper thin targets
diff --git a/doc/gluster.8 b/doc/gluster.8
index b23e2c891..3c78fb8b1 100644
--- a/doc/gluster.8
+++ b/doc/gluster.8
@@ -8,7 +8,7 @@
.\" cases as published by the Free Software Foundation.
.\"
.\"
-.TH Gluster 8 "Gluster command line utility" "22 November 2012" "Gluster Inc."
+.TH Gluster 8 "Gluster command line utility" "07 March 2011" "Gluster Inc."
.SH NAME
gluster - Gluster Console Manager (command line utility)
.SH SYNOPSIS
@@ -36,11 +36,9 @@ The Gluster Console Manager is a command line utility for elastic volume managem
\fB\ volume info [all|<VOLNAME>] \fR
Display information about all volumes, or the specified volume.
.TP
-\fB\ volume create <NEW-VOLNAME> [device vg] [stripe <COUNT>] [replica <COUNT>] [transport <tcp|rdma|tcp,rdma>] <NEW-BRICK> ... \fR
+\fB\ volume create <NEW-VOLNAME> [stripe <COUNT>] [replica <COUNT>] [transport <tcp|rdma|tcp,rdma>] <NEW-BRICK> ... \fR
Create a new volume of the specified type using the specified bricks and transport type (the default transport type is tcp).
To create a volume with both transports (tcp and rdma), give 'transport tcp,rdma' as an option.
-device vg parameter specifies volume should use block backend instead of regular posix backend. In this case NEW-BRICK should specify an existing Volume Group and there can be only one brick for Block backend volumes. \fR
-Refer Block backend section for more details
.TP
\fB\ volume delete <VOLNAME> \fR
Delete the specified volume.
@@ -59,9 +57,6 @@ Set the volume options.
.TP
\fB\ volume help \fR
Display help for the volume command.
-.SS "Block backend"
-.TP
-By specifying "device vg" in volume create, a volume capable of exporting block devices(ie Volume Groups (VG)) is created. As of now exporting only VG is supported. While creating block backend volume the "VG" (mentioned in NEW-BRICK) must exist (ie created with vgcreate). VG is exported as a directory and all LVs under that VG will be exported as files. Please refer BD commands section for Block backend related commands
.SS "Brick Commands"
.PP
.TP
@@ -110,20 +105,6 @@ Display the status of peers.
.TP
\fB\ peer help \fR
Display help for the peer command.
-.SS "BD commands"
-.TP
-\fB\ bd create <VOLNAME:/path-to-image> <size> \fR
-Creates a new image of given size in the volume. Size can be suffixed with MB, GB etc, if nothing specified MB is taken as default.
-.TP
-\fB\ bd delete <VOLNAME:/path-to-image> \fR
-Deletes a image in the volume
-.TP
-\fB\ bd clone <VOLNAME:/path-to-image> <new-image> \fR
-Clones an existing image (full clone)
-.TP
-\fB\ bd snapshot <VOLNAME:/path-to-image> <new-image> <size> \fR
-Creates a linked clone of an existing image with given size. Size can be suffixed with MB, GB etc, if nothing specified MB is taken as default.
-
.SS "Other Commands"
.TP
\fB\ help \fR
diff --git a/doc/split-brain.md b/doc/split-brain.md
new file mode 100644
index 000000000..b0d938e26
--- /dev/null
+++ b/doc/split-brain.md
@@ -0,0 +1,251 @@
+Steps to recover from File split-brain.
+======================================
+
+Quick Start:
+============
+1. Get the path of the file that is in split-brain:
+> It can be obtained either by
+> a) The command `gluster volume heal info split-brain`.
+> b) Identify the files for which file operations performed
+ from the client keep failing with Input/Output error.
+
+2. Close the applications that opened this file from the mount point.
+In case of VMs, they need to be powered-off.
+
+3. Decide on the correct copy:
+> This is done by observing the afr changelog extended attributes of the file on
+the bricks using the getfattr command; then identifying the type of split-brain
+(data split-brain, metadata split-brain, entry split-brain or split-brain due to
+gfid-mismatch); and finally determining which of the bricks contains the 'good copy'
+of the file.
+> `getfattr -d -m . -e hex <file-path-on-brick>`.
+It is also possible that one brick might contain the correct data while the
+other might contain the correct metadata.
+
+4. Reset the relevant extended attribute on the brick(s) that contains the
+'bad copy' of the file data/metadata using the setfattr command.
+> `setfattr -n <attribute-name> -v <attribute-value> <file-path-on-brick>`
+
+5. Trigger self-heal on the file by performing lookup from the client:
+> `ls -l <file-path-on-gluster-mount>`
+
+Detailed Instructions for steps 3 through 5:
+===========================================
+To understand how to resolve split-brain we need to know how to interpret the
+afr changelog extended attributes.
+
+Execute `getfattr -d -m . -e hex <file-path-on-brick>`
+
+* Example:
+[root@store3 ~]# getfattr -d -e hex -m. brick-a/file.txt
+\#file: brick-a/file.txt
+security.selinux=0x726f6f743a6f626a6563745f723a66696c655f743a733000
+trusted.afr.vol-client-2=0x000000000000000000000000
+trusted.afr.vol-client-3=0x000000000200000000000000
+trusted.gfid=0x307a5c9efddd4e7c96e94fd4bcdcbd1b
+
+The extended attributes with `trusted.afr.<volname>-client-<subvolume-index>`
+are used by afr to maintain changelog of the file.The values of the
+`trusted.afr.<volname>-client-<subvolume-index>` are calculated by the glusterfs
+client (fuse or nfs-server) processes. When the glusterfs client modifies a file
+or directory, the client contacts each brick and updates the changelog extended
+attribute according to the response of the brick.
+
+'subvolume-index' is nothing but (brick number - 1) in
+`gluster volume info <volname>` output.
+
+* Example:
+[root@pranithk-laptop ~]# gluster volume info vol
+ Volume Name: vol
+ Type: Distributed-Replicate
+ Volume ID: 4f2d7849-fbd6-40a2-b346-d13420978a01
+ Status: Created
+ Number of Bricks: 4 x 2 = 8
+ Transport-type: tcp
+ Bricks:
+ brick-a: pranithk-laptop:/gfs/brick-a
+ brick-b: pranithk-laptop:/gfs/brick-b
+ brick-c: pranithk-laptop:/gfs/brick-c
+ brick-d: pranithk-laptop:/gfs/brick-d
+ brick-e: pranithk-laptop:/gfs/brick-e
+ brick-f: pranithk-laptop:/gfs/brick-f
+ brick-g: pranithk-laptop:/gfs/brick-g
+ brick-h: pranithk-laptop:/gfs/brick-h
+
+In the example above:
+```
+Brick | Replica set | Brick subvolume index
+----------------------------------------------------------------------------
+-/gfs/brick-a | 0 | 0
+-/gfs/brick-b | 0 | 1
+-/gfs/brick-c | 1 | 2
+-/gfs/brick-d | 1 | 3
+-/gfs/brick-e | 2 | 4
+-/gfs/brick-f | 2 | 5
+-/gfs/brick-g | 3 | 6
+-/gfs/brick-h | 3 | 7
+```
+
+Each file in a brick maintains the changelog of itself and that of the files
+present in all the other bricks in it's replica set as seen by that brick.
+
+In the example volume given above, all files in brick-a will have 2 entries,
+one for itself and the other for the file present in it's replica pair, i.e.brick-b:
+trusted.afr.vol-client-0=0x000000000000000000000000 -->changelog for itself (brick-a)
+trusted.afr.vol-client-1=0x000000000000000000000000 -->changelog for brick-b as seen by brick-a
+
+Likewise, all files in brick-b will have:
+trusted.afr.vol-client-0=0x000000000000000000000000 -->changelog for brick-a as seen by brick-b
+trusted.afr.vol-client-1=0x000000000000000000000000 -->changelog for itself (brick-b)
+
+The same can be extended for other replica pairs.
+
+Interpreting Changelog (roughly pending operation count) Value:
+Each extended attribute has a value which is 24 hexa decimal digits.
+First 8 digits represent changelog of data. Second 8 digits represent changelog
+of metadata. Last 8 digits represent Changelog of directory entries.
+
+Pictorially representing the same, we have:
+```
+0x 000003d7 00000001 00000000
+ | | |
+ | | \_ changelog of directory entries
+ | \_ changelog of metadata
+ \ _ changelog of data
+```
+
+
+For Directories metadata and entry changelogs are valid.
+For regular files data and metadata changelogs are valid.
+For special files like device files etc metadata changelog is valid.
+When a file split-brain happens it could be either data split-brain or
+meta-data split-brain or both. When a split-brain happens the changelog of the
+file would be something like this:
+
+* Example:(Lets consider both data, metadata split-brain on same file).
+[root@pranithk-laptop vol]# getfattr -d -m . -e hex /gfs/brick-?/a
+getfattr: Removing leading '/' from absolute path names
+\#file: gfs/brick-a/a
+trusted.afr.vol-client-0=0x000000000000000000000000
+trusted.afr.vol-client-1=0x000003d70000000100000000
+trusted.gfid=0x80acdbd886524f6fbefa21fc356fed57
+\#file: gfs/brick-b/a
+trusted.afr.vol-client-0=0x000003b00000000100000000
+trusted.afr.vol-client-1=0x000000000000000000000000
+trusted.gfid=0x80acdbd886524f6fbefa21fc356fed57
+
+###Observations:
+
+####According to changelog extended attributes on file /gfs/brick-a/a:
+The first 8 digits of trusted.afr.vol-client-0 are all
+zeros (0x00000000................), and the first 8 digits of
+trusted.afr.vol-client-1 are not all zeros (0x000003d7................).
+So the changelog on /gfs/brick-a/a implies that some data operations succeeded
+on itself but failed on /gfs/brick-b/a.
+
+The second 8 digits of trusted.afr.vol-client-0 are
+all zeros (0x........00000000........), and the second 8 digits of
+trusted.afr.vol-client-1 are not all zeros (0x........00000001........).
+So the changelog on /gfs/brick-a/a implies that some metadata operations succeeded
+on itself but failed on /gfs/brick-b/a.
+
+####According to Changelog extended attributes on file /gfs/brick-b/a:
+The first 8 digits of trusted.afr.vol-client-0 are not all
+zeros (0x000003b0................), and the first 8 digits of
+trusted.afr.vol-client-1 are all zeros (0x00000000................).
+So the changelog on /gfs/brick-b/a implies that some data operations succeeded
+on itself but failed on /gfs/brick-a/a.
+
+The second 8 digits of trusted.afr.vol-client-0 are not
+all zeros (0x........00000001........), and the second 8 digits of
+trusted.afr.vol-client-1 are all zeros (0x........00000000........).
+So the changelog on /gfs/brick-b/a implies that some metadata operations succeeded
+on itself but failed on /gfs/brick-a/a.
+
+Since both the copies have data, metadata changes that are not on the other
+file, it is in both data and metadata split-brain.
+
+Deciding on the correct copy:
+-----------------------------
+The user may have to inspect stat,getfattr output of the files to decide which
+metadata to retain and contents of the file to decide which data to retain.
+Continuing with the example above, lets say we want to retain the data
+of /gfs/brick-a/a and metadata of /gfs/brick-b/a.
+
+Resetting the relevant changelogs to resolve the split-brain:
+-------------------------------------------------------------
+For resolving data-split-brain:
+We need to change the changelog extended attributes on the files as if some data
+operations succeeded on /gfs/brick-a/a but failed on /gfs/brick-b/a. But
+/gfs/brick-b/a should NOT have any changelog which says some data operations
+succeeded on /gfs/brick-b/a but failed on /gfs/brick-a/a. We need to reset the
+data part of the changelog on trusted.afr.vol-client-0 of /gfs/brick-b/a.
+
+For resolving metadata-split-brain:
+We need to change the changelog extended attributes on the files as if some
+metadata operations succeeded on /gfs/brick-b/a but failed on /gfs/brick-a/a.
+But /gfs/brick-a/a should NOT have any changelog which says some metadata
+operations succeeded on /gfs/brick-a/a but failed on /gfs/brick-b/a.
+We need to reset metadata part of the changelog on
+trusted.afr.vol-client-1 of /gfs/brick-a/a
+
+So, the intended changes are:
+On /gfs/brick-b/a:
+For trusted.afr.vol-client-0
+0x000003b00000000100000000 to 0x000000000000000100000000
+(Note that the metadata part is still not all zeros)
+Hence execute
+`setfattr -n trusted.afr.vol-client-0 -v 0x000000000000000100000000 /gfs/brick-b/a`
+
+On /gfs/brick-a/a:
+For trusted.afr.vol-client-1
+0x0000000000000000ffffffff to 0x000003d70000000000000000
+(Note that the data part is still not all zeros)
+Hence execute
+`setfattr -n trusted.afr.vol-client-1 -v 0x000003d70000000000000000 /gfs/brick-a/a`
+
+Thus after the above operations are done, the changelogs look like this:
+[root@pranithk-laptop vol]# getfattr -d -m . -e hex /gfs/brick-?/a
+getfattr: Removing leading '/' from absolute path names
+\#file: gfs/brick-a/a
+trusted.afr.vol-client-0=0x000000000000000000000000
+trusted.afr.vol-client-1=0x000003d70000000000000000
+trusted.gfid=0x80acdbd886524f6fbefa21fc356fed57
+
+\#file: gfs/brick-b/a
+trusted.afr.vol-client-0=0x000000000000000100000000
+trusted.afr.vol-client-1=0x000000000000000000000000
+trusted.gfid=0x80acdbd886524f6fbefa21fc356fed57
+
+
+Triggering Self-heal:
+---------------------
+Perform `ls -l <file-path-on-gluster-mount>` to trigger healing.
+
+Fixing Directory entry split-brain:
+----------------------------------
+Afr has the ability to conservatively merge different entries in the directories
+when there is a split-brain on directory.
+If on one brick directory 'd' has entries '1', '2' and has entries '3', '4' on
+the other brick then afr will merge all of the entries in the directory to have
+'1', '2', '3', '4' entries in the same directory.
+(Note: this may result in deleted files to re-appear in case the split-brain
+happens because of deletion of files on the directory)
+Split-brain resolution needs human intervention when there is at least one entry
+which has same file name but different gfid in that directory.
+Example:
+On brick-a the directory has entries '1' (with gfid g1), '2' and on brick-b
+directory has entries '1' (with gfid g2) and '3'.
+These kinds of directory split-brains need human intervention to resolve.
+The user needs to remove either file '1' on brick-a or the file '1' on brick-b
+to resolve the split-brain. In addition, the corresponding gfid-link file also
+needs to be removed.The gfid-link files are present in the .glusterfs folder
+in the top-level directory of the brick. If the gfid of the file is
+0x307a5c9efddd4e7c96e94fd4bcdcbd1b (the trusted.gfid extended attribute got
+from the getfattr command earlier),the gfid-link file can be found at
+> /gfs/brick-a/.glusterfs/30/7a/307a5c9efddd4e7c96e94fd4bcdcbd1b
+
+####Word of caution:
+Before deleting the gfid-link, we have to ensure that there are no hard links
+to the file present on that brick. If hard-links exist,they must be deleted as
+well.
diff --git a/extras/Makefile.am b/extras/Makefile.am
index 1ccd9dbd9..cf619329b 100644
--- a/extras/Makefile.am
+++ b/extras/Makefile.am
@@ -6,7 +6,7 @@ SUBDIRS = init.d systemd benchmarking hook-scripts $(OCF_SUBDIR) LinuxRPM geo-re
confdir = $(sysconfdir)/glusterfs
conf_DATA = glusterfs-logrotate gluster-rsyslog-7.2.conf gluster-rsyslog-5.8.conf \
- logger.conf.example
+ logger.conf.example glusterfs-georep-logrotate
voldir = $(sysconfdir)/glusterfs
vol_DATA = glusterd.vol
@@ -16,4 +16,5 @@ EXTRA_DIST = specgen.scm MacOSX/Portfile glusterfs-mode.el glusterfs.vim \
backend-cleanup.sh disk_usage_sync.sh quota-remove-xattr.sh \
quota-metadata-cleanup.sh glusterfs-logrotate clear_xattrs.sh \
group-virt.example glusterd-sysconfig gluster-rsyslog-7.2.conf \
- gluster-rsyslog-5.8.conf logger.conf.example glusterd.vol
+ gluster-rsyslog-5.8.conf logger.conf.example glusterd.vol \
+ glusterfs-georep-logrotate
diff --git a/extras/glusterd.vol b/extras/glusterd.vol
index de17d8fd8..9bac52ab7 100644
--- a/extras/glusterd.vol
+++ b/extras/glusterd.vol
@@ -5,4 +5,5 @@ volume management
option transport.socket.keepalive-time 10
option transport.socket.keepalive-interval 2
option transport.socket.read-fail-log off
+# option base-port 49152
end-volume
diff --git a/extras/glusterfs-georep-logrotate b/extras/glusterfs-georep-logrotate
new file mode 100644
index 000000000..6a69ab1e3
--- /dev/null
+++ b/extras/glusterfs-georep-logrotate
@@ -0,0 +1,18 @@
+
+rotate 52
+missingok
+
+compress
+delaycompress
+notifempty
+
+/var/log/glusterfs/geo-replication/*/*.log {
+}
+
+
+/var/log/glusterfs/geo-replication-slaves/*.log {
+}
+
+
+/var/log/glusterfs/geo-replication-slaves/*/*.log {
+}
diff --git a/extras/hook-scripts/S30samba-set.sh b/extras/hook-scripts/S30samba-set.sh
index 87cd31c5a..6b11f5a4f 100755
--- a/extras/hook-scripts/S30samba-set.sh
+++ b/extras/hook-scripts/S30samba-set.sh
@@ -63,7 +63,7 @@ function add_samba_share () {
STRING+="comment = For samba share of volume $volname\n"
STRING+="vfs objects = glusterfs\n"
STRING+="glusterfs:volume = $volname\n"
- STRING+="glusterfs:logfile = /var/log/samba/glusterfs-$volname.log\n"
+ STRING+="glusterfs:logfile = /var/log/samba/glusterfs-$volname.%%M.log\n"
STRING+="glusterfs:loglevel = 7\n"
STRING+="path = /\n"
STRING+="read only = no\n"
@@ -73,7 +73,7 @@ function add_samba_share () {
function sighup_samba () {
pid=`cat /var/run/smbd.pid`
- if [ "$pid" != "" ]
+ if [ "x$pid" != "x" ]
then
kill -HUP "$pid";
else
@@ -83,9 +83,7 @@ function sighup_samba () {
function del_samba_share () {
volname=$1
- cp /etc/samba/smb.conf /tmp/smb.conf
- sed -i "/gluster-$volname/,/^$/d" /tmp/smb.conf &&\
- cp /tmp/smb.conf /etc/samba/smb.conf
+ sed -i "/\[gluster-$volname\]/,/^$/d" /etc/samba/smb.conf
}
function is_volume_started () {
@@ -100,8 +98,10 @@ if [ "0" = $(is_volume_started "$VOL") ]; then
fi
if [ "$enable_smb" = "enable" ]; then
- add_samba_share $VOL
- sighup_samba
+ if ! grep --quiet "\[gluster-$VOL\]" /etc/samba/smb.conf ; then
+ add_samba_share $VOL
+ sighup_samba
+ fi
elif [ "$enable_smb" = "disable" ]; then
del_samba_share $VOL
diff --git a/extras/hook-scripts/S30samba-start.sh b/extras/hook-scripts/S30samba-start.sh
index 2517f10bf..34fde0ef8 100755
--- a/extras/hook-scripts/S30samba-start.sh
+++ b/extras/hook-scripts/S30samba-start.sh
@@ -23,6 +23,9 @@
PROGNAME="Ssamba-start"
OPTSPEC="volname:"
VOL=
+CONFIGFILE=
+LOGFILEBASE=
+PIDDIR=
function parse_args () {
ARGS=$(getopt -l $OPTSPEC -name $PROGNAME $@)
@@ -43,23 +46,34 @@ function parse_args () {
done
}
+function find_config_info () {
+ cmdout=`smbd -b | grep smb.conf`
+ if [ $? -ne 0 ];then
+ echo "Samba is not installed"
+ exit 1
+ fi
+ CONFIGFILE=`echo $cmdout | awk {'print $2'}`
+ PIDDIR=`smbd -b | grep PIDDIR | awk {'print $2'}`
+ LOGFILEBASE=`smbd -b | grep 'LOGFILEBASE' | awk '{print $2}'`
+}
+
function add_samba_share () {
volname=$1
STRING="\n[gluster-$volname]\n"
STRING+="comment = For samba share of volume $volname\n"
STRING+="vfs objects = glusterfs\n"
STRING+="glusterfs:volume = $volname\n"
- STRING+="glusterfs:logfile = /var/log/samba/glusterfs-$volname.log\n"
+ STRING+="glusterfs:logfile = $LOGFILEBASE/glusterfs-$volname.%%M.log\n"
STRING+="glusterfs:loglevel = 7\n"
STRING+="path = /\n"
STRING+="read only = no\n"
STRING+="guest ok = yes\n"
- printf "$STRING" >> /etc/samba/smb.conf
+ printf "$STRING" >> ${CONFIGFILE}
}
function sighup_samba () {
- pid=`cat /var/run/smbd.pid`
- if [ "$pid" != "" ]
+ pid=`cat ${PIDDIR}/smbd.pid`
+ if [ "x$pid" != "x" ]
then
kill -HUP "$pid";
else
@@ -87,7 +101,10 @@ if [ $(get_smb "$VOL") = "disable" ]; then
exit 0
fi
-if ! grep --quiet "gluster-$VOL" /etc/samba/smb.conf ; then
+#Find smb.conf, smbd pid directory and smbd logfile path
+find_config_info
+
+if ! grep --quiet "\[gluster-$VOL\]" ${CONFIGFILE} ; then
add_samba_share $VOL
sighup_samba
fi
diff --git a/extras/hook-scripts/S30samba-stop.sh b/extras/hook-scripts/S30samba-stop.sh
index def87e00e..8950eea43 100755
--- a/extras/hook-scripts/S30samba-stop.sh
+++ b/extras/hook-scripts/S30samba-stop.sh
@@ -18,6 +18,8 @@
PROGNAME="Ssamba-stop"
OPTSPEC="volname:"
VOL=
+CONFIGFILE=
+PIDDIR=
function parse_args () {
ARGS=$(getopt -l $OPTSPEC -name $PROGNAME $@)
@@ -38,16 +40,24 @@ function parse_args () {
done
}
+function find_config_info () {
+ cmdout=`smbd -b | grep smb.conf`
+ if [ $? -ne 0 ];then
+ echo "Samba is not installed"
+ exit 1
+ fi
+ CONFIGFILE=`echo $cmdout | awk {'print $2'}`
+ PIDDIR=`smbd -b | grep PIDDIR | awk {'print $2'}`
+}
+
function del_samba_share () {
volname=$1
- cp /etc/samba/smb.conf /tmp/smb.conf
- sed -i "/gluster-$volname/,/^$/d" /tmp/smb.conf &&\
- cp /tmp/smb.conf /etc/samba/smb.conf
+ sed -i "/\[gluster-$volname\]/,/^$/d" ${CONFIGFILE}
}
function sighup_samba () {
- pid=`cat /var/run/smbd.pid`
- if [ $pid != "" ]
+ pid=`cat ${PIDDIR}/smbd.pid`
+ if [ "x$pid" != "x" ]
then
kill -HUP $pid;
else
@@ -56,5 +66,6 @@ function sighup_samba () {
}
parse_args $@
+find_config_info
del_samba_share $VOL
sighup_samba
diff --git a/extras/hook-scripts/S56glusterd-geo-rep-create-post.sh b/extras/hook-scripts/S56glusterd-geo-rep-create-post.sh
index 71e44b6ed..1369c22fc 100755
--- a/extras/hook-scripts/S56glusterd-geo-rep-create-post.sh
+++ b/extras/hook-scripts/S56glusterd-geo-rep-create-post.sh
@@ -22,6 +22,7 @@ if [ "$val" == "" ]; then
exit;
fi
pub_file=`echo $val`
+pub_file_tmp=`echo $val`_tmp
key=`echo $key_val_pair3 | cut -d '=' -f 1`
val=`echo $key_val_pair3 | cut -d '=' -f 2`
@@ -34,8 +35,8 @@ fi
slave_ip=`echo $val`
if [ -f $pub_file ]; then
- ssh $slave_ip "\rm -rf $pub_file"
- scp $pub_file $slave_ip:$pub_file &> /dev/null
+ scp $pub_file $slave_ip:$pub_file_tmp
+ ssh $slave_ip "mv $pub_file_tmp $pub_file"
ssh $slave_ip "gluster system:: copy file /geo-replication/common_secret.pem.pub > /dev/null"
ssh $slave_ip "gluster system:: execute add_secret_pub > /dev/null"
fi
diff --git a/extras/logger.conf.example b/extras/logger.conf.example
index e01c141f1..248be5bda 100644
--- a/extras/logger.conf.example
+++ b/extras/logger.conf.example
@@ -1,10 +1,13 @@
#
-# Sample logger.conf file to configure enhanced Logging in RHS
+# Sample logger.conf file to configure enhanced Logging in GlusterFS
#
-# To enable enhanced logging capabilities, rename this file to
+# To enable enhanced logging capabilities,
#
-# /etc/glusterfs/logger.conf
+# 1. rename this file to /etc/glusterfs/logger.conf
#
-# This change requires restart of all gluster services/volumes.
+# 2. rename /etc/rsyslog.d/gluster.conf.example to
+# /etc/rsyslog.d/gluster.conf
#
+# This change requires restart of all gluster services/volumes and
+# rsyslog.
#
diff --git a/extras/systemd/glusterd.service.in b/extras/systemd/glusterd.service.in
index 072a1278b..fc8d8c9a2 100644
--- a/extras/systemd/glusterd.service.in
+++ b/extras/systemd/glusterd.service.in
@@ -1,6 +1,7 @@
[Unit]
-Description=GlusterFS an clustered file-system server
+Description=GlusterFS, a clustered file-system server
After=network.target rpcbind.service
+Before=network-online.target
[Service]
Type=forking
diff --git a/extras/who-wrote-glusterfs/gitdm.aliases b/extras/who-wrote-glusterfs/gitdm.aliases
new file mode 100644
index 000000000..784a3e3bc
--- /dev/null
+++ b/extras/who-wrote-glusterfs/gitdm.aliases
@@ -0,0 +1,48 @@
+#
+# This is the email aliases file, mapping secondary addresses onto a single,
+# canonical address. This file should probably match the contents of .mailmap
+# in the root of the git repository.
+#
+# Format: <alias> <real>
+
+amar@gluster.com amarts@redhat.com
+amar@del.gluster.com amarts@redhat.com
+avati@amp.gluster.com avati@redhat.com
+avati@blackhole.gluster.com avati@redhat.com
+avati@dev.gluster.com avati@redhat.com
+avati@gluster.com avati@redhat.com
+wheelear@gmail.com awheeler@redhat.com
+anush@gluster.com ashetty@redhat.com
+csaba@gluster.com csaba@redhat.com
+csaba@lowlife.hu csaba@redhat.com
+csaba@zresearch.com csaba@redhat.com
+harsha@gluster.com fharshav@redhat.com
+harsha@zresearch.com fharshav@redhat.com
+harsha@dev.gluster.com fharshav@redhat.com
+harsha@harshavardhana.net fharshav@redhat.com
+kkeithle@f16node1.kkeithle.usersys.redhat.com kkeithle@redhat.com
+kaushal@gluster.com kaushal@redhat.com
+kaushikbv@gluster.com kbudiger@redhat.com
+krishna@gluster.com ksriniva@redhat.com
+krishna@zresearch.com ksriniva@redhat.com
+krishna@guest-laptop ksriniva@redhat.com
+kp@gluster.com kparthas@redhat.com
+me@louiszuckerman.com louiszuckerman@gmail.com
+msvbhat@gmail.com vbhat@redhat.com
+vishwanath@gluster.com vbhat@redhat.com
+pavan@dev.gluster.com pavan@gluster.com
+zaitcev@yahoo.com zaitcev@kotori.zaitcev.us
+pranithk@gluster.com pkarampu@redhat.com
+raghavendrabhat@gluster.com raghavendra@redhat.com
+raghavendra@gluster.com rgowdapp@redhat.com
+raghavendra@zresearch.com rgowdapp@redhat.com
+rahulcssjce@gmail.com rahulcs@redhat.com
+rajesh@gluster.com rajesh@redhat.com
+rajesh.amaravathi@gmail.com rajesh@redhat.com
+shehjart@zresearch.com shehjart@gluster.com
+venky@gluster.com vshankar@redhat.com
+vijay@gluster.com vbellur@redhat.com
+vijay@dev.gluster.com vbellur@redhat.com
+vijaykumar.koppad@gmail.com vkoppad@redhat.com
+vikas@zresearch.com vikas@gluster.com
+shishirng@gluster.com sgowda@redhat.com
diff --git a/extras/who-wrote-glusterfs/gitdm.config b/extras/who-wrote-glusterfs/gitdm.config
new file mode 100644
index 000000000..e1ff2bd5b
--- /dev/null
+++ b/extras/who-wrote-glusterfs/gitdm.config
@@ -0,0 +1,8 @@
+#
+# This is the gitdm configuration file for GlusterFS.
+# See the gitdm.config in the gitdm repositofy for additional options and
+# comments.
+#
+
+EmailAliases gitdm.aliases
+EmailMap gitdm.domain-map
diff --git a/extras/who-wrote-glusterfs/gitdm.domain-map b/extras/who-wrote-glusterfs/gitdm.domain-map
new file mode 100644
index 000000000..f1c305898
--- /dev/null
+++ b/extras/who-wrote-glusterfs/gitdm.domain-map
@@ -0,0 +1,15 @@
+#
+# Here is a set of mappings of domain names onto employer names.
+#
+active.by ActiveCloud
+cern.ch CERN
+gluster.com Red Hat
+gooddata.com GoodData
+hastexo.com hastexo
+ibm.com IBM
+linbit.com LINBIT
+netbsd.org NetBSD
+netdirect.ca Net Direct
+redhat.com Red Hat
+stepping-stone.ch stepping stone GmbH
+zresearch.com Red Hat
diff --git a/extras/who-wrote-glusterfs/who-wrote-glusterfs.sh b/extras/who-wrote-glusterfs/who-wrote-glusterfs.sh
new file mode 100755
index 000000000..487f5874b
--- /dev/null
+++ b/extras/who-wrote-glusterfs/who-wrote-glusterfs.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# Gather statistics on "Who wrote GlusterFS". The idea comes from the excellent
+# articles on http://lwn.net/ named "Who wrote <linux-version>?".
+#
+# gitdm comes from git://git.lwn.net/gitdm.git by Jonathan Corbet.
+#
+# Confguration files used:
+# - gitdm.config: main configuration file, pointing to the others
+# - gitdm.aliases: merge users with different emailaddresses into one
+# - gitdm.domain-map: map domain names from emailaddresses to companies
+#
+
+DIRNAME=$(dirname $0)
+
+GITDM_REPO=git://git.lwn.net/gitdm.git
+GITDM_DIR=${DIRNAME}/gitdm
+GITDM_CMD="python ${GITDM_DIR}/gitdm"
+
+error()
+{
+ local ret=${?}
+ printf "${@}\n" > /dev/stderr
+ return ${ret}
+}
+
+check_gitdm()
+{
+ if [ ! -e "${GITDM_DIR}/gitdm" ]
+ then
+ git clone --quiet git://git.lwn.net/gitdm.git ${DIRNAME}/gitdm
+ fi
+}
+
+# The first argument is the revision-range (see 'git rev-list --help').
+# REV can be empty, and the statistics will be calculated over the whole
+# current branch.
+REV=${1}
+shift
+# all remaining options are passed to gitdm, see the gitdm script for an
+# explanation of the accepted options.
+GITDM_OPTS=${@}
+
+if ! check_gitdm
+then
+ error "Could not find 'gitdm', exiting..."
+ exit 1
+fi
+
+git log --numstat -M ${REV} | ${GITDM_CMD} -b ${DIRNAME} -n ${GITDM_OPTS}
diff --git a/geo-replication/src/gverify.sh b/geo-replication/src/gverify.sh
index 186af53a4..bd1b25f24 100755
--- a/geo-replication/src/gverify.sh
+++ b/geo-replication/src/gverify.sh
@@ -4,7 +4,8 @@
# To use ./gverify <master volume> <slave host> <slave volume>
# Returns 0 if master and slave compatible.
-BUFFER_SIZE=1000;
+# Considering buffer_size 100MB
+BUFFER_SIZE=104857600;
slave_log_file=`gluster --print-logdir`/geo-replication-slaves/slave.log
function SSHM()
@@ -61,10 +62,11 @@ exit 1;
fi;
cd \$d;
available_size=\$(df \$d | tail -1 | awk "{print \\\$4}");
+no_of_files=\$(find \$d -maxdepth 0 -empty);
umount -l \$d;
rmdir \$d;
ver=\$(gluster --version | head -1 | cut -f2 -d " ");
-echo \$available_size:\$ver;
+echo \$available_size:\$ver:\$no_of_files:;
};
cd /tmp;
[ x$VOL != x ] && do_verify $VOL;
@@ -95,6 +97,24 @@ function slave_stats()
function main()
{
+ log_file=$4
+ > $log_file
+
+ # Use FORCE_BLOCKER flag in the error message to differentiate
+ # between the errors which the force command should bypass
+
+ ping -w 5 $2;
+ if [ $? -ne 0 ]; then
+ echo "FORCE_BLOCKER|$2 not reachable." > $log_file
+ exit 1;
+ fi;
+
+ ssh -oNumberOfPasswordPrompts=0 $2 "echo Testing_Passwordless_SSH";
+ if [ $? -ne 0 ]; then
+ echo "FORCE_BLOCKER|Passwordless ssh login has not been setup with $2." > $log_file
+ exit 1;
+ fi;
+
ERRORS=0;
master_data=$(master_stats $1);
slave_data=$(slave_stats $2 $3);
@@ -102,37 +122,35 @@ function main()
slave_size=$(echo $slave_data | cut -f1 -d':');
master_version=$(echo $master_data | cut -f2 -d':');
slave_version=$(echo $slave_data | cut -f2 -d':');
- log_file=$4
+ slave_no_of_files=$(echo $slave_data | cut -f3 -d':');
if [[ "x$master_size" = "x" || "x$master_version" = "x" || "$master_size" -eq "0" ]]; then
- echo "Unable to fetch master volume details." > $log_file;
+ echo "FORCE_BLOCKER|Unable to fetch master volume details. Please check the master cluster and master volume." > $log_file;
exit 1;
fi;
if [[ "x$slave_size" = "x" || "x$slave_version" = "x" || "$slave_size" -eq "0" ]]; then
- ping -w 5 $2;
- if [ $? -ne 0 ]; then
- echo "$2 not reachable." > $log_file
- exit 1;
- fi;
- echo "Unable to fetch slave volume details." > $log_file;
+ echo "FORCE_BLOCKER|Unable to fetch slave volume details. Please check the slave cluster and slave volume." > $log_file;
exit 1;
fi;
- if [ $slave_size -ge $(($master_size - $BUFFER_SIZE )) ]; then
- echo "Total size of master is lesser than available size of slave." > $log_file;
- else
- echo "Total size of master is greater than available size of slave." > $log_file;
+ # The above checks are mandatory and force command should be blocked
+ # if they fail. The checks below can be bypassed if force option is
+ # provided hence no FORCE_BLOCKER flag.
+
+ if [ ! $slave_size -ge $(($master_size - $BUFFER_SIZE )) ]; then
+ echo "Total size of master is greater than available size of slave." >> $log_file;
ERRORS=$(($ERRORS + 1));
- exit $ERRORS;
fi;
- if [[ $master_version < $slave_version || $master_version == $slave_version ]]; then
- echo "Gluster version of master and slave matches." > $log_file;
- else
- echo "Gluster version mismatch between master and slave." > $log_file;
+ if [ -z $slave_no_of_files ]; then
+ echo "$2::$3 is not empty. Please delete existing files in $2::$3 and retry, or use force to continue without deleting the existing files." >> $log_file;
+ ERRORS=$(($ERRORS + 1));
+ fi;
+
+ if [[ $master_version > $slave_version ]]; then
+ echo "Gluster version mismatch between master and slave." >> $log_file;
ERRORS=$(($ERRORS + 1));
- exit $ERRORS;
fi;
exit $ERRORS;
diff --git a/geo-replication/syncdaemon/gconf.py b/geo-replication/syncdaemon/gconf.py
index 146c72a18..fe5795f16 100644
--- a/geo-replication/syncdaemon/gconf.py
+++ b/geo-replication/syncdaemon/gconf.py
@@ -12,9 +12,4 @@ class GConf(object):
permanent_handles = []
log_metadata = {}
- @classmethod
- def setup_ssh_ctl(cls, ctld):
- cls.ssh_ctl_dir = ctld
- cls.ssh_ctl_args = ["-oControlMaster=auto", "-S", os.path.join(ctld, "gsycnd-ssh-%r@%h:%p")]
-
gconf = GConf()
diff --git a/geo-replication/syncdaemon/gsyncd.py b/geo-replication/syncdaemon/gsyncd.py
index 67ba07370..7fcc3165a 100644
--- a/geo-replication/syncdaemon/gsyncd.py
+++ b/geo-replication/syncdaemon/gsyncd.py
@@ -12,7 +12,7 @@ import optparse
import fcntl
import fnmatch
from optparse import OptionParser, SUPPRESS_HELP
-from logging import Logger
+from logging import Logger, handlers
from errno import EEXIST, ENOENT
from ipaddr import IPAddress, IPNetwork
@@ -58,7 +58,24 @@ class GLogger(Logger):
logging.root = cls("root", lvl)
logging.setLoggerClass(cls)
logging.getLogger().handlers = []
- logging.basicConfig(**lprm)
+ logging.getLogger().setLevel(lprm['level'])
+
+ if 'filename' in lprm:
+ try:
+ logging_handler = handlers.WatchedFileHandler(lprm['filename'])
+ formatter = logging.Formatter(fmt=lprm['format'],
+ datefmt=lprm['datefmt'])
+ logging_handler.setFormatter(formatter)
+ logging.getLogger().addHandler(logging_handler)
+ except AttributeError:
+ # Python version < 2.6 will not have WatchedFileHandler
+ # so fallback to logging without any handler.
+ # Note: logrotate will not work if Python version is < 2.6
+ logging.basicConfig(**lprm)
+ else:
+ # If filename not passed(not available in lprm) then it may be
+ # streaming.(Ex: {"stream": "/dev/stdout"})
+ logging.basicConfig(**lprm)
@classmethod
def _gsyncd_loginit(cls, **kw):
@@ -347,6 +364,8 @@ def main_i():
for j in range(3):
namedict[mods[j](name)] = pa[j][i]
namedict[name + 'vol'] = x.volume
+ if name == 'remote':
+ namedict['remotehost'] = x.remotehost
if not 'config_file' in rconf:
rconf['config_file'] = os.path.join(os.path.dirname(sys.argv[0]), "conf/gsyncd_template.conf")
gcnf = GConffile(rconf['config_file'], canon_peers, defaults.__dict__, opts.__dict__, namedict)
diff --git a/geo-replication/syncdaemon/master.py b/geo-replication/syncdaemon/master.py
index 58df14954..95810a61e 100644
--- a/geo-replication/syncdaemon/master.py
+++ b/geo-replication/syncdaemon/master.py
@@ -17,7 +17,8 @@ from datetime import datetime
from gconf import gconf
from tempfile import mkdtemp, NamedTemporaryFile
from syncdutils import FreeObject, Thread, GsyncdError, boolify, escape, \
- unescape, select, gauxpfx, md5hex, selfkill, entry2pb
+ unescape, select, gauxpfx, md5hex, selfkill, entry2pb, \
+ lstat, errno_wrap
URXTIME = (-1, 0)
@@ -40,11 +41,7 @@ def _volinfo_hook_relax_foreign(self):
expiry)
time.sleep(expiry)
volinfo_sys = self.get_sys_volinfo()
- self.volinfo_state, state_change = self.volinfo_state_machine(self.volinfo_state,
- volinfo_sys)
- if self.inter_master:
- raise GsyncdError("cannot be intermediate master in special mode")
- return (volinfo_sys, state_change)
+ return volinfo_sys
# The API!
@@ -133,10 +130,7 @@ class NormalMixin(object):
return (vi, gap)
def volinfo_hook(self):
- volinfo_sys = self.get_sys_volinfo()
- self.volinfo_state, state_change = self.volinfo_state_machine(self.volinfo_state,
- volinfo_sys)
- return (volinfo_sys, state_change)
+ return self.get_sys_volinfo()
def xtime_reversion_hook(self, path, xtl, xtr):
if xtr > xtl:
@@ -147,6 +141,7 @@ class NormalMixin(object):
def set_slave_xtime(self, path, mark):
self.slave.server.set_xtime(path, self.uuid, mark)
+ self.slave.server.set_xtime_remote(path, self.uuid, mark)
class PartialMixin(NormalMixin):
"""a variant tuned towards operation with a master
@@ -155,7 +150,7 @@ class PartialMixin(NormalMixin):
def xtime_reversion_hook(self, path, xtl, xtr):
pass
-class WrapupMixin(NormalMixin):
+class RecoverMixin(NormalMixin):
"""a variant that differs from normal in terms
of ignoring non-indexed files"""
@@ -166,142 +161,12 @@ class WrapupMixin(NormalMixin):
if not 'default_xtime' in opts:
opts['default_xtime'] = URXTIME
- @staticmethod
def keepalive_payload_hook(self, timo, gap):
return (None, gap)
def volinfo_hook(self):
return _volinfo_hook_relax_foreign(self)
-class BlindMixin(object):
- """Geo-rep flavor using vectored xtime.
-
- Coordinates are the master, slave uuid pair;
- in master coordinate behavior is normal,
- in slave coordinate we force synchronization
- on any value difference (these are in disjunctive
- relation, ie. if either orders the entry to be
- synced, it shall be synced.
- """
-
- minus_infinity = (URXTIME, None)
-
- @staticmethod
- def serialize_xtime(xt):
- a = []
- for x in xt:
- if not x:
- x = ('None', '')
- a.extend(x)
- return '.'.join(str(n) for n in a)
-
- @staticmethod
- def deserialize_xtime(xt):
- a = xt.split(".")
- a = (tuple(a[0:2]), tuple(a[3:4]))
- b = []
- for p in a:
- if p[0] == 'None':
- p = None
- else:
- p = tuple(int(x) for x in p)
- b.append(p)
- return tuple(b)
-
- @staticmethod
- def native_xtime(xt):
- return xt[0]
-
- @staticmethod
- def xtime_geq(xt0, xt1):
- return (not xt1[0] or xt0[0] >= xt1[0]) and \
- (not xt1[1] or xt0[1] >= xt1[1])
-
- @property
- def ruuid(self):
- if self.volinfo_r:
- return self.volinfo_r['uuid']
-
- @staticmethod
- def make_xtime_opts(is_master, opts):
- if not 'create' in opts:
- opts['create'] = is_master
- if not 'default_xtime' in opts:
- opts['default_xtime'] = URXTIME
-
- def xtime_low(self, server, path, **opts):
- xtd = server.xtime_vec(path, self.uuid, self.ruuid)
- if isinstance(xtd, int):
- return xtd
- xt = (xtd[self.uuid], xtd[self.ruuid])
- if not xt[1] and (not xt[0] or xt[0] < self.volmark):
- if opts['create']:
- # not expected, but can happen if file originates
- # from interrupted gsyncd transfer
- logging.warn('have to fix up missing xtime on ' + path)
- xt0 = _xtime_now()
- server.aggregated.set_xtime(path, self.uuid, xt0)
- else:
- xt0 = opts['default_xtime']
- xt = (xt0, xt[1])
- return xt
-
- @staticmethod
- def keepalive_payload_hook(self, timo, gap):
- return (None, gap)
-
- def volinfo_hook(self):
- res = _volinfo_hook_relax_foreign(self)
- volinfo_r_new = self.slave.server.aggregated.native_volume_info()
- if volinfo_r_new['retval']:
- raise GsyncdError("slave is corrupt")
- if getattr(self, 'volinfo_r', None):
- if self.volinfo_r['uuid'] != volinfo_r_new['uuid']:
- raise GsyncdError("uuid mismatch on slave")
- self.volinfo_r = volinfo_r_new
- return res
-
- def xtime_reversion_hook(self, path, xtl, xtr):
- if not isinstance(xtr[0], int) and \
- (isinstance(xtl[0], int) or xtr[0] > xtl[0]):
- raise GsyncdError("timestamp corruption for " + path)
-
- def need_sync(self, e, xte, xtrd):
- if xte[0]:
- if not xtrd[0] or xte[0] > xtrd[0]:
- # there is outstanding diff at 0th pos,
- # we can short-cut to true
- return True
- # we arrived to this point by either of these
- # two possiblilites:
- # - no outstanding difference at 0th pos,
- # wanna see 1st pos if he raises veto
- # against "no need to sync" proposal
- # - no data at 0th pos, 1st pos will have
- # to decide (due to xtime assignment,
- # in this case 1st pos does carry data
- # -- iow, if 1st pos did not have data,
- # and 0th neither, 0th would have been
- # force-feeded)
- if not xte[1]:
- # no data, no veto
- return False
- # the hard work: for 1st pos,
- # the conduct is fetch corresponding
- # slave data and do a "blind" comparison
- # (ie. do not care who is newer, we trigger
- # sync on non-identical xitmes)
- xtr = self.xtime(e, self.slave)
- return isinstance(xtr, int) or xte[1] != xtr[1]
-
- def set_slave_xtime(self, path, mark):
- xtd = {}
- for (u, t) in zip((self.uuid, self.ruuid), mark):
- if t:
- xtd[u] = t
- self.slave.server.set_xtime_vec(path, xtd)
-
-
# Further mixins for certain tunable behaviors
class SendmarkNormalMixin(object):
@@ -355,13 +220,6 @@ class GMasterCommon(object):
if self.volinfo:
return self.volinfo['volume_mark']
- @property
- def inter_master(self):
- """decide if we are an intermediate master
- in a cascading setup
- """
- return self.volinfo_state[self.KFGN] and True or False
-
def xtime(self, path, *a, **opts):
"""get amended xtime
@@ -379,7 +237,13 @@ class GMasterCommon(object):
return self.xtime_low(rsc.server, path, **opts)
def get_initial_crawl_data(self):
- default_data = {'sync_time': 0, 'files_synced': 0, 'bytes_synced': 0}
+ # while persisting only 'files_syncd' is non-zero, rest of
+ # the stats are nulls. lets keep it that way in case they
+ # are needed to be used some day...
+ default_data = {'files_syncd': 0,
+ 'files_remaining': 0,
+ 'bytes_remaining': 0,
+ 'purges_remaining': 0}
if getattr(gconf, 'state_detail_file', None):
try:
return json.load(open(gconf.state_detail_file))
@@ -392,7 +256,6 @@ class GMasterCommon(object):
return default_data
else:
raise
-
return default_data
def update_crawl_data(self):
@@ -421,17 +284,11 @@ class GMasterCommon(object):
self.crawls = 0
self.turns = 0
self.total_turns = int(gconf.turns)
+ self.crawl_start = datetime.now()
self.lastreport = {'crawls': 0, 'turns': 0, 'time': 0}
- self.crawl_stats = {'sync_time': 0, 'last_synctime': 0, 'crawl_starttime': 0,
- 'crawl_time': 0, 'files_synced': 0, 'bytes_synced' :0}
- self.total_crawl_stats = self.get_initial_crawl_data()
+ self.total_crawl_stats = None
self.start = None
self.change_seen = None
- # the authoritative (foreign, native) volinfo pair
- # which lets us deduce what to do when we refetch
- # the volinfos from system
- uuid_preset = getattr(gconf, 'volume_id', None)
- self.volinfo_state = (uuid_preset and {'uuid': uuid_preset}, None)
# the actual volinfo we make use of
self.volinfo = None
self.terminate = False
@@ -450,34 +307,6 @@ class GMasterCommon(object):
t = Thread(target=keep_alive)
t.start()
- def volinfo_query(self):
- """volume info state machine"""
- volinfo_sys, state_change = self.volinfo_hook()
- if self.inter_master:
- self.volinfo = volinfo_sys[self.KFGN]
- else:
- self.volinfo = volinfo_sys[self.KNAT]
- if state_change == self.KFGN or (state_change == self.KNAT and not self.inter_master):
- logging.info('new master is %s', self.uuid)
- if self.volinfo:
- logging.info("%s master with volume id %s ..." % \
- (self.inter_master and "intermediate" or "primary",
- self.uuid))
- if state_change == self.KFGN:
- gconf.configinterface.set('volume_id', self.uuid)
- if self.volinfo:
- if self.volinfo['retval']:
- raise GsyncdError ("master is corrupt")
- self.start_checkpoint_thread()
- else:
- if should_display_info or self.crawls == 0:
- if self.inter_master:
- logging.info("waiting for being synced from %s ..." % \
- self.volinfo_state[self.KFGN]['uuid'])
- else:
- logging.info("waiting for volume info ...")
- return True
-
def should_crawl(cls):
return (gconf.glusterd_uuid in cls.master.server.node_uuid())
@@ -490,26 +319,38 @@ class GMasterCommon(object):
# for a passive gsyncd (ie. in a replicate scenario)
# the keepalive thread would keep the connection alive.
self.init_keep_alive()
- self.lastreport['time'] = time.time()
- self.crawl_stats['crawl_starttime'] = datetime.now()
+ # no need to maintain volinfo state machine.
+ # in a cascading setup, each geo-replication session is
+ # independent (ie. 'volume-mark' and 'xtime' are not
+ # propogated). This is beacuse the slave's xtime is now
+ # stored on the master itself. 'volume-mark' just identifies
+ # that we are in a cascading setup and need to enable
+ # 'geo-replication.ignore-pid-check' option.
+ volinfo_sys = self.volinfo_hook()
+ self.volinfo = volinfo_sys[self.KNAT]
+ inter_master = volinfo_sys[self.KFGN]
+ logging.info("%s master with volume id %s ..." % \
+ (inter_master and "intermediate" or "primary",
+ self.uuid))
+ gconf.configinterface.set('volume_id', self.uuid)
+ if self.volinfo:
+ if self.volinfo['retval']:
+ raise GsyncdError("master is corrupt")
+ self.start_checkpoint_thread()
+ else:
+ raise GsyncdError("master volinfo unavailable")
+ self.total_crawl_stats = self.get_initial_crawl_data()
+ self.lastreport['time'] = time.time()
logging.info('crawl interval: %d seconds' % self.sleep_interval)
+
t0 = time.time()
crawl = self.should_crawl()
while not self.terminate:
- if self.volinfo_query():
- continue
- t1 = time.time()
- if int(t1 - t0) >= 60: #lets hardcode this check to 60 seconds
- crawl = self.should_crawl()
- t0 = t1
- if not crawl:
- time.sleep(5)
- continue
if self.start:
logging.debug("... crawl #%d done, took %.6f seconds" % \
(self.crawls, time.time() - self.start))
- self.start = t1
+ self.start = time.time()
should_display_info = self.start - self.lastreport['time'] >= 60
if should_display_info:
logging.info("%d crawls, %d turns",
@@ -518,6 +359,13 @@ class GMasterCommon(object):
self.lastreport.update(crawls = self.crawls,
turns = self.turns,
time = self.start)
+ t1 = time.time()
+ if int(t1 - t0) >= 60: #lets hardcode this check to 60 seconds
+ crawl = self.should_crawl()
+ t0 = t1
+ if not crawl:
+ time.sleep(5)
+ continue
self.crawl()
if oneshot:
return
@@ -555,17 +403,13 @@ class GMasterCommon(object):
return ts
def get_extra_info(self):
- str_info = "\nFilesSynced=%d;" % (self.crawl_stats['files_synced'])
- str_info += "BytesSynced=%s;" % (self.crawl_stats['bytes_synced'])
-
- self.crawl_stats['crawl_time'] = datetime.now() - self.crawl_stats['crawl_starttime']
-
- str_info += "Uptime=%s;" % (self._crawl_time_format(self.crawl_stats['crawl_time']))
- str_info += "SyncTime=%s;" % (self.crawl_stats['sync_time'])
- str_info += "TotalSyncTime=%s;" % (self.total_crawl_stats['sync_time'])
- str_info += "TotalFilesSynced=%d;" % (self.total_crawl_stats['files_synced'])
- str_info += "TotalBytesSynced=%s;" % (self.total_crawl_stats['bytes_synced'])
- str_info += "\0"
+ str_info = '\nUptime=%s;FilesSyncd=%d;FilesPending=%d;BytesPending=%d;DeletesPending=%d;' % \
+ (self._crawl_time_format(datetime.now() - self.crawl_start), \
+ self.total_crawl_stats['files_syncd'], \
+ self.total_crawl_stats['files_remaining'], \
+ self.total_crawl_stats['bytes_remaining'], \
+ self.total_crawl_stats['purges_remaining'])
+ str_info += '\0'
logging.debug(str_info)
return str_info
@@ -714,46 +558,6 @@ class GMasterCommon(object):
self.slave.server.setattr(path, adct)
self.set_slave_xtime(path, mark)
- @staticmethod
- def volinfo_state_machine(volinfo_state, volinfo_sys):
- """compute new volinfo_state from old one and incoming
- as of current system state, also indicating if there was a
- change regarding which volume mark is the authoritative one
-
- @volinfo_state, @volinfo_sys are pairs of volume mark dicts
- (foreign, native).
-
- Note this method is marked as static, ie. the computation is
- pure, without reliance on any excess implicit state. State
- transitions which are deemed as ambiguous or banned will raise
- an exception.
-
- """
- # store the value below "boxed" to emulate proper closures
- # (variables of the enclosing scope are available inner functions
- # provided they are no reassigned; mutation is OK).
- param = FreeObject(relax_mismatch = False, state_change = None, index=-1)
- def select_vi(vi0, vi):
- param.index += 1
- if vi and (not vi0 or vi0['uuid'] == vi['uuid']):
- if not vi0 and not param.relax_mismatch:
- param.state_change = param.index
- # valid new value found; for the rest, we are graceful about
- # uuid mismatch
- param.relax_mismatch = True
- return vi
- if vi0 and vi and vi0['uuid'] != vi['uuid'] and not param.relax_mismatch:
- # uuid mismatch for master candidate, bail out
- raise GsyncdError("aborting on uuid change from %s to %s" % \
- (vi0['uuid'], vi['uuid']))
- # fall back to old
- return vi0
- newstate = tuple(select_vi(*vip) for vip in zip(volinfo_state, volinfo_sys))
- srep = lambda vi: vi and vi['uuid'][0:8]
- logging.debug('(%s, %s) << (%s, %s) -> (%s, %s)' % \
- tuple(srep(vi) for vi in volinfo_state + volinfo_sys + newstate))
- return newstate, param.state_change
-
class GMasterChangelogMixin(GMasterCommon):
""" changelog based change detection and syncing """
@@ -776,6 +580,9 @@ class GMasterChangelogMixin(GMasterCommon):
# flat directory heirarchy for gfid based access
FLAT_DIR_HIERARCHY = '.'
+ # maximum retries per changelog before giving up
+ MAX_RETRIES = 10
+
def fallback_xsync(self):
logging.info('falling back to xsync mode')
gconf.configinterface.set('change-detector', 'xsync')
@@ -787,15 +594,11 @@ class GMasterChangelogMixin(GMasterCommon):
logging.debug('changelog working dir %s (log: %s)' % (workdir, logfile))
return (workdir, logfile)
- def lstat(self, e):
- try:
- return os.lstat(e)
- except (IOError, OSError):
- ex = sys.exc_info()[1]
- if ex.errno == ENOENT:
- return ex.errno
- else:
- raise
+ # update stats from *this* crawl
+ def update_cumulative_stats(self, files_pending):
+ self.total_crawl_stats['files_remaining'] = files_pending['count']
+ self.total_crawl_stats['bytes_remaining'] = files_pending['bytes']
+ self.total_crawl_stats['purges_remaining'] = files_pending['purge']
# sync data
def syncdata(self, datas):
@@ -803,43 +606,31 @@ class GMasterChangelogMixin(GMasterCommon):
for data in datas:
logging.debug('candidate for syncing %s' % data)
pb = self.syncer.add(data)
- timeA = datetime.now()
def regjob(se, xte, pb):
rv = pb.wait()
if rv[0]:
logging.debug('synced ' + se)
- # update stats
- timeB = datetime.now()
- self.crawl_stats['last_synctime'] = timeB - timeA
- self.crawl_stats['sync_time'] += ((self.crawl_stats['last_synctime'].microseconds) / (10.0 ** 6))
- self.crawl_stats['files_synced'] += 1
- self.crawl_stats['bytes_synced'] += self.syncer.bytes_synced
-
- # cumulative statistics
- self.total_crawl_stats['bytes_synced'] += self.syncer.bytes_synced
- self.total_crawl_stats['sync_time'] += ((self.crawl_stats['last_synctime'].microseconds) / (10.0 ** 6))
- self.total_crawl_stats['files_synced'] += 1
return True
else:
if rv[1] in [23, 24]:
# stat to check if the file exist
- st = self.lstat(se)
+ st = lstat(se)
if isinstance(st, int):
# file got unlinked in the interim
return True
logging.warn('Rsync: %s [errcode: %d]' % (se, rv[1]))
self.add_job(self.FLAT_DIR_HIERARCHY, 'reg', regjob, data, None, pb)
if self.wait(self.FLAT_DIR_HIERARCHY, None):
- self.update_crawl_data()
return True
- def process_change(self, change, done):
+ def process_change(self, change, done, retry):
+ pfx = gauxpfx()
clist = []
entries = []
- purges = set()
- links = set()
datas = set()
- pfx = gauxpfx()
+
+ # basic crawl stats: files and bytes
+ files_pending = {'count': 0, 'purge': 0, 'bytes': 0, 'files': []}
try:
f = open(change, "r")
clist = f.readlines()
@@ -860,6 +651,27 @@ class GMasterChangelogMixin(GMasterCommon):
else:
dct[k] = ed[k]
return dct
+
+ # regular file update: bytes & count
+ def _update_reg(entry, size):
+ if not entry in files_pending['files']:
+ files_pending['count'] += 1
+ files_pending['bytes'] += size
+ files_pending['files'].append(entry)
+ # updates for directories, symlinks etc..
+ def _update_rest():
+ files_pending['count'] += 1
+
+ # entry count
+ def entry_update(entry, size, mode):
+ if stat.S_ISREG(mode):
+ _update_reg(entry, size)
+ else:
+ _update_rest()
+ # purge count
+ def purge_update():
+ files_pending['purge'] += 1
+
for e in clist:
e = e.strip()
et = e[self.IDX_START:self.IDX_END]
@@ -870,51 +682,75 @@ class GMasterChangelogMixin(GMasterCommon):
gfid = ec[self.POS_GFID]
# definitely need a better way bucketize entry ops
if ty in ['UNLINK', 'RMDIR']:
- entries.append(edct(ty, gfid=gfid, entry=en))
- purges.update([os.path.join(pfx, gfid)])
- continue
- if not ty == 'RENAME':
- go = os.path.join(pfx, gfid)
- st = self.lstat(go)
- if isinstance(st, int):
+ purge_update()
+ entries.append(edct(ty, gfid=gfid, entry=en))
+ continue
+ go = os.path.join(pfx, gfid)
+ st = lstat(go)
+ if isinstance(st, int):
+ if ty == 'RENAME':
+ entries.append(edct('UNLINK', gfid=gfid, entry=en))
+ else:
logging.debug('file %s got purged in the interim' % go)
- continue
+ continue
+ entry_update(go, st.st_size, st.st_mode)
if ty in ['CREATE', 'MKDIR', 'MKNOD']:
entries.append(edct(ty, stat=st, entry=en, gfid=gfid))
elif ty == 'LINK':
entries.append(edct(ty, stat=st, entry=en, gfid=gfid))
- links.update([os.path.join(pfx, gfid)])
elif ty == 'SYMLINK':
- entries.append(edct(ty, stat=st, entry=en, gfid=gfid, link=os.readlink(en)))
+ rl = errno_wrap(os.readlink, [en], [ENOENT])
+ if isinstance(rl, int):
+ continue
+ entries.append(edct(ty, stat=st, entry=en, gfid=gfid, link=rl))
elif ty == 'RENAME':
e2 = unescape(os.path.join(pfx, ec[self.POS_ENTRY2]))
- entries.append(edct(ty, gfid=gfid, entry=en, entry1=e2))
+ entries.append(edct(ty, gfid=gfid, entry=en, entry1=e2, stat=st))
else:
- pass
+ logging.warn('ignoring %s [op %s]' % (gfid, ty))
elif et in self.TYPE_GFID:
- da = os.path.join(pfx, ec[0])
- st = self.lstat(da)
+ go = os.path.join(pfx, ec[0])
+ st = lstat(go)
if isinstance(st, int):
- logging.debug('file %s got purged in the interim' % da)
+ logging.debug('file %s got purged in the interim' % go)
continue
- datas.update([da])
+ entry_update(go, st.st_size, st.st_mode)
+ datas.update([go])
logging.debug('entries: %s' % repr(entries))
+ if not retry:
+ self.update_cumulative_stats(files_pending)
# sync namespace
if (entries):
self.slave.server.entry_ops(entries)
# sync data
- if self.syncdata(datas - (purges - links)):
+ if self.syncdata(datas):
if done:
self.master.server.changelog_done(change)
return True
+ def sync_done(self):
+ self.total_crawl_stats['files_syncd'] += self.total_crawl_stats['files_remaining']
+ self.total_crawl_stats['files_remaining'] = 0
+ self.total_crawl_stats['bytes_remaining'] = 0
+ self.total_crawl_stats['purges_remaining'] = 0
+ self.update_crawl_data()
+
def process(self, changes, done=1):
for change in changes:
- times = 0
+ tries = 0
+ retry = False
while True:
- times += 1
- logging.debug('processing change %s [%d time(s)]' % (change, times))
- if self.process_change(change, done):
+ logging.debug('processing change %s' % change)
+ if self.process_change(change, done, retry):
+ self.sync_done()
+ break
+ retry = True
+ tries += 1
+ if tries == self.MAX_RETRIES:
+ logging.warn('changelog %s could not be processed - moving on...' % os.path.basename(change))
+ self.sync_done()
+ if done:
+ self.master.server.changelog_done(change)
break
# it's either entry_ops() or Rsync that failed to do it's
# job. Mostly it's entry_ops() [which currently has a problem
@@ -928,7 +764,7 @@ class GMasterChangelogMixin(GMasterCommon):
self.turns += 1
def upd_stime(self, stime):
- if stime:
+ if not stime == URXTIME:
self.sendmark(self.FLAT_DIR_HIERARCHY, stime)
def crawl(self):
@@ -1031,7 +867,7 @@ class GMasterXsyncMixin(GMasterChangelogMixin):
for e in dem:
bname = e
e = os.path.join(path, e)
- st = self.lstat(e)
+ st = lstat(e)
if isinstance(st, int):
logging.warn('%s got purged in the interim..' % e)
continue
@@ -1048,178 +884,27 @@ class GMasterXsyncMixin(GMasterChangelogMixin):
if stat.S_ISDIR(mo):
self.write_entry_change("E", [gfid, 'MKDIR', escape(os.path.join(pargfid, bname))])
self.crawl(e, xtr)
- elif stat.S_ISREG(mo):
- self.write_entry_change("E", [gfid, 'CREATE', escape(os.path.join(pargfid, bname))])
- self.write_entry_change("D", [gfid])
elif stat.S_ISLNK(mo):
- self.write_entry_change("E", [gfid, 'SYMLINK', escape(os.path.join(pargfid, bname))])
+ rl = errno_wrap(os.readlink, [en], [ENOENT])
+ if isinstance(rl, int):
+ continue
+ self.write_entry_change("E", [gfid, 'SYMLINK', escape(os.path.join(pargfid, bname)), rl])
else:
- logging.info('ignoring %s' % e)
+ # if a file has a hardlink, create a Changelog entry as 'LINK' so the slave
+ # side will decide if to create the new entry, or to create link.
+ if st.st_nlink == 1:
+ self.write_entry_change("E", [gfid, 'MKNOD', escape(os.path.join(pargfid, bname))])
+ else:
+ self.write_entry_change("E", [gfid, 'LINK', escape(os.path.join(pargfid, bname))])
+ if stat.S_ISREG(mo):
+ self.write_entry_change("D", [gfid])
+
if path == '.':
logging.info('processing xsync changelog %s' % self.fname())
self.close()
self.process([self.fname()], done)
self.upd_stime(xtl)
-class GMasterXtimeMixin(GMasterCommon):
- """ xtime based change detection and syncing """
-
- def register(self):
- pass
-
- def crawl(self, path='.', xtl=None):
- """crawling...
-
- Standing around
- All the right people
- Crawling
- Tennis on Tuesday
- The ladder is long
- It is your nature
- You've gotta suntan
- Football on Sunday
- Society boy
-
- Recursively walk the master side tree and check if updates are
- needed due to xtime differences. One invocation of crawl checks
- children of @path and do a recursive enter only on
- those directory children where there is an update needed.
-
- Way of updates depend on file type:
- - for symlinks, sync them directy and synchronously
- - for regular children, register jobs for @path (cf. .add_job) to start
- and wait on their rsync
- - for directory children, register a job for @path which waits (.wait)
- on jobs for the given child
- (other kind of filesystem nodes are not considered)
-
- Those slave side children which do not exist on master are simply
- purged (see Server.purge).
-
- Behavior is fault tolerant, synchronization is adaptive: if some action fails,
- just go on relentlessly, adding a fail job (see .add_failjob) which will prevent
- the .sendmark on @path, so when the next crawl will arrive to @path it will not
- see it as up-to-date and will try to sync it again. While this semantics can be
- supported by funky design principles (http://c2.com/cgi/wiki?LazinessImpatienceHubris),
- the ultimate reason which excludes other possibilities is simply transience: we cannot
- assert that the file systems (master / slave) underneath do not change and actions
- taken upon some condition will not lose their context by the time they are performed.
- """
- logging.debug("entering " + path)
- if not xtl:
- xtl = self.xtime(path)
- if isinstance(xtl, int):
- self.add_failjob(path, 'no-local-node')
- return
- xtr = self.xtime(path, self.slave)
- if isinstance(xtr, int):
- if xtr != ENOENT:
- self.slave.server.purge(path)
- try:
- self.slave.server.mkdir(path)
- except OSError:
- self.add_failjob(path, 'no-remote-node')
- return
- xtr = self.minus_infinity
- else:
- self.xtime_reversion_hook(path, xtl, xtr)
- if xtl == xtr:
- if path == '.' and self.change_seen:
- self.turns += 1
- self.change_seen = False
- if self.total_turns:
- logging.info("finished turn #%s/%s" % \
- (self.turns, self.total_turns))
- if self.turns == self.total_turns:
- logging.info("reached turn limit")
- self.terminate = True
- return
- if path == '.':
- self.change_seen = True
- try:
- dem = self.master.server.entries(path)
- except OSError:
- self.add_failjob(path, 'local-entries-fail')
- return
- random.shuffle(dem)
- try:
- des = self.slave.server.entries(path)
- except OSError:
- self.slave.server.purge(path)
- try:
- self.slave.server.mkdir(path)
- des = self.slave.server.entries(path)
- except OSError:
- self.add_failjob(path, 'remote-entries-fail')
- return
- dd = set(des) - set(dem)
- if dd:
- self.purge_missing(path, dd)
- chld = []
- for e in dem:
- e = os.path.join(path, e)
- xte = self.xtime(e)
- if isinstance(xte, int):
- logging.warn("irregular xtime for %s: %s" % (e, errno.errorcode[xte]))
- elif self.need_sync(e, xte, xtr):
- chld.append((e, xte))
- def indulgently(e, fnc, blame=None):
- if not blame:
- blame = path
- try:
- return fnc(e)
- except (IOError, OSError):
- ex = sys.exc_info()[1]
- if ex.errno == ENOENT:
- logging.warn("salvaged ENOENT for " + e)
- self.add_failjob(blame, 'by-indulgently')
- return False
- else:
- raise
- for e, xte in chld:
- st = indulgently(e, lambda e: os.lstat(e))
- if st == False:
- continue
-
- mo = st.st_mode
- adct = {'own': (st.st_uid, st.st_gid)}
- if stat.S_ISLNK(mo):
- if indulgently(e, lambda e: self.slave.server.symlink(os.readlink(e), e)) == False:
- continue
- self.sendmark(e, xte, adct)
- elif stat.S_ISREG(mo):
- logging.debug("syncing %s ..." % e)
- pb = self.syncer.add(e)
- timeA = datetime.now()
- def regjob(e, xte, pb):
- if pb.wait()[0]:
- logging.debug("synced " + e)
- self.sendmark_regular(e, xte)
- # update stats
- timeB = datetime.now()
- self.crawl_stats['last_synctime'] = timeB - timeA
- self.crawl_stats['sync_time'] += ((self.crawl_stats['last_synctime'].microseconds) / (10.0 ** 6))
- self.crawl_stats['files_synced'] += 1
- self.total_crawl_stats['sync_time'] += ((self.crawl_stats['last_synctime'].microseconds) / (10.0 ** 6))
- self.total_crawl_stats['files_synced'] += 1
- self.update_crawl_data()
- return True
- else:
- logging.warn("failed to sync " + e)
- self.add_job(path, 'reg', regjob, e, xte, pb)
- elif stat.S_ISDIR(mo):
- adct['mode'] = mo
- if indulgently(e, lambda e: (self.add_job(path, 'cwait', self.wait, e, xte, adct),
- self.crawl(e, xte),
- True)[-1], blame=e) == False:
- continue
- else:
- # ignore fifos, sockets and special files
- pass
- if path == '.':
- self.wait(path, xtl)
-
-
class BoxClosedErr(Exception):
pass
diff --git a/geo-replication/syncdaemon/monitor.py b/geo-replication/syncdaemon/monitor.py
index badd0d9c5..0c3a42fa6 100644
--- a/geo-replication/syncdaemon/monitor.py
+++ b/geo-replication/syncdaemon/monitor.py
@@ -176,19 +176,6 @@ class Monitor(object):
return ret
def multiplex(self, wspx, suuid):
- def sigcont_handler(*a):
- """
- Re-init logging and send group kill signal
- """
- md = gconf.log_metadata
- logging.shutdown()
- lcls = logging.getLoggerClass()
- lcls.setup(label=md.get('saved_label'), **md)
- pid = os.getpid()
- os.kill(-pid, signal.SIGUSR1)
- signal.signal(signal.SIGUSR1, lambda *a: ())
- signal.signal(signal.SIGCONT, sigcont_handler)
-
argv = sys.argv[:]
for o in ('-N', '--no-daemon', '--monitor'):
while o in argv:
@@ -218,7 +205,6 @@ def distribute(*resources):
master, slave = resources
mvol = Volinfo(master.volume, master.host)
logging.debug('master bricks: ' + repr(mvol.bricks))
- locmbricks = [ b['dir'] for b in mvol.bricks if is_host_local(b['host']) ]
prelude = []
si = slave
if isinstance(slave, SSH):
@@ -240,7 +226,7 @@ def distribute(*resources):
else:
slavenodes = set(b['host'] for b in sbricks)
if isinstance(slave, SSH) and not gconf.isolated_slave:
- rap = SSH.parse_ssh_address(slave.remote_addr)
+ rap = SSH.parse_ssh_address(slave)
slaves = [ 'ssh://' + rap['user'] + '@' + h + ':' + si.url for h in slavenodes ]
else:
slavevols = [ h + ':' + si.volume for h in slavenodes ]
@@ -248,11 +234,8 @@ def distribute(*resources):
slaves = [ 'ssh://' + rap.remote_addr + ':' + v for v in slavevols ]
else:
slaves = slavevols
- locmbricks.sort()
- slaves.sort()
- workerspex = []
- for i in range(len(locmbricks)):
- workerspex.append((locmbricks[i], slaves[i % len(slaves)]))
+
+ workerspex = [ (brick['dir'], slaves[idx % len(slaves)]) for idx, brick in enumerate(mvol.bricks) if is_host_local(brick['host']) ]
logging.info('worker specs: ' + repr(workerspex))
return workerspex, suuid
diff --git a/geo-replication/syncdaemon/resource.py b/geo-replication/syncdaemon/resource.py
index 4b0183b98..faf62f868 100644
--- a/geo-replication/syncdaemon/resource.py
+++ b/geo-replication/syncdaemon/resource.py
@@ -12,7 +12,7 @@ import logging
import tempfile
import threading
import subprocess
-from errno import EEXIST, ENOENT, ENODATA, ENOTDIR, ELOOP, EISDIR, ENOTEMPTY
+from errno import EEXIST, ENOENT, ENODATA, ENOTDIR, ELOOP, EISDIR, ENOTEMPTY, ESTALE, EINVAL
from select import error as SelectError
from gconf import gconf
@@ -21,7 +21,7 @@ from repce import RepceServer, RepceClient
from master import gmaster_builder
import syncdutils
from syncdutils import GsyncdError, select, privileged, boolify, funcode
-from syncdutils import umask, entry2pb, gauxpfx, errno_wrap
+from syncdutils import umask, entry2pb, gauxpfx, errno_wrap, lstat
UrlRX = re.compile('\A(\w+)://([^ *?[]*)\Z')
HostRX = re.compile('[a-z\d](?:[a-z\d.-]*[a-z\d])?', re.I)
@@ -398,7 +398,7 @@ class Server(object):
@classmethod
def gfid(cls, gfidpath):
- return errno_wrap(Xattr.lgetxattr, [gfidpath, 'glusterfs.gfid', cls.GX_GFID_CANONICAL_LEN], [ENOENT])
+ return errno_wrap(Xattr.lgetxattr, [gfidpath, 'glusterfs.gfid.string', cls.GX_GFID_CANONICAL_LEN], [ENOENT])
@classmethod
def node_uuid(cls, path='.'):
@@ -432,6 +432,18 @@ class Server(object):
Xattr.lsetxattr(path, '.'.join([cls.GX_NSPACE, uuid, 'xtime']), struct.pack('!II', *mark))
@classmethod
+ @_pathguard
+ def set_xtime_remote(cls, path, uuid, mark):
+ """
+ set @mark as xtime for @uuid on @path
+ the difference b/w this and set_xtime() being
+ set_xtime() being overloaded to set the xtime
+ on the brick (this method sets xtime on the
+ remote slave)
+ """
+ Xattr.lsetxattr(path, '.'.join([cls.GX_NSPACE, uuid, 'xtime']), struct.pack('!II', *mark))
+
+ @classmethod
def set_xtime_vec(cls, path, mark_dct):
"""vectored (or dictered) version of set_xtime
@@ -497,19 +509,30 @@ class Server(object):
time.sleep(1)
else:
break
- elif op == 'CREATE':
+ elif op in ['CREATE', 'MKNOD']:
blob = entry_pack_reg(gfid, bname, e['stat'])
elif op == 'MKDIR':
blob = entry_pack_mkdir(gfid, bname, e['stat'])
elif op == 'LINK':
- errno_wrap(os.link, [os.path.join(pfx, gfid), entry], [ENOENT, EEXIST])
+ slink = os.path.join(pfx, gfid)
+ st = lstat(slink)
+ if isinstance(st, int):
+ (pg, bname) = entry2pb(entry)
+ blob = entry_pack_reg(gfid, bname, e['stat'])
+ else:
+ errno_wrap(os.link, [slink, entry], [ENOENT, EEXIST])
elif op == 'SYMLINK':
blob = entry_pack_symlink(gfid, bname, e['link'], e['stat'])
elif op == 'RENAME':
en = e['entry1']
- errno_wrap(os.rename, [entry, en], [ENOENT, EEXIST])
+ st = lstat(entry)
+ if isinstance(st, int):
+ (pg, bname) = entry2pb(en)
+ blob = entry_pack_reg(gfid, bname, e['stat'])
+ else:
+ errno_wrap(os.rename, [entry, en], [ENOENT, EEXIST])
if blob:
- errno_wrap(Xattr.lsetxattr_l, [pg, 'glusterfs.gfid.newfile', blob], [ENOENT, EEXIST])
+ errno_wrap(Xattr.lsetxattr_l, [pg, 'glusterfs.gfid.newfile', blob], [EEXIST], [ENOENT, ESTALE, EINVAL])
@classmethod
def changelog_register(cls, cl_brick, cl_dir, cl_log, cl_level, retries = 0):
@@ -1059,16 +1082,17 @@ class SSH(AbstractUrl, SlaveRemote):
self.volume = inner_url[1:]
@staticmethod
- def parse_ssh_address(addr):
- m = re.match('([^@]+)@(.+)', addr)
+ def parse_ssh_address(self):
+ m = re.match('([^@]+)@(.+)', self.remote_addr)
if m:
u, h = m.groups()
else:
- u, h = syncdutils.getusername(), addr
+ u, h = syncdutils.getusername(), self.remote_addr
+ self.remotehost = h
return {'user': u, 'host': h}
def canonical_path(self):
- rap = self.parse_ssh_address(self.remote_addr)
+ rap = self.parse_ssh_address(self)
remote_addr = '@'.join([rap['user'], gethostbyname(rap['host'])])
return ':'.join([remote_addr, self.inner_rsc.get_url(canonical=True)])
@@ -1115,9 +1139,15 @@ class SSH(AbstractUrl, SlaveRemote):
"""
if go_daemon == 'done':
return self.start_fd_client(*self.fd_pair)
- gconf.setup_ssh_ctl(tempfile.mkdtemp(prefix='gsyncd-aux-ssh-'))
+
+ syncdutils.setup_ssh_ctl(tempfile.mkdtemp(prefix='gsyncd-aux-ssh-'),
+ self.remote_addr,
+ self.inner_rsc.url)
+
deferred = go_daemon == 'postconn'
- ret = sup(self, gconf.ssh_command.split() + gconf.ssh_ctl_args + [self.remote_addr], slave=self.inner_rsc.url, deferred=deferred)
+ ret = sup(self, gconf.ssh_command.split() + gconf.ssh_ctl_args + [self.remote_addr],
+ slave=self.inner_rsc.url, deferred=deferred)
+
if deferred:
# send a message to peer so that we can wait for
# the answer from which we know connection is
diff --git a/geo-replication/syncdaemon/syncdutils.py b/geo-replication/syncdaemon/syncdutils.py
index 720200018..348eb38c1 100644
--- a/geo-replication/syncdaemon/syncdutils.py
+++ b/geo-replication/syncdaemon/syncdutils.py
@@ -12,6 +12,7 @@ from signal import signal, SIGTERM, SIGKILL
from time import sleep
import select as oselect
from os import waitpid as owaitpid
+
try:
from cPickle import PickleError
except ImportError:
@@ -34,6 +35,7 @@ except ImportError:
# auxillary gfid based access prefix
_CL_AUX_GFID_PFX = ".gfid/"
+GF_OP_RETRIES = 20
def escape(s):
"""the chosen flavor of string escaping, used all over
@@ -78,6 +80,38 @@ def update_file(path, updater, merger = lambda f: True):
if fx:
fx.close()
+def create_manifest(fname, content):
+ """
+ Create manifest file for SSH Control Path
+ """
+ fd = None
+ try:
+ fd = os.open(fname, os.O_CREAT|os.O_RDWR)
+ try:
+ os.write(fd, content)
+ except:
+ os.close(fd)
+ raise
+ finally:
+ if fd != None:
+ os.close(fd)
+
+def setup_ssh_ctl(ctld, remote_addr, resource_url):
+ """
+ Setup GConf ssh control path parameters
+ """
+ gconf.ssh_ctl_dir = ctld
+ content = "SLAVE_HOST=%s\nSLAVE_RESOURCE_URL=%s" % (remote_addr,
+ resource_url)
+ content_md5 = md5hex(content)
+ fname = os.path.join(gconf.ssh_ctl_dir,
+ "%s.mft" % content_md5)
+
+ create_manifest(fname, content)
+ ssh_ctl_path = os.path.join(gconf.ssh_ctl_dir,
+ "%s.sock" % content_md5)
+ gconf.ssh_ctl_args = ["-oControlMaster=auto", "-S", ssh_ctl_path]
+
def grabfile(fname, content=None):
"""open @fname + contest for its fcntl lock
@@ -372,10 +406,11 @@ def md5hex(s):
def selfkill(sig=SIGTERM):
os.kill(os.getpid(), sig)
-def errno_wrap(call, arg=[], errnos=[]):
+def errno_wrap(call, arg=[], errnos=[], retry_errnos=[ESTALE]):
""" wrapper around calls resilient to errnos.
- retry in case of ESTALE
+ retry in case of ESTALE by default.
"""
+ nr_tries = 0
while True:
try:
return call(*arg)
@@ -383,6 +418,21 @@ def errno_wrap(call, arg=[], errnos=[]):
ex = sys.exc_info()[1]
if ex.errno in errnos:
return ex.errno
- if not ex.errno == ESTALE:
+ if not ex.errno in retry_errnos:
raise
- time.sleep(0.5) # retry the call
+ nr_tries += 1
+ if nr_tries == GF_OP_RETRIES:
+ # probably a screwed state, cannot do much...
+ logging.warn('reached maximum retries (%s)...' % repr(arg))
+ return
+ time.sleep(0.250) # retry the call
+
+def lstat(e):
+ try:
+ return os.lstat(e)
+ except (IOError, OSError):
+ ex = sys.exc_info()[1]
+ if ex.errno == ENOENT:
+ return ex.errno
+ else:
+ raise
diff --git a/glusterfs-api.pc.in b/glusterfs-api.pc.in
index 5252a6f40..fab4a57d5 100644
--- a/glusterfs-api.pc.in
+++ b/glusterfs-api.pc.in
@@ -7,6 +7,6 @@ includedir=@includedir@
Name: glusterfs-api
Description: GlusterFS API
/* This is the API version, NOT package version */
-Version: 5
+Version: 6
Libs: -L${libdir} -lgfapi -lglusterfs -lgfrpc -lgfxdr
Cflags: -I${includedir}/glusterfs -D_FILE_OFFSET_BITS=64 -D__USE_FILE_OFFSET64
diff --git a/glusterfs.spec.in b/glusterfs.spec.in
index f47418752..040500c5f 100644
--- a/glusterfs.spec.in
+++ b/glusterfs.spec.in
@@ -1,4 +1,3 @@
-
%global _hardened_build 1
%global _for_fedora_koji_builds 0
@@ -35,8 +34,8 @@
# rpmbuild -ta @PACKAGE_NAME@-@PACKAGE_VERSION@tar.gz --without syslog
%{?_without_syslog:%global _without_syslog --disable-syslog}
-# disable syslog forcefully as rhel < 6 doesn't have rsyslog
-%if ( 0%{?rhel} && 0%{?rhel} < 6 )
+# disable syslog forcefully as rhel <= 6 doesn't have rsyslog or rsyslog-mmcount
+%if ( 0%{?rhel} && 0%{?rhel} <= 6 )
%global _without_syslog --disable-syslog
%endif
@@ -51,15 +50,30 @@
%define _without_bd --disable-bd-xlator
%endif
+# if you wish to compile an rpm without the qemu-block support...
+# rpmbuild -ta @PACKAGE_NAME@-@PACKAGE_VERSION@.tar.gz --without qemu-block
+%{?_without_qemu_block:%global _without_qemu_block --disable-qemu-block}
+
+%if ( 0%{?rhel} && 0%{?rhel} < 6 )
+# xlators/features/qemu-block fails to build on RHEL5, disable it
+%define _without_qemu_block --disable-qemu-block
+%endif
+
%if ( 0%{?fedora} && 0%{?fedora} > 16 ) || ( 0%{?rhel} && 0%{?rhel} > 6 )
%global _with_systemd true
%endif
+# From https://fedoraproject.org/wiki/Packaging:Python#Macros
+%if ( 0%{?rhel} && 0%{?rhel} <= 5 )
+%{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")}
+%{!?python_sitearch: %global python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")}
+%endif
+
Summary: Cluster File System
%if ( 0%{_for_fedora_koji_builds} )
Name: glusterfs
-Version: 3.4.0
-Release: 8%{?prereltag:.%{prereltag}}%{?dist}
+Version: 3.4.1
+Release: 3%{?prereltag:.%{prereltag}}%{?dist}
Vendor: Fedora Project
%else
Name: @PACKAGE_NAME@
@@ -140,6 +154,9 @@ BuildRequires: systemtap-sdt-devel
%if ( 0%{!?_without_bd:1} )
BuildRequires: lvm2-devel
%endif
+%if ( 0%{!?_without_qemu_block:1} )
+BuildRequires: glib2-devel
+%endif
Obsoletes: hekafs <= 0.7
Obsoletes: %{name}-libs <= 2.0.0
@@ -164,6 +181,11 @@ Provides: %{name}-core = %{version}-%{release}
%global __provides_exclude_from ^%{_libdir}/glusterfs/%{version}/.*$
%endif
+%if ( 0%{?rhel} && 0%{?rhel} < 6 )
+ # _sharedstatedir is not provided by RHEL5
+ %define _sharedstatedir /var/lib
+%endif
+
%description
GlusterFS is a clustered file-system capable of scaling to several
petabytes. It aggregates various storage bricks over Infiniband RDMA
@@ -304,6 +326,9 @@ This package provides the glusterfs server daemon.
Summary: Clustered file-system api library
Group: System Environment/Daemons
Requires: %{name} = %{version}-%{release}
+Requires: %{name}-devel = %{version}-%{release}
+# we provide the Python package/namespace 'gluster'
+Provides: python-gluster = %{version}-%{release}
%description api
GlusterFS is a clustered file-system capable of scaling to several
@@ -314,7 +339,7 @@ terms of features and extensibility. It borrows a powerful concept
called Translators from GNU Hurd kernel. Much of the code in GlusterFS
is in user space and easily manageable.
-This package provides the glusterfs libgfapi library
+This package provides the glusterfs libgfapi library.
%if ( 0%{!?_without_ocf:1} )
%package resource-agents
@@ -369,6 +394,7 @@ This package provides the development libraries and include files.
Summary: Development Libraries
Group: Development/Libraries
Requires: %{name} = %{version}-%{release}
+Requires: %{name}-devel = %{version}-%{release}
%description api-devel
GlusterFS is a clustered file-system capable of scaling to several
@@ -381,6 +407,19 @@ is in user space and easily manageable.
This package provides the api include files.
+%package regression-tests
+Summary: Development Tools
+Group: Development/Tools
+Requires: %{name} = %{version}-%{release}
+Requires: %{name}-fuse = %{version}-%{release}
+Requires: %{name}-server = %{version}-%{release}
+Requires: perl(App::Prove) perl(Test::Harness) gcc util-linux-ng lvm2
+Requires: python attr dbench git nfs-utils xfsprogs
+
+%description regression-tests
+The Gluster Test Framework, is a suite of scripts used for
+regression testing of Gluster.
+
%prep
%setup -q -n %{name}-%{version}%{?prereltag}
%if ( 0%{_for_fedora_koji_builds} )
@@ -393,7 +432,16 @@ This package provides the api include files.
%build
./autogen.sh
-%configure %{?_without_rdma} %{?_without_epoll} %{?_without_fusermount} %{?_without_georeplication} %{?_without_ocf} %{?_without_syslog} %{?_without_bd} %{?_without_systemtap}
+%configure \
+ %{?_without_rdma} \
+ %{?_without_epoll} \
+ %{?_without_fusermount} \
+ %{?_without_georeplication} \
+ %{?_without_ocf} \
+ %{?_without_syslog} \
+ %{?_without_bd} \
+ %{?_without_qemu_block} \
+ %{?_without_systemtap}
# fix hardening and remove rpath in shlibs
%if ( 0%{?fedora} && 0%{?fedora} > 17 ) || ( 0%{?rhel} && 0%{?rhel} > 6 )
@@ -404,9 +452,17 @@ This package provides the api include files.
%{__make} %{?_smp_mflags}
+pushd api/examples
+FLAGS="$RPM_OPT_FLAGS" %{__python} setup.py build
+popd
+
%install
%{__rm} -rf %{buildroot}
%{__make} install DESTDIR=%{buildroot}
+# install the gfapi Python library in /usr/lib/python*/site-packages
+pushd api/examples
+%{__python} setup.py install --skip-build --verbose --root %{buildroot}
+popd
# Install include directory
%{__mkdir_p} %{buildroot}%{_includedir}/glusterfs
%{__install} -p -m 0644 libglusterfs/src/*.h \
@@ -470,11 +526,9 @@ sed -i 's|option working-directory /etc/glusterd|option working-directory %{_sha
%{buildroot}%{_sysconfdir}/glusterfs/glusterd.vol
# Install glusterfsd .service or init.d file
-%if ( 0%{?_with_systemd:1} )
%if ( 0%{_for_fedora_koji_builds} )
%_init_install %{glusterfsd_service} glusterfsd
%endif
-%endif
%if ( 0%{_for_fedora_koji_builds} )
# Client logrotate entry
@@ -496,17 +550,19 @@ sed -i 's|option working-directory /etc/glusterd|option working-directory %{_sha
# geo-rep ghosts
%{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/geo-replication
touch %{buildroot}%{_sharedstatedir}/glusterd/geo-replication/gsyncd_template.conf
+%{__install} -D -p -m 0644 extras/glusterfs-georep-logrotate \
+ %{buildroot}%{_sysconfdir}/logrotate.d/glusterfs-georep
%endif
%if ( 0%{!?_without_syslog:1} )
%if ( 0%{?fedora} ) || ( 0%{?rhel} && 0%{?rhel} > 6 )
%{__install} -D -p -m 0644 extras/gluster-rsyslog-7.2.conf \
- %{buildroot}%{_sysconfdir}/rsyslog.d/gluster.conf
+ %{buildroot}%{_sysconfdir}/rsyslog.d/gluster.conf.example
%endif
%if ( 0%{?rhel} && 0%{?rhel} == 6 )
%{__install} -D -p -m 0644 extras/gluster-rsyslog-5.8.conf \
- %{buildroot}%{_sysconfdir}/rsyslog.d/gluster.conf
+ %{buildroot}%{_sysconfdir}/rsyslog.d/gluster.conf.example
%endif
%if ( 0%{?fedora} ) || ( 0%{?rhel} && 0%{?rhel} >= 6 )
@@ -555,20 +611,37 @@ touch %{buildroot}%{_sharedstatedir}/glusterd/options
touch %{buildroot}%{_sharedstatedir}/glusterd/nfs/nfs-server.vol
touch %{buildroot}%{_sharedstatedir}/glusterd/nfs/run/nfs.pid
+find ./tests ./run-tests.sh -type f | cpio -pd %{buildroot}%{_prefix}/share/glusterfs
+
%clean
%{__rm} -rf %{buildroot}
%post
/sbin/ldconfig
+%if ( 0%{!?_without_syslog:1} )
+%if ( 0%{?fedora} ) || ( 0%{?rhel} && 0%{?rhel} >= 6 )
+%_init_restart rsyslog
+%endif
+%endif
%postun
/sbin/ldconfig
+%if ( 0%{!?_without_syslog:1} )
+%if ( 0%{?fedora} ) || ( 0%{?rhel} && 0%{?rhel} >= 6 )
+%_init_restart rsyslog
+%endif
+%endif
%files
%defattr(-,root,root,-)
%doc ChangeLog COPYING-GPLV2 COPYING-LGPLV3 INSTALL README THANKS
%config(noreplace) %{_sysconfdir}/logrotate.d/*
%config(noreplace) %{_sysconfdir}/sysconfig/*
+%if ( 0%{!?_without_syslog:1} )
+%if ( 0%{?fedora} ) || ( 0%{?rhel} && 0%{?rhel} >= 6 )
+%{_sysconfdir}/rsyslog.d/gluster.conf.example
+%endif
+%endif
%{_libdir}/glusterfs
%{_sbindir}/glusterfs*
%{_mandir}/man8/*gluster*.8*
@@ -594,27 +667,12 @@ touch %{buildroot}%{_sharedstatedir}/glusterd/nfs/run/nfs.pid
%post libs
/sbin/ldconfig
-%if ( 0%{!?_without_syslog:1} )
-%if ( 0%{?fedora} ) || ( 0%{?rhel} && 0%{?rhel} >= 6 )
-%_init_restart rsyslog
-%endif
-%endif
%postun libs
/sbin/ldconfig
-%if ( 0%{!?_without_syslog:1} )
-%if ( 0%{?fedora} ) || ( 0%{?rhel} && 0%{?rhel} >= 6 )
-%_init_restart rsyslog
-%endif
-%endif
%files libs
%{_libdir}/*.so.*
-%if ( 0%{!?_without_syslog:1} )
-%if ( 0%{?fedora} ) || ( 0%{?rhel} && 0%{?rhel} >= 6 )
-%{_sysconfdir}/rsyslog.d/gluster.conf
-%endif
-%endif
%exclude %{_libdir}/libgfapi.*
%files cli
@@ -676,7 +734,7 @@ fi
%endif
# init files
%_init_glusterd
-%if ( 0%{_for_fedora_koji_builds} && 0%{?_with_systemd:1} )
+%if ( 0%{_for_fedora_koji_builds} )
%_init_glusterfsd
%endif
# binaries
@@ -686,8 +744,7 @@ fi
%{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/protocol/server*
%{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/mgmt*
%{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/nfs*
-%config(noreplace) %{_sharedstatedir}/glusterd/glusterd.info
-%ghost %attr(0644,-,-) %{_sharedstatedir}/glusterd/glusterd.info
+%ghost %attr(0644,-,-) %config(noreplace) %{_sharedstatedir}/glusterd/glusterd.info
%ghost %attr(0600,-,-) %{_sharedstatedir}/glusterd/options
# This is really ugly, but I have no idea how to mark these directories in an
# other way. They should belong to the glusterfs-server package, but don't
@@ -734,6 +791,7 @@ fi
%exclude %{_libdir}/*.so
%{_libdir}/libgfapi.*
%{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/mount/api*
+%{python_sitelib}/*
%if ( 0%{!?_without_ocf:1} )
%files resource-agents
@@ -756,6 +814,11 @@ fi
%{_libdir}/libgfapi.so
%{_includedir}/glusterfs/api/*
+%files regression-tests
+%defattr(-,root,root,-)
+%{_prefix}/share/glusterfs/*
+%exclude %{_prefix}/share/glusterfs/tests/basic/rpm.t
+
%post server
# Legacy server
%_init_enable glusterd
@@ -819,6 +882,22 @@ if [ $1 -ge 1 ]; then
fi
%changelog
+* Wed Oct 11 2013 Harshavardhana <fharshav@redhat.com>
+- Add '_sharedstatedir' macro to `/var/lib` on <= RHEL5 (#1003184)
+
+* Wed Oct 9 2013 Kaleb S. KEITHLEY <kkeithle@redhat.com>
+- Sync with Fedora glusterfs.spec 3.4.1-2+
+
+* Wed Oct 9 2013 Niels de Vos <ndevos@redhat.com>
+- glusterfs-api-devel requires glusterfs-devel (#1016938, #1017094)
+
+* Mon Sep 30 2013 Niels de Vos <ndevos@redhat.com>
+- Package gfapi.py into the Python site-packages path (#1005146)
+
+* Tue Sep 17 2013 Harshavardhana <fharshav@redhat.com>
+- Provide a new package called "glusterfs-regression-tests" for standalone
+ regression testing.
+
* Thu Aug 22 2013 Niels de Vos <ndevos@redhat.com>
- Correct the day/date for some entries in this changelog (#1000019)
diff --git a/glusterfsd/src/glusterfsd-mem-types.h b/glusterfsd/src/glusterfsd-mem-types.h
index 83f97b5d3..7135c0ada 100644
--- a/glusterfsd/src/glusterfsd-mem-types.h
+++ b/glusterfsd/src/glusterfsd-mem-types.h
@@ -17,6 +17,7 @@
enum gfd_mem_types_ {
gfd_mt_xlator_list_t = GF_MEM_TYPE_START,
gfd_mt_xlator_t,
+ gfd_mt_server_cmdline_t,
gfd_mt_xlator_cmdline_option_t,
gfd_mt_char,
gfd_mt_call_pool_t,
diff --git a/glusterfsd/src/glusterfsd-mgmt.c b/glusterfsd/src/glusterfsd-mgmt.c
index e26bf5a2f..1c9220927 100644
--- a/glusterfsd/src/glusterfsd-mgmt.c
+++ b/glusterfsd/src/glusterfsd-mgmt.c
@@ -1124,74 +1124,82 @@ out:
}
int
-glusterfs_handle_bd_op (rpcsvc_request_t *req)
+glusterfs_handle_volume_barrier_op (rpcsvc_request_t *req)
{
- int32_t ret = -1;
+ int32_t ret = -1;
gd1_mgmt_brick_op_req xlator_req = {0,};
- dict_t *input = NULL;
- xlator_t *xlator = NULL;
- xlator_t *any = NULL;
- dict_t *output = NULL;
- char *xname = NULL;
- glusterfs_ctx_t *ctx = NULL;
- glusterfs_graph_t *active = NULL;
- xlator_t *this = NULL;
- char *error = NULL;
+ dict_t *dict = NULL;
+ xlator_t *xlator = NULL;
+ xlator_t *any = NULL;
+ dict_t *output = NULL;
+ char msg[2048] = {0};
+ glusterfs_ctx_t *ctx = NULL;
+ glusterfs_graph_t *active = NULL;
+ xlator_t *this = NULL;
GF_ASSERT (req);
this = THIS;
GF_ASSERT (this);
+ ctx = glusterfsd_ctx;
+ GF_ASSERT (ctx);
+
+ active = ctx->active;
+ if (!active) {
+ req->rpc_err = GARBAGE_ARGS;
+ goto out;
+ }
+
+ any = active->first;
ret = xdr_to_generic (req->msg[0], &xlator_req,
(xdrproc_t)xdr_gd1_mgmt_brick_op_req);
if (ret < 0) {
- /* failed to decode msg */
+ //failed to decode msg;
req->rpc_err = GARBAGE_ARGS;
goto out;
}
+ dict = dict_new ();
+ if (!dict)
+ goto out;
- ctx = glusterfsd_ctx;
- active = ctx->active;
- any = active->first;
- input = dict_new ();
ret = dict_unserialize (xlator_req.input.input_val,
xlator_req.input.input_len,
- &input);
+ &dict);
if (ret < 0) {
gf_log (this->name, GF_LOG_ERROR,
"failed to "
"unserialize req-buffer to dictionary");
goto out;
- } else {
- input->extra_stdfree = xlator_req.input.input_val;
}
-
- /* FIXME, hardcoded */
- xlator = xlator_search_by_xl_type (any, "storage/bd_map");
+ xlator = xlator_search_by_name (any, xlator_req.name);
if (!xlator) {
- gf_log (this->name, GF_LOG_ERROR, "xlator %s is not "
- "loaded", xname);
- goto out;
+ snprintf (msg, sizeof (msg), "xlator %s is not loaded",
+ xlator_req.name);
+ goto out;
}
+
output = dict_new ();
- XLATOR_NOTIFY (xlator, GF_EVENT_TRANSLATOR_OP, input, output);
-out:
- if (ret < 0) {
- int retval;
- retval = dict_get_str (output, "error", &error);
+ if (!output) {
+ ret = -1;
+ goto out;
}
- glusterfs_xlator_op_response_send (req, ret, error, output);
- if (input)
- dict_unref (input);
+
+ ret = xlator->notify (xlator, GF_EVENT_VOLUME_BARRIER_OP,
+ dict, output);
+
+ ret = glusterfs_translator_info_response_send (req, ret,
+ msg, output);
+out:
+ if (dict)
+ dict_unref (dict);
+ free (xlator_req.input.input_val); // malloced by xdr
if (output)
dict_unref (output);
- if (xlator_req.name)
- /* malloced by xdr */
- free (xlator_req.name);
+ free (xlator_req.name); //malloced by xdr
- return 0;
-}
+ return ret;
+}
int
glusterfs_handle_rpc_msg (rpcsvc_request_t *req)
{
@@ -1200,7 +1208,7 @@ glusterfs_handle_rpc_msg (rpcsvc_request_t *req)
return ret;
}
-rpcclnt_cb_actor_t gluster_cbk_actors[] = {
+rpcclnt_cb_actor_t mgmt_cbk_actors[] = {
[GF_CBK_FETCHSPEC] = {"FETCHSPEC", GF_CBK_FETCHSPEC, mgmt_cbk_spec },
[GF_CBK_EVENT_NOTIFY] = {"EVENTNOTIFY", GF_CBK_EVENT_NOTIFY,
mgmt_cbk_event},
@@ -1211,7 +1219,7 @@ struct rpcclnt_cb_program mgmt_cbk_prog = {
.progname = "GlusterFS Callback",
.prognum = GLUSTER_CBK_PROGRAM,
.progver = GLUSTER_CBK_VERSION,
- .actors = gluster_cbk_actors,
+ .actors = mgmt_cbk_actors,
.numactors = GF_CBK_MAXVALUE,
};
@@ -1256,9 +1264,7 @@ rpcsvc_actor_t glusterfs_actors[] = {
[GLUSTERD_BRICK_XLATOR_DEFRAG] = {"TRANSLATOR DEFRAG", GLUSTERD_BRICK_XLATOR_DEFRAG, glusterfs_handle_defrag, NULL, 0, DRC_NA},
[GLUSTERD_NODE_PROFILE] = {"NFS PROFILE", GLUSTERD_NODE_PROFILE, glusterfs_handle_nfs_profile, NULL, 0, DRC_NA},
[GLUSTERD_NODE_STATUS] = {"NFS STATUS", GLUSTERD_NODE_STATUS, glusterfs_handle_node_status, NULL, 0, DRC_NA},
-#ifdef HAVE_BD_XLATOR
- [GLUSTERD_BRICK_BD_OP] = {"BD OP", GLUSTERD_BRICK_BD_OP, glusterfs_handle_bd_op, NULL, 0, DRC_NA}
-#endif
+ [GLUSTERD_VOLUME_BARRIER_OP] = {"VOLUME BARRIER OP", GLUSTERD_VOLUME_BARRIER_OP, glusterfs_handle_volume_barrier_op, NULL, 0, DRC_NA},
};
struct rpcsvc_program glusterfs_mop_prog = {
@@ -1330,187 +1336,7 @@ out:
static char *oldvolfile = NULL;
static int oldvollen = 0;
-static int
-xlator_equal_rec (xlator_t *xl1, xlator_t *xl2)
-{
- xlator_list_t *trav1 = NULL;
- xlator_list_t *trav2 = NULL;
- int ret = 0;
-
- if (xl1 == NULL || xl2 == NULL) {
- gf_log ("xlator", GF_LOG_DEBUG, "invalid argument");
- return -1;
- }
-
- trav1 = xl1->children;
- trav2 = xl2->children;
-
- while (trav1 && trav2) {
- ret = xlator_equal_rec (trav1->xlator, trav2->xlator);
- if (ret) {
- gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
- "xlators children not equal");
- goto out;
- }
-
- trav1 = trav1->next;
- trav2 = trav2->next;
- }
-
- if (trav1 || trav2) {
- ret = -1;
- goto out;
- }
-
- if (strcmp (xl1->name, xl2->name)) {
- ret = -1;
- goto out;
- }
-
- /* type could have changed even if xlator names match,
- e.g cluster/distrubte and cluster/nufa share the same
- xlator name
- */
- if (strcmp (xl1->type, xl2->type)) {
- ret = -1;
- goto out;
- }
-out :
- return ret;
-}
-
-static gf_boolean_t
-is_graph_topology_equal (glusterfs_graph_t *graph1,
- glusterfs_graph_t *graph2)
-{
- xlator_t *trav1 = NULL;
- xlator_t *trav2 = NULL;
- gf_boolean_t ret = _gf_true;
-
- trav1 = graph1->first;
- trav2 = graph2->first;
-
- ret = xlator_equal_rec (trav1, trav2);
-
- if (ret) {
- gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
- "graphs are not equal");
- ret = _gf_false;
- goto out;
- }
-
- ret = _gf_true;
- gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
- "graphs are equal");
-
-out:
- return ret;
-}
-
-/* Function has 3types of return value 0, -ve , 1
- * return 0 =======> reconfiguration of options has succeeded
- * return 1 =======> the graph has to be reconstructed and all the xlators should be inited
- * return -1(or -ve) =======> Some Internal Error occurred during the operation
- */
-static int
-glusterfs_volfile_reconfigure (FILE *newvolfile_fp)
-{
- glusterfs_graph_t *oldvolfile_graph = NULL;
- glusterfs_graph_t *newvolfile_graph = NULL;
- int oldvolfile_fd = -1;
- FILE *oldvolfile_fp = NULL;
- glusterfs_ctx_t *ctx = NULL;
- char template[PATH_MAX] = {0};
-
- int ret = -1;
-
- strcpy (template, "/tmp/tmp.XXXXXX");
- oldvolfile_fd = mkstemp (template);
- if (oldvolfile_fd == -1) {
- gf_log ("glusterfsd-mgmt", GF_LOG_ERROR, "Unable to create "
- "temporary file: %s (%s)", template,
- strerror (errno));
- goto out;
- }
- ret = unlink (template);
- if (ret < 0) {
- gf_log ("glusterfsd-mgmt", GF_LOG_WARNING, "Unable to delete "
- "file: %s", template);
- }
-
- oldvolfile_fp = fdopen (oldvolfile_fd, "w+b");
- if (!oldvolfile_fp) {
- gf_log ("glusterfsd-mgmt", GF_LOG_CRITICAL, "Failed to create "
- "temporary volfile");
- goto out;
- }
-
- if (!oldvollen) {
- ret = 1; // Has to call INIT for the whole graph
- goto out;
- }
- fwrite (oldvolfile, oldvollen, 1, oldvolfile_fp);
- fflush (oldvolfile_fp);
- if (ferror (oldvolfile_fp)) {
- goto out;
- }
-
-
- oldvolfile_graph = glusterfs_graph_construct (oldvolfile_fp);
- if (!oldvolfile_graph) {
- goto out;
- }
-
- newvolfile_graph = glusterfs_graph_construct (newvolfile_fp);
- if (!newvolfile_graph) {
- goto out;
- }
-
- if (!is_graph_topology_equal (oldvolfile_graph,
- newvolfile_graph)) {
-
- ret = 1;
- gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
- "Graph topology not equal(should call INIT)");
- goto out;
- }
-
- gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
- "Only options have changed in the new "
- "graph");
-
- ctx = glusterfsd_ctx;
-
- oldvolfile_graph = ctx->active;
-
- if (!oldvolfile_graph) {
- gf_log ("glusterfsd-mgmt", GF_LOG_ERROR,
- "glusterfs_ctx->active is NULL");
- goto out;
- }
-
- /* */
- ret = glusterfs_graph_reconfigure (oldvolfile_graph,
- newvolfile_graph);
- if (ret) {
- gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
- "Could not reconfigure new options in old graph");
- goto out;
- }
-
- ret = 0;
-out:
- if (oldvolfile_fp) {
- fclose (oldvolfile_fp);
-
- } else if (-1 != oldvolfile_fd) {
- close (oldvolfile_fd);
-
- }
-
- return ret;
-}
int
mgmt_getspec_cbk (struct rpc_req *req, struct iovec *iov, int count,
@@ -1576,7 +1402,7 @@ mgmt_getspec_cbk (struct rpc_req *req, struct iovec *iov, int count,
* return -1(or -ve) =======> Some Internal Error occurred during the operation
*/
- ret = glusterfs_volfile_reconfigure (tmpfp);
+ ret = glusterfs_volfile_reconfigure (oldvollen, tmpfp, ctx, oldvolfile);
if (ret == 0) {
gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
"No need to re-load volfile, reconfigure done");
@@ -1609,6 +1435,7 @@ mgmt_getspec_cbk (struct rpc_req *req, struct iovec *iov, int count,
volfilebuf = GF_REALLOC (oldvolfile, size);
else
volfilebuf = GF_CALLOC (1, size, gf_common_mt_char);
+
if (!volfilebuf) {
ret = -1;
goto out;
@@ -1821,30 +1648,52 @@ static int
mgmt_rpc_notify (struct rpc_clnt *rpc, void *mydata, rpc_clnt_event_t event,
void *data)
{
- xlator_t *this = NULL;
- cmd_args_t *cmd_args = NULL;
- glusterfs_ctx_t *ctx = NULL;
+ xlator_t *this = NULL;
+ glusterfs_ctx_t *ctx = NULL;
int ret = 0;
- int need_term = 0;
- int emval = 0;
+ server_cmdline_t *server = NULL;
+ rpc_transport_t *rpc_trans = NULL;
+ int need_term = 0;
+ int emval = 0;
this = mydata;
+ rpc_trans = rpc->conn.trans;
ctx = this->ctx;
- cmd_args = &ctx->cmd_args;
+
switch (event) {
case RPC_CLNT_DISCONNECT:
if (!ctx->active) {
- cmd_args->max_connect_attempts--;
gf_log ("glusterfsd-mgmt", GF_LOG_ERROR,
- "failed to connect with remote-host: %s",
+ "failed to connect with remote-host: %s (%s)",
+ ctx->cmd_args.volfile_server,
strerror (errno));
- gf_log ("glusterfsd-mgmt", GF_LOG_INFO,
- "%d connect attempts left",
- cmd_args->max_connect_attempts);
- if (0 >= cmd_args->max_connect_attempts) {
+ server = ctx->cmd_args.curr_server;
+ if (server->list.next == &ctx->cmd_args.volfile_servers) {
+ need_term = 1;
+ emval = ENOTCONN;
+ gf_log("glusterfsd-mgmt", GF_LOG_INFO,
+ "Exhausted all volfile servers");
+ break;
+ }
+ server = list_entry (server->list.next, typeof(*server),
+ list);
+ ctx->cmd_args.curr_server = server;
+ ctx->cmd_args.volfile_server = server->volfile_server;
+
+ ret = dict_set_str (rpc_trans->options,
+ "remote-host",
+ server->volfile_server);
+ if (ret != 0) {
+ gf_log ("glusterfsd-mgmt", GF_LOG_ERROR,
+ "failed to set remote-host: %s",
+ server->volfile_server);
need_term = 1;
emval = ENOTCONN;
+ break;
}
+ gf_log ("glusterfsd-mgmt", GF_LOG_INFO,
+ "connecting to next volfile server %s",
+ server->volfile_server);
}
break;
case RPC_CLNT_CONNECT:
@@ -2048,7 +1897,8 @@ glusterfs_mgmt_init (glusterfs_ctx_t *ctx)
ret = rpc_clnt_register_notify (rpc, mgmt_rpc_notify, THIS);
if (ret) {
- gf_log (THIS->name, GF_LOG_WARNING, "failed to register notify function");
+ gf_log (THIS->name, GF_LOG_WARNING,
+ "failed to register notify function");
goto out;
}
diff --git a/glusterfsd/src/glusterfsd.c b/glusterfsd/src/glusterfsd.c
index 7b2ccd6eb..3cb8f0f51 100644
--- a/glusterfsd/src/glusterfsd.c
+++ b/glusterfsd/src/glusterfsd.c
@@ -98,10 +98,6 @@ static struct argp_option gf_options[] = {
{"volfile-server", ARGP_VOLFILE_SERVER_KEY, "SERVER", 0,
"Server to get the volume file from. This option overrides "
"--volfile option"},
- {"volfile-max-fetch-attempts", ARGP_VOLFILE_MAX_FETCH_ATTEMPTS,
- "MAX-ATTEMPTS", 0, "Maximum number of connect attempts to server. "
- "This option should be provided with --volfile-server option"
- "[default: 1]"},
{"volfile", ARGP_VOLUME_FILE_KEY, "VOLFILE", 0,
"File to use as VOLUME_FILE"},
{"spec-file", ARGP_VOLUME_FILE_KEY, "VOLFILE", OPTION_HIDDEN,
@@ -167,7 +163,7 @@ static struct argp_option gf_options[] = {
"Brick name to be registered with Gluster portmapper" },
{"brick-port", ARGP_BRICK_PORT_KEY, "BRICK-PORT", OPTION_HIDDEN,
"Brick Port to be registered with Gluster portmapper" },
- {"fopen-keep-cache", ARGP_FOPEN_KEEP_CACHE_KEY, 0, 0,
+ {"fopen-keep-cache", ARGP_FOPEN_KEEP_CACHE_KEY, "BOOL", OPTION_ARG_OPTIONAL,
"Do not purge the cache on file open"},
{0, 0, 0, 0, "Fuse options:"},
@@ -383,7 +379,8 @@ set_fuse_mount_options (glusterfs_ctx_t *ctx, dict_t *options)
}
}
- if (cmd_args->fopen_keep_cache) {
+ switch (cmd_args->fopen_keep_cache) {
+ case GF_OPTION_ENABLE:
ret = dict_set_static_ptr(options, "fopen-keep-cache",
"on");
if (ret < 0) {
@@ -392,6 +389,23 @@ set_fuse_mount_options (glusterfs_ctx_t *ctx, dict_t *options)
"fopen-keep-cache");
goto err;
}
+ break;
+ case GF_OPTION_DISABLE:
+ ret = dict_set_static_ptr(options, "fopen-keep-cache",
+ "off");
+ if (ret < 0) {
+ gf_log("glusterfsd", GF_LOG_ERROR,
+ "failed to set dict value for key "
+ "fopen-keep-cache");
+ goto err;
+ }
+ break;
+ case GF_OPTION_DEFERRED: /* default */
+ default:
+ gf_log ("glusterfsd", GF_LOG_DEBUG,
+ "fopen-keep-cache mode %d",
+ cmd_args->fopen_keep_cache);
+ break;
}
if (cmd_args->gid_timeout) {
@@ -582,7 +596,58 @@ get_volfp (glusterfs_ctx_t *ctx)
}
static int
-gf_remember_xlator_option (struct list_head *options, char *arg)
+gf_remember_backup_volfile_server (char *arg)
+{
+ glusterfs_ctx_t *ctx = NULL;
+ cmd_args_t *cmd_args = NULL;
+ int ret = -1;
+ server_cmdline_t *server = NULL;
+
+ ctx = glusterfsd_ctx;
+ if (!ctx)
+ goto out;
+ cmd_args = &ctx->cmd_args;
+
+ if(!cmd_args)
+ goto out;
+
+ server = GF_CALLOC (1, sizeof (server_cmdline_t),
+ gfd_mt_server_cmdline_t);
+ if (!server)
+ goto out;
+
+ INIT_LIST_HEAD(&server->list);
+
+ server->volfile_server = gf_strdup(arg);
+
+ if (!cmd_args->volfile_server) {
+ cmd_args->volfile_server = server->volfile_server;
+ cmd_args->curr_server = server;
+ }
+
+ if (!server->volfile_server) {
+ gf_log ("", GF_LOG_WARNING,
+ "xlator option %s is invalid", arg);
+ goto out;
+ }
+
+ list_add_tail (&server->list, &cmd_args->volfile_servers);
+
+ ret = 0;
+out:
+ if (ret == -1) {
+ if (server) {
+ GF_FREE (server->volfile_server);
+ GF_FREE (server);
+ }
+ }
+
+ return ret;
+
+}
+
+static int
+gf_remember_xlator_option (char *arg)
{
glusterfs_ctx_t *ctx = NULL;
cmd_args_t *cmd_args = NULL;
@@ -673,19 +738,8 @@ parse_opts (int key, char *arg, struct argp_state *state)
switch (key) {
case ARGP_VOLFILE_SERVER_KEY:
- cmd_args->volfile_server = gf_strdup (arg);
- break;
-
- case ARGP_VOLFILE_MAX_FETCH_ATTEMPTS:
- n = 0;
+ gf_remember_backup_volfile_server (arg);
- if (gf_string2uint_base10 (arg, &n) == 0) {
- cmd_args->max_connect_attempts = n;
- break;
- }
-
- argp_failure (state, -1, 0,
- "Invalid limit on connect attempts %s", arg);
break;
case ARGP_READ_ONLY_KEY:
@@ -694,14 +748,12 @@ parse_opts (int key, char *arg, struct argp_state *state)
case ARGP_ACL_KEY:
cmd_args->acl = 1;
- gf_remember_xlator_option (&cmd_args->xlator_options,
- "*-md-cache.cache-posix-acl=true");
+ gf_remember_xlator_option ("*-md-cache.cache-posix-acl=true");
break;
case ARGP_SELINUX_KEY:
cmd_args->selinux = 1;
- gf_remember_xlator_option (&cmd_args->xlator_options,
- "*-md-cache.cache-selinux=true");
+ gf_remember_xlator_option ("*-md-cache.cache-selinux=true");
break;
case ARGP_AUX_GFID_MOUNT_KEY:
@@ -906,8 +958,9 @@ parse_opts (int key, char *arg, struct argp_state *state)
break;
case ARGP_XLATOR_OPTION_KEY:
- if (gf_remember_xlator_option (&cmd_args->xlator_options, arg))
- argp_failure (state, -1, 0, "invalid xlator option %s", arg);
+ if (gf_remember_xlator_option (arg))
+ argp_failure (state, -1, 0, "invalid xlator option %s",
+ arg);
break;
@@ -955,7 +1008,18 @@ parse_opts (int key, char *arg, struct argp_state *state)
break;
case ARGP_FOPEN_KEEP_CACHE_KEY:
- cmd_args->fopen_keep_cache = 1;
+ if (!arg)
+ arg = "on";
+
+ if (gf_string2boolean (arg, &b) == 0) {
+ cmd_args->fopen_keep_cache = b;
+
+ break;
+ }
+
+ argp_failure (state, -1, 0,
+ "unknown cache setting \"%s\"", arg);
+
break;
case ARGP_GID_TIMEOUT_KEY:
@@ -985,7 +1049,7 @@ parse_opts (int key, char *arg, struct argp_state *state)
case ARGP_FUSE_USE_READDIRP_KEY:
if (!arg)
- arg = "no";
+ arg = "yes";
if (gf_string2boolean (arg, &b) == 0) {
if (b) {
@@ -1136,72 +1200,12 @@ gf_get_process_mode (char *exec_name)
}
-
-static int
-set_log_file_path (cmd_args_t *cmd_args)
-{
- int i = 0;
- int j = 0;
- int ret = 0;
- int port = 0;
- char tmp_str[1024] = {0,};
-
- if (cmd_args->mount_point) {
- j = 0;
- i = 0;
- if (cmd_args->mount_point[0] == '/')
- i = 1;
- for (; i < strlen (cmd_args->mount_point); i++,j++) {
- tmp_str[j] = cmd_args->mount_point[i];
- if (cmd_args->mount_point[i] == '/')
- tmp_str[j] = '-';
- }
-
- ret = gf_asprintf (&cmd_args->log_file,
- DEFAULT_LOG_FILE_DIRECTORY "/%s.log",
- tmp_str);
- goto done;
- }
-
- if (cmd_args->volfile) {
- j = 0;
- i = 0;
- if (cmd_args->volfile[0] == '/')
- i = 1;
- for (; i < strlen (cmd_args->volfile); i++,j++) {
- tmp_str[j] = cmd_args->volfile[i];
- if (cmd_args->volfile[i] == '/')
- tmp_str[j] = '-';
- }
- ret = gf_asprintf (&cmd_args->log_file,
- DEFAULT_LOG_FILE_DIRECTORY "/%s.log",
- tmp_str);
- goto done;
- }
-
- if (cmd_args->volfile_server) {
- port = GF_DEFAULT_BASE_PORT;
-
- if (cmd_args->volfile_server_port)
- port = cmd_args->volfile_server_port;
-
- ret = gf_asprintf (&cmd_args->log_file,
- DEFAULT_LOG_FILE_DIRECTORY "/%s-%s-%d.log",
- cmd_args->volfile_server,
- cmd_args->volfile_id, port);
- }
-done:
- return ret;
-}
-
-
static int
glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx)
{
- cmd_args_t *cmd_args = NULL;
- struct rlimit lim = {0, };
- call_pool_t *pool = NULL;
- int ret = -1;
+ cmd_args_t *cmd_args = NULL;
+ struct rlimit lim = {0, };
+ int ret = -1;
xlator_mem_acct_init (THIS, gfd_mt_end);
@@ -1228,24 +1232,26 @@ glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx)
goto out;
}
- pool = GF_CALLOC (1, sizeof (call_pool_t),
- gfd_mt_call_pool_t);
- if (!pool) {
+ ctx->pool = GF_CALLOC (1, sizeof (call_pool_t), gfd_mt_call_pool_t);
+ if (!ctx->pool) {
gf_log ("", GF_LOG_CRITICAL,
"ERROR: glusterfs call pool creation failed");
goto out;
}
+ INIT_LIST_HEAD (&ctx->pool->all_frames);
+ LOCK_INIT (&ctx->pool->lock);
+
/* frame_mem_pool size 112 * 4k */
- pool->frame_mem_pool = mem_pool_new (call_frame_t, 4096);
- if (!pool->frame_mem_pool) {
+ ctx->pool->frame_mem_pool = mem_pool_new (call_frame_t, 4096);
+ if (!ctx->pool->frame_mem_pool) {
gf_log ("", GF_LOG_CRITICAL,
"ERROR: glusterfs frame pool creation failed");
goto out;
}
/* stack_mem_pool size 256 * 1024 */
- pool->stack_mem_pool = mem_pool_new (call_stack_t, 1024);
- if (!pool->stack_mem_pool) {
+ ctx->pool->stack_mem_pool = mem_pool_new (call_stack_t, 1024);
+ if (!ctx->pool->stack_mem_pool) {
gf_log ("", GF_LOG_CRITICAL,
"ERROR: glusterfs stack pool creation failed");
goto out;
@@ -1260,24 +1266,22 @@ glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx)
ctx->dict_pool = mem_pool_new (dict_t, GF_MEMPOOL_COUNT_OF_DICT_T);
if (!ctx->dict_pool)
- return -1;
+ goto out;
ctx->dict_pair_pool = mem_pool_new (data_pair_t,
GF_MEMPOOL_COUNT_OF_DATA_PAIR_T);
if (!ctx->dict_pair_pool)
- return -1;
+ goto out;
ctx->dict_data_pool = mem_pool_new (data_t, GF_MEMPOOL_COUNT_OF_DATA_T);
if (!ctx->dict_data_pool)
- return -1;
-
- INIT_LIST_HEAD (&pool->all_frames);
- LOCK_INIT (&pool->lock);
- ctx->pool = pool;
+ goto out;
pthread_mutex_init (&(ctx->lock), NULL);
ctx->clienttable = gf_clienttable_alloc();
+ if (!ctx->clienttable)
+ goto out;
cmd_args = &ctx->cmd_args;
@@ -1295,8 +1299,10 @@ glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx)
#endif
cmd_args->fuse_attribute_timeout = -1;
cmd_args->fuse_entry_timeout = -1;
+ cmd_args->fopen_keep_cache = GF_OPTION_DEFERRED;
INIT_LIST_HEAD (&cmd_args->xlator_options);
+ INIT_LIST_HEAD (&cmd_args->volfile_servers);
lim.rlim_cur = RLIM_INFINITY;
lim.rlim_max = RLIM_INFINITY;
@@ -1305,29 +1311,16 @@ glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx)
ret = 0;
out:
- if (ret && pool) {
-
- if (pool->frame_mem_pool)
- mem_pool_destroy (pool->frame_mem_pool);
-
- if (pool->stack_mem_pool)
- mem_pool_destroy (pool->stack_mem_pool);
-
- GF_FREE (pool);
- }
-
if (ret && ctx) {
- if (ctx->stub_mem_pool)
- mem_pool_destroy (ctx->stub_mem_pool);
-
- if (ctx->dict_pool)
- mem_pool_destroy (ctx->dict_pool);
-
- if (ctx->dict_data_pool)
- mem_pool_destroy (ctx->dict_data_pool);
-
- if (ctx->dict_pair_pool)
- mem_pool_destroy (ctx->dict_pair_pool);
+ if (ctx->pool) {
+ mem_pool_destroy (ctx->pool->frame_mem_pool);
+ mem_pool_destroy (ctx->pool->stack_mem_pool);
+ }
+ GF_FREE (ctx->pool);
+ mem_pool_destroy (ctx->stub_mem_pool);
+ mem_pool_destroy (ctx->dict_pool);
+ mem_pool_destroy (ctx->dict_data_pool);
+ mem_pool_destroy (ctx->dict_pair_pool);
}
return ret;
@@ -1345,7 +1338,7 @@ logging_init (glusterfs_ctx_t *ctx, const char *progpath)
cmd_args = &ctx->cmd_args;
if (cmd_args->log_file == NULL) {
- ret = set_log_file_path (cmd_args);
+ ret = gf_set_log_file_path (cmd_args);
if (ret == -1) {
fprintf (stderr, "ERROR: failed to set the log file path\n");
return -1;
diff --git a/glusterfsd/src/glusterfsd.h b/glusterfsd/src/glusterfsd.h
index 06b4aacc8..9e2a0e56e 100644
--- a/glusterfsd/src/glusterfsd.h
+++ b/glusterfsd/src/glusterfsd.h
@@ -20,8 +20,6 @@
#define DEFAULT_GLUSTERD_VOLFILE CONFDIR "/glusterd.vol"
#define DEFAULT_CLIENT_VOLFILE CONFDIR "/glusterfs.vol"
#define DEFAULT_SERVER_VOLFILE CONFDIR "/glusterfsd.vol"
-#define DEFAULT_LOG_FILE_DIRECTORY DATADIR "/log/glusterfs"
-#define DEFAULT_LOG_LEVEL GF_LOG_INFO
#define DEFAULT_EVENT_POOL_SIZE 16384
diff --git a/libglusterfs/src/Makefile.am b/libglusterfs/src/Makefile.am
index fc54f49a3..907399ae6 100644
--- a/libglusterfs/src/Makefile.am
+++ b/libglusterfs/src/Makefile.am
@@ -15,7 +15,7 @@ CONTRIB_BUILDDIR = $(top_builddir)/contrib
libglusterfs_la_SOURCES = dict.c xlator.c logging.c \
hashfn.c defaults.c common-utils.c timer.c inode.c call-stub.c \
compat.c fd.c compat-errno.c event.c mem-pool.c gf-dirent.c syscall.c \
- iobuf.c globals.c statedump.c stack.c checksum.c daemon.c \
+ iobuf.c globals.c statedump.c stack.c checksum.c daemon.c timespec.c \
$(CONTRIBDIR)/rbtree/rb.c rbthash.c store.c latency.c \
graph.c $(CONTRIBDIR)/uuid/clear.c $(CONTRIBDIR)/uuid/copy.c \
$(CONTRIBDIR)/uuid/gen_uuid.c $(CONTRIBDIR)/uuid/pack.c \
@@ -23,17 +23,16 @@ libglusterfs_la_SOURCES = dict.c xlator.c logging.c \
$(CONTRIBDIR)/uuid/uuid_time.c $(CONTRIBDIR)/uuid/compare.c \
$(CONTRIBDIR)/uuid/isnull.c $(CONTRIBDIR)/uuid/unpack.c syncop.c \
graph-print.c trie.c run.c options.c fd-lk.c circ-buff.c \
- event-history.c gidcache.c ctx.c client_t.c lock-table.c \
+ event-history.c gidcache.c ctx.c client_t.c event-poll.c event-epoll.c \
$(CONTRIBDIR)/libgen/basename_r.c $(CONTRIBDIR)/libgen/dirname_r.c \
- $(CONTRIBDIR)/stdlib/gf_mkostemp.c \
- event-poll.c event-epoll.c
+ $(CONTRIBDIR)/stdlib/gf_mkostemp.c
nodist_libglusterfs_la_SOURCES = y.tab.c graph.lex.c gf-error-codes.h
BUILT_SOURCES = graph.lex.c
-noinst_HEADERS = common-utils.h defaults.h dict.h glusterfs.h hashfn.h \
+noinst_HEADERS = common-utils.h defaults.h dict.h glusterfs.h hashfn.h timespec.h \
logging.h xlator.h stack.h timer.h list.h inode.h call-stub.h compat.h \
fd.h revision.h compat-errno.h event.h mem-pool.h byte-order.h \
gf-dirent.h locking.h syscall.h iobuf.h globals.h statedump.h \
@@ -42,16 +41,16 @@ noinst_HEADERS = common-utils.h defaults.h dict.h glusterfs.h hashfn.h \
$(CONTRIBDIR)/uuid/uuid.h $(CONTRIBDIR)/uuid/uuidP.h \
$(CONTRIB_BUILDDIR)/uuid/uuid_types.h syncop.h graph-utils.h trie.h \
run.h options.h lkowner.h fd-lk.h circ-buff.h event-history.h \
- gidcache.h client_t.h lock-table.h
+ gidcache.h client_t.h glusterfs-acl.h
EXTRA_DIST = graph.l graph.y
graph.lex.c: graph.l y.tab.h
- $(LEX) -t $(srcdir)/graph.l > $@
+ $(LEX) -Pgraphyy -t $(srcdir)/graph.l > $@
y.tab.c: y.tab.h
y.tab.h: graph.y
- $(YACC) -d $(srcdir)/graph.y
+ $(YACC) -p graphyy -d $(srcdir)/graph.y
CLEANFILES = graph.lex.c y.tab.c y.tab.h
CONFIG_CLEAN_FILES = $(CONTRIB_BUILDDIR)/uuid/uuid_types.h
diff --git a/libglusterfs/src/call-stub.c b/libglusterfs/src/call-stub.c
index 2f07a0074..ac79cf071 100644
--- a/libglusterfs/src/call-stub.c
+++ b/libglusterfs/src/call-stub.c
@@ -2241,6 +2241,62 @@ out:
}
+call_stub_t *
+fop_zerofill_cbk_stub(call_frame_t *frame, fop_zerofill_cbk_t fn,
+ int32_t op_ret, int32_t op_errno,
+ struct iatt *statpre, struct iatt *statpost,
+ dict_t *xdata)
+{
+ call_stub_t *stub = NULL;
+
+ GF_VALIDATE_OR_GOTO ("call-stub", frame, out);
+
+ stub = stub_new (frame, 0, GF_FOP_ZEROFILL);
+ GF_VALIDATE_OR_GOTO ("call-stub", stub, out);
+
+ stub->fn_cbk.zerofill = fn;
+
+ stub->args_cbk.op_ret = op_ret;
+ stub->args_cbk.op_errno = op_errno;
+
+ if (statpre)
+ stub->args_cbk.prestat = *statpre;
+ if (statpost)
+ stub->args_cbk.poststat = *statpost;
+ if (xdata)
+ stub->args_cbk.xdata = dict_ref (xdata);
+out:
+ return stub;
+}
+
+call_stub_t *
+fop_zerofill_stub(call_frame_t *frame, fop_zerofill_t fn, fd_t *fd,
+ off_t offset, size_t len, dict_t *xdata)
+{
+ call_stub_t *stub = NULL;
+
+ GF_VALIDATE_OR_GOTO ("call-stub", frame, out);
+ GF_VALIDATE_OR_GOTO ("call-stub", fn, out);
+
+ stub = stub_new (frame, 1, GF_FOP_ZEROFILL);
+ GF_VALIDATE_OR_GOTO ("call-stub", stub, out);
+
+ stub->fn.zerofill = fn;
+
+ if (fd)
+ stub->args.fd = fd_ref (fd);
+
+ stub->args.offset = offset;
+ stub->args.size = len;
+
+ if (xdata)
+ stub->args.xdata = dict_ref (xdata);
+out:
+ return stub;
+
+}
+
+
static void
call_resume_wind (call_stub_t *stub)
{
@@ -2468,6 +2524,12 @@ call_resume_wind (call_stub_t *stub)
stub->args.fd, stub->args.offset,
stub->args.size, stub->args.xdata);
break;
+ case GF_FOP_ZEROFILL:
+ stub->fn.zerofill(stub->frame, stub->frame->this,
+ stub->args.fd, stub->args.offset,
+ stub->args.size, stub->args.xdata);
+ break;
+
default:
gf_log_callingfn ("call-stub", GF_LOG_ERROR,
"Invalid value of FOP (%d)",
@@ -2670,6 +2732,11 @@ call_resume_unwind (call_stub_t *stub)
STUB_UNWIND(stub, discard, &stub->args_cbk.prestat,
&stub->args_cbk.poststat, stub->args_cbk.xdata);
break;
+ case GF_FOP_ZEROFILL:
+ STUB_UNWIND(stub, zerofill, &stub->args_cbk.prestat,
+ &stub->args_cbk.poststat, stub->args_cbk.xdata);
+ break;
+
default:
gf_log_callingfn ("call-stub", GF_LOG_ERROR,
"Invalid value of FOP (%d)",
diff --git a/libglusterfs/src/call-stub.h b/libglusterfs/src/call-stub.h
index f0872b121..45bef8044 100644
--- a/libglusterfs/src/call-stub.h
+++ b/libglusterfs/src/call-stub.h
@@ -71,6 +71,7 @@ typedef struct {
fop_fsetattr_t fsetattr;
fop_fallocate_t fallocate;
fop_discard_t discard;
+ fop_zerofill_t zerofill;
} fn;
union {
@@ -117,6 +118,7 @@ typedef struct {
fop_fsetattr_cbk_t fsetattr;
fop_fallocate_cbk_t fallocate;
fop_discard_cbk_t discard;
+ fop_zerofill_cbk_t zerofill;
} fn_cbk;
struct {
@@ -745,6 +747,20 @@ fop_discard_cbk_stub(call_frame_t *frame,
struct iatt *statpre, struct iatt *statpost,
dict_t *xdata);
+call_stub_t *
+fop_zerofill_stub(call_frame_t *frame,
+ fop_zerofill_t fn,
+ fd_t *fd,
+ off_t offset,
+ size_t len, dict_t *xdata);
+
+call_stub_t *
+fop_zerofill_cbk_stub(call_frame_t *frame,
+ fop_zerofill_cbk_t fn,
+ int32_t op_ret, int32_t op_errno,
+ struct iatt *statpre, struct iatt *statpost,
+ dict_t *xdata);
+
void call_resume (call_stub_t *stub);
void call_stub_destroy (call_stub_t *stub);
void call_unwind_error (call_stub_t *stub, int op_ret, int op_errno);
diff --git a/libglusterfs/src/circ-buff.c b/libglusterfs/src/circ-buff.c
index a48c92879..484ce7dc9 100644
--- a/libglusterfs/src/circ-buff.c
+++ b/libglusterfs/src/circ-buff.c
@@ -10,6 +10,17 @@
#include "circ-buff.h"
+void
+cb_destroy_data (circular_buffer_t *cb,
+ void (*destroy_buffer_data) (void *data))
+{
+ if (destroy_buffer_data)
+ destroy_buffer_data (cb->data);
+ GF_FREE (cb->data);
+ return;
+}
+
+
/* hold lock while calling this function */
int
__cb_add_entry_buffer (buffer_t *buffer, void *item)
@@ -29,7 +40,8 @@ __cb_add_entry_buffer (buffer_t *buffer, void *item)
if (buffer->cb[buffer->w_index]) {
ptr = buffer->cb[buffer->w_index];
if (ptr->data) {
- GF_FREE (ptr->data);
+ cb_destroy_data (ptr,
+ buffer->destroy_buffer_data);
ptr->data = NULL;
GF_FREE (ptr);
}
@@ -131,7 +143,8 @@ cb_buffer_dump (buffer_t *buffer, void *data,
}
buffer_t *
-cb_buffer_new (size_t buffer_size, gf_boolean_t use_once)
+cb_buffer_new (size_t buffer_size, gf_boolean_t use_once,
+ void (*destroy_buffer_data) (void *data))
{
buffer_t *buffer = NULL;
@@ -157,6 +170,7 @@ cb_buffer_new (size_t buffer_size, gf_boolean_t use_once)
buffer->size_buffer = buffer_size;
buffer->use_once = use_once;
buffer->used_len = 0;
+ buffer->destroy_buffer_data = destroy_buffer_data;
pthread_mutex_init (&buffer->lock, NULL);
out:
@@ -166,12 +180,18 @@ out:
void
cb_buffer_destroy (buffer_t *buffer)
{
- int i = 0;
-
+ int i = 0;
+ circular_buffer_t *ptr = NULL;
if (buffer) {
if (buffer->cb) {
for (i = 0; i < buffer->used_len ; i++) {
- GF_FREE (buffer->cb[i]);
+ ptr = buffer->cb[i];
+ if (ptr->data) {
+ cb_destroy_data (ptr,
+ buffer->destroy_buffer_data);
+ ptr->data = NULL;
+ GF_FREE (ptr);
+ }
}
GF_FREE (buffer->cb);
}
diff --git a/libglusterfs/src/circ-buff.h b/libglusterfs/src/circ-buff.h
index 5b5acc387..e3459f5e3 100644
--- a/libglusterfs/src/circ-buff.h
+++ b/libglusterfs/src/circ-buff.h
@@ -38,7 +38,7 @@ struct _buffer {
/* indicates the amount of circular buffer used. */
circular_buffer_t **cb;
-
+ void (*destroy_buffer_data) (void *data);
pthread_mutex_t lock;
};
@@ -51,7 +51,8 @@ void
cb_buffer_show (buffer_t *buffer);
buffer_t *
-cb_buffer_new (size_t buffer_size,gf_boolean_t use_buffer_once);
+cb_buffer_new (size_t buffer_size,gf_boolean_t use_buffer_once,
+ void (*destroy_data) (void *data));
void
cb_buffer_destroy (buffer_t *buffer);
diff --git a/libglusterfs/src/client_t.c b/libglusterfs/src/client_t.c
index f0d66da3a..06447dc5d 100644
--- a/libglusterfs/src/client_t.c
+++ b/libglusterfs/src/client_t.c
@@ -11,9 +11,9 @@
#include "glusterfs.h"
#include "dict.h"
#include "statedump.h"
-#include "lock-table.h"
-#include "rpcsvc.h"
#include "client_t.h"
+#include "list.h"
+#include "rpcsvc.h"
#ifndef _CONFIG_H
@@ -103,7 +103,7 @@ gf_clienttable_alloc (void)
clienttable_t *clienttable = NULL;
clienttable =
- GF_CALLOC (1, sizeof (*clienttable), gf_common_mt_clienttable_t);
+ GF_CALLOC (1, sizeof (clienttable_t), gf_common_mt_clienttable_t);
if (!clienttable)
return NULL;
@@ -116,14 +116,11 @@ gf_clienttable_alloc (void)
void
gf_client_clienttable_destroy (clienttable_t *clienttable)
{
- struct list_head list = {0, };
client_t *client = NULL;
cliententry_t *cliententries = NULL;
uint32_t client_count = 0;
int32_t i = 0;
- INIT_LIST_HEAD (&list);
-
if (!clienttable) {
gf_log_callingfn ("client_t", GF_LOG_WARNING, "!clienttable");
return;
@@ -152,9 +149,8 @@ gf_client_clienttable_destroy (clienttable_t *clienttable)
}
}
-
client_t *
-gf_client_get (xlator_t *this, rpcsvc_auth_data_t *cred, char *client_uid)
+gf_client_get (xlator_t *this, struct rpcsvc_auth_data *cred, char *client_uid)
{
client_t *client = NULL;
cliententry_t *cliententry = NULL;
@@ -181,13 +177,13 @@ gf_client_get (xlator_t *this, rpcsvc_auth_data_t *cred, char *client_uid)
* look for matching client_uid, _and_
* if auth was used, matching auth flavour and data
*/
- if (strcmp (client_uid, client->server_ctx.client_uid) == 0 &&
+ if (strcmp (client_uid, client->client_uid) == 0 &&
(cred->flavour != AUTH_NONE &&
- (cred->flavour == client->server_ctx.auth.flavour &&
- (size_t) cred->datalen == client->server_ctx.auth.len &&
+ (cred->flavour == client->auth.flavour &&
+ (size_t) cred->datalen == client->auth.len &&
memcmp (cred->authdata,
- client->server_ctx.auth.data,
- client->server_ctx.auth.len) == 0))) {
+ client->auth.data,
+ client->auth.len) == 0))) {
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
__sync_add_and_fetch(&client->ref.bind, 1);
#else
@@ -211,58 +207,49 @@ gf_client_get (xlator_t *this, rpcsvc_auth_data_t *cred, char *client_uid)
}
client->this = this;
- /* client->server_ctx.lk_version = 0; redundant */
- LOCK_INIT (&client->server_ctx.fdtable_lock);
- LOCK_INIT (&client->locks_ctx.ltable_lock);
LOCK_INIT (&client->scratch_ctx.lock);
LOCK_INIT (&client->ref.lock);
- client->server_ctx.client_uid = gf_strdup (client_uid);
- if (client->server_ctx.client_uid == NULL) {
- errno = ENOMEM;
+ client->client_uid = gf_strdup (client_uid);
+ if (client->client_uid == NULL) {
GF_FREE (client);
client = NULL;
- goto unlock;
- }
- client->server_ctx.fdtable = gf_fd_fdtable_alloc ();
- if (client->server_ctx.fdtable == NULL) {
errno = ENOMEM;
- GF_FREE (client->server_ctx.client_uid);
- GF_FREE (client);
- client = NULL;
goto unlock;
}
-
- client->locks_ctx.ltable = gf_lock_table_new ();
- if (client->locks_ctx.ltable == NULL) {
- errno = ENOMEM;
- GF_FREE (client->server_ctx.fdtable);
- GF_FREE (client->server_ctx.client_uid);
+ client->scratch_ctx.count = GF_CLIENTCTX_INITIAL_SIZE;
+ client->scratch_ctx.ctx =
+ GF_CALLOC (GF_CLIENTCTX_INITIAL_SIZE,
+ sizeof (struct client_ctx),
+ gf_common_mt_client_ctx);
+ if (client->scratch_ctx.ctx == NULL) {
+ GF_FREE (client->client_uid);
GF_FREE (client);
client = NULL;
+ errno = ENOMEM;
goto unlock;
}
/* no need to do these atomically here */
client->ref.bind = client->ref.count = 1;
- client->server_ctx.auth.flavour = cred->flavour;
+ client->auth.flavour = cred->flavour;
if (cred->flavour != AUTH_NONE) {
- client->server_ctx.auth.data =
- GF_CALLOC (1, cred->datalen, gf_common_mt_client_t);
- if (client->server_ctx.auth.data == NULL) {
- errno = ENOMEM;
- GF_FREE (client->locks_ctx.ltable);
- GF_FREE (client->server_ctx.fdtable);
- GF_FREE (client->server_ctx.client_uid);
+ client->auth.data =
+ GF_CALLOC (1, cred->datalen,
+ gf_common_mt_client_t);
+ if (client->auth.data == NULL) {
+ GF_FREE (client->scratch_ctx.ctx);
+ GF_FREE (client->client_uid);
GF_FREE (client);
client = NULL;
+ errno = ENOMEM;
goto unlock;
}
- memcpy (client->server_ctx.auth.data, cred->authdata,
+ memcpy (client->auth.data, cred->authdata,
cred->datalen);
- client->server_ctx.auth.len = cred->datalen;
+ client->auth.len = cred->datalen;
}
client->tbl_index = clienttable->first_free;
@@ -301,7 +288,7 @@ gf_client_put (client_t *client, gf_boolean_t *detached)
if (unref) {
gf_log (THIS->name, GF_LOG_INFO, "Shutting down connection %s",
- client->server_ctx.client_uid);
+ client->client_uid);
if (detached)
*detached = _gf_true;
gf_client_unref (client);
@@ -333,7 +320,9 @@ gf_client_ref (client_t *client)
static void
client_destroy (client_t *client)
{
- clienttable_t *clienttable = NULL;
+ clienttable_t *clienttable = NULL;
+ glusterfs_graph_t *gtrav = NULL;
+ xlator_t *xtrav = NULL;
if (client == NULL){
gf_log_callingfn ("xlator", GF_LOG_ERROR, "invalid argument");
@@ -342,8 +331,6 @@ client_destroy (client_t *client)
clienttable = client->this->ctx->clienttable;
- LOCK_DESTROY (&client->server_ctx.fdtable_lock);
- LOCK_DESTROY (&client->locks_ctx.ltable_lock);
LOCK_DESTROY (&client->scratch_ctx.lock);
LOCK_DESTROY (&client->ref.lock);
@@ -356,17 +343,44 @@ client_destroy (client_t *client)
}
UNLOCK (&clienttable->lock);
- GF_FREE (client->server_ctx.auth.data);
+ list_for_each_entry (gtrav, &client->this->ctx->graphs, list) {
+ xtrav = gtrav->top;
+ while (xtrav != NULL) {
+ if (xtrav->cbks->client_destroy != NULL)
+ xtrav->cbks->client_destroy (xtrav, client);
+ xtrav = xtrav->next;
+ }
+ }
+ GF_FREE (client->auth.data);
GF_FREE (client->scratch_ctx.ctx);
- GF_FREE (client->locks_ctx.ltable);
- GF_FREE (client->server_ctx.fdtable);
- GF_FREE (client->server_ctx.client_uid);
+ GF_FREE (client->client_uid);
GF_FREE (client);
out:
return;
}
+int
+gf_client_disconnect (client_t *client)
+{
+ int ret = 0;
+ glusterfs_graph_t *gtrav = NULL;
+ xlator_t *xtrav = NULL;
+
+ list_for_each_entry (gtrav, &client->this->ctx->graphs, list) {
+ xtrav = gtrav->top;
+ while (xtrav != NULL) {
+ if (xtrav->cbks->client_disconnect != NULL)
+ if (xtrav->cbks->client_disconnect (xtrav, client) != 0)
+ ret = -1;
+ xtrav = xtrav->next;
+ }
+ }
+
+ return ret;
+}
+
+
void
gf_client_unref (client_t *client)
{
@@ -392,37 +406,33 @@ gf_client_unref (client_t *client)
}
-int
-__client_ctx_set (client_t *client, xlator_t *xlator, uint64_t value)
+static int
+client_ctx_set_int (client_t *client, void *key, void *value)
{
int index = 0;
int ret = 0;
int set_idx = -1;
- if (!client || !xlator)
- return -1;
-
for (index = 0; index < client->scratch_ctx.count; index++) {
- if (!client->scratch_ctx.ctx[index].key) {
+ if (!client->scratch_ctx.ctx[index].ctx_key) {
if (set_idx == -1)
set_idx = index;
/* dont break, to check if key already exists
further on */
}
- if (client->scratch_ctx.ctx[index].xl_key == xlator) {
+ if (client->scratch_ctx.ctx[index].ctx_key == key) {
set_idx = index;
break;
}
}
if (set_idx == -1) {
- gf_log_callingfn ("", GF_LOG_WARNING, "%p %s", client, xlator->name);
ret = -1;
goto out;
}
- client->scratch_ctx.ctx[set_idx].xl_key = xlator;
- client->scratch_ctx.ctx[set_idx].value = value;
+ client->scratch_ctx.ctx[set_idx].ctx_key = key;
+ client->scratch_ctx.ctx[set_idx].ctx_value = value;
out:
return ret;
@@ -430,18 +440,16 @@ out:
int
-client_ctx_set (client_t *client, xlator_t *xlator, uint64_t value)
+client_ctx_set (client_t *client, void *key, void *value)
{
int ret = 0;
- if (!client || !xlator) {
- gf_log_callingfn ("", GF_LOG_WARNING, "%p %p", client, xlator);
+ if (!client || !key)
return -1;
- }
LOCK (&client->scratch_ctx.lock);
{
- ret = __client_ctx_set (client, xlator, value);
+ ret = client_ctx_set_int (client, key, value);
}
UNLOCK (&client->scratch_ctx.lock);
@@ -449,17 +457,14 @@ client_ctx_set (client_t *client, xlator_t *xlator, uint64_t value)
}
-int
-__client_ctx_get (client_t *client, xlator_t *xlator, uint64_t *value)
+static int
+client_ctx_get_int (client_t *client, void *key, void **value)
{
int index = 0;
int ret = 0;
- if (!client || !xlator)
- return -1;
-
for (index = 0; index < client->scratch_ctx.count; index++) {
- if (client->scratch_ctx.ctx[index].xl_key == xlator)
+ if (client->scratch_ctx.ctx[index].ctx_key == key)
break;
}
@@ -469,7 +474,7 @@ __client_ctx_get (client_t *client, xlator_t *xlator, uint64_t *value)
}
if (value)
- *value = client->scratch_ctx.ctx[index].value;
+ *value = client->scratch_ctx.ctx[index].ctx_value;
out:
return ret;
@@ -477,16 +482,16 @@ out:
int
-client_ctx_get (client_t *client, xlator_t *xlator, uint64_t *value)
+client_ctx_get (client_t *client, void *key, void **value)
{
int ret = 0;
- if (!client || !xlator)
+ if (!client || !key)
return -1;
LOCK (&client->scratch_ctx.lock);
{
- ret = __client_ctx_get (client, xlator, value);
+ ret = client_ctx_get_int (client, key, value);
}
UNLOCK (&client->scratch_ctx.lock);
@@ -494,17 +499,14 @@ client_ctx_get (client_t *client, xlator_t *xlator, uint64_t *value)
}
-int
-__client_ctx_del (client_t *client, xlator_t *xlator, uint64_t *value)
+static int
+client_ctx_del_int (client_t *client, void *key, void **value)
{
int index = 0;
int ret = 0;
- if (!client || !xlator)
- return -1;
-
for (index = 0; index < client->scratch_ctx.count; index++) {
- if (client->scratch_ctx.ctx[index].xl_key == xlator)
+ if (client->scratch_ctx.ctx[index].ctx_key == key)
break;
}
@@ -514,10 +516,10 @@ __client_ctx_del (client_t *client, xlator_t *xlator, uint64_t *value)
}
if (value)
- *value = client->scratch_ctx.ctx[index].value;
+ *value = client->scratch_ctx.ctx[index].ctx_value;
- client->scratch_ctx.ctx[index].key = 0;
- client->scratch_ctx.ctx[index].value = 0;
+ client->scratch_ctx.ctx[index].ctx_key = 0;
+ client->scratch_ctx.ctx[index].ctx_value = 0;
out:
return ret;
@@ -525,16 +527,16 @@ out:
int
-client_ctx_del (client_t *client, xlator_t *xlator, uint64_t *value)
+client_ctx_del (client_t *client, void *key, void **value)
{
int ret = 0;
- if (!client || !xlator)
+ if (!client || !key)
return -1;
LOCK (&client->scratch_ctx.lock);
{
- ret = __client_ctx_del (client, xlator, value);
+ ret = client_ctx_del_int (client, key, value);
}
UNLOCK (&client->scratch_ctx.lock);
@@ -659,11 +661,13 @@ out:
int
gf_client_dump_fdtables_to_dict (xlator_t *this, dict_t *dict)
{
- client_t *client = NULL;
clienttable_t *clienttable = NULL;
int count = 0;
int ret = -1;
+#ifdef NOTYET
+ client_t *client = NULL;
char key[GF_DUMP_MAX_BUF_LEN] = {0,};
+#endif
GF_VALIDATE_OR_GOTO (THIS->name, this, out);
GF_VALIDATE_OR_GOTO (this->name, dict, out);
@@ -673,6 +677,7 @@ gf_client_dump_fdtables_to_dict (xlator_t *this, dict_t *dict)
if (!clienttable)
return -1;
+#ifdef NOTYET
ret = TRY_LOCK (&clienttable->lock);
{
if (ret) {
@@ -692,6 +697,7 @@ gf_client_dump_fdtables_to_dict (xlator_t *this, dict_t *dict)
}
}
UNLOCK(&clienttable->lock);
+#endif
ret = dict_set_int32 (dict, "conncount", count);
out:
@@ -729,11 +735,11 @@ gf_client_dump_fdtables (xlator_t *this)
continue;
client = clienttable->cliententries[count].client;
memset(key, 0, sizeof key);
- if (client->server_ctx.client_uid) {
+ if (client->client_uid) {
gf_proc_dump_build_key (key, "conn",
"%d.id", count);
gf_proc_dump_write (key, "%s",
- client->server_ctx.client_uid);
+ client->client_uid);
}
gf_proc_dump_build_key (key, "conn", "%d.ref",
@@ -746,8 +752,10 @@ gf_client_dump_fdtables (xlator_t *this)
client->bound_xl->name);
}
+#ifdef NOTYET
gf_proc_dump_build_key (key, "conn","%d.id", count);
fdtable_dump (client->server_ctx.fdtable, key);
+#endif
}
}
@@ -836,14 +844,14 @@ gf_client_dump_inodes (xlator_t *this)
clienttable = this->ctx->clienttable;
if (!clienttable)
- return -1;
+ goto out;
ret = TRY_LOCK (&clienttable->lock);
{
if (ret) {
gf_log ("client_t", GF_LOG_WARNING,
"Unable to acquire lock");
- return -1;
+ goto out;
}
for ( ; count < clienttable->max_clients; count++) {
@@ -879,3 +887,4 @@ gf_client_dump_inodes (xlator_t *this)
out:
return ret;
}
+
diff --git a/libglusterfs/src/client_t.h b/libglusterfs/src/client_t.h
index 7b3fcf0dd..f7812f8f0 100644
--- a/libglusterfs/src/client_t.h
+++ b/libglusterfs/src/client_t.h
@@ -20,37 +20,13 @@
#include "locking.h" /* for gf_lock_t, not included by glusterfs.h */
struct client_ctx {
- union {
- uint64_t key;
- void *xl_key;
- };
- union {
- uint64_t value;
- void *ptr1;
- };
+ void *ctx_key;
+ void *ctx_value;
};
-struct _client_t {
+typedef struct _client_t {
struct {
- /* ctx for .../xlators/protocol/server */
- gf_lock_t fdtable_lock;
- fdtable_t *fdtable;
- char *client_uid;
- struct _gf_timer *grace_timer;
- uint32_t lk_version;
- struct {
- int flavour;
- size_t len;
- char *data;
- } auth;
- } server_ctx;
- struct {
- /* ctx for .../xlators/features/locks */
- gf_lock_t ltable_lock;
- struct _lock_table *ltable;
- } locks_ctx;
- struct {
- /* e.g. hekafs uidmap can stash stuff here */
+ /* e.g. protocol/server stashes its ctx here */
gf_lock_t lock;
unsigned short count;
struct client_ctx *ctx;
@@ -63,9 +39,15 @@ struct _client_t {
xlator_t *bound_xl;
xlator_t *this;
int tbl_index;
-};
-typedef struct _client_t client_t;
+ char *client_uid;
+ struct {
+ int flavour;
+ size_t len;
+ char *data;
+ } auth;
+} client_t;
+#define GF_CLIENTCTX_INITIAL_SIZE 8
struct client_table_entry {
client_t *client;
@@ -73,14 +55,13 @@ struct client_table_entry {
};
typedef struct client_table_entry cliententry_t;
-
-struct _clienttable {
+struct clienttable {
unsigned int max_clients;
gf_lock_t lock;
cliententry_t *cliententries;
int first_free;
};
-typedef struct _clienttable clienttable_t;
+typedef struct clienttable clienttable_t;
#define GF_CLIENTTABLE_INITIAL_SIZE 32
@@ -92,10 +73,10 @@ typedef struct _clienttable clienttable_t;
*/
#define GF_CLIENTENTRY_ALLOCATED -2
-
+struct rpcsvc_auth_data;
client_t *
-gf_client_get (xlator_t *this, rpcsvc_auth_data_t *cred, char *client_uid);
+gf_client_get (xlator_t *this, struct rpcsvc_auth_data *cred, char *client_uid);
void
gf_client_put (client_t *client, gf_boolean_t *detached);
@@ -103,15 +84,12 @@ gf_client_put (client_t *client, gf_boolean_t *detached);
clienttable_t *
gf_clienttable_alloc (void);
-
void
gf_client_clienttable_destroy (clienttable_t *clienttable);
-
client_t *
gf_client_ref (client_t *client);
-
void
gf_client_unref (client_t *client);
@@ -128,27 +106,13 @@ int
gf_client_dump_inodes (xlator_t *this);
int
-client_ctx_set (client_t *client, xlator_t *xlator, uint64_t value);
-
-
-int
-client_ctx_get (client_t *client, xlator_t *xlator, uint64_t *value);
-
-
-int
-client_ctx_del (client_t *client, xlator_t *xlator, uint64_t *value);
-
+client_ctx_set (client_t *client, void *key, void *value);
int
-_client_ctx_set (client_t *client, xlator_t *xlator, uint64_t value);
-
+client_ctx_get (client_t *client, void *key, void **value);
int
-_client_ctx_get (client_t *client, xlator_t *xlator, uint64_t *value);
-
-
-int
-_client_ctx_del (client_t *client, xlator_t *xlator, uint64_t *value);
+client_ctx_del (client_t *client, void *key, void **value);
void
client_ctx_dump (client_t *client, char *prefix);
@@ -165,4 +129,7 @@ gf_client_dump_inodes_to_dict (xlator_t *this, dict_t *dict);
int
gf_client_dump_inodes (xlator_t *this);
+int
+gf_client_disconnect (client_t *client);
+
#endif /* _CLIENT_T_H */
diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c
index 6eb886b38..827475282 100644
--- a/libglusterfs/src/common-utils.c
+++ b/libglusterfs/src/common-utils.c
@@ -1125,7 +1125,7 @@ gf_string2int8 (const char *str, int8_t *n)
if (rv != 0)
return rv;
- if (l >= INT8_MIN && l <= INT8_MAX) {
+ if ((l >= INT8_MIN) && (l <= INT8_MAX)) {
*n = (int8_t) l;
return 0;
}
@@ -1144,7 +1144,7 @@ gf_string2int16 (const char *str, int16_t *n)
if (rv != 0)
return rv;
- if (l >= INT16_MIN && l <= INT16_MAX) {
+ if ((l >= INT16_MIN) && (l <= INT16_MAX)) {
*n = (int16_t) l;
return 0;
}
@@ -1163,7 +1163,7 @@ gf_string2int32 (const char *str, int32_t *n)
if (rv != 0)
return rv;
- if (l >= INT32_MIN && l <= INT32_MAX) {
+ if ((l >= INT32_MIN) && (l <= INT32_MAX)) {
*n = (int32_t) l;
return 0;
}
@@ -1182,7 +1182,7 @@ gf_string2int64 (const char *str, int64_t *n)
if (rv != 0)
return rv;
- if (l >= INT64_MIN && l <= INT64_MAX) {
+ if ((l >= INT64_MIN) && (l <= INT64_MAX)) {
*n = (int64_t) l;
return 0;
}
@@ -1441,6 +1441,11 @@ gf_string2bytesize (const char *str, uint64_t *n)
return -1;
}
+ if ((UINT64_MAX - value) < 0) {
+ errno = ERANGE;
+ return -1;
+ }
+
*n = (uint64_t) value;
return 0;
@@ -1500,6 +1505,12 @@ gf_string2percent_or_bytesize (const char *str,
return -1;
}
+ /* Error out if we cannot store the value in uint64 */
+ if ((UINT64_MAX - value) < 0) {
+ errno = ERANGE;
+ return -1;
+ }
+
*n = (uint64_t) value;
return 0;
@@ -2807,3 +2818,91 @@ out:
}
+
+/* Sets log file path from user provided arguments */
+int
+gf_set_log_file_path (cmd_args_t *cmd_args)
+{
+ int i = 0;
+ int j = 0;
+ int ret = 0;
+ char tmp_str[1024] = {0,};
+
+ if (!cmd_args)
+ goto done;
+
+ if (cmd_args->mount_point) {
+ j = 0;
+ i = 0;
+ if (cmd_args->mount_point[0] == '/')
+ i = 1;
+ for (; i < strlen (cmd_args->mount_point); i++,j++) {
+ tmp_str[j] = cmd_args->mount_point[i];
+ if (cmd_args->mount_point[i] == '/')
+ tmp_str[j] = '-';
+ }
+
+ ret = gf_asprintf (&cmd_args->log_file,
+ DEFAULT_LOG_FILE_DIRECTORY "/%s.log",
+ tmp_str);
+ if (ret > 0)
+ ret = 0;
+ goto done;
+ }
+
+ if (cmd_args->volfile) {
+ j = 0;
+ i = 0;
+ if (cmd_args->volfile[0] == '/')
+ i = 1;
+ for (; i < strlen (cmd_args->volfile); i++,j++) {
+ tmp_str[j] = cmd_args->volfile[i];
+ if (cmd_args->volfile[i] == '/')
+ tmp_str[j] = '-';
+ }
+ ret = gf_asprintf (&cmd_args->log_file,
+ DEFAULT_LOG_FILE_DIRECTORY "/%s.log",
+ tmp_str);
+ if (ret > 0)
+ ret = 0;
+ goto done;
+ }
+
+ if (cmd_args->volfile_server) {
+
+ ret = gf_asprintf (&cmd_args->log_file,
+ DEFAULT_LOG_FILE_DIRECTORY "/%s-%s-%d.log",
+ cmd_args->volfile_server,
+ cmd_args->volfile_id, getpid());
+ if (ret > 0)
+ ret = 0;
+ }
+done:
+ return ret;
+}
+
+int
+gf_thread_create (pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg)
+{
+ sigset_t set, old;
+ int ret;
+
+ sigemptyset (&set);
+
+ sigfillset (&set);
+ sigdelset (&set, SIGSEGV);
+ sigdelset (&set, SIGBUS);
+ sigdelset (&set, SIGILL);
+ sigdelset (&set, SIGSYS);
+ sigdelset (&set, SIGFPE);
+ sigdelset (&set, SIGABRT);
+
+ pthread_sigmask (SIG_BLOCK, &set, &old);
+
+ ret = pthread_create (thread, attr, start_routine, arg);
+
+ pthread_sigmask (SIG_SETMASK, &old, NULL);
+
+ return ret;
+}
diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h
index bf41444d1..3c99a4212 100644
--- a/libglusterfs/src/common-utils.h
+++ b/libglusterfs/src/common-utils.h
@@ -112,6 +112,7 @@ in_addr_t gf_resolve_ip (const char *hostname, void **dnscache);
void gf_log_dump_graph (FILE *specfp, glusterfs_graph_t *graph);
void gf_print_trace (int32_t signal, glusterfs_ctx_t *ctx);
+int gf_set_log_file_path (cmd_args_t *cmd_args);
#define VECTORSIZE(count) (count * (sizeof (struct iovec)))
@@ -587,4 +588,7 @@ gf_boolean_t gf_is_local_addr (char *hostname);
gf_boolean_t gf_is_same_address (char *host1, char *host2);
void md5_wrapper(const unsigned char *data, size_t len, char *md5);
+int gf_thread_create (pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg);
+
#endif /* _COMMON_UTILS_H */
diff --git a/libglusterfs/src/defaults.c b/libglusterfs/src/defaults.c
index a3c8d97f1..2ebb25150 100644
--- a/libglusterfs/src/defaults.c
+++ b/libglusterfs/src/defaults.c
@@ -473,6 +473,17 @@ default_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
}
int32_t
+default_zerofill_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *pre,
+ struct iatt *post, dict_t *xdata)
+{
+ STACK_UNWIND_STRICT(zerofill, frame, op_ret, op_errno, pre,
+ post, xdata);
+ return 0;
+}
+
+
+int32_t
default_getspec_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, char *spec_data)
{
@@ -900,6 +911,17 @@ default_discard_resume(call_frame_t *frame, xlator_t *this, fd_t *fd,
return 0;
}
+int32_t
+default_zerofill_resume(call_frame_t *frame, xlator_t *this, fd_t *fd,
+ off_t offset, size_t len, dict_t *xdata)
+{
+ STACK_WIND(frame, default_zerofill_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->zerofill, fd, offset, len,
+ xdata);
+ return 0;
+}
+
+
/* FOPS */
int32_t
@@ -1325,6 +1347,17 @@ default_discard(call_frame_t *frame, xlator_t *this, fd_t *fd,
}
int32_t
+default_zerofill(call_frame_t *frame, xlator_t *this, fd_t *fd,
+ off_t offset, size_t len, dict_t *xdata)
+{
+ STACK_WIND_TAIL(frame, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->zerofill, fd, offset, len,
+ xdata);
+ return 0;
+}
+
+
+int32_t
default_forget (xlator_t *this, inode_t *inode)
{
gf_log_callingfn (this->name, GF_LOG_WARNING, "xlator does not "
diff --git a/libglusterfs/src/defaults.h b/libglusterfs/src/defaults.h
index f3cbb3a4b..0747027bc 100644
--- a/libglusterfs/src/defaults.h
+++ b/libglusterfs/src/defaults.h
@@ -255,6 +255,13 @@ int32_t default_discard(call_frame_t *frame,
off_t offset,
size_t len, dict_t *xdata);
+int32_t default_zerofill(call_frame_t *frame,
+ xlator_t *this,
+ fd_t *fd,
+ off_t offset,
+ size_t len, dict_t *xdata);
+
+
/* Resume */
int32_t default_getspec_resume (call_frame_t *frame,
xlator_t *this,
@@ -477,6 +484,13 @@ int32_t default_discard_resume(call_frame_t *frame,
off_t offset,
size_t len, dict_t *xdata);
+int32_t default_zerofill_resume(call_frame_t *frame,
+ xlator_t *this,
+ fd_t *fd,
+ off_t offset,
+ size_t len, dict_t *xdata);
+
+
/* _cbk */
int32_t
@@ -695,6 +709,10 @@ int32_t default_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, struct iatt *pre,
struct iatt *post, dict_t *xdata);
+int32_t default_zerofill_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *pre,
+ struct iatt *post, dict_t *xdata);
+
int32_t
default_getspec_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, char *spec_data);
diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c
index b017f87e5..3b7ddce5e 100644
--- a/libglusterfs/src/dict.c
+++ b/libglusterfs/src/dict.c
@@ -896,7 +896,7 @@ data_to_int32 (data_t *data)
int16_t
data_to_int16 (data_t *data)
{
- int16_t value = 0;
+ int16_t value = 0;
if (!data) {
gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL");
@@ -910,16 +910,16 @@ data_to_int16 (data_t *data)
memcpy (str, data->data, data->len);
str[data->len] = '\0';
- errno = 0;
- value = strtol (str, NULL, 0);
+ errno = 0;
+ value = strtol (str, NULL, 0);
- if ((SHRT_MAX > value) || (SHRT_MIN < value)) {
- errno = ERANGE;
+ if ((value > SHRT_MAX) || (value < SHRT_MIN)) {
+ errno = ERANGE;
gf_log_callingfn ("dict", GF_LOG_WARNING,
- "Error in data conversion: "
- "detected overflow");
+ "Error in data conversion: "
+ "detected overflow");
return -1;
- }
+ }
return (int16_t)value;
}
@@ -928,7 +928,7 @@ data_to_int16 (data_t *data)
int8_t
data_to_int8 (data_t *data)
{
- int32_t value = 0;
+ int8_t value = 0;
if (!data) {
gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL");
@@ -942,16 +942,16 @@ data_to_int8 (data_t *data)
memcpy (str, data->data, data->len);
str[data->len] = '\0';
- errno = 0;
- value = strtol (str, NULL, 0);
+ errno = 0;
+ value = strtol (str, NULL, 0);
- if ((SCHAR_MAX > value) || (SCHAR_MIN < value)) {
- errno = ERANGE;
+ if ((value > SCHAR_MAX) || (value < SCHAR_MIN)) {
+ errno = ERANGE;
gf_log_callingfn ("dict", GF_LOG_WARNING,
- "Error in data conversion: "
- "detected overflow");
+ "Error in data conversion: "
+ "detected overflow");
return -1;
- }
+ }
return (int8_t)value;
}
diff --git a/libglusterfs/src/event-history.c b/libglusterfs/src/event-history.c
index fe511caeb..82baa521a 100644
--- a/libglusterfs/src/event-history.c
+++ b/libglusterfs/src/event-history.c
@@ -11,7 +11,8 @@
#include "event-history.h"
eh_t *
-eh_new (size_t buffer_size, gf_boolean_t use_buffer_once)
+eh_new (size_t buffer_size, gf_boolean_t use_buffer_once,
+ void (*destroy_buffer_data) (void *data))
{
eh_t *history = NULL;
buffer_t *buffer = NULL;
@@ -22,7 +23,8 @@ eh_new (size_t buffer_size, gf_boolean_t use_buffer_once)
goto out;
}
- buffer = cb_buffer_new (buffer_size, use_buffer_once);
+ buffer = cb_buffer_new (buffer_size, use_buffer_once,
+ destroy_buffer_data);
if (!buffer) {
gf_log ("", GF_LOG_ERROR, "allocating circular buffer failed");
GF_FREE (history);
diff --git a/libglusterfs/src/event-history.h b/libglusterfs/src/event-history.h
index b1750bbae..b64f63b5e 100644
--- a/libglusterfs/src/event-history.h
+++ b/libglusterfs/src/event-history.h
@@ -32,7 +32,8 @@ eh_dump (eh_t *event , void *data,
int (fn) (circular_buffer_t *buffer, void *data));
eh_t *
-eh_new (size_t buffer_size, gf_boolean_t use_buffer_once);
+eh_new (size_t buffer_size, gf_boolean_t use_buffer_once,
+ void (*destroy_data) (void *data));
int
eh_save_history (eh_t *history, void *string);
diff --git a/libglusterfs/src/gidcache.c b/libglusterfs/src/gidcache.c
index c55ed2581..c5bdda925 100644
--- a/libglusterfs/src/gidcache.c
+++ b/libglusterfs/src/gidcache.c
@@ -35,6 +35,21 @@ int gid_cache_init(gid_cache_t *cache, uint32_t timeout)
}
/*
+ * Reconfigure the cache timeout.
+ */
+int gid_cache_reconf(gid_cache_t *cache, uint32_t timeout)
+{
+ if (!cache)
+ return -1;
+
+ LOCK(&cache->gc_lock);
+ cache->gc_max_age = timeout;
+ UNLOCK(&cache->gc_lock);
+
+ return 0;
+}
+
+/*
* Look up an ID in the cache. If found, return the actual cache entry to avoid
* an additional allocation and memory copy. The caller should copy the data and
* release (unlock) the cache as soon as possible.
diff --git a/libglusterfs/src/gidcache.h b/libglusterfs/src/gidcache.h
index f904f26eb..9379f8e8b 100644
--- a/libglusterfs/src/gidcache.h
+++ b/libglusterfs/src/gidcache.h
@@ -45,6 +45,7 @@ typedef struct {
} gid_cache_t;
int gid_cache_init(gid_cache_t *, uint32_t);
+int gid_cache_reconf(gid_cache_t *, uint32_t);
const gid_list_t *gid_cache_lookup(gid_cache_t *, uint64_t);
void gid_cache_release(gid_cache_t *, const gid_list_t *);
int gid_cache_add(gid_cache_t *, gid_list_t *);
diff --git a/libglusterfs/src/globals.c b/libglusterfs/src/globals.c
index 459291b33..259c5c885 100644
--- a/libglusterfs/src/globals.c
+++ b/libglusterfs/src/globals.c
@@ -19,6 +19,7 @@
#include "globals.h"
#include "xlator.h"
#include "mem-pool.h"
+#include "syncop.h"
const char *gf_fop_list[GF_FOP_MAXVALUE] = {
[GF_FOP_NULL] = "NULL",
@@ -69,6 +70,7 @@ const char *gf_fop_list[GF_FOP_MAXVALUE] = {
[GF_FOP_FREMOVEXATTR]= "FREMOVEXATTR",
[GF_FOP_FALLOCATE] = "FALLOCATE",
[GF_FOP_DISCARD] = "DISCARD",
+ [GF_FOP_ZEROFILL] = "ZEROFILL",
};
/* THIS */
@@ -164,6 +166,54 @@ glusterfs_this_set (xlator_t *this)
return 0;
}
+/* SYNCOPCTX */
+static pthread_key_t syncopctx_key;
+
+static void
+syncopctx_key_destroy (void *ptr)
+{
+ struct syncopctx *opctx = ptr;
+
+ if (opctx) {
+ if (opctx->groups)
+ GF_FREE (opctx->groups);
+
+ GF_FREE (opctx);
+ }
+
+ return;
+}
+
+void *
+syncopctx_getctx ()
+{
+ void *opctx = NULL;
+
+ opctx = pthread_getspecific (syncopctx_key);
+
+ return opctx;
+}
+
+int
+syncopctx_setctx (void *ctx)
+{
+ int ret = 0;
+
+ ret = pthread_setspecific (syncopctx_key, ctx);
+
+ return ret;
+}
+
+static int
+syncopctx_init (void)
+{
+ int ret;
+
+ ret = pthread_key_create (&syncopctx_key, syncopctx_key_destroy);
+
+ return ret;
+}
+
/* SYNCTASK */
int
@@ -176,7 +226,6 @@ synctask_init ()
return ret;
}
-
void *
synctask_get ()
{
@@ -300,6 +349,13 @@ glusterfs_globals_init (glusterfs_ctx_t *ctx)
"ERROR: glusterfs synctask init failed");
goto out;
}
+
+ ret = syncopctx_init ();
+ if (ret) {
+ gf_log ("", GF_LOG_CRITICAL,
+ "ERROR: glusterfs syncopctx init failed");
+ goto out;
+ }
out:
return ret;
}
diff --git a/libglusterfs/src/globals.h b/libglusterfs/src/globals.h
index 857965bb4..3085db21c 100644
--- a/libglusterfs/src/globals.h
+++ b/libglusterfs/src/globals.h
@@ -41,6 +41,10 @@ xlator_t **__glusterfs_this_location ();
xlator_t *glusterfs_this_get ();
int glusterfs_this_set (xlator_t *);
+/* syncopctx */
+void *syncopctx_getctx ();
+int syncopctx_setctx (void *ctx);
+
/* task */
void *synctask_get ();
int synctask_set (void *);
diff --git a/libglusterfs/src/glusterfs-acl.h b/libglusterfs/src/glusterfs-acl.h
new file mode 100644
index 000000000..b7de1cdb4
--- /dev/null
+++ b/libglusterfs/src/glusterfs-acl.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (c) 2008-2013 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#ifndef _GLUSTERFS_ACL_H
+#define _GLUSTERFS_ACL_H
+
+#include <stdint.h>
+#include <sys/types.h> /* For uid_t */
+
+#include "locking.h" /* For gf_lock_t in struct posix_acl_conf */
+
+#define ACL_PROGRAM 100227
+#define ACLV3_VERSION 3
+
+#define POSIX_ACL_MINIMAL_ACE_COUNT 3
+
+#define POSIX_ACL_READ (0x04)
+#define POSIX_ACL_WRITE (0x02)
+#define POSIX_ACL_EXECUTE (0x01)
+
+#define POSIX_ACL_UNDEFINED_TAG (0x00)
+#define POSIX_ACL_USER_OBJ (0x01)
+#define POSIX_ACL_USER (0x02)
+#define POSIX_ACL_GROUP_OBJ (0x04)
+#define POSIX_ACL_GROUP (0x08)
+#define POSIX_ACL_MASK (0x10)
+#define POSIX_ACL_OTHER (0x20)
+
+#define POSIX_ACL_UNDEFINED_ID (-1)
+
+#define POSIX_ACL_VERSION (0x02)
+
+#define POSIX_ACL_ACCESS_XATTR "system.posix_acl_access"
+#define POSIX_ACL_DEFAULT_XATTR "system.posix_acl_default"
+
+struct posix_acl_xattr_entry {
+ uint16_t tag;
+ uint16_t perm;
+ uint32_t id;
+};
+
+struct posix_acl_xattr_header {
+ uint32_t version;
+ struct posix_acl_xattr_entry entries[];
+};
+
+struct posix_ace {
+ uint16_t tag;
+ uint16_t perm;
+ uint32_t id;
+};
+
+
+struct posix_acl {
+ int refcnt;
+ int count;
+ struct posix_ace entries[];
+};
+
+struct posix_acl_ctx {
+ uid_t uid;
+ gid_t gid;
+ mode_t perm;
+ struct posix_acl *acl_access;
+ struct posix_acl *acl_default;
+};
+
+struct posix_acl_conf {
+ gf_lock_t acl_lock;
+ uid_t super_uid;
+ struct posix_acl *minimal_acl;
+};
+
+#endif /* _GLUSTERFS_ACL_H */
diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h
index ede208b38..2f1e12ee7 100644
--- a/libglusterfs/src/glusterfs.h
+++ b/libglusterfs/src/glusterfs.h
@@ -70,6 +70,7 @@
#define FNM_EXTMATCH 0
#endif
+#define GLUSTERD_MAX_SNAP_NAME 256
#define ZR_MOUNTPOINT_OPT "mountpoint"
#define ZR_ATTR_TIMEOUT_OPT "attribute-timeout"
#define ZR_ENTRY_TIMEOUT_OPT "entry-timeout"
@@ -88,6 +89,8 @@
#define GF_READDIR_SKIP_DIRS "readdir-filter-directories"
+#define BD_XATTR_KEY "user.glusterfs"
+
#define XATTR_IS_PATHINFO(x) (strncmp (x, GF_XATTR_PATHINFO_KEY, \
strlen (GF_XATTR_PATHINFO_KEY)) == 0)
#define XATTR_IS_NODE_UUID(x) (strncmp (x, GF_XATTR_NODE_UUID_KEY, \
@@ -95,6 +98,8 @@
#define XATTR_IS_LOCKINFO(x) (strncmp (x, GF_XATTR_LOCKINFO_KEY, \
strlen (GF_XATTR_LOCKINFO_KEY)) == 0)
+#define XATTR_IS_BD(x) (strncmp (x, BD_XATTR_KEY, strlen (BD_XATTR_KEY)) == 0)
+
#define GF_XATTR_LINKINFO_KEY "trusted.distribute.linkinfo"
#define GFID_XATTR_KEY "trusted.gfid"
#define VIRTUAL_GFID_XATTR_KEY_STR "glusterfs.gfid.string"
@@ -119,6 +124,7 @@
/* Index xlator related */
#define GF_XATTROP_INDEX_GFID "glusterfs.xattrop_index_gfid"
+#define GF_BASE_INDICES_HOLDER_GFID "glusterfs.base_indicies_holder_gfid"
#define GF_GFIDLESS_LOOKUP "gfidless-lookup"
/* replace-brick and pump related internal xattrs */
@@ -128,9 +134,6 @@
#define RB_PUMP_CMD_ABORT "glusterfs.pump.abort"
#define RB_PUMP_CMD_STATUS "glusterfs.pump.status"
-#define POSIX_ACL_DEFAULT_XATTR "system.posix_acl_default"
-#define POSIX_ACL_ACCESS_XATTR "system.posix_acl_access"
-
#define GLUSTERFS_RDMA_INLINE_THRESHOLD (2048)
#define GLUSTERFS_RDMA_MAX_HEADER_SIZE (228) /* (sizeof (rdma_header_t) \
+ RDMA_MAX_SEGMENTS \
@@ -159,6 +162,11 @@
#define UUID_CANONICAL_FORM_LEN 36
+/* Adding this here instead of any glusterd*.h files as it is also required by
+ * cli
+ */
+#define DEFAULT_GLUSTERD_SOCKFILE DATADIR "/run/glusterd.socket"
+
/* NOTE: add members ONLY at the end (just before _MAXVALUE) */
typedef enum {
GF_FOP_NULL = 0,
@@ -209,6 +217,7 @@ typedef enum {
GF_FOP_FREMOVEXATTR,
GF_FOP_FALLOCATE,
GF_FOP_DISCARD,
+ GF_FOP_ZEROFILL,
GF_FOP_MAXVALUE,
} glusterfs_fop_t;
@@ -294,6 +303,11 @@ struct _xlator_cmdline_option {
};
typedef struct _xlator_cmdline_option xlator_cmdline_option_t;
+struct _server_cmdline {
+ struct list_head list;
+ char *volfile_server;
+};
+typedef struct _server_cmdline server_cmdline_t;
#define GF_OPTION_ENABLE _gf_true
#define GF_OPTION_DISABLE _gf_false
@@ -301,9 +315,12 @@ typedef struct _xlator_cmdline_option xlator_cmdline_option_t;
struct _cmd_args {
/* basic options */
- char *volfile_server;
- char *volfile;
- char *log_server;
+ char *volfile_server;
+ server_cmdline_t *curr_server;
+ /* List of backup volfile servers, including original */
+ struct list_head volfile_servers;
+ char *volfile;
+ char *log_server;
gf_loglevel_t log_level;
char *log_file;
int32_t max_connect_attempts;
@@ -322,14 +339,14 @@ struct _cmd_args {
int enable_ino32;
int worm;
int mac_compat;
- int fopen_keep_cache;
- int gid_timeout;
+ int fopen_keep_cache;
+ int gid_timeout;
int aux_gfid_mount;
- struct list_head xlator_options; /* list of xlator_option_t */
+ struct list_head xlator_options; /* list of xlator_option_t */
- /* fuse options */
- int fuse_direct_io_mode;
- char *use_readdirp;
+ /* fuse options */
+ int fuse_direct_io_mode;
+ char *use_readdirp;
int volfile_check;
double fuse_entry_timeout;
double fuse_negative_timeout;
@@ -343,7 +360,7 @@ struct _cmd_args {
unsigned uid_map_root;
int background_qlen;
int congestion_threshold;
- char *fuse_mountopts;
+ char *fuse_mountopts;
/* key args */
char *mount_point;
@@ -353,7 +370,6 @@ struct _cmd_args {
int brick_port;
char *brick_name;
int brick_port2;
-
};
typedef struct _cmd_args cmd_args_t;
@@ -382,7 +398,7 @@ struct _glusterfs_ctx {
char fin;
void *timer;
void *ib;
- void *pool;
+ struct call_pool *pool;
void *event_pool;
void *iobuf_pool;
pthread_mutex_t lock;
@@ -420,7 +436,8 @@ struct _glusterfs_ctx {
int daemon_pipe[2];
- struct _clienttable *clienttable;
+ struct client_disconnect *client_disconnect;
+ struct clienttable *clienttable;
};
typedef struct _glusterfs_ctx glusterfs_ctx_t;
@@ -444,6 +461,7 @@ typedef enum {
GF_EVENT_AUTH_FAILED,
GF_EVENT_VOLUME_DEFRAG,
GF_EVENT_PARENT_DOWN,
+ GF_EVENT_VOLUME_BARRIER_OP,
GF_EVENT_MAXVAL,
} glusterfs_event_t;
diff --git a/libglusterfs/src/graph.c b/libglusterfs/src/graph.c
index 1dba63fc0..e76df1ca5 100644
--- a/libglusterfs/src/graph.c
+++ b/libglusterfs/src/graph.c
@@ -537,6 +537,184 @@ glusterfs_graph_activate (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx)
int
+xlator_equal_rec (xlator_t *xl1, xlator_t *xl2)
+{
+ xlator_list_t *trav1 = NULL;
+ xlator_list_t *trav2 = NULL;
+ int ret = 0;
+
+ if (xl1 == NULL || xl2 == NULL) {
+ gf_log ("xlator", GF_LOG_DEBUG, "invalid argument");
+ return -1;
+ }
+
+ trav1 = xl1->children;
+ trav2 = xl2->children;
+
+ while (trav1 && trav2) {
+ ret = xlator_equal_rec (trav1->xlator, trav2->xlator);
+ if (ret) {
+ gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
+ "xlators children not equal");
+ goto out;
+ }
+
+ trav1 = trav1->next;
+ trav2 = trav2->next;
+ }
+
+ if (trav1 || trav2) {
+ ret = -1;
+ goto out;
+ }
+
+ if (strcmp (xl1->name, xl2->name)) {
+ ret = -1;
+ goto out;
+ }
+
+ /* type could have changed even if xlator names match,
+ e.g cluster/distrubte and cluster/nufa share the same
+ xlator name
+ */
+ if (strcmp (xl1->type, xl2->type)) {
+ ret = -1;
+ goto out;
+ }
+out :
+ return ret;
+}
+
+
+gf_boolean_t
+is_graph_topology_equal (glusterfs_graph_t *graph1, glusterfs_graph_t *graph2)
+{
+ xlator_t *trav1 = NULL;
+ xlator_t *trav2 = NULL;
+ gf_boolean_t ret = _gf_true;
+
+ trav1 = graph1->first;
+ trav2 = graph2->first;
+
+ ret = xlator_equal_rec (trav1, trav2);
+
+ if (ret) {
+ gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
+ "graphs are not equal");
+ ret = _gf_false;
+ goto out;
+ }
+
+ ret = _gf_true;
+ gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
+ "graphs are equal");
+
+out:
+ return ret;
+}
+
+
+/* Function has 3types of return value 0, -ve , 1
+ * return 0 =======> reconfiguration of options has succeeded
+ * return 1 =======> the graph has to be reconstructed and all the xlators should be inited
+ * return -1(or -ve) =======> Some Internal Error occurred during the operation
+ */
+int
+glusterfs_volfile_reconfigure (int oldvollen, FILE *newvolfile_fp,
+ glusterfs_ctx_t *ctx, const char *oldvolfile)
+{
+ glusterfs_graph_t *oldvolfile_graph = NULL;
+ glusterfs_graph_t *newvolfile_graph = NULL;
+ FILE *oldvolfile_fp = NULL;
+ gf_boolean_t active_graph_found = _gf_true;
+
+ int ret = -1;
+
+ if (!oldvollen) {
+ ret = 1; // Has to call INIT for the whole graph
+ goto out;
+ }
+
+ if (!ctx) {
+ gf_log ("glusterfsd-mgmt", GF_LOG_ERROR,
+ "ctx is NULL");
+ goto out;
+ }
+
+ oldvolfile_graph = ctx->active;
+ if (!oldvolfile_graph) {
+ active_graph_found = _gf_false;
+ gf_log ("glusterfsd-mgmt", GF_LOG_ERROR,
+ "glusterfs_ctx->active is NULL");
+
+ oldvolfile_fp = tmpfile ();
+ if (!oldvolfile_fp) {
+ gf_log ("glusterfsd-mgmt", GF_LOG_ERROR, "Unable to "
+ "create temporary volfile: (%s)",
+ strerror (errno));
+ goto out;
+ }
+
+ fwrite (oldvolfile, oldvollen, 1, oldvolfile_fp);
+ fflush (oldvolfile_fp);
+ if (ferror (oldvolfile_fp)) {
+ goto out;
+ }
+
+ oldvolfile_graph = glusterfs_graph_construct (oldvolfile_fp);
+ if (!oldvolfile_graph)
+ goto out;
+ }
+
+ newvolfile_graph = glusterfs_graph_construct (newvolfile_fp);
+ if (!newvolfile_graph) {
+ goto out;
+ }
+
+ if (!is_graph_topology_equal (oldvolfile_graph,
+ newvolfile_graph)) {
+
+ ret = 1;
+ gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
+ "Graph topology not equal(should call INIT)");
+ goto out;
+ }
+
+ gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
+ "Only options have changed in the new "
+ "graph");
+
+ /* */
+ ret = glusterfs_graph_reconfigure (oldvolfile_graph,
+ newvolfile_graph);
+ if (ret) {
+ gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG,
+ "Could not reconfigure new options in old graph");
+ goto out;
+ }
+
+ ret = 0;
+out:
+ if (oldvolfile_fp)
+ fclose (oldvolfile_fp);
+
+ /* Do not simply destroy the old graph here. If the oldgraph
+ is constructed here in this function itself instead of getting
+ it from ctx->active (which happens only of ctx->active is NULL),
+ then destroy the old graph. If some i/o is still happening in
+ the old graph and the old graph is obtained from ctx->active,
+ then destroying the graph will cause problems.
+ */
+ if (!active_graph_found && oldvolfile_graph)
+ glusterfs_graph_destroy (oldvolfile_graph);
+ if (newvolfile_graph)
+ glusterfs_graph_destroy (newvolfile_graph);
+
+ return ret;
+}
+
+
+int
glusterfs_graph_reconfigure (glusterfs_graph_t *oldgraph,
glusterfs_graph_t *newgraph)
{
@@ -562,5 +740,12 @@ glusterfs_graph_reconfigure (glusterfs_graph_t *oldgraph,
int
glusterfs_graph_destroy (glusterfs_graph_t *graph)
{
+ xlator_tree_free (graph->first);
+
+ if (graph) {
+ list_del_init (&graph->list);
+ GF_FREE (graph);
+ }
+
return 0;
}
diff --git a/libglusterfs/src/graph.l b/libglusterfs/src/graph.l
index ff34f6ef1..e4eba9cbe 100644
--- a/libglusterfs/src/graph.l
+++ b/libglusterfs/src/graph.l
@@ -70,10 +70,10 @@ TYPE [t][y][p][e]
yyunput (0, NULL);
}
BEGIN (INITIAL);
- yylval = text;
+ graphyylval = text;
return STRING_TOK;
}
}
-[^ \t\r\n\"\\]+ { yylval = gf_strdup (yytext) ; return ID; }
+[^ \t\r\n\"\\]+ { graphyylval = gf_strdup (yytext) ; return ID; }
[ \t\r\n]+ ;
%%
diff --git a/libglusterfs/src/graph.y b/libglusterfs/src/graph.y
index e2f16ff71..a220abeb9 100644
--- a/libglusterfs/src/graph.y
+++ b/libglusterfs/src/graph.y
@@ -18,6 +18,7 @@
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <pthread.h>
#define RELAX_POISONING
@@ -37,8 +38,8 @@ static void option_error (void);
#define YYSTYPE char *
#define GF_CMD_BUFFER_LEN (8 * GF_UNIT_KB)
-int yyerror (const char *);
-int yylex ();
+int graphyyerror (const char *);
+int graphyylex ();
%}
@@ -78,11 +79,11 @@ glusterfs_graph_t *construct;
static void
type_error (void)
{
- extern int yylineno;
+ extern int graphyylineno;
gf_log ("parser", GF_LOG_ERROR,
"Volume %s, before line %d: Please specify volume type",
- curr->name, yylineno);
+ curr->name, graphyylineno);
return;
}
@@ -90,11 +91,11 @@ type_error (void)
static void
sub_error (void)
{
- extern int yylineno;
+ extern int graphyylineno;
gf_log ("parser", GF_LOG_ERROR,
"Volume %s, before line %d: Please specify subvolumes",
- curr->name, yylineno);
+ curr->name, graphyylineno);
return;
}
@@ -102,12 +103,12 @@ sub_error (void)
static void
option_error (void)
{
- extern int yylineno;
+ extern int graphyylineno;
gf_log ("parser", GF_LOG_ERROR,
"Volume %s, before line %d: Please specify "
"option <key> <value>",
- curr->name, yylineno);
+ curr->name, graphyylineno);
return;
}
@@ -115,7 +116,7 @@ option_error (void)
static int
new_volume (char *name)
{
- extern int yylineno;
+ extern int graphyylineno;
xlator_t *trav = NULL;
int ret = 0;
@@ -129,7 +130,7 @@ new_volume (char *name)
if (curr) {
gf_log ("parser", GF_LOG_ERROR,
"new volume (%s) defintion in line %d unexpected",
- name, yylineno);
+ name, graphyylineno);
ret = -1;
goto out;
}
@@ -149,7 +150,7 @@ new_volume (char *name)
if (!strcmp (name, trav->name)) {
gf_log ("parser", GF_LOG_ERROR,
"Line %d: volume '%s' defined again",
- yylineno, name);
+ graphyylineno, name);
ret = -1;
goto out;
}
@@ -194,7 +195,7 @@ out:
static int
volume_type (char *type)
{
- extern int yylineno;
+ extern int graphyylineno;
int32_t ret = 0;
if (!type) {
@@ -208,7 +209,7 @@ volume_type (char *type)
gf_log ("parser", GF_LOG_ERROR,
"Volume '%s', line %d: type '%s' is not valid or "
"not found on this machine",
- curr->name, yylineno, type);
+ curr->name, graphyylineno, type);
ret = -1;
goto out;
}
@@ -225,7 +226,7 @@ out:
static int
volume_option (char *key, char *value)
{
- extern int yylineno;
+ extern int graphyylineno;
int ret = 0;
char *set_value = NULL;
@@ -242,7 +243,7 @@ volume_option (char *key, char *value)
gf_log ("parser", GF_LOG_ERROR,
"Volume '%s', line %d: duplicate entry "
"('option %s') present",
- curr->name, yylineno, key);
+ curr->name, graphyylineno, key);
ret = -1;
goto out;
}
@@ -261,7 +262,7 @@ out:
static int
volume_sub (char *sub)
{
- extern int yylineno;
+ extern int graphyylineno;
xlator_t *trav = NULL;
int ret = 0;
@@ -283,7 +284,7 @@ volume_sub (char *sub)
gf_log ("parser", GF_LOG_ERROR,
"Volume '%s', line %d: subvolume '%s' is not defined "
"prior to usage",
- curr->name, yylineno, sub);
+ curr->name, graphyylineno, sub);
ret = -1;
goto out;
}
@@ -291,7 +292,7 @@ volume_sub (char *sub)
if (trav == curr) {
gf_log ("parser", GF_LOG_ERROR,
"Volume '%s', line %d: has '%s' itself as subvolume",
- curr->name, yylineno, sub);
+ curr->name, graphyylineno, sub);
ret = -1;
goto out;
}
@@ -328,46 +329,46 @@ volume_end (void)
int
-yywrap ()
+graphyywrap ()
{
return 1;
}
int
-yyerror (const char *str)
+graphyyerror (const char *str)
{
- extern char *yytext;
- extern int yylineno;
+ extern char *graphyytext;
+ extern int graphyylineno;
- if (curr && curr->name && yytext) {
- if (!strcmp (yytext, "volume")) {
+ if (curr && curr->name && graphyytext) {
+ if (!strcmp (graphyytext, "volume")) {
gf_log ("parser", GF_LOG_ERROR,
"'end-volume' not defined for volume '%s'",
curr->name);
- } else if (!strcmp (yytext, "type")) {
+ } else if (!strcmp (graphyytext, "type")) {
gf_log ("parser", GF_LOG_ERROR,
"line %d: duplicate 'type' defined for "
"volume '%s'",
- yylineno, curr->name);
- } else if (!strcmp (yytext, "subvolumes")) {
+ graphyylineno, curr->name);
+ } else if (!strcmp (graphyytext, "subvolumes")) {
gf_log ("parser", GF_LOG_ERROR,
"line %d: duplicate 'subvolumes' defined for "
"volume '%s'",
- yylineno, curr->name);
+ graphyylineno, curr->name);
} else if (curr) {
gf_log ("parser", GF_LOG_ERROR,
"syntax error: line %d (volume '%s'): \"%s\""
"\nallowed tokens are 'volume', 'type', "
"'subvolumes', 'option', 'end-volume'()",
- yylineno, curr->name,
- yytext);
+ graphyylineno, curr->name,
+ graphyytext);
} else {
gf_log ("parser", GF_LOG_ERROR,
"syntax error: line %d (just after volume "
"'%s'): \"%s\"\n(%s)",
- yylineno, curr->name,
- yytext,
+ graphyylineno, curr->name,
+ graphyytext,
"allowed tokens are 'volume', 'type', "
"'subvolumes', 'option', 'end-volume'");
}
@@ -376,7 +377,7 @@ yyerror (const char *str)
"syntax error in line %d: \"%s\" \n"
"(allowed tokens are 'volume', 'type', "
"'subvolumes', 'option', 'end-volume')\n",
- yylineno, yytext);
+ graphyylineno, graphyytext);
}
return -1;
@@ -481,6 +482,7 @@ preprocess (FILE *srcfp, FILE *dstfp)
cmd_buf_size *= 2;
cmd = GF_REALLOC (cmd, cmd_buf_size);
if (cmd == NULL) {
+ GF_FREE (result);
return -1;
}
@@ -522,6 +524,7 @@ preprocess (FILE *srcfp, FILE *dstfp)
out:
fseek (srcfp, 0L, SEEK_SET);
fseek (dstfp, 0L, SEEK_SET);
+
GF_FREE (cmd);
GF_FREE (result);
@@ -529,7 +532,7 @@ out:
}
-extern FILE *yyin;
+extern FILE *graphyyin;
glusterfs_graph_t *
glusterfs_graph_new ()
@@ -557,6 +560,7 @@ glusterfs_graph_construct (FILE *fp)
glusterfs_graph_t *graph = NULL;
FILE *tmp_file = NULL;
char template[PATH_MAX] = {0};
+ static pthread_mutex_t graph_mutex = PTHREAD_MUTEX_INITIALIZER;
graph = glusterfs_graph_new ();
if (!graph)
@@ -583,10 +587,14 @@ glusterfs_graph_construct (FILE *fp)
goto err;
}
- yyin = tmp_file;
- construct = graph;
- ret = yyparse ();
- construct = NULL;
+ pthread_mutex_lock (&graph_mutex);
+ {
+ graphyyin = tmp_file;
+ construct = graph;
+ ret = yyparse ();
+ construct = NULL;
+ }
+ pthread_mutex_unlock (&graph_mutex);
if (ret == 1) {
gf_log ("parser", GF_LOG_DEBUG,
diff --git a/libglusterfs/src/inode.c b/libglusterfs/src/inode.c
index add686fd2..15e0ccf78 100644
--- a/libglusterfs/src/inode.c
+++ b/libglusterfs/src/inode.c
@@ -1493,6 +1493,18 @@ out:
return ret;
}
+int
+__inode_ctx_set0 (inode_t *inode, xlator_t *xlator, uint64_t *value1_p)
+{
+ return __inode_ctx_set2 (inode, xlator, value1_p, NULL);
+}
+
+int
+__inode_ctx_set1 (inode_t *inode, xlator_t *xlator, uint64_t *value2_p)
+{
+ return __inode_ctx_set2 (inode, xlator, NULL, value2_p);
+}
+
int
inode_ctx_set2 (inode_t *inode, xlator_t *xlator, uint64_t *value1_p,
@@ -1512,34 +1524,97 @@ inode_ctx_set2 (inode_t *inode, xlator_t *xlator, uint64_t *value1_p,
return ret;
}
+int
+inode_ctx_set1 (inode_t *inode, xlator_t *xlator, uint64_t *value2_p)
+{
+ int ret = 0;
+
+ if (!inode || !xlator)
+ return -1;
+
+ LOCK (&inode->lock);
+ {
+ ret = __inode_ctx_set1 (inode, xlator, value2_p);
+ }
+ UNLOCK (&inode->lock);
+
+ return ret;
+}
+int
+inode_ctx_set0 (inode_t *inode, xlator_t *xlator, uint64_t *value1_p)
+{
+ int ret = 0;
+
+ if (!inode || !xlator)
+ return -1;
+
+ LOCK (&inode->lock);
+ {
+ ret = __inode_ctx_set0 (inode, xlator, value1_p);
+ }
+ UNLOCK (&inode->lock);
+
+ return ret;
+}
+
int
__inode_ctx_get2 (inode_t *inode, xlator_t *xlator, uint64_t *value1,
uint64_t *value2)
{
int index = 0;
- int ret = 0;
+ int ret = -1;
if (!inode || !xlator)
- return -1;
+ goto out;
for (index = 0; index < inode->table->ctxcount; index++) {
if (inode->_ctx[index].xl_key == xlator)
break;
}
- if (index == inode->table->ctxcount) {
- ret = -1;
+ if (index == inode->table->ctxcount)
goto out;
+
+ if (inode->_ctx[index].value1) {
+ if (value1)
+ *value1 = inode->_ctx[index].value1;
+ ret = 0;
}
+ if (inode->_ctx[index].value2) {
+ if (value2)
+ *value2 = inode->_ctx[index].value2;
+ ret = 0;
+ }
+out:
+ return ret;
+}
- if (value1)
- *value1 = inode->_ctx[index].value1;
- if (value2)
- *value2 = inode->_ctx[index].value2;
-out:
+int
+__inode_ctx_get0 (inode_t *inode, xlator_t *xlator, uint64_t *value1)
+{
+ uint64_t tmp_value = 0;
+ int ret = 0;
+
+ ret = __inode_ctx_get2 (inode, xlator, &tmp_value, NULL);
+ if (!ret)
+ *value1 = tmp_value;
+
+ return ret;
+}
+
+int
+__inode_ctx_get1 (inode_t *inode, xlator_t *xlator, uint64_t *value2)
+{
+ uint64_t tmp_value = 0;
+ int ret = 0;
+
+ ret = __inode_ctx_get2 (inode, xlator, NULL, &tmp_value);
+ if (!ret)
+ *value2 = tmp_value;
+
return ret;
}
@@ -1562,6 +1637,40 @@ inode_ctx_get2 (inode_t *inode, xlator_t *xlator, uint64_t *value1,
return ret;
}
+int
+inode_ctx_get1 (inode_t *inode, xlator_t *xlator, uint64_t *value2)
+{
+ int ret = 0;
+
+ if (!inode || !xlator)
+ return -1;
+
+ LOCK (&inode->lock);
+ {
+ ret = __inode_ctx_get1 (inode, xlator, value2);
+ }
+ UNLOCK (&inode->lock);
+
+ return ret;
+}
+
+int
+inode_ctx_get0 (inode_t *inode, xlator_t *xlator, uint64_t *value1)
+{
+ int ret = 0;
+
+ if (!inode || !xlator)
+ return -1;
+
+ LOCK (&inode->lock);
+ {
+ ret = __inode_ctx_get0 (inode, xlator, value1);
+ }
+ UNLOCK (&inode->lock);
+
+ return ret;
+}
+
int
inode_ctx_del2 (inode_t *inode, xlator_t *xlator, uint64_t *value1,
@@ -1586,9 +1695,9 @@ inode_ctx_del2 (inode_t *inode, xlator_t *xlator, uint64_t *value1,
goto unlock;
}
- if (value1)
+ if (inode->_ctx[index].value1 && value1)
*value1 = inode->_ctx[index].value1;
- if (value2)
+ if (inode->_ctx[index].value2 && value2)
*value2 = inode->_ctx[index].value2;
inode->_ctx[index].key = 0;
@@ -1601,6 +1710,97 @@ unlock:
return ret;
}
+/* function behavior:
+ - if value1 is set, value1 in ctx is reset to 0 with current value passed
+ back in value1 address.
+ - if value2 is set, value2 in ctx is reset to 0 with current value passed
+ back in value2 address.
+ - if both are set, both fields are reset.
+*/
+static int
+__inode_ctx_reset2 (inode_t *inode, xlator_t *xlator, uint64_t *value1,
+ uint64_t *value2)
+{
+ int index = 0;
+ int ret = 0;
+
+ if (!inode || !xlator)
+ return -1;
+
+ LOCK (&inode->lock);
+ {
+ for (index = 0; index < inode->table->ctxcount;
+ index++) {
+ if (inode->_ctx[index].xl_key == xlator)
+ break;
+ }
+
+ if (index == inode->table->ctxcount) {
+ ret = -1;
+ goto unlock;
+ }
+
+ if (inode->_ctx[index].value1 && value1) {
+ *value1 = inode->_ctx[index].value1;
+ inode->_ctx[index].value1 = 0;
+ }
+ if (inode->_ctx[index].value2 && value2) {
+ *value2 = inode->_ctx[index].value2;
+ inode->_ctx[index].value2 = 0;
+ }
+ }
+unlock:
+ UNLOCK (&inode->lock);
+
+ return ret;
+}
+
+int
+inode_ctx_reset2 (inode_t *inode, xlator_t *xlator, uint64_t *value1_p,
+ uint64_t *value2_p)
+{
+ uint64_t tmp_value1 = 0;
+ uint64_t tmp_value2 = 0;
+ int ret = 0;
+
+ ret = __inode_ctx_reset2 (inode, xlator, &tmp_value1, &tmp_value2);
+ if (!ret) {
+ if (value1_p)
+ *value1_p = tmp_value1;
+ if (value2_p)
+ *value2_p = tmp_value2;
+ }
+ return ret;
+}
+
+int
+inode_ctx_reset1 (inode_t *inode, xlator_t *xlator, uint64_t *value2_p)
+{
+ uint64_t tmp_value2 = 0;
+ int ret = 0;
+
+ ret = __inode_ctx_reset2 (inode, xlator, NULL, &tmp_value2);
+
+ if (!ret && value2_p)
+ *value2_p = tmp_value2;
+
+ return ret;
+
+}
+int
+inode_ctx_reset0 (inode_t *inode, xlator_t *xlator, uint64_t *value1_p)
+{
+ uint64_t tmp_value1 = 0;
+ int ret = 0;
+
+ ret = __inode_ctx_reset2 (inode, xlator, &tmp_value1, NULL);
+
+ if (!ret && value1_p)
+ *value1_p = tmp_value1;
+
+ return ret;
+}
+
void
inode_dump (inode_t *inode, char *prefix)
diff --git a/libglusterfs/src/inode.h b/libglusterfs/src/inode.h
index cf766a31b..a88976265 100644
--- a/libglusterfs/src/inode.h
+++ b/libglusterfs/src/inode.h
@@ -73,10 +73,12 @@ struct _inode_ctx {
uint64_t key;
xlator_t *xl_key;
};
+ /* if value1 is 0, then field is not set.. */
union {
uint64_t value1;
void *ptr1;
};
+ /* if value2 is 0, then field is not set.. */
union {
uint64_t value2;
void *ptr2;
@@ -159,6 +161,11 @@ __inode_path (inode_t *inode, const char *name, char **bufp);
inode_t *
inode_from_path (inode_table_t *table, const char *path);
+inode_t *
+inode_resolve (inode_table_t *table, char *path);
+
+/* deal with inode ctx's both values */
+
int
inode_ctx_set2 (inode_t *inode, xlator_t *xlator, uint64_t *value1,
uint64_t *value2);
@@ -177,29 +184,66 @@ int
inode_ctx_del2 (inode_t *inode, xlator_t *xlator, uint64_t *value1,
uint64_t *value2);
-inode_t *
-inode_resolve (inode_table_t *table, char *path);
+int
+inode_ctx_reset2 (inode_t *inode, xlator_t *xlator, uint64_t *value1,
+ uint64_t *value2);
+
+/* deal with inode ctx's 1st value */
+
+int
+inode_ctx_set0 (inode_t *inode, xlator_t *xlator, uint64_t *value1);
+
+int
+__inode_ctx_set0 (inode_t *inode, xlator_t *xlator, uint64_t *value1);
+
+int
+inode_ctx_get0 (inode_t *inode, xlator_t *xlator, uint64_t *value1);
+int
+__inode_ctx_get0 (inode_t *inode, xlator_t *xlator, uint64_t *value1);
+
+int
+inode_ctx_reset0 (inode_t *inode, xlator_t *xlator, uint64_t *value1);
+
+/* deal with inode ctx's 2st value */
+
+int
+inode_ctx_set1 (inode_t *inode, xlator_t *xlator, uint64_t *value2);
+
+int
+__inode_ctx_set1 (inode_t *inode, xlator_t *xlator, uint64_t *value2);
+
+int
+inode_ctx_get1 (inode_t *inode, xlator_t *xlator, uint64_t *value2);
+int
+__inode_ctx_get1 (inode_t *inode, xlator_t *xlator, uint64_t *value2);
+
+int
+inode_ctx_reset1 (inode_t *inode, xlator_t *xlator, uint64_t *value2);
-#define __inode_ctx_set(i,x,v_p) __inode_ctx_set2(i,x,v_p,0)
-#define inode_ctx_set(i,x,v_p) inode_ctx_set2(i,x,v_p,0)
static inline int
__inode_ctx_put(inode_t *inode, xlator_t *this, uint64_t v)
{
- return __inode_ctx_set2 (inode, this, &v, 0);
+ return __inode_ctx_set0 (inode, this, &v);
}
static inline int
inode_ctx_put(inode_t *inode, xlator_t *this, uint64_t v)
{
- return inode_ctx_set2(inode, this, &v, 0);
+ return inode_ctx_set0 (inode, this, &v);
}
-#define __inode_ctx_get(i,x,v) __inode_ctx_get2(i,x,v,0)
-#define inode_ctx_get(i,x,v) inode_ctx_get2(i,x,v,0)
+#define __inode_ctx_set(i,x,v_p) __inode_ctx_set0(i,x,v_p)
-#define inode_ctx_del(i,x,v) inode_ctx_del2(i,x,v,0)
+#define inode_ctx_set(i,x,v_p) inode_ctx_set0(i,x,v_p)
+#define inode_ctx_reset(i,x,v) inode_ctx_reset0(i,x,v)
+
+#define __inode_ctx_get(i,x,v) __inode_ctx_get0(i,x,v)
+
+#define inode_ctx_get(i,x,v) inode_ctx_get0(i,x,v)
+
+#define inode_ctx_del(i,x,v) inode_ctx_del2(i,x,v,0)
gf_boolean_t
__is_root_gfid (uuid_t gfid);
diff --git a/libglusterfs/src/list.h b/libglusterfs/src/list.h
index 7f3712b51..392c22ceb 100644
--- a/libglusterfs/src/list.h
+++ b/libglusterfs/src/list.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
+ Copyright (c) 2008-2014 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
@@ -11,7 +11,6 @@
#ifndef _LLIST_H
#define _LLIST_H
-
struct list_head {
struct list_head *next;
struct list_head *prev;
@@ -45,6 +44,31 @@ list_add_tail (struct list_head *new, struct list_head *head)
}
+/* This function will insert the element to the list in a order.
+ Order will be based on the compare function provided as a input.
+ If element to be inserted in ascending order compare should return:
+ 0: if both the arguments are equal
+ >0: if first argument is greater than second argument
+ <0: if first argument is less than second argument */
+static inline void
+list_add_order (struct list_head *new, struct list_head *head,
+ int (*compare)(struct list_head *, struct list_head *))
+{
+ struct list_head *pos = head->prev;
+
+ while ( pos != head ) {
+ if (compare(new, pos) >= 0)
+ break;
+
+ /* Iterate the list in the reverse order. This will have
+ better efficiency if the elements are inserted in the
+ ascending order */
+ pos = pos->prev;
+ }
+
+ list_add (new, pos);
+}
+
static inline void
list_del (struct list_head *old)
{
diff --git a/libglusterfs/src/lock-table.c b/libglusterfs/src/lock-table.c
deleted file mode 100644
index 42b7ed8a7..000000000
--- a/libglusterfs/src/lock-table.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
- This file is part of GlusterFS.
-
- This file is licensed to you under your choice of the GNU Lesser
- General Public License, version 3 or any later version (LGPLv3 or
- later), or the GNU General Public License, version 2 (GPLv2), in all
- cases as published by the Free Software Foundation.
-*/
-
-#include "lock-table.h"
-#include "common-utils.h"
-
-
-struct _lock_table *
-gf_lock_table_new (void)
-{
- struct _lock_table *new = NULL;
-
- new = GF_CALLOC (1, sizeof (struct _lock_table), gf_common_mt_lock_table);
- if (new == NULL) {
- goto out;
- }
- INIT_LIST_HEAD (&new->entrylk_lockers);
- INIT_LIST_HEAD (&new->inodelk_lockers);
- LOCK_INIT (&new->lock);
-out:
- return new;
-}
-
-
-int
-gf_add_locker (struct _lock_table *table, const char *volume,
- loc_t *loc, fd_t *fd, pid_t pid, gf_lkowner_t *owner,
- glusterfs_fop_t type)
-{
- int32_t ret = -1;
- struct _locker *new = NULL;
-
- GF_VALIDATE_OR_GOTO ("lock-table", table, out);
- GF_VALIDATE_OR_GOTO ("lock-table", volume, out);
-
- new = GF_CALLOC (1, sizeof (struct _locker), gf_common_mt_locker);
- if (new == NULL) {
- goto out;
- }
- INIT_LIST_HEAD (&new->lockers);
-
- new->volume = gf_strdup (volume);
-
- if (fd == NULL) {
- loc_copy (&new->loc, loc);
- } else {
- new->fd = fd_ref (fd);
- }
-
- new->pid = pid;
- new->owner = *owner;
-
- LOCK (&table->lock);
- {
- if (type == GF_FOP_ENTRYLK)
- list_add_tail (&new->lockers, &table->entrylk_lockers);
- else
- list_add_tail (&new->lockers, &table->inodelk_lockers);
- }
- UNLOCK (&table->lock);
-out:
- return ret;
-}
-
-int
-gf_del_locker (struct _lock_table *table, const char *volume,
- loc_t *loc, fd_t *fd, gf_lkowner_t *owner, glusterfs_fop_t type)
-{
- struct _locker *locker = NULL;
- struct _locker *tmp = NULL;
- int32_t ret = -1;
- struct list_head *head = NULL;
- struct list_head del;
-
- GF_VALIDATE_OR_GOTO ("lock-table", table, out);
- GF_VALIDATE_OR_GOTO ("lock-table", volume, out);
-
- INIT_LIST_HEAD (&del);
-
- LOCK (&table->lock);
- {
- if (type == GF_FOP_ENTRYLK) {
- head = &table->entrylk_lockers;
- } else {
- head = &table->inodelk_lockers;
- }
-
- list_for_each_entry_safe (locker, tmp, head, lockers) {
- if (!is_same_lkowner (&locker->owner, owner) ||
- strcmp (locker->volume, volume))
- continue;
-
- /*
- * It is possible for inodelk lock to come on anon-fd
- * and inodelk unlock to come on normal fd in case of
- * client re-opens. So don't check for fds to be equal.
- */
- if (locker->fd && fd)
- list_move_tail (&locker->lockers, &del);
- else if (locker->loc.inode && loc &&
- (locker->loc.inode == loc->inode))
- list_move_tail (&locker->lockers, &del);
- }
- }
- UNLOCK (&table->lock);
-
- tmp = NULL;
- locker = NULL;
-
- list_for_each_entry_safe (locker, tmp, &del, lockers) {
- list_del_init (&locker->lockers);
- if (locker->fd)
- fd_unref (locker->fd);
- else
- loc_wipe (&locker->loc);
-
- GF_FREE (locker->volume);
- GF_FREE (locker);
- }
-
- ret = 0;
-out:
- return ret;
-
-}
-
diff --git a/libglusterfs/src/lock-table.h b/libglusterfs/src/lock-table.h
deleted file mode 100644
index 4a9083873..000000000
--- a/libglusterfs/src/lock-table.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
- This file is part of GlusterFS.
-
- This file is licensed to you under your choice of the GNU Lesser
- General Public License, version 3 or any later version (LGPLv3 or
- later), or the GNU General Public License, version 2 (GPLv2), in all
- cases as published by the Free Software Foundation.
-*/
-
-#ifndef _LOCK_TABLE_H
-#define _LOCK_TABLE_H
-
-#ifndef _CONFIG_H
-#define _CONFIG_H
-#include "config.h"
-#endif
-
-#include "xlator.h"
-
-struct _locker {
- struct list_head lockers;
- char *volume;
- loc_t loc;
- fd_t *fd;
- gf_lkowner_t owner;
- pid_t pid;
-};
-
-struct _lock_table {
- struct list_head inodelk_lockers;
- struct list_head entrylk_lockers;
- gf_lock_t lock;
-};
-
-int32_t
-gf_add_locker (struct _lock_table *table, const char *volume,
- loc_t *loc,
- fd_t *fd,
- pid_t pid,
- gf_lkowner_t *owner,
- glusterfs_fop_t type);
-
-int32_t
-gf_del_locker (struct _lock_table *table, const char *volume,
- loc_t *loc,
- fd_t *fd,
- gf_lkowner_t *owner,
- glusterfs_fop_t type);
-
-struct _lock_table *
-gf_lock_table_new (void);
-
-#endif /* _LOCK_TABLE_H */
diff --git a/libglusterfs/src/logging.h b/libglusterfs/src/logging.h
index 9da1379e7..cc806a767 100644
--- a/libglusterfs/src/logging.h
+++ b/libglusterfs/src/logging.h
@@ -35,6 +35,7 @@
#define GF_PRI_BLKSIZE PRId32
#define GF_PRI_SIZET "zu"
+
#if 0
/* Syslog definitions :-) */
#define LOG_EMERG 0 /* system is unusable */
@@ -60,6 +61,9 @@ typedef enum {
GF_LOG_TRACE, /* full trace of operation */
} gf_loglevel_t;
+#define DEFAULT_LOG_FILE_DIRECTORY DATADIR "/log/glusterfs"
+#define DEFAULT_LOG_LEVEL GF_LOG_INFO
+
typedef struct gf_log_handle_ {
pthread_mutex_t logfile_mutex;
uint8_t logrotate;
diff --git a/libglusterfs/src/mem-types.h b/libglusterfs/src/mem-types.h
index 7dcbfb3dc..666bd120a 100644
--- a/libglusterfs/src/mem-types.h
+++ b/libglusterfs/src/mem-types.h
@@ -115,6 +115,11 @@ enum gf_common_mem_types_ {
gf_common_mt_client_ctx = 99,
gf_common_mt_lock_table = 100,
gf_common_mt_locker = 101,
- gf_common_mt_end = 102
+ gf_common_mt_auxgids = 102,
+ gf_common_mt_syncopctx = 103,
+ gf_common_mt_uuid_t = 104,
+ gf_common_mt_mgmt_v3_lock_obj_t = 105,
+ gf_common_mt_txn_opinfo_obj_t = 106,
+ gf_common_mt_end = 107
};
#endif
diff --git a/libglusterfs/src/run.c b/libglusterfs/src/run.c
index ebe7f3962..4fd2a3a0d 100644
--- a/libglusterfs/src/run.c
+++ b/libglusterfs/src/run.c
@@ -187,7 +187,7 @@ runner_log (runner_t *runner, const char *dom, gf_loglevel_t lvl,
if (len > 0)
buf[len - 1] = '\0';
- gf_log (dom, lvl, "%s: %s", msg, buf);
+ gf_log_callingfn (dom, lvl, "%s: %s", msg, buf);
GF_FREE (buf);
}
diff --git a/libglusterfs/src/stack.h b/libglusterfs/src/stack.h
index 0e8b705bd..f2d2ef950 100644
--- a/libglusterfs/src/stack.h
+++ b/libglusterfs/src/stack.h
@@ -25,8 +25,8 @@ struct _call_stack_t;
typedef struct _call_stack_t call_stack_t;
struct _call_frame_t;
typedef struct _call_frame_t call_frame_t;
-struct _call_pool_t;
-typedef struct _call_pool_t call_pool_t;
+struct call_pool;
+typedef struct call_pool call_pool_t;
#include <sys/time.h>
@@ -36,6 +36,7 @@ typedef struct _call_pool_t call_pool_t;
#include "common-utils.h"
#include "globals.h"
#include "lkowner.h"
+#include "client_t.h"
#define NFS_PID 1
#define LOW_PRIO_PROC_PID -1
@@ -46,7 +47,7 @@ typedef int32_t (*ret_fn_t) (call_frame_t *frame,
int32_t op_errno,
...);
-struct _call_pool_t {
+struct call_pool {
union {
struct list_head all_frames;
struct {
@@ -94,7 +95,7 @@ struct _call_stack_t {
};
call_pool_t *pool;
gf_lock_t stack_lock;
- void *trans;
+ client_t *client;
uint64_t unique;
void *state; /* pointer to request state */
uid_t uid;
diff --git a/libglusterfs/src/store.c b/libglusterfs/src/store.c
index 48c79ee02..1e6601837 100644
--- a/libglusterfs/src/store.c
+++ b/libglusterfs/src/store.c
@@ -168,10 +168,12 @@ int
gf_store_read_and_tokenize (FILE *file, char *str, char **iter_key,
char **iter_val, gf_store_op_errno_t *store_errno)
{
- int32_t ret = -1;
- char *savetok = NULL;
- char *key = NULL;
- char *value = NULL;
+ int32_t ret = -1;
+ char *savetok = NULL;
+ char *key = NULL;
+ char *value = NULL;
+ char *temp = NULL;
+ size_t str_len = 0;
GF_ASSERT (file);
GF_ASSERT (str);
@@ -179,13 +181,17 @@ gf_store_read_and_tokenize (FILE *file, char *str, char **iter_key,
GF_ASSERT (iter_val);
GF_ASSERT (store_errno);
- ret = fscanf (file, "%s", str);
- if (ret <= 0 || feof (file)) {
+ temp = fgets (str, PATH_MAX, file);
+ if (temp == NULL || feof (file)) {
ret = -1;
*store_errno = GD_STORE_EOF;
goto out;
}
+ str_len = strlen(str);
+ str[str_len - 1] = '\0';
+ /* Truncate the "\n", as fgets stores "\n" in str */
+
key = strtok_r (str, "=", &savetok);
if (!key) {
ret = -1;
@@ -253,8 +259,13 @@ gf_store_retrieve_value (gf_store_handle_t *handle, char *key, char **value)
goto out;
}
- scan_str = GF_CALLOC (1, st.st_size,
+ /* "st.st_size + 1" is used as we are fetching each
+ * line of a file using fgets, fgets will append "\0"
+ * to the end of the string
+ */
+ scan_str = GF_CALLOC (1, st.st_size + 1,
gf_common_mt_char);
+
if (scan_str == NULL) {
ret = -1;
store_errno = GD_STORE_ENOMEM;
@@ -532,7 +543,11 @@ gf_store_iter_get_next (gf_store_iter_t *iter, char **key, char **value,
goto out;
}
- scan_str = GF_CALLOC (1, st.st_size,
+ /* "st.st_size + 1" is used as we are fetching each
+ * line of a file using fgets, fgets will append "\0"
+ * to the end of the string
+ */
+ scan_str = GF_CALLOC (1, st.st_size + 1,
gf_common_mt_char);
if (!scan_str) {
ret = -1;
@@ -596,7 +611,9 @@ gf_store_iter_get_matching (gf_store_iter_t *iter, char *key, char **value)
goto out;
}
GF_FREE (tmp_key);
+ tmp_key = NULL;
GF_FREE (tmp_value);
+ tmp_value = NULL;
ret = gf_store_iter_get_next (iter, &tmp_key, &tmp_value,
NULL);
}
diff --git a/libglusterfs/src/syncop.c b/libglusterfs/src/syncop.c
index d2c8381a3..c1620bb70 100644
--- a/libglusterfs/src/syncop.c
+++ b/libglusterfs/src/syncop.c
@@ -15,6 +15,160 @@
#include "syncop.h"
+int
+syncopctx_setfsuid (void *uid)
+{
+ struct syncopctx *opctx = NULL;
+ int ret = 0;
+
+ /* In args check */
+ if (!uid) {
+ ret = -1;
+ errno = EINVAL;
+ goto out;
+ }
+
+ opctx = syncopctx_getctx ();
+
+ /* alloc for this thread the first time */
+ if (!opctx) {
+ opctx = GF_CALLOC (1, sizeof (*opctx), gf_common_mt_syncopctx);
+ if (!opctx) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = syncopctx_setctx (opctx);
+ if (ret != 0) {
+ GF_FREE (opctx);
+ opctx = NULL;
+ goto out;
+ }
+ }
+
+out:
+ if (opctx && uid) {
+ opctx->uid = *(uid_t *)uid;
+ opctx->valid |= SYNCOPCTX_UID;
+ }
+
+ return ret;
+}
+
+int
+syncopctx_setfsgid (void *gid)
+{
+ struct syncopctx *opctx = NULL;
+ int ret = 0;
+
+ /* In args check */
+ if (!gid) {
+ ret = -1;
+ errno = EINVAL;
+ goto out;
+ }
+
+ opctx = syncopctx_getctx ();
+
+ /* alloc for this thread the first time */
+ if (!opctx) {
+ opctx = GF_CALLOC (1, sizeof (*opctx), gf_common_mt_syncopctx);
+ if (!opctx) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = syncopctx_setctx (opctx);
+ if (ret != 0) {
+ GF_FREE (opctx);
+ opctx = NULL;
+ goto out;
+ }
+ }
+
+out:
+ if (opctx && gid) {
+ opctx->gid = *(gid_t *)gid;
+ opctx->valid |= SYNCOPCTX_GID;
+ }
+
+ return ret;
+}
+
+int
+syncopctx_setfsgroups (int count, const void *groups)
+{
+ struct syncopctx *opctx = NULL;
+ gid_t *tmpgroups = NULL;
+ int ret = 0;
+
+ /* In args check */
+ if (count != 0 && !groups) {
+ ret = -1;
+ errno = EINVAL;
+ goto out;
+ }
+
+ opctx = syncopctx_getctx ();
+
+ /* alloc for this thread the first time */
+ if (!opctx) {
+ opctx = GF_CALLOC (1, sizeof (*opctx), gf_common_mt_syncopctx);
+ if (!opctx) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = syncopctx_setctx (opctx);
+ if (ret != 0) {
+ GF_FREE (opctx);
+ opctx = NULL;
+ goto out;
+ }
+ }
+
+ /* resize internal groups as required */
+ if (count && opctx->grpsize < count) {
+ if (opctx->groups) {
+ tmpgroups = GF_REALLOC (opctx->groups,
+ (sizeof (gid_t) * count));
+ /* NOTE: Not really required to zero the reallocation,
+ * as ngrps controls the validity of data,
+ * making a note irrespective */
+ if (tmpgroups == NULL) {
+ opctx->grpsize = 0;
+ GF_FREE (opctx->groups);
+ opctx->groups = NULL;
+ ret = -1;
+ goto out;
+ }
+ }
+ else {
+ tmpgroups = GF_CALLOC (count, sizeof (gid_t),
+ gf_common_mt_syncopctx);
+ if (tmpgroups == NULL) {
+ opctx->grpsize = 0;
+ ret = -1;
+ goto out;
+ }
+ }
+
+ opctx->groups = tmpgroups;
+ opctx->grpsize = count;
+ }
+
+ /* copy out the groups passed */
+ if (count)
+ memcpy (opctx->groups, groups, (sizeof (gid_t) * count));
+
+ /* set/reset the ngrps, this is where reset of groups is handled */
+ opctx->ngrps = count;
+ opctx->valid |= SYNCOPCTX_GROUPS;
+
+out:
+ return ret;
+}
+
static void
__run (struct synctask *task)
{
@@ -453,8 +607,8 @@ syncenv_scale (struct syncenv *env)
}
env->proc[i].env = env;
- ret = pthread_create (&env->proc[i].processor, NULL,
- syncenv_processor, &env->proc[i]);
+ ret = gf_thread_create (&env->proc[i].processor, NULL,
+ syncenv_processor, &env->proc[i]);
if (ret)
break;
env->procs++;
@@ -507,8 +661,8 @@ syncenv_new (size_t stacksize, int procmin, int procmax)
for (i = 0; i < newenv->procmin; i++) {
newenv->proc[i].env = newenv;
- ret = pthread_create (&newenv->proc[i].processor, NULL,
- syncenv_processor, &newenv->proc[i]);
+ ret = gf_thread_create (&newenv->proc[i].processor, NULL,
+ syncenv_processor, &newenv->proc[i]);
if (ret)
break;
newenv->procs++;
@@ -2019,6 +2173,35 @@ syncop_discard(xlator_t *subvol, fd_t *fd, off_t offset, size_t len)
return args.op_ret;
}
+int
+syncop_zerofill_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int op_ret, int op_errno, struct iatt *prebuf,
+ struct iatt *postbuf, dict_t *xdata)
+{
+ struct syncargs *args = NULL;
+
+ args = cookie;
+
+ args->op_ret = op_ret;
+ args->op_errno = op_errno;
+
+ __wake (args);
+
+ return 0;
+}
+
+int
+syncop_zerofill(xlator_t *subvol, fd_t *fd, off_t offset, size_t len)
+{
+ struct syncargs args = {0, };
+
+ SYNCOP (subvol, (&args), syncop_zerofill_cbk, subvol->fops->zerofill,
+ fd, offset, len, NULL);
+
+ errno = args.op_errno;
+ return args.op_ret;
+}
+
int
syncop_lk_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
diff --git a/libglusterfs/src/syncop.h b/libglusterfs/src/syncop.h
index 64350030e..f790981f0 100644
--- a/libglusterfs/src/syncop.h
+++ b/libglusterfs/src/syncop.h
@@ -25,6 +25,13 @@
#define SYNCENV_PROC_MIN 2
#define SYNCPROC_IDLE_TIME 600
+/*
+ * Flags for syncopctx valid elements
+ */
+#define SYNCOPCTX_UID 0x00000001
+#define SYNCOPCTX_GID 0x00000002
+#define SYNCOPCTX_GROUPS 0x00000004
+
struct synctask;
struct syncproc;
struct syncenv;
@@ -150,6 +157,14 @@ struct syncargs {
int done;
};
+struct syncopctx {
+ unsigned int valid; /* valid flags for elements that are set */
+ uid_t uid;
+ gid_t gid;
+ int grpsize;
+ int ngrps;
+ gid_t *groups;
+};
#define __yawn(args) do { \
args->task = synctask_get (); \
@@ -242,34 +257,63 @@ void synctask_waitfor (struct synctask *task, int count);
int synctask_setid (struct synctask *task, uid_t uid, gid_t gid);
#define SYNCTASK_SETID(uid, gid) synctask_setid (synctask_get(), uid, gid);
+int syncopctx_setfsuid (void *uid);
+int syncopctx_setfsgid (void *gid);
+int syncopctx_setfsgroups (int count, const void *groups);
static inline call_frame_t *
syncop_create_frame (xlator_t *this)
{
- call_frame_t *frame = NULL;
- int ngrps = -1;
+ call_frame_t *frame = NULL;
+ int ngrps = -1;
+ struct syncopctx *opctx = NULL;
frame = create_frame (this, this->ctx->pool);
if (!frame)
return NULL;
- frame->root->pid = getpid();
- frame->root->uid = geteuid ();
- frame->root->gid = getegid ();
- ngrps = getgroups (0, 0);
- if (ngrps < 0) {
- STACK_DESTROY (frame->root);
- return NULL;
- }
+ frame->root->pid = getpid ();
- if (call_stack_alloc_groups (frame->root, ngrps) != 0) {
- STACK_DESTROY (frame->root);
- return NULL;
- }
+ opctx = syncopctx_getctx ();
+ if (opctx && (opctx->valid & SYNCOPCTX_UID))
+ frame->root->uid = opctx->uid;
+ else
+ frame->root->uid = geteuid ();
- if (getgroups (ngrps, frame->root->groups) < 0) {
- STACK_DESTROY (frame->root);
- return NULL;
+ if (opctx && (opctx->valid & SYNCOPCTX_GID))
+ frame->root->gid = opctx->gid;
+ else
+ frame->root->gid = getegid ();
+
+ if (opctx && (opctx->valid & SYNCOPCTX_GROUPS)) {
+ ngrps = opctx->ngrps;
+
+ if (ngrps != 0 && opctx->groups != NULL) {
+ if (call_stack_alloc_groups (frame->root, ngrps) != 0) {
+ STACK_DESTROY (frame->root);
+ return NULL;
+ }
+
+ memcpy (frame->root->groups, opctx->groups,
+ (sizeof (gid_t) * ngrps));
+ }
+ }
+ else {
+ ngrps = getgroups (0, 0);
+ if (ngrps < 0) {
+ STACK_DESTROY (frame->root);
+ return NULL;
+ }
+
+ if (call_stack_alloc_groups (frame->root, ngrps) != 0) {
+ STACK_DESTROY (frame->root);
+ return NULL;
+ }
+
+ if (getgroups (ngrps, frame->root->groups) < 0) {
+ STACK_DESTROY (frame->root);
+ return NULL;
+ }
}
return frame;
@@ -359,6 +403,8 @@ int syncop_fallocate(xlator_t *subvol, fd_t *fd, int32_t keep_size, off_t offset
size_t len);
int syncop_discard(xlator_t *subvol, fd_t *fd, off_t offset, size_t len);
+int syncop_zerofill(xlator_t *subvol, fd_t *fd, off_t offset, size_t len);
+
int syncop_rename (xlator_t *subvol, loc_t *oldloc, loc_t *newloc);
int syncop_lk (xlator_t *subvol, fd_t *fd, int cmd, struct gf_flock *flock);
diff --git a/libglusterfs/src/timer.c b/libglusterfs/src/timer.c
index ae40142ad..a059cc212 100644
--- a/libglusterfs/src/timer.c
+++ b/libglusterfs/src/timer.c
@@ -17,19 +17,18 @@
#include "logging.h"
#include "common-utils.h"
#include "globals.h"
-
-#define TS(tv) ((((unsigned long long) tv.tv_sec) * 1000000) + (tv.tv_usec))
+#include "timespec.h"
gf_timer_t *
gf_timer_call_after (glusterfs_ctx_t *ctx,
- struct timeval delta,
+ struct timespec delta,
gf_timer_cbk_t callbk,
void *data)
{
gf_timer_registry_t *reg = NULL;
gf_timer_t *event = NULL;
gf_timer_t *trav = NULL;
- unsigned long long at = 0L;
+ uint64_t at = 0;
if (ctx == NULL)
{
@@ -48,10 +47,8 @@ gf_timer_call_after (glusterfs_ctx_t *ctx,
if (!event) {
return NULL;
}
- gettimeofday (&event->at, NULL);
- event->at.tv_usec = ((event->at.tv_usec + delta.tv_usec) % 1000000);
- event->at.tv_sec += ((event->at.tv_usec + delta.tv_usec) / 1000000);
- event->at.tv_sec += delta.tv_sec;
+ timespec_now (&event->at);
+ timespec_adjust_delta (&event->at, delta);
at = TS (event->at);
event->callbk = callbk;
event->data = data;
@@ -127,7 +124,7 @@ void *
gf_timer_proc (void *ctx)
{
gf_timer_registry_t *reg = NULL;
- const struct timespec sleepts = {.tv_sec = 1, .tv_nsec = 0, };
+ const struct timespec sleepts = {.tv_sec = 1, .tv_nsec = 0, };
if (ctx == NULL)
{
@@ -142,14 +139,14 @@ gf_timer_proc (void *ctx)
}
while (!reg->fin) {
- unsigned long long now;
- struct timeval now_tv;
+ uint64_t now;
+ struct timespec now_ts;
gf_timer_t *event = NULL;
- gettimeofday (&now_tv, NULL);
- now = TS (now_tv);
+ timespec_now (&now_ts);
+ now = TS (now_ts);
while (1) {
- unsigned long long at;
+ uint64_t at;
char need_cbk = 0;
pthread_mutex_lock (&reg->lock);
@@ -213,7 +210,7 @@ gf_timer_registry_init (glusterfs_ctx_t *ctx)
reg->stale.prev = &reg->stale;
ctx->timer = reg;
- pthread_create (&reg->th, NULL, gf_timer_proc, ctx);
+ gf_thread_create (&reg->th, NULL, gf_timer_proc, ctx);
}
out:
return ctx->timer;
diff --git a/libglusterfs/src/timer.h b/libglusterfs/src/timer.h
index 2954f6aff..2f963adbf 100644
--- a/libglusterfs/src/timer.h
+++ b/libglusterfs/src/timer.h
@@ -25,7 +25,7 @@ typedef void (*gf_timer_cbk_t) (void *);
struct _gf_timer {
struct _gf_timer *next, *prev;
- struct timeval at;
+ struct timespec at;
gf_timer_cbk_t callbk;
void *data;
xlator_t *xl;
@@ -44,7 +44,7 @@ typedef struct _gf_timer_registry gf_timer_registry_t;
gf_timer_t *
gf_timer_call_after (glusterfs_ctx_t *ctx,
- struct timeval delta,
+ struct timespec delta,
gf_timer_cbk_t cbk,
void *data);
diff --git a/libglusterfs/src/timespec.c b/libglusterfs/src/timespec.c
new file mode 100644
index 000000000..a0c281a1e
--- /dev/null
+++ b/libglusterfs/src/timespec.c
@@ -0,0 +1,68 @@
+/*
+ Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#include <stdio.h>
+#include <inttypes.h>
+#if defined GF_LINUX_HOST_OS || defined GF_SOLARIS_HOST_OS || defined GF_BSD_HOST_OS
+#include <time.h>
+#include <sys/time.h>
+#endif
+
+#if defined GF_DARWIN_HOST_OS
+#include <mach/mach_time.h>
+#endif
+
+#include "logging.h"
+#include "time.h"
+
+
+void tv2ts (struct timeval tv, struct timespec *ts)
+{
+ ts->tv_sec = tv.tv_sec;
+ ts->tv_nsec = tv.tv_usec * 1000;
+}
+
+void timespec_now (struct timespec *ts)
+{
+#if defined GF_LINUX_HOST_OS || defined GF_SOLARIS_HOST_OS || defined GF_BSD_HOST_OS
+
+ if (0 == clock_gettime(CLOCK_MONOTONIC, ts))
+ return;
+ else {
+ struct timeval tv;
+ if (0 == gettimeofday(&tv, NULL))
+ tv2ts(tv, ts);
+ }
+#elif defined GF_DARWIN_HOST_OS
+ mach_timebase_info_data_t tb = { 0 };
+ static double timebase = 0.0;
+ uint64_t time = 0;
+ mach_timebase_info (&tb);
+
+ timebase *= info.numer;
+ timebase /= info.denom;
+
+ time = mach_absolute_time();
+ time *= timebase;
+
+ ts->tv_sec = (time * NANO);
+ ts->tv_nsec = (time - (ts.tv_sec * GIGA));
+
+#endif /* Platform verification */
+ gf_log_callingfn ("timer", GF_LOG_DEBUG, "%"PRIu64".%09"PRIu64,
+ ts->tv_sec, ts->tv_nsec);
+}
+
+void timespec_adjust_delta (struct timespec *ts, struct timespec delta)
+{
+ ts->tv_nsec = ((ts->tv_nsec + delta.tv_nsec) % 1000000000);
+ ts->tv_sec += ((ts->tv_nsec + delta.tv_nsec) / 1000000000);
+ ts->tv_sec += delta.tv_sec;
+}
diff --git a/libglusterfs/src/timespec.h b/libglusterfs/src/timespec.h
new file mode 100644
index 000000000..490255df9
--- /dev/null
+++ b/libglusterfs/src/timespec.h
@@ -0,0 +1,24 @@
+/*
+ Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#ifndef __INCLUDE_TIMESPEC_H__
+#define __INCLUDE_TIMESPEC_H__
+
+#include <stdint.h>
+
+#define TS(ts) ((ts.tv_sec * 1000000000LL) + ts.tv_nsec)
+#define NANO (+1.0E-9)
+#define GIGA UINT64_C(1000000000)
+
+void tv2ts (struct timeval tv, struct timespec *ts);
+void timespec_now (struct timespec *ts);
+void timespec_adjust_delta (struct timespec *ts, struct timespec delta);
+
+#endif /* __INCLUDE_TIMESPEC_H__ */
diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c
index a7caedf02..a277c58a8 100644
--- a/libglusterfs/src/xlator.c
+++ b/libglusterfs/src/xlator.c
@@ -81,6 +81,7 @@ fill_defaults (xlator_t *xl)
SET_DEFAULT_FOP (fsetattr);
SET_DEFAULT_FOP (fallocate);
SET_DEFAULT_FOP (discard);
+ SET_DEFAULT_FOP (zerofill);
SET_DEFAULT_FOP (getspec);
@@ -361,29 +362,6 @@ out:
return search;
}
-xlator_t *
-xlator_search_by_xl_type (xlator_t *any, const char *type)
-{
- xlator_t *search = NULL;
-
- GF_VALIDATE_OR_GOTO ("xlator", any, out);
- GF_VALIDATE_OR_GOTO ("xlator", type, out);
-
- search = any;
-
- while (search->prev)
- search = search->prev;
-
- while (search) {
- if (!strcmp (search->type, type))
- break;
- search = search->next;
- }
-
-out:
- return search;
-}
-
static int
__xlator_init(xlator_t *xl)
{
@@ -538,10 +516,26 @@ out:
return;
}
+int
+xlator_list_destroy (xlator_list_t *list)
+{
+ xlator_list_t *next = NULL;
+
+ while (list) {
+ next = list->next;
+ GF_FREE (list);
+ list = next;
+ }
+
+ return 0;
+}
+
int
xlator_tree_free (xlator_t *tree)
{
+ volume_opt_list_t *vol_opt = NULL;
+ volume_opt_list_t *tmp = NULL;
xlator_t *trav = tree;
xlator_t *prev = tree;
@@ -552,9 +546,19 @@ xlator_tree_free (xlator_t *tree)
while (prev) {
trav = prev->next;
- dict_destroy (prev->options);
+ if (prev->dlhandle)
+ dlclose (prev->dlhandle);
+ dict_unref (prev->options);
GF_FREE (prev->name);
GF_FREE (prev->type);
+ xlator_list_destroy (prev->children);
+ xlator_list_destroy (prev->parents);
+
+ list_for_each_entry_safe (vol_opt, tmp, &prev->volume_options,
+ list) {
+ list_del_init (&vol_opt->list);
+ GF_FREE (vol_opt);
+ }
GF_FREE (prev);
prev = trav;
}
@@ -696,21 +700,6 @@ loc_is_root (loc_t *loc)
}
int
-xlator_list_destroy (xlator_list_t *list)
-{
- xlator_list_t *next = NULL;
-
- while (list) {
- next = list->next;
- GF_FREE (list);
- list = next;
- }
-
- return 0;
-}
-
-
-int
xlator_destroy (xlator_t *xl)
{
volume_opt_list_t *vol_opt = NULL;
diff --git a/libglusterfs/src/xlator.h b/libglusterfs/src/xlator.h
index d23ee0c25..b57e5873e 100644
--- a/libglusterfs/src/xlator.h
+++ b/libglusterfs/src/xlator.h
@@ -66,6 +66,7 @@ typedef int32_t (*event_notify_fn_t) (xlator_t *this, int32_t event, void *data,
#include "globals.h"
#include "iatt.h"
#include "options.h"
+#include "client_t.h"
struct _loc {
@@ -433,6 +434,14 @@ typedef int32_t (*fop_discard_cbk_t) (call_frame_t *frame,
struct iatt *preop_stbuf,
struct iatt *postop_stbuf, dict_t *xdata);
+typedef int32_t (*fop_zerofill_cbk_t) (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ struct iatt *preop_stbuf,
+ struct iatt *postop_stbuf, dict_t *xdata);
+
typedef int32_t (*fop_lookup_t) (call_frame_t *frame,
xlator_t *this,
loc_t *loc,
@@ -664,6 +673,12 @@ typedef int32_t (*fop_discard_t) (call_frame_t *frame,
off_t offset,
size_t len,
dict_t *xdata);
+typedef int32_t (*fop_zerofill_t) (call_frame_t *frame,
+ xlator_t *this,
+ fd_t *fd,
+ off_t offset,
+ size_t len,
+ dict_t *xdata);
struct xlator_fops {
fop_lookup_t lookup;
@@ -710,6 +725,7 @@ struct xlator_fops {
fop_getspec_t getspec;
fop_fallocate_t fallocate;
fop_discard_t discard;
+ fop_zerofill_t zerofill;
/* these entries are used for a typechecking hack in STACK_WIND _only_ */
fop_lookup_cbk_t lookup_cbk;
@@ -756,6 +772,7 @@ struct xlator_fops {
fop_getspec_cbk_t getspec_cbk;
fop_fallocate_cbk_t fallocate_cbk;
fop_discard_cbk_t discard_cbk;
+ fop_zerofill_cbk_t zerofill_cbk;
};
typedef int32_t (*cbk_forget_t) (xlator_t *this,
@@ -766,11 +783,15 @@ typedef int32_t (*cbk_release_t) (xlator_t *this,
typedef int32_t (*cbk_invalidate_t)(xlator_t *this, inode_t *inode);
+typedef int32_t (*cbk_client_t)(xlator_t *this, client_t *client);
+
struct xlator_cbks {
- cbk_forget_t forget;
- cbk_release_t release;
- cbk_release_t releasedir;
- cbk_invalidate_t invalidate;
+ cbk_forget_t forget;
+ cbk_release_t release;
+ cbk_release_t releasedir;
+ cbk_invalidate_t invalidate;
+ cbk_client_t client_destroy;
+ cbk_client_t client_disconnect;
};
typedef int32_t (*dumpop_priv_t) (xlator_t *this);
@@ -912,7 +933,6 @@ void xlator_foreach_depth_first (xlator_t *this,
void *data);
xlator_t *xlator_search_by_name (xlator_t *any, const char *name);
-xlator_t *xlator_search_by_xl_type (xlator_t *any, const char *type);
void inode_destroy_notify (inode_t *inode, const char *xlname);
@@ -932,5 +952,9 @@ enum gf_hdsk_event_notify_op {
GF_EN_DEFRAG_STATUS,
GF_EN_MAX,
};
-
+gf_boolean_t
+is_graph_topology_equal (glusterfs_graph_t *graph1, glusterfs_graph_t *graph2);
+int
+glusterfs_volfile_reconfigure (int oldvollen, FILE *newvolfile_fp,
+ glusterfs_ctx_t *ctx, const char *oldvolfile);
#endif /* _XLATOR_H */
diff --git a/rfc.sh b/rfc.sh
index 04efa6f3e..baf700495 100755
--- a/rfc.sh
+++ b/rfc.sh
@@ -1,7 +1,7 @@
#!/bin/sh -e
-branch="master";
+branch="development";
set_hooks_commit_msg()
diff --git a/rpc/rpc-lib/src/auth-glusterfs.c b/rpc/rpc-lib/src/auth-glusterfs.c
index 9c6f8385b..db488434c 100644
--- a/rpc/rpc-lib/src/auth-glusterfs.c
+++ b/rpc/rpc-lib/src/auth-glusterfs.c
@@ -96,6 +96,22 @@ int auth_glusterfs_authenticate (rpcsvc_request_t *req, void *priv)
goto err;
}
+ if (req->auxgidcount > SMALL_GROUP_COUNT) {
+ req->auxgidlarge = GF_CALLOC(req->auxgidcount,
+ sizeof(req->auxgids[0]),
+ gf_common_mt_auxgids);
+ req->auxgids = req->auxgidlarge;
+ } else {
+ req->auxgids = req->auxgidsmall;
+ }
+
+ if (!req->auxgids) {
+ gf_log ("auth-glusterfs", GF_LOG_WARNING,
+ "cannot allocate gid list");
+ ret = RPCSVC_AUTH_REJECT;
+ goto err;
+ }
+
for (gidcount = 0; gidcount < au.ngrps; ++gidcount)
req->auxgids[gidcount] = au.groups[gidcount];
@@ -203,6 +219,22 @@ int auth_glusterfs_v2_authenticate (rpcsvc_request_t *req, void *priv)
goto err;
}
+ if (req->auxgidcount > SMALL_GROUP_COUNT) {
+ req->auxgidlarge = GF_CALLOC(req->auxgidcount,
+ sizeof(req->auxgids[0]),
+ gf_common_mt_auxgids);
+ req->auxgids = req->auxgidlarge;
+ } else {
+ req->auxgids = req->auxgidsmall;
+ }
+
+ if (!req->auxgids) {
+ gf_log ("auth-glusterfs-v2", GF_LOG_WARNING,
+ "cannot allocate gid list");
+ ret = RPCSVC_AUTH_REJECT;
+ goto err;
+ }
+
for (i = 0; i < req->auxgidcount; ++i)
req->auxgids[i] = au.groups.groups_val[i];
diff --git a/rpc/rpc-lib/src/auth-unix.c b/rpc/rpc-lib/src/auth-unix.c
index 6251d60a8..fa5f0576e 100644
--- a/rpc/rpc-lib/src/auth-unix.c
+++ b/rpc/rpc-lib/src/auth-unix.c
@@ -42,6 +42,7 @@ int auth_unix_authenticate (rpcsvc_request_t *req, void *priv)
if (!req)
return ret;
+ req->auxgids = req->auxgidsmall;
ret = xdr_to_auth_unix_cred (req->cred.authdata, req->cred.datalen,
&aup, machname, req->auxgids);
if (ret == -1) {
diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h
index 704b1540a..8bef906cc 100644
--- a/rpc/rpc-lib/src/protocol-common.h
+++ b/rpc/rpc-lib/src/protocol-common.h
@@ -58,6 +58,7 @@ enum gf_fop_procnum {
GFS3_OP_FREMOVEXATTR,
GFS3_OP_FALLOCATE,
GFS3_OP_DISCARD,
+ GFS3_OP_ZEROFILL,
GFS3_OP_MAXVALUE,
} ;
@@ -156,10 +157,10 @@ enum gluster_cli_procnum {
GLUSTER_CLI_LIST_VOLUME,
GLUSTER_CLI_CLRLOCKS_VOLUME,
GLUSTER_CLI_UUID_RESET,
- GLUSTER_CLI_BD_OP,
GLUSTER_CLI_UUID_GET,
GLUSTER_CLI_COPY_FILE,
GLUSTER_CLI_SYS_EXEC,
+ GLUSTER_CLI_SNAP,
GLUSTER_CLI_MAXVALUE,
};
@@ -191,7 +192,7 @@ enum glusterd_brick_procnum {
GLUSTERD_BRICK_XLATOR_DEFRAG,
GLUSTERD_NODE_PROFILE,
GLUSTERD_NODE_STATUS,
- GLUSTERD_BRICK_BD_OP,
+ GLUSTERD_VOLUME_BARRIER_OP,
GLUSTERD_BRICK_MAXVALUE,
};
@@ -209,16 +210,22 @@ typedef enum {
GF_AFR_OP_INDEX_SUMMARY,
GF_AFR_OP_HEALED_FILES,
GF_AFR_OP_HEAL_FAILED_FILES,
- GF_AFR_OP_SPLIT_BRAIN_FILES
+ GF_AFR_OP_SPLIT_BRAIN_FILES,
+ GF_AFR_OP_STATISTICS,
+ GF_AFR_OP_STATISTICS_HEAL_COUNT,
+ GF_AFR_OP_STATISTICS_HEAL_COUNT_PER_REPLICA,
} gf_xl_afr_op_t ;
-typedef enum {
- GF_BD_OP_INVALID,
- GF_BD_OP_NEW_BD,
- GF_BD_OP_DELETE_BD,
- GF_BD_OP_CLONE_BD,
- GF_BD_OP_SNAPSHOT_BD,
-} gf_xl_bd_op_t ;
+enum glusterd_mgmt_v3_procnum {
+ GLUSTERD_MGMT_V3_NULL, /* 0 */
+ GLUSTERD_MGMT_V3_LOCK,
+ GLUSTERD_MGMT_V3_PRE_VALIDATE,
+ GLUSTERD_MGMT_V3_BRICK_OP,
+ GLUSTERD_MGMT_V3_COMMIT,
+ GLUSTERD_MGMT_V3_POST_VALIDATE,
+ GLUSTERD_MGMT_V3_UNLOCK,
+ GLUSTERD_MGMT_V3_MAXVALUE,
+};
#define GLUSTER_HNDSK_PROGRAM 14398633 /* Completely random */
#define GLUSTER_HNDSK_VERSION 2 /* 0.0.2 */
@@ -246,6 +253,10 @@ typedef enum {
#define GD_BRICK_PROGRAM 4867634 /*Completely random*/
#define GD_BRICK_VERSION 2
+/* Third version */
+#define GD_MGMT_V3_PROGRAM 2210013 /* Completely random */
+#define GD_MGMT_V3_VERSION 3
+
/* OP-VERSION handshake */
#define GD_MGMT_HNDSK_PROGRAM 1239873 /* Completely random */
#define GD_MGMT_HNDSK_VERSION 1
diff --git a/rpc/rpc-lib/src/rpc-clnt.c b/rpc/rpc-lib/src/rpc-clnt.c
index b1d004aa8..ac98a5c91 100644
--- a/rpc/rpc-lib/src/rpc-clnt.c
+++ b/rpc/rpc-lib/src/rpc-clnt.c
@@ -145,7 +145,7 @@ call_bail (void *data)
struct saved_frame *trav = NULL;
struct saved_frame *tmp = NULL;
char frame_sent[256] = {0,};
- struct timeval timeout = {0,};
+ struct timespec timeout = {0,};
struct iovec iov = {0,};
GF_VALIDATE_OR_GOTO ("client", data, out);
@@ -163,7 +163,7 @@ call_bail (void *data)
call-once timer */
if (conn->timer) {
timeout.tv_sec = 10;
- timeout.tv_usec = 0;
+ timeout.tv_nsec = 0;
gf_timer_call_cancel (clnt->ctx, conn->timer);
conn->timer = gf_timer_call_after (clnt->ctx,
@@ -173,7 +173,8 @@ call_bail (void *data)
if (conn->timer == NULL) {
gf_log (conn->trans->name, GF_LOG_WARNING,
- "Cannot create bailout timer");
+ "Cannot create bailout timer for %s",
+ conn->trans->peerinfo.identifier);
}
}
@@ -198,13 +199,13 @@ call_bail (void *data)
gf_log (conn->trans->name, GF_LOG_ERROR,
"bailing out frame type(%s) op(%s(%d)) xid = 0x%x "
- "sent = %s. timeout = %d",
+ "sent = %s. timeout = %d for %s",
trav->rpcreq->prog->progname,
(trav->rpcreq->prog->procnames) ?
trav->rpcreq->prog->procnames[trav->rpcreq->procnum] :
"--",
trav->rpcreq->procnum, trav->rpcreq->xid, frame_sent,
- conn->frame_timeout);
+ conn->frame_timeout, conn->trans->peerinfo.identifier);
clnt = rpc_clnt_ref (clnt);
trav->rpcreq->rpc_status = -1;
@@ -226,7 +227,7 @@ __save_frame (struct rpc_clnt *rpc_clnt, call_frame_t *frame,
struct rpc_req *rpcreq)
{
rpc_clnt_connection_t *conn = NULL;
- struct timeval timeout = {0, };
+ struct timespec timeout = {0, };
struct saved_frame *saved_frame = NULL;
conn = &rpc_clnt->conn;
@@ -240,7 +241,7 @@ __save_frame (struct rpc_clnt *rpc_clnt, call_frame_t *frame,
/* TODO: make timeout configurable */
if (conn->timer == NULL) {
timeout.tv_sec = 10;
- timeout.tv_usec = 0;
+ timeout.tv_nsec = 0;
conn->timer = gf_timer_call_after (rpc_clnt->ctx,
timeout,
call_bail,
@@ -397,7 +398,7 @@ rpc_clnt_reconnect (void *trans_ptr)
{
rpc_transport_t *trans = NULL;
rpc_clnt_connection_t *conn = NULL;
- struct timeval tv = {0, 0};
+ struct timespec ts = {0, 0};
int32_t ret = 0;
struct rpc_clnt *clnt = NULL;
@@ -416,14 +417,15 @@ rpc_clnt_reconnect (void *trans_ptr)
conn->reconnect = 0;
if (conn->connected == 0) {
- tv.tv_sec = 3;
+ ts.tv_sec = 3;
+ ts.tv_nsec = 0;
gf_log (trans->name, GF_LOG_TRACE,
"attempting reconnect");
ret = rpc_transport_connect (trans,
conn->config.remote_port);
conn->reconnect =
- gf_timer_call_after (clnt->ctx, tv,
+ gf_timer_call_after (clnt->ctx, ts,
rpc_clnt_reconnect,
trans);
} else {
@@ -831,7 +833,7 @@ rpc_clnt_notify (rpc_transport_t *trans, void *mydata,
int ret = -1;
rpc_request_info_t *req_info = NULL;
rpc_transport_pollin_t *pollin = NULL;
- struct timeval tv = {0, };
+ struct timespec ts = {0, };
conn = mydata;
if (conn == NULL) {
@@ -850,10 +852,11 @@ rpc_clnt_notify (rpc_transport_t *trans, void *mydata,
{
if (!conn->rpc_clnt->disabled
&& (conn->reconnect == NULL)) {
- tv.tv_sec = 10;
+ ts.tv_sec = 10;
+ ts.tv_nsec = 0;
conn->reconnect =
- gf_timer_call_after (clnt->ctx, tv,
+ gf_timer_call_after (clnt->ctx, ts,
rpc_clnt_reconnect,
conn->trans);
}
@@ -1695,4 +1698,3 @@ rpc_clnt_reconfig (struct rpc_clnt *rpc, struct rpc_clnt_config *config)
rpc->conn.config.remote_host = gf_strdup (config->remote_host);
}
}
-
diff --git a/rpc/rpc-lib/src/rpc-drc.c b/rpc/rpc-lib/src/rpc-drc.c
index 66d07cfe6..8181e6aee 100644
--- a/rpc/rpc-lib/src/rpc-drc.c
+++ b/rpc/rpc-lib/src/rpc-drc.c
@@ -708,10 +708,15 @@ rpcsvc_drc_init (rpcsvc_t *svc, dict_t *options)
uint32_t drc_size = 0;
uint32_t drc_factor = 0;
rpcsvc_drc_globals_t *drc = NULL;
+ static gf_boolean_t drc_inited = _gf_false;
GF_ASSERT (svc);
GF_ASSERT (options);
+ /* Already inited */
+ if (drc_inited)
+ return 0;
+
if (!svc->drc) {
drc = GF_CALLOC (1, sizeof (rpcsvc_drc_globals_t),
gf_common_mt_drc_globals_t);
@@ -732,11 +737,12 @@ rpcsvc_drc_init (rpcsvc_t *svc, dict_t *options)
/* Toggle DRC on/off, when more drc types(persistent/cluster)
are added, we shouldn't treat this as boolean */
- ret = dict_get_str_boolean (options, "nfs.drc", _gf_false);
+ ret = dict_get_str_boolean (options, "nfs.drc", _gf_true);
if (ret == -1) {
gf_log (GF_RPCSVC, GF_LOG_INFO, "drc user options need second look");
ret = _gf_true;
}
+ drc->enable_drc = ret;
if (ret == _gf_false) {
/* drc off */
@@ -796,6 +802,7 @@ rpcsvc_drc_init (rpcsvc_t *svc, dict_t *options)
gf_log (GF_RPCSVC, GF_LOG_DEBUG, "drc init successful");
drc->status = DRC_INITIATED;
+ drc_inited = _gf_true;
out:
UNLOCK (&drc->lock);
@@ -809,3 +816,57 @@ rpcsvc_drc_init (rpcsvc_t *svc, dict_t *options)
}
return ret;
}
+
+int
+rpcsvc_drc_reconfigure (rpcsvc_t *svc, dict_t *options)
+{
+ int ret = -1;
+ gf_boolean_t enable_drc = _gf_false;
+ rpcsvc_drc_globals_t *drc = NULL;
+ uint32_t drc_size = 0;
+
+ if ((!svc) || (!options))
+ return (-1);
+
+ drc = svc->drc;
+ /* reconfig for drc-size */
+ if (dict_get_uint32 (options, "nfs.drc-size", &drc_size))
+ drc_size = DRC_DEFAULT_CACHE_SIZE;
+
+ if (drc->global_cache_size != drc_size) {
+ gf_log (GF_RPCSVC, GF_LOG_DEBUG, "nfs.drc-size size can not "
+ "be reconfigured without NFS server restart.");
+ return (-1);
+ }
+
+ /* reconfig for nfs.drc */
+ ret = dict_get_str_boolean (options, "nfs.drc", _gf_true);
+ if (ret < 0) {
+ ret = _gf_true;
+ }
+ enable_drc = ret;
+
+ if (drc->enable_drc == enable_drc)
+ return 0;
+
+ drc->enable_drc = enable_drc;
+ if (enable_drc) {
+ if (drc == NULL)
+ return rpcsvc_drc_init(svc, options);
+ } else {
+ if (drc == NULL)
+ return (0);
+
+ LOCK (&drc->lock);
+ (void) rpcsvc_unregister_notify (svc, rpcsvc_drc_notify, THIS);
+ if (drc->mempool) {
+ mem_pool_destroy (drc->mempool);
+ drc->mempool = NULL;
+ }
+ UNLOCK (&drc->lock);
+ GF_FREE (drc);
+ svc->drc = NULL;
+ }
+
+ return (0);
+}
diff --git a/rpc/rpc-lib/src/rpc-drc.h b/rpc/rpc-lib/src/rpc-drc.h
index 0a1688992..7dfaef978 100644
--- a/rpc/rpc-lib/src/rpc-drc.h
+++ b/rpc/rpc-lib/src/rpc-drc.h
@@ -71,6 +71,7 @@ struct drc_globals {
struct list_head cache_head;
uint32_t client_count;
struct list_head clients_head;
+ gf_boolean_t enable_drc;
};
int
@@ -97,4 +98,7 @@ rpcsvc_drc_priv (rpcsvc_drc_globals_t *drc);
int
rpcsvc_drc_init (rpcsvc_t *svc, dict_t *options);
+int
+rpcsvc_drc_reconfigure (rpcsvc_t *svc, dict_t *options);
+
#endif /* RPC_DRC_H */
diff --git a/rpc/rpc-lib/src/rpc-transport.c b/rpc/rpc-lib/src/rpc-transport.c
index 89f3b3e8a..c24d41084 100644
--- a/rpc/rpc-lib/src/rpc-transport.c
+++ b/rpc/rpc-lib/src/rpc-transport.c
@@ -69,6 +69,19 @@ out:
return ret;
}
+int
+rpc_transport_throttle (rpc_transport_t *this, gf_boolean_t onoff)
+{
+ int ret = 0;
+
+ if (!this->ops->throttle)
+ return -ENOSYS;
+
+ ret = this->ops->throttle (this, onoff);
+
+ return ret;
+}
+
int32_t
rpc_transport_get_peeraddr (rpc_transport_t *this, char *peeraddr, int addrlen,
struct sockaddr_storage *sa, size_t salen)
@@ -282,7 +295,7 @@ rpc_transport_load (glusterfs_ctx_t *ctx, dict_t *options, char *trans_name)
}
*VOID(&(trans->reconfigure)) = dlsym (handle, "reconfigure");
- if (trans->fini == NULL) {
+ if (trans->reconfigure == NULL) {
gf_log ("rpc-transport", GF_LOG_DEBUG,
"dlsym (gf_rpc_transport_reconfigure) on %s", dlerror());
}
diff --git a/rpc/rpc-lib/src/rpc-transport.h b/rpc/rpc-lib/src/rpc-transport.h
index aa9df72b2..2db9072ae 100644
--- a/rpc/rpc-lib/src/rpc-transport.h
+++ b/rpc/rpc-lib/src/rpc-transport.h
@@ -192,6 +192,8 @@ struct rpc_transport {
pthread_mutex_t lock;
int32_t refcount;
+ int32_t outstanding_rpc_count;
+
glusterfs_ctx_t *ctx;
dict_t *options;
char *name;
@@ -235,6 +237,7 @@ struct rpc_transport_ops {
int32_t (*get_myaddr) (rpc_transport_t *this, char *peeraddr,
int addrlen, struct sockaddr_storage *sa,
socklen_t sasize);
+ int32_t (*throttle) (rpc_transport_t *this, gf_boolean_t onoff);
};
@@ -288,6 +291,9 @@ int32_t
rpc_transport_get_myaddr (rpc_transport_t *this, char *peeraddr, int addrlen,
struct sockaddr_storage *sa, size_t salen);
+int
+rpc_transport_throttle (rpc_transport_t *this, gf_boolean_t onoff);
+
rpc_transport_pollin_t *
rpc_transport_pollin_alloc (rpc_transport_t *this, struct iovec *vector,
int count, struct iobuf *hdr_iobuf,
diff --git a/rpc/rpc-lib/src/rpcsvc-auth.c b/rpc/rpc-lib/src/rpcsvc-auth.c
index 108279456..4cb86a758 100644
--- a/rpc/rpc-lib/src/rpcsvc-auth.c
+++ b/rpc/rpc-lib/src/rpcsvc-auth.c
@@ -178,6 +178,29 @@ err:
}
int
+rpcsvc_set_addr_namelookup (rpcsvc_t *svc, dict_t *options)
+{
+ int ret;
+ static char *addrlookup_key = "rpc-auth.addr.namelookup";
+
+ if (!svc || !options)
+ return (-1);
+
+ /* By default it's disabled */
+ ret = dict_get_str_boolean (options, addrlookup_key, _gf_false);
+ if (ret < 0) {
+ svc->addr_namelookup = _gf_false;
+ } else {
+ svc->addr_namelookup = ret;
+ }
+
+ if (svc->addr_namelookup)
+ gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Addr-Name lookup enabled");
+
+ return (0);
+}
+
+int
rpcsvc_set_allow_insecure (rpcsvc_t *svc, dict_t *options)
{
int ret = -1;
@@ -233,6 +256,7 @@ rpcsvc_auth_init (rpcsvc_t *svc, dict_t *options)
(void) rpcsvc_set_allow_insecure (svc, options);
(void) rpcsvc_set_root_squash (svc, options);
+ (void) rpcsvc_set_addr_namelookup (svc, options);
ret = rpcsvc_auth_add_initers (svc);
if (ret == -1) {
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to add initers");
@@ -249,6 +273,25 @@ out:
return ret;
}
+int
+rpcsvc_auth_reconf (rpcsvc_t *svc, dict_t *options)
+{
+ int ret = 0;
+
+ if ((!svc) || (!options))
+ return (-1);
+
+ ret = rpcsvc_set_allow_insecure (svc, options);
+ if (ret)
+ return (-1);
+
+ ret = rpcsvc_set_root_squash (svc, options);
+ if (ret)
+ return (-1);
+
+ return rpcsvc_set_addr_namelookup (svc, options);
+}
+
rpcsvc_auth_t *
__rpcsvc_auth_get_handler (rpcsvc_request_t *req)
@@ -327,6 +370,9 @@ rpcsvc_auth_request_init (rpcsvc_request_t *req)
if (!auth->authops->request_init)
ret = auth->authops->request_init (req, auth->authprivate);
+ req->auxgids = req->auxgidsmall; /* reset to auxgidlarge during
+ unsersialize if necessary */
+ req->auxgidlarge = NULL;
err:
return ret;
}
diff --git a/rpc/rpc-lib/src/rpcsvc-common.h b/rpc/rpc-lib/src/rpcsvc-common.h
index 054e187c9..aed55e039 100644
--- a/rpc/rpc-lib/src/rpcsvc-common.h
+++ b/rpc/rpc-lib/src/rpcsvc-common.h
@@ -52,25 +52,29 @@ typedef struct rpcsvc_state {
dict_t *options;
/* Allow insecure ports. */
- int allow_insecure;
+ gf_boolean_t allow_insecure;
gf_boolean_t register_portmap;
gf_boolean_t root_squash;
glusterfs_ctx_t *ctx;
/* list of connections which will listen for incoming connections */
- struct list_head listeners;
+ struct list_head listeners;
/* list of programs registered with rpcsvc */
- struct list_head programs;
+ struct list_head programs;
/* list of notification callbacks */
- struct list_head notify;
- int notify_count;
+ struct list_head notify;
+ int notify_count;
void *mydata; /* This is xlator */
- rpcsvc_notify_t notifyfn;
+ rpcsvc_notify_t notifyfn;
struct mem_pool *rxpool;
rpcsvc_drc_globals_t *drc;
+
+ /* per-client limit of outstanding rpc requests */
+ int outstanding_rpc_limit;
+ gf_boolean_t addr_namelookup;
} rpcsvc_t;
/* DRC START */
diff --git a/rpc/rpc-lib/src/rpcsvc.c b/rpc/rpc-lib/src/rpcsvc.c
index d6f5e754d..037c157f2 100644
--- a/rpc/rpc-lib/src/rpcsvc.c
+++ b/rpc/rpc-lib/src/rpcsvc.c
@@ -42,8 +42,7 @@
#include <stdio.h>
#include "xdr-rpcclnt.h"
-
-#define ACL_PROGRAM 100227
+#include "glusterfs-acl.h"
struct rpcsvc_program gluster_dump_prog;
@@ -130,6 +129,37 @@ rpcsvc_get_program_vector_sizer (rpcsvc_t *svc, uint32_t prognum,
return NULL;
}
+int
+rpcsvc_request_outstanding (rpcsvc_t *svc, rpc_transport_t *trans, int delta)
+{
+ int ret = 0;
+ int old_count = 0;
+ int new_count = 0;
+ int limit = 0;
+
+ pthread_mutex_lock (&trans->lock);
+ {
+ limit = svc->outstanding_rpc_limit;
+ if (!limit)
+ goto unlock;
+
+ old_count = trans->outstanding_rpc_count;
+ trans->outstanding_rpc_count += delta;
+ new_count = trans->outstanding_rpc_count;
+
+ if (old_count <= limit && new_count > limit)
+ ret = rpc_transport_throttle (trans, _gf_true);
+
+ if (old_count > limit && new_count <= limit)
+ ret = rpc_transport_throttle (trans, _gf_false);
+ }
+unlock:
+ pthread_mutex_unlock (&trans->lock);
+
+ return ret;
+}
+
+
/* This needs to change to returning errors, since
* we need to return RPC specific error messages when some
* of the pointers below are NULL.
@@ -280,8 +310,17 @@ rpcsvc_request_destroy (rpcsvc_request_t *req)
if (req->hdr_iobuf)
iobuf_unref (req->hdr_iobuf);
+ /* This marks the "end" of an RPC request. Reply is
+ completely written to the socket and is on the way
+ to the client. It is time to decrement the
+ outstanding request counter by 1.
+ */
+ rpcsvc_request_outstanding (req->svc, req->trans, -1);
+
rpc_transport_unref (req->trans);
+ GF_FREE (req->auxgidlarge);
+
mem_put (req);
out:
@@ -364,6 +403,12 @@ rpcsvc_request_create (rpcsvc_t *svc, rpc_transport_t *trans,
goto err;
}
+ /* We just received a new request from the wire. Account for
+ it in the outsanding request counter to make sure we don't
+ ingest too many concurrent requests from the same client.
+ */
+ ret = rpcsvc_request_outstanding (svc, trans, +1);
+
msgbuf = msg->vector[0].iov_base;
msglen = msg->vector[0].iov_len;
@@ -1204,12 +1249,13 @@ rpcsvc_error_reply (rpcsvc_request_t *req)
inline int
rpcsvc_program_register_portmap (rpcsvc_program_t *newprog, uint32_t port)
{
- int ret = 0;
+ int ret = -1; /* FAIL */
if (!newprog) {
goto out;
}
+ /* pmap_set() returns 0 for FAIL and 1 for SUCCESS */
if (!(pmap_set (newprog->prognum, newprog->progver, IPPROTO_TCP,
port))) {
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Could not register with"
@@ -1217,16 +1263,16 @@ rpcsvc_program_register_portmap (rpcsvc_program_t *newprog, uint32_t port)
goto out;
}
- ret = 0;
+ ret = 0; /* SUCCESS */
out:
return ret;
}
-static inline int
+inline int
rpcsvc_program_unregister_portmap (rpcsvc_program_t *prog)
{
- int ret = 0;
+ int ret = -1;
if (!prog)
goto out;
@@ -1844,12 +1890,92 @@ rpcsvc_init_options (rpcsvc_t *svc, dict_t *options)
gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Portmap registration "
"disabled");
- ret = 0;
+ ret = rpcsvc_set_outstanding_rpc_limit (svc, options);
out:
return ret;
}
int
+rpcsvc_reconfigure_options (rpcsvc_t *svc, dict_t *options)
+{
+ xlator_t *xlator = NULL;
+ xlator_list_t *volentry = NULL;
+ char *srchkey = NULL;
+ char *keyval = NULL;
+ int ret = -1;
+
+ if ((!svc) || (!svc->options) || (!options))
+ return (-1);
+
+ /* Fetch the xlator from svc */
+ xlator = (xlator_t *) svc->mydata;
+ if (!xlator)
+ return (-1);
+
+ /* Reconfigure the volume specific rpc-auth.addr allow part */
+ volentry = xlator->children;
+ while (volentry) {
+ ret = gf_asprintf (&srchkey, "rpc-auth.addr.%s.allow",
+ volentry->xlator->name);
+ if (ret == -1) {
+ gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed");
+ return (-1);
+ }
+
+ /* If found the srchkey, delete old key/val pair
+ * and set the key with new value.
+ */
+ if (!dict_get_str (options, srchkey, &keyval)) {
+ dict_del (svc->options, srchkey);
+ ret = dict_set_str (svc->options, srchkey, keyval);
+ if (ret < 0) {
+ gf_log (GF_RPCSVC, GF_LOG_ERROR,
+ "dict_set_str error");
+ GF_FREE (srchkey);
+ return (-1);
+ }
+ }
+
+ GF_FREE (srchkey);
+ volentry = volentry->next;
+ }
+
+ /* Reconfigure the volume specific rpc-auth.addr reject part */
+ volentry = xlator->children;
+ while (volentry) {
+ ret = gf_asprintf (&srchkey, "rpc-auth.addr.%s.reject",
+ volentry->xlator->name);
+ if (ret == -1) {
+ gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed");
+ return (-1);
+ }
+
+ /* If found the srchkey, delete old key/val pair
+ * and set the key with new value.
+ */
+ if (!dict_get_str (options, srchkey, &keyval)) {
+ dict_del (svc->options, srchkey);
+ ret = dict_set_str (svc->options, srchkey, keyval);
+ if (ret < 0) {
+ gf_log (GF_RPCSVC, GF_LOG_ERROR,
+ "dict_set_str error");
+ GF_FREE (srchkey);
+ return (-1);
+ }
+ }
+
+ GF_FREE (srchkey);
+ volentry = volentry->next;
+ }
+
+ ret = rpcsvc_init_options (svc, options);
+ if (ret)
+ return (-1);
+
+ return rpcsvc_auth_reconf (svc, options);
+}
+
+int
rpcsvc_transport_unix_options_build (dict_t **options, char *filepath)
{
dict_t *dict = NULL;
@@ -1895,6 +2021,48 @@ out:
return ret;
}
+/*
+ * Reconfigure() the rpc.outstanding-rpc-limit param.
+ */
+int
+rpcsvc_set_outstanding_rpc_limit (rpcsvc_t *svc, dict_t *options)
+{
+ int ret = -1; /* FAILURE */
+ int rpclim = 0;
+ static char *rpclimkey = "rpc.outstanding-rpc-limit";
+
+ if ((!svc) || (!options))
+ return (-1);
+
+ /* Reconfigure() the rpc.outstanding-rpc-limit param */
+ ret = dict_get_int32 (options, rpclimkey, &rpclim);
+ if (ret < 0) {
+ /* Fall back to default for FAILURE */
+ rpclim = RPCSVC_DEFAULT_OUTSTANDING_RPC_LIMIT;
+ } else {
+ /* SUCCESS: round off to multiple of 8.
+ * If the input value fails Boundary check, fall back to
+ * default i.e. RPCSVC_DEFAULT_OUTSTANDING_RPC_LIMIT.
+ * NB: value 0 is special, means its unset i.e. unlimited.
+ */
+ rpclim = ((rpclim + 8 - 1) >> 3) * 8;
+ if (rpclim < RPCSVC_MIN_OUTSTANDING_RPC_LIMIT) {
+ rpclim = RPCSVC_DEFAULT_OUTSTANDING_RPC_LIMIT;
+ } else if (rpclim > RPCSVC_MAX_OUTSTANDING_RPC_LIMIT) {
+ rpclim = RPCSVC_MAX_OUTSTANDING_RPC_LIMIT;
+ }
+ }
+
+ if (svc->outstanding_rpc_limit != rpclim) {
+ svc->outstanding_rpc_limit = rpclim;
+ gf_log (GF_RPCSVC, GF_LOG_INFO,
+ "Configured %s with value %d",
+ rpclimkey, rpclim);
+ }
+
+ return (0);
+}
+
/* The global RPC service initializer.
*/
rpcsvc_t *
@@ -2026,7 +2194,7 @@ err:
}
-int
+static int
rpcsvc_transport_peer_check_allow (dict_t *options, char *volname,
char *ip, char *hostname)
{
@@ -2055,7 +2223,7 @@ out:
return ret;
}
-int
+static int
rpcsvc_transport_peer_check_reject (dict_t *options, char *volname,
char *ip, char *hostname)
{
@@ -2107,7 +2275,7 @@ rpcsvc_combine_allow_reject_volume_check (int allow, int reject)
}
int
-rpcsvc_auth_check (dict_t *options, char *volname,
+rpcsvc_auth_check (rpcsvc_t *svc, char *volname,
rpc_transport_t *trans)
{
int ret = RPCSVC_AUTH_REJECT;
@@ -2119,8 +2287,14 @@ rpcsvc_auth_check (dict_t *options, char *volname,
char *allow_str = NULL;
char *reject_str = NULL;
char *srchstr = NULL;
+ dict_t *options = NULL;
+
+ if (!svc || !volname || !trans)
+ return ret;
- if (!options || !volname || !trans)
+ /* Fetch the options from svc struct and validate */
+ options = svc->options;
+ if (!options)
return ret;
ret = rpcsvc_transport_peername (trans, client_ip, RPCSVC_PEER_STRLEN);
@@ -2162,9 +2336,8 @@ rpcsvc_auth_check (dict_t *options, char *volname,
if (!get_host_name (client_ip, &ip))
ip = client_ip;
- /* addr-namelookup disabled by default */
- ret = dict_get_str_boolean (options, "rpc-auth.addr.namelookup", 0);
- if (ret == _gf_true) {
+ /* addr-namelookup check */
+ if (svc->addr_namelookup == _gf_true) {
ret = gf_get_hostname_from_ip (ip, &hostname);
if (ret) {
if (hostname)
diff --git a/rpc/rpc-lib/src/rpcsvc.h b/rpc/rpc-lib/src/rpcsvc.h
index 67ff74be6..cbc1f4226 100644
--- a/rpc/rpc-lib/src/rpcsvc.h
+++ b/rpc/rpc-lib/src/rpcsvc.h
@@ -38,6 +38,10 @@
#define MAX_IOVEC 16
#endif
+#define RPCSVC_DEFAULT_OUTSTANDING_RPC_LIMIT 64
+#define RPCSVC_MAX_OUTSTANDING_RPC_LIMIT 65536
+#define RPCSVC_MIN_OUTSTANDING_RPC_LIMIT 0 /* No limit i.e. Unlimited */
+
#define GF_RPCSVC "rpc-service"
#define RPCSVC_THREAD_STACK_SIZE ((size_t)(1024 * GF_UNIT_KB))
@@ -181,7 +185,9 @@ struct rpcsvc_request {
/* Might want to move this to AUTH_UNIX specific state since this array
* is not available for every authentication scheme.
*/
- gid_t auxgids[GF_MAX_AUX_GROUPS];
+ gid_t *auxgids;
+ gid_t auxgidsmall[SMALL_GROUP_COUNT];
+ gid_t *auxgidlarge;
int auxgidcount;
@@ -435,6 +441,9 @@ extern int
rpcsvc_program_register_portmap (rpcsvc_program_t *newprog, uint32_t port);
extern int
+rpcsvc_program_unregister_portmap (rpcsvc_program_t *newprog);
+
+extern int
rpcsvc_register_portmap_enabled (rpcsvc_t *svc);
/* Inits the global RPC service data structures.
@@ -444,6 +453,9 @@ extern rpcsvc_t *
rpcsvc_init (xlator_t *xl, glusterfs_ctx_t *ctx, dict_t *options,
uint32_t poolcount);
+extern int
+rpcsvc_reconfigure_options (rpcsvc_t *svc, dict_t *options);
+
int
rpcsvc_register_notify (rpcsvc_t *svc, rpcsvc_notify_t notify, void *mydata);
@@ -486,8 +498,7 @@ rpcsvc_transport_peeraddr (rpc_transport_t *trans, char *addrstr, int addrlen,
struct sockaddr_storage *returnsa, socklen_t sasize);
extern int
-rpcsvc_auth_check (dict_t *options, char *volname,
- rpc_transport_t *trans);
+rpcsvc_auth_check (rpcsvc_t *svc, char *volname, rpc_transport_t *trans);
extern int
rpcsvc_transport_privport_check (rpcsvc_t *svc, char *volname,
@@ -548,6 +559,9 @@ extern int
rpcsvc_auth_init (rpcsvc_t *svc, dict_t *options);
extern int
+rpcsvc_auth_reconf (rpcsvc_t *svc, dict_t *options);
+
+extern int
rpcsvc_auth_transport_init (rpc_transport_t *xprt);
extern int
@@ -579,11 +593,13 @@ rpcsvc_transport_unix_options_build (dict_t **options, char *filepath);
int
rpcsvc_set_allow_insecure (rpcsvc_t *svc, dict_t *options);
int
+rpcsvc_set_addr_namelookup (rpcsvc_t *svc, dict_t *options);
+int
rpcsvc_set_root_squash (rpcsvc_t *svc, dict_t *options);
int
+rpcsvc_set_outstanding_rpc_limit (rpcsvc_t *svc, dict_t *options);
+int
rpcsvc_auth_array (rpcsvc_t *svc, char *volname, int *autharr, int arrlen);
-char *
-rpcsvc_volume_allowed (dict_t *options, char *volname);
rpcsvc_vector_sizer
rpcsvc_get_program_vector_sizer (rpcsvc_t *svc, uint32_t prognum,
uint32_t progver, uint32_t procnum);
diff --git a/rpc/rpc-transport/rdma/src/rdma.c b/rpc/rpc-transport/rdma/src/rdma.c
index 8ef7d1e3a..6e6099a98 100644
--- a/rpc/rpc-transport/rdma/src/rdma.c
+++ b/rpc/rpc-transport/rdma/src/rdma.c
@@ -619,10 +619,9 @@ gf_rdma_get_device (rpc_transport_t *this, struct ibv_context *ibctx,
}
/* completion threads */
- ret = pthread_create (&trav->send_thread,
- NULL,
- gf_rdma_send_completion_proc,
- trav->send_chan);
+ ret = gf_thread_create (&trav->send_thread, NULL,
+ gf_rdma_send_completion_proc,
+ trav->send_chan);
if (ret) {
gf_log (this->name, GF_LOG_ERROR,
"could not create send completion thread for "
@@ -630,10 +629,9 @@ gf_rdma_get_device (rpc_transport_t *this, struct ibv_context *ibctx,
goto out;
}
- ret = pthread_create (&trav->recv_thread,
- NULL,
- gf_rdma_recv_completion_proc,
- trav->recv_chan);
+ ret = gf_thread_create (&trav->recv_thread, NULL,
+ gf_rdma_recv_completion_proc,
+ trav->recv_chan);
if (ret) {
gf_log (this->name, GF_LOG_ERROR,
"could not create recv completion thread "
@@ -641,10 +639,9 @@ gf_rdma_get_device (rpc_transport_t *this, struct ibv_context *ibctx,
return NULL;
}
- ret = pthread_create (&trav->async_event_thread,
- NULL,
- gf_rdma_async_event_thread,
- ibctx);
+ ret = gf_thread_create (&trav->async_event_thread, NULL,
+ gf_rdma_async_event_thread,
+ ibctx);
if (ret) {
gf_log (this->name, GF_LOG_ERROR,
"could not create async_event_thread");
@@ -4198,9 +4195,9 @@ __gf_rdma_ctx_create (void)
goto out;
}
- ret = pthread_create (&rdma_ctx->rdma_cm_thread, NULL,
- gf_rdma_cm_event_handler,
- rdma_ctx->rdma_cm_event_channel);
+ ret = gf_thread_create (&rdma_ctx->rdma_cm_thread, NULL,
+ gf_rdma_cm_event_handler,
+ rdma_ctx->rdma_cm_event_channel);
if (ret != 0) {
gf_log (GF_RDMA_LOG_NAME, GF_LOG_WARNING,
"creation of thread to handle rdma-cm events "
diff --git a/rpc/rpc-transport/socket/src/socket.c b/rpc/rpc-transport/socket/src/socket.c
index e63c27018..93da3f296 100644
--- a/rpc/rpc-transport/socket/src/socket.c
+++ b/rpc/rpc-transport/socket/src/socket.c
@@ -2162,8 +2162,6 @@ socket_connect_finish (rpc_transport_t *this)
priv->connect_finish_log = 1;
}
__socket_disconnect (this);
- notify_rpc = 1;
- event = RPC_TRANSPORT_DISCONNECT;
goto unlock;
}
@@ -2425,7 +2423,7 @@ socket_spawn (rpc_transport_t *this)
gf_log (this->name, GF_LOG_TRACE,
"spawning %p with gen %u", this, priv->ot_gen);
- if (pthread_create(&priv->thread,NULL,socket_poller,this) != 0) {
+ if (gf_thread_create(&priv->thread,NULL,socket_poller,this) != 0) {
gf_log (this->name, GF_LOG_ERROR,
"could not create poll thread");
}
@@ -2469,7 +2467,7 @@ socket_server_event_handler (int fd, int idx, void *data,
goto unlock;
}
- if (priv->nodelay) {
+ if (priv->nodelay && (new_sockaddr.ss_family != AF_UNIX)) {
ret = __socket_nodelay (new_sock);
if (ret == -1) {
gf_log (this->name, GF_LOG_WARNING,
@@ -2753,7 +2751,7 @@ socket_connect (rpc_transport_t *this, int port)
}
}
- if (priv->nodelay) {
+ if (priv->nodelay && (sa_family != AF_UNIX)) {
ret = __socket_nodelay (priv->sock);
if (ret == -1) {
@@ -2967,7 +2965,7 @@ socket_listen (rpc_transport_t *this)
}
}
- if (priv->nodelay) {
+ if (priv->nodelay && (sa_family != AF_UNIX)) {
ret = __socket_nodelay (priv->sock);
if (ret == -1) {
gf_log (this->name, GF_LOG_ERROR,
@@ -3263,6 +3261,25 @@ out:
}
+static int
+socket_throttle (rpc_transport_t *this, gf_boolean_t onoff)
+{
+ socket_private_t *priv = NULL;
+
+ priv = this->private;
+
+ /* The way we implement throttling is by taking off
+ POLLIN event from the polled flags. This way we
+ never get called with the POLLIN event and therefore
+ will never read() any more data until throttling
+ is turned off.
+ */
+ priv->idx = event_select_on (this->ctx->event_pool, priv->sock,
+ priv->idx, (int) !onoff, -1);
+ return 0;
+}
+
+
struct rpc_transport_ops tops = {
.listen = socket_listen,
.connect = socket_connect,
@@ -3273,6 +3290,7 @@ struct rpc_transport_ops tops = {
.get_peeraddr = socket_getpeeraddr,
.get_myname = socket_getmyname,
.get_myaddr = socket_getmyaddr,
+ .throttle = socket_throttle,
};
int
diff --git a/rpc/xdr/src/cli1-xdr.c b/rpc/xdr/src/cli1-xdr.c
index 7d85b43c1..97b210e14 100644
--- a/rpc/xdr/src/cli1-xdr.c
+++ b/rpc/xdr/src/cli1-xdr.c
@@ -179,6 +179,28 @@ xdr_gf_cli_status_type (XDR *xdrs, gf_cli_status_type *objp)
}
bool_t
+xdr_gf1_cli_snapshot (XDR *xdrs, gf1_cli_snapshot *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+ if (!xdr_enum (xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gf1_cli_snapshot_config (XDR *xdrs, gf1_cli_snapshot_config *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+ if (!xdr_enum (xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
xdr_gf_cli_req (XDR *xdrs, gf_cli_req *objp)
{
register int32_t *buf;
diff --git a/rpc/xdr/src/cli1-xdr.h b/rpc/xdr/src/cli1-xdr.h
index 20787c494..5e8c29fbb 100644
--- a/rpc/xdr/src/cli1-xdr.h
+++ b/rpc/xdr/src/cli1-xdr.h
@@ -48,6 +48,10 @@ enum gf_defrag_status_t {
GF_DEFRAG_STATUS_STOPPED = 2,
GF_DEFRAG_STATUS_COMPLETE = 3,
GF_DEFRAG_STATUS_FAILED = 4,
+ GF_DEFRAG_STATUS_LAYOUT_FIX_STARTED = 5,
+ GF_DEFRAG_STATUS_LAYOUT_FIX_STOPPED = 6,
+ GF_DEFRAG_STATUS_LAYOUT_FIX_COMPLETE = 7,
+ GF_DEFRAG_STATUS_LAYOUT_FIX_FAILED = 8,
};
typedef enum gf_defrag_status_t gf_defrag_status_t;
@@ -155,6 +159,7 @@ enum gf_cli_status_type {
GF_CLI_STATUS_FD = 0x0008,
GF_CLI_STATUS_CALLPOOL = 0x0010,
GF_CLI_STATUS_DETAIL = 0x0020,
+ GF_CLI_STATUS_TASKS = 0x0040,
GF_CLI_STATUS_MASK = 0x00FF,
GF_CLI_STATUS_VOL = 0x0100,
GF_CLI_STATUS_ALL = 0x0200,
@@ -164,6 +169,41 @@ enum gf_cli_status_type {
};
typedef enum gf_cli_status_type gf_cli_status_type;
+enum gf1_cli_snapshot {
+ GF_SNAP_OPTION_TYPE_NONE = 0,
+ GF_SNAP_OPTION_TYPE_CREATE = 1,
+ GF_SNAP_OPTION_TYPE_DELETE = 2,
+ GF_SNAP_OPTION_TYPE_RESTORE = 3,
+ GF_SNAP_OPTION_TYPE_START = 4,
+ GF_SNAP_OPTION_TYPE_STOP = 5,
+ GF_SNAP_OPTION_TYPE_LIST = 6,
+ GF_SNAP_OPTION_TYPE_STATUS = 7,
+ GF_SNAP_OPTION_TYPE_CONFIG = 8,
+ GF_SNAP_OPTION_TYPE_INFO = 9,
+};
+typedef enum gf1_cli_snapshot gf1_cli_snapshot;
+
+enum gf1_cli_snapshot_info {
+ GF_SNAP_INFO_TYPE_ALL = 0,
+ GF_SNAP_INFO_TYPE_SNAP = 1,
+ GF_SNAP_INFO_TYPE_VOL = 2,
+};
+typedef enum gf1_cli_snapshot_info gf1_cli_snapshot_info;
+
+enum gf1_cli_snapshot_config {
+ GF_SNAP_CONFIG_TYPE_NONE = 0,
+ GF_SNAP_CONFIG_TYPE_SET = 1,
+ GF_SNAP_CONFIG_DISPLAY = 2,
+};
+typedef enum gf1_cli_snapshot_config gf1_cli_snapshot_config;
+
+enum gf1_cli_snapshot_status {
+ GF_SNAP_STATUS_TYPE_ALL = 0,
+ GF_SNAP_STATUS_TYPE_SNAP = 1,
+ GF_SNAP_STATUS_TYPE_VOL = 2,
+};
+typedef enum gf1_cli_snapshot_status gf1_cli_snapshot_status;
+
struct gf_cli_req {
struct {
u_int dict_len;
@@ -275,6 +315,8 @@ extern bool_t xdr_gf1_cli_gsync_set (XDR *, gf1_cli_gsync_set*);
extern bool_t xdr_gf1_cli_stats_op (XDR *, gf1_cli_stats_op*);
extern bool_t xdr_gf1_cli_top_op (XDR *, gf1_cli_top_op*);
extern bool_t xdr_gf_cli_status_type (XDR *, gf_cli_status_type*);
+extern bool_t xdr_gf1_cli_snapshot (XDR *, gf1_cli_snapshot*);
+extern bool_t xdr_gf1_cli_snapshot_config (XDR *, gf1_cli_snapshot_config*);
extern bool_t xdr_gf_cli_req (XDR *, gf_cli_req*);
extern bool_t xdr_gf_cli_rsp (XDR *, gf_cli_rsp*);
extern bool_t xdr_gf1_cli_peer_list_req (XDR *, gf1_cli_peer_list_req*);
@@ -303,6 +345,8 @@ extern bool_t xdr_gf1_cli_gsync_set ();
extern bool_t xdr_gf1_cli_stats_op ();
extern bool_t xdr_gf1_cli_top_op ();
extern bool_t xdr_gf_cli_status_type ();
+extern bool_t xdr_gf1_cli_snapshot ();
+extern bool_t xdr_gf1_cli_snapshot_config ();
extern bool_t xdr_gf_cli_req ();
extern bool_t xdr_gf_cli_rsp ();
extern bool_t xdr_gf1_cli_peer_list_req ();
diff --git a/rpc/xdr/src/cli1-xdr.x b/rpc/xdr/src/cli1-xdr.x
index b85ecf87a..f9d29b7e1 100644
--- a/rpc/xdr/src/cli1-xdr.x
+++ b/rpc/xdr/src/cli1-xdr.x
@@ -11,7 +11,11 @@
GF_DEFRAG_STATUS_STARTED,
GF_DEFRAG_STATUS_STOPPED,
GF_DEFRAG_STATUS_COMPLETE,
- GF_DEFRAG_STATUS_FAILED
+ GF_DEFRAG_STATUS_FAILED,
+ GF_DEFRAG_STATUS_LAYOUT_FIX_STARTED,
+ GF_DEFRAG_STATUS_LAYOUT_FIX_STOPPED,
+ GF_DEFRAG_STATUS_LAYOUT_FIX_COMPLETE,
+ GF_DEFRAG_STATUS_LAYOUT_FIX_FAILED
} ;
enum gf1_cluster_type {
@@ -76,8 +80,8 @@ enum gf1_cli_gsync_set {
GF_GSYNC_OPTION_TYPE_CONFIG,
GF_GSYNC_OPTION_TYPE_STATUS,
GF_GSYNC_OPTION_TYPE_ROTATE,
- GF_GSYNC_OPTION_TYPE_DELETE,
- GF_GSYNC_OPTION_TYPE_CREATE
+ GF_GSYNC_OPTION_TYPE_CREATE,
+ GF_GSYNC_OPTION_TYPE_DELETE
};
enum gf1_cli_stats_op {
@@ -109,6 +113,7 @@ enum gf_cli_status_type {
GF_CLI_STATUS_FD = 0x0008, /*0000000001000*/
GF_CLI_STATUS_CALLPOOL = 0x0010, /*0000000010000*/
GF_CLI_STATUS_DETAIL = 0x0020, /*0000000100000*/
+ GF_CLI_STATUS_TASKS = 0x0040, /*0000001000000*/
GF_CLI_STATUS_MASK = 0x00FF, /*0000011111111 Used to get the op*/
GF_CLI_STATUS_VOL = 0x0100, /*0000100000000*/
GF_CLI_STATUS_ALL = 0x0200, /*0001000000000*/
@@ -117,6 +122,26 @@ enum gf_cli_status_type {
GF_CLI_STATUS_SHD = 0x1000 /*1000000000000*/
};
+/* Identifiers for snapshot clis */
+enum gf1_cli_snapshot {
+ GF_SNAP_OPTION_TYPE_NONE = 0,
+ GF_SNAP_OPTION_TYPE_CREATE,
+ GF_SNAP_OPTION_TYPE_DELETE,
+ GF_SNAP_OPTION_TYPE_RESTORE,
+ GF_SNAP_OPTION_TYPE_START,
+ GF_SNAP_OPTION_TYPE_STOP,
+ GF_SNAP_OPTION_TYPE_LIST,
+ GF_SNAP_OPTION_TYPE_STATUS,
+ GF_SNAP_OPTION_TYPE_CONFIG
+};
+
+enum gf1_cli_snapshot_config {
+ GF_SNAP_CONFIG_TYPE_NONE = 0,
+ GF_SNAP_CONFIG_TYPE_SET,
+ GF_SNAP_CONFIG_DISPLAY,
+
+};
+
struct gf_cli_req {
opaque dict<>;
} ;
diff --git a/rpc/xdr/src/glusterd1-xdr.c b/rpc/xdr/src/glusterd1-xdr.c
index 213b48bc6..7fa98aaeb 100644
--- a/rpc/xdr/src/glusterd1-xdr.c
+++ b/rpc/xdr/src/glusterd1-xdr.c
@@ -491,3 +491,433 @@ xdr_gd1_mgmt_brick_op_rsp (XDR *xdrs, gd1_mgmt_brick_op_rsp *objp)
return FALSE;
return TRUE;
}
+
+bool_t
+xdr_gd1_mgmt_v3_lock_req (XDR *xdrs, gd1_mgmt_v3_lock_req *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_vector (xdrs, (char *)objp->txn_id, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gd1_mgmt_v3_lock_rsp (XDR *xdrs, gd1_mgmt_v3_lock_rsp *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_vector (xdrs, (char *)objp->txn_id, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gd1_mgmt_v3_pre_val_req (XDR *xdrs, gd1_mgmt_v3_pre_val_req *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gd1_mgmt_v3_pre_val_rsp (XDR *xdrs, gd1_mgmt_v3_pre_val_rsp *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+
+ } else {
+ IXDR_PUT_LONG(buf, objp->op);
+ IXDR_PUT_LONG(buf, objp->op_ret);
+ IXDR_PUT_LONG(buf, objp->op_errno);
+ }
+ if (!xdr_string (xdrs, &objp->op_errstr, ~0))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+ } else if (xdrs->x_op == XDR_DECODE) {
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+
+ } else {
+ objp->op = IXDR_GET_LONG(buf);
+ objp->op_ret = IXDR_GET_LONG(buf);
+ objp->op_errno = IXDR_GET_LONG(buf);
+ }
+ if (!xdr_string (xdrs, &objp->op_errstr, ~0))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+ }
+
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->op_errstr, ~0))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gd1_mgmt_v3_brick_op_req (XDR *xdrs, gd1_mgmt_v3_brick_op_req *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gd1_mgmt_v3_brick_op_rsp (XDR *xdrs, gd1_mgmt_v3_brick_op_rsp *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+
+ } else {
+ IXDR_PUT_LONG(buf, objp->op);
+ IXDR_PUT_LONG(buf, objp->op_ret);
+ IXDR_PUT_LONG(buf, objp->op_errno);
+ }
+ if (!xdr_string (xdrs, &objp->op_errstr, ~0))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+ } else if (xdrs->x_op == XDR_DECODE) {
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+
+ } else {
+ objp->op = IXDR_GET_LONG(buf);
+ objp->op_ret = IXDR_GET_LONG(buf);
+ objp->op_errno = IXDR_GET_LONG(buf);
+ }
+ if (!xdr_string (xdrs, &objp->op_errstr, ~0))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+ }
+
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->op_errstr, ~0))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gd1_mgmt_v3_commit_req (XDR *xdrs, gd1_mgmt_v3_commit_req *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gd1_mgmt_v3_commit_rsp (XDR *xdrs, gd1_mgmt_v3_commit_rsp *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+
+ } else {
+ IXDR_PUT_LONG(buf, objp->op);
+ IXDR_PUT_LONG(buf, objp->op_ret);
+ IXDR_PUT_LONG(buf, objp->op_errno);
+ }
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->op_errstr, ~0))
+ return FALSE;
+ return TRUE;
+ } else if (xdrs->x_op == XDR_DECODE) {
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+
+ } else {
+ objp->op = IXDR_GET_LONG(buf);
+ objp->op_ret = IXDR_GET_LONG(buf);
+ objp->op_errno = IXDR_GET_LONG(buf);
+ }
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->op_errstr, ~0))
+ return FALSE;
+ return TRUE;
+ }
+
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->op_errstr, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gd1_mgmt_v3_post_val_req (XDR *xdrs, gd1_mgmt_v3_post_val_req *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gd1_mgmt_v3_post_val_rsp (XDR *xdrs, gd1_mgmt_v3_post_val_rsp *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+
+ } else {
+ IXDR_PUT_LONG(buf, objp->op);
+ IXDR_PUT_LONG(buf, objp->op_ret);
+ IXDR_PUT_LONG(buf, objp->op_errno);
+ }
+ if (!xdr_string (xdrs, &objp->op_errstr, ~0))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+ } else if (xdrs->x_op == XDR_DECODE) {
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+
+ } else {
+ objp->op = IXDR_GET_LONG(buf);
+ objp->op_ret = IXDR_GET_LONG(buf);
+ objp->op_errno = IXDR_GET_LONG(buf);
+ }
+ if (!xdr_string (xdrs, &objp->op_errstr, ~0))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+ }
+
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->op_errstr, ~0))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gd1_mgmt_v3_unlock_req (XDR *xdrs, gd1_mgmt_v3_unlock_req *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_vector (xdrs, (char *)objp->txn_id, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gd1_mgmt_v3_unlock_rsp (XDR *xdrs, gd1_mgmt_v3_unlock_rsp *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+ if (!xdr_vector (xdrs, (char *)objp->uuid, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_vector (xdrs, (char *)objp->txn_id, 16,
+ sizeof (u_char), (xdrproc_t) xdr_u_char))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+ return TRUE;
+}
diff --git a/rpc/xdr/src/glusterd1-xdr.h b/rpc/xdr/src/glusterd1-xdr.h
index c35930cad..b6be23d06 100644
--- a/rpc/xdr/src/glusterd1-xdr.h
+++ b/rpc/xdr/src/glusterd1-xdr.h
@@ -202,6 +202,145 @@ struct gd1_mgmt_brick_op_rsp {
};
typedef struct gd1_mgmt_brick_op_rsp gd1_mgmt_brick_op_rsp;
+struct gd1_mgmt_v3_lock_req {
+ u_char uuid[16];
+ u_char txn_id[16];
+ int op;
+ struct {
+ u_int dict_len;
+ char *dict_val;
+ } dict;
+};
+typedef struct gd1_mgmt_v3_lock_req gd1_mgmt_v3_lock_req;
+
+struct gd1_mgmt_v3_lock_rsp {
+ u_char uuid[16];
+ u_char txn_id[16];
+ struct {
+ u_int dict_len;
+ char *dict_val;
+ } dict;
+ int op_ret;
+ int op_errno;
+};
+typedef struct gd1_mgmt_v3_lock_rsp gd1_mgmt_v3_lock_rsp;
+
+struct gd1_mgmt_v3_pre_val_req {
+ u_char uuid[16];
+ int op;
+ struct {
+ u_int dict_len;
+ char *dict_val;
+ } dict;
+};
+typedef struct gd1_mgmt_v3_pre_val_req gd1_mgmt_v3_pre_val_req;
+
+struct gd1_mgmt_v3_pre_val_rsp {
+ u_char uuid[16];
+ int op;
+ int op_ret;
+ int op_errno;
+ char *op_errstr;
+ struct {
+ u_int dict_len;
+ char *dict_val;
+ } dict;
+};
+typedef struct gd1_mgmt_v3_pre_val_rsp gd1_mgmt_v3_pre_val_rsp;
+
+struct gd1_mgmt_v3_brick_op_req {
+ u_char uuid[16];
+ int op;
+ struct {
+ u_int dict_len;
+ char *dict_val;
+ } dict;
+};
+typedef struct gd1_mgmt_v3_brick_op_req gd1_mgmt_v3_brick_op_req;
+
+struct gd1_mgmt_v3_brick_op_rsp {
+ u_char uuid[16];
+ int op;
+ int op_ret;
+ int op_errno;
+ char *op_errstr;
+ struct {
+ u_int dict_len;
+ char *dict_val;
+ } dict;
+};
+typedef struct gd1_mgmt_v3_brick_op_rsp gd1_mgmt_v3_brick_op_rsp;
+
+struct gd1_mgmt_v3_commit_req {
+ u_char uuid[16];
+ int op;
+ struct {
+ u_int dict_len;
+ char *dict_val;
+ } dict;
+};
+typedef struct gd1_mgmt_v3_commit_req gd1_mgmt_v3_commit_req;
+
+struct gd1_mgmt_v3_commit_rsp {
+ u_char uuid[16];
+ int op;
+ int op_ret;
+ int op_errno;
+ struct {
+ u_int dict_len;
+ char *dict_val;
+ } dict;
+ char *op_errstr;
+};
+typedef struct gd1_mgmt_v3_commit_rsp gd1_mgmt_v3_commit_rsp;
+
+struct gd1_mgmt_v3_post_val_req {
+ u_char uuid[16];
+ int op;
+ int op_ret;
+ struct {
+ u_int dict_len;
+ char *dict_val;
+ } dict;
+};
+typedef struct gd1_mgmt_v3_post_val_req gd1_mgmt_v3_post_val_req;
+
+struct gd1_mgmt_v3_post_val_rsp {
+ u_char uuid[16];
+ int op;
+ int op_ret;
+ int op_errno;
+ char *op_errstr;
+ struct {
+ u_int dict_len;
+ char *dict_val;
+ } dict;
+};
+typedef struct gd1_mgmt_v3_post_val_rsp gd1_mgmt_v3_post_val_rsp;
+
+struct gd1_mgmt_v3_unlock_req {
+ u_char uuid[16];
+ u_char txn_id[16];
+ int op;
+ struct {
+ u_int dict_len;
+ char *dict_val;
+ } dict;
+};
+typedef struct gd1_mgmt_v3_unlock_req gd1_mgmt_v3_unlock_req;
+
+struct gd1_mgmt_v3_unlock_rsp {
+ u_char uuid[16];
+ u_char txn_id[16];
+ struct {
+ u_int dict_len;
+ char *dict_val;
+ } dict;
+ int op_ret;
+ int op_errno;
+};
+typedef struct gd1_mgmt_v3_unlock_rsp gd1_mgmt_v3_unlock_rsp;
+
/* the xdr functions */
#if defined(__STDC__) || defined(__cplusplus)
@@ -224,6 +363,18 @@ extern bool_t xdr_gd1_mgmt_friend_update (XDR *, gd1_mgmt_friend_update*);
extern bool_t xdr_gd1_mgmt_friend_update_rsp (XDR *, gd1_mgmt_friend_update_rsp*);
extern bool_t xdr_gd1_mgmt_brick_op_req (XDR *, gd1_mgmt_brick_op_req*);
extern bool_t xdr_gd1_mgmt_brick_op_rsp (XDR *, gd1_mgmt_brick_op_rsp*);
+extern bool_t xdr_gd1_mgmt_v3_lock_req (XDR *, gd1_mgmt_v3_lock_req*);
+extern bool_t xdr_gd1_mgmt_v3_lock_rsp (XDR *, gd1_mgmt_v3_lock_rsp*);
+extern bool_t xdr_gd1_mgmt_v3_pre_val_req (XDR *, gd1_mgmt_v3_pre_val_req*);
+extern bool_t xdr_gd1_mgmt_v3_pre_val_rsp (XDR *, gd1_mgmt_v3_pre_val_rsp*);
+extern bool_t xdr_gd1_mgmt_v3_brick_op_req (XDR *, gd1_mgmt_v3_brick_op_req*);
+extern bool_t xdr_gd1_mgmt_v3_brick_op_rsp (XDR *, gd1_mgmt_v3_brick_op_rsp*);
+extern bool_t xdr_gd1_mgmt_v3_commit_req (XDR *, gd1_mgmt_v3_commit_req*);
+extern bool_t xdr_gd1_mgmt_v3_commit_rsp (XDR *, gd1_mgmt_v3_commit_rsp*);
+extern bool_t xdr_gd1_mgmt_v3_post_val_req (XDR *, gd1_mgmt_v3_post_val_req*);
+extern bool_t xdr_gd1_mgmt_v3_post_val_rsp (XDR *, gd1_mgmt_v3_post_val_rsp*);
+extern bool_t xdr_gd1_mgmt_v3_unlock_req (XDR *, gd1_mgmt_v3_unlock_req*);
+extern bool_t xdr_gd1_mgmt_v3_unlock_rsp (XDR *, gd1_mgmt_v3_unlock_rsp*);
#else /* K&R C */
extern bool_t xdr_glusterd_volume_status ();
@@ -245,6 +396,18 @@ extern bool_t xdr_gd1_mgmt_friend_update ();
extern bool_t xdr_gd1_mgmt_friend_update_rsp ();
extern bool_t xdr_gd1_mgmt_brick_op_req ();
extern bool_t xdr_gd1_mgmt_brick_op_rsp ();
+extern bool_t xdr_gd1_mgmt_v3_lock_req ();
+extern bool_t xdr_gd1_mgmt_v3_lock_rsp ();
+extern bool_t xdr_gd1_mgmt_v3_pre_val_req ();
+extern bool_t xdr_gd1_mgmt_v3_pre_val_rsp ();
+extern bool_t xdr_gd1_mgmt_v3_brick_op_req ();
+extern bool_t xdr_gd1_mgmt_v3_brick_op_rsp ();
+extern bool_t xdr_gd1_mgmt_v3_commit_req ();
+extern bool_t xdr_gd1_mgmt_v3_commit_rsp ();
+extern bool_t xdr_gd1_mgmt_v3_post_val_req ();
+extern bool_t xdr_gd1_mgmt_v3_post_val_rsp ();
+extern bool_t xdr_gd1_mgmt_v3_unlock_req ();
+extern bool_t xdr_gd1_mgmt_v3_unlock_rsp ();
#endif /* K&R C */
diff --git a/rpc/xdr/src/glusterd1-xdr.x b/rpc/xdr/src/glusterd1-xdr.x
index fc1bb58b4..f5c45c9e4 100644
--- a/rpc/xdr/src/glusterd1-xdr.x
+++ b/rpc/xdr/src/glusterd1-xdr.x
@@ -125,3 +125,94 @@ struct gd1_mgmt_brick_op_rsp {
opaque output<>;
string op_errstr<>;
} ;
+
+struct gd1_mgmt_v3_lock_req {
+ unsigned char uuid[16];
+ unsigned char txn_id[16];
+ int op;
+ opaque dict<>;
+} ;
+
+struct gd1_mgmt_v3_lock_rsp {
+ unsigned char uuid[16];
+ unsigned char txn_id[16];
+ opaque dict<>;
+ int op_ret;
+ int op_errno;
+} ;
+
+struct gd1_mgmt_v3_pre_val_req {
+ unsigned char uuid[16];
+ int op;
+ opaque dict<>;
+} ;
+
+struct gd1_mgmt_v3_pre_val_rsp {
+ unsigned char uuid[16];
+ int op;
+ int op_ret;
+ int op_errno;
+ string op_errstr<>;
+ opaque dict<>;
+} ;
+
+struct gd1_mgmt_v3_brick_op_req {
+ unsigned char uuid[16];
+ int op;
+ opaque dict<>;
+} ;
+
+struct gd1_mgmt_v3_brick_op_rsp {
+ unsigned char uuid[16];
+ int op;
+ int op_ret;
+ int op_errno;
+ string op_errstr<>;
+ opaque dict<>;
+} ;
+
+struct gd1_mgmt_v3_commit_req {
+ unsigned char uuid[16];
+ int op;
+ opaque dict<>;
+} ;
+
+struct gd1_mgmt_v3_commit_rsp {
+ unsigned char uuid[16];
+ int op;
+ int op_ret;
+ int op_errno;
+ opaque dict<>;
+ string op_errstr<>;
+} ;
+
+struct gd1_mgmt_v3_post_val_req {
+ unsigned char uuid[16];
+ int op;
+ int op_ret;
+ opaque dict<>;
+} ;
+
+struct gd1_mgmt_v3_post_val_rsp {
+ unsigned char uuid[16];
+ int op;
+ int op_ret;
+ int op_errno;
+ string op_errstr<>;
+ opaque dict<>;
+} ;
+
+struct gd1_mgmt_v3_unlock_req {
+ unsigned char uuid[16];
+ unsigned char txn_id[16];
+ int op;
+ opaque dict<>;
+} ;
+
+struct gd1_mgmt_v3_unlock_rsp {
+ unsigned char uuid[16];
+ unsigned char txn_id[16];
+ opaque dict<>;
+ int op_ret;
+ int op_errno;
+} ;
diff --git a/rpc/xdr/src/glusterfs3-xdr.c b/rpc/xdr/src/glusterfs3-xdr.c
index 4e9791b20..3205c551e 100644
--- a/rpc/xdr/src/glusterfs3-xdr.c
+++ b/rpc/xdr/src/glusterfs3-xdr.c
@@ -1585,6 +1585,47 @@ xdr_gfs3_discard_rsp (XDR *xdrs, gfs3_discard_rsp *objp)
}
bool_t
+xdr_gfs3_zerofill_req (XDR *xdrs, gfs3_zerofill_req *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+ if (!xdr_opaque (xdrs, objp->gfid, 16))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->fd))
+ return FALSE;
+ if (!xdr_u_quad_t (xdrs, &objp->offset))
+ return FALSE;
+ if (!xdr_u_quad_t (xdrs, &objp->size))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->xdata.xdata_val,
+ (u_int *) &objp->xdata.xdata_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gfs3_zerofill_rsp (XDR *xdrs, gfs3_zerofill_rsp *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+ if (!xdr_int (xdrs, &objp->op_ret))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->op_errno))
+ return FALSE;
+ if (!xdr_gf_iatt (xdrs, &objp->statpre))
+ return FALSE;
+ if (!xdr_gf_iatt (xdrs, &objp->statpost))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->xdata.xdata_val,
+ (u_int *) &objp->xdata.xdata_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+
+bool_t
xdr_gfs3_rchecksum_req (XDR *xdrs, gfs3_rchecksum_req *objp)
{
register int32_t *buf;
diff --git a/rpc/xdr/src/glusterfs3-xdr.h b/rpc/xdr/src/glusterfs3-xdr.h
index 9e5d2e67b..13566e694 100644
--- a/rpc/xdr/src/glusterfs3-xdr.h
+++ b/rpc/xdr/src/glusterfs3-xdr.h
@@ -936,6 +936,31 @@ struct gfs3_discard_rsp {
};
typedef struct gfs3_discard_rsp gfs3_discard_rsp;
+struct gfs3_zerofill_req {
+ char gfid[16];
+ quad_t fd;
+ u_quad_t offset;
+ u_quad_t size;
+ struct {
+ u_int xdata_len;
+ char *xdata_val;
+ } xdata;
+};
+typedef struct gfs3_zerofill_req gfs3_zerofill_req;
+
+struct gfs3_zerofill_rsp {
+ int op_ret;
+ int op_errno;
+ struct gf_iatt statpre;
+ struct gf_iatt statpost;
+ struct {
+ u_int xdata_len;
+ char *xdata_val;
+ } xdata;
+};
+typedef struct gfs3_zerofill_rsp gfs3_zerofill_rsp;
+
+
struct gfs3_rchecksum_req {
quad_t fd;
u_quad_t offset;
@@ -1235,6 +1260,8 @@ extern bool_t xdr_gfs3_fallocate_req (XDR *, gfs3_fallocate_req*);
extern bool_t xdr_gfs3_fallocate_rsp (XDR *, gfs3_fallocate_rsp*);
extern bool_t xdr_gfs3_discard_req (XDR *, gfs3_discard_req*);
extern bool_t xdr_gfs3_discard_rsp (XDR *, gfs3_discard_rsp*);
+extern bool_t xdr_gfs3_zerofill_req (XDR *, gfs3_zerofill_req*);
+extern bool_t xdr_gfs3_zerofill_rsp (XDR *, gfs3_zerofill_rsp*);
extern bool_t xdr_gfs3_rchecksum_req (XDR *, gfs3_rchecksum_req*);
extern bool_t xdr_gfs3_rchecksum_rsp (XDR *, gfs3_rchecksum_rsp*);
extern bool_t xdr_gf_setvolume_req (XDR *, gf_setvolume_req*);
@@ -1333,6 +1360,8 @@ extern bool_t xdr_gfs3_fallocate_req ();
extern bool_t xdr_gfs3_fallocate_rsp ();
extern bool_t xdr_gfs3_discard_req ();
extern bool_t xdr_gfs3_discard_rsp ();
+extern bool_t xdr_gfs3_zerofill_req ();
+extern bool_t xdr_gfs3_zerofill_rsp ();
extern bool_t xdr_gfs3_rchecksum_req ();
extern bool_t xdr_gfs3_rchecksum_rsp ();
extern bool_t xdr_gf_setvolume_req ();
diff --git a/rpc/xdr/src/glusterfs3-xdr.x b/rpc/xdr/src/glusterfs3-xdr.x
index e2b086b1d..1edbda3ad 100644
--- a/rpc/xdr/src/glusterfs3-xdr.x
+++ b/rpc/xdr/src/glusterfs3-xdr.x
@@ -599,6 +599,23 @@ struct gfs3_fstat_req {
opaque xdata<>; /* Extra data */
} ;
+ struct gfs3_zerofill_req {
+ opaque gfid[16];
+ hyper fd;
+ unsigned hyper offset;
+ unsigned hyper size;
+ opaque xdata<>;
+} ;
+
+ struct gfs3_zerofill_rsp {
+ int op_ret;
+ int op_errno;
+ struct gf_iatt statpre;
+ struct gf_iatt statpost;
+ opaque xdata<>;
+} ;
+
+
struct gfs3_rchecksum_req {
hyper fd;
unsigned hyper offset;
diff --git a/run-tests.sh b/run-tests.sh
index d3c9af2ac..128404ed5 100755
--- a/run-tests.sh
+++ b/run-tests.sh
@@ -1,3 +1,30 @@
#!/bin/bash
+# Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
+#
-prove -rf --timer $(dirname $0)/tests;
+function _init()
+{
+ regression_testsdir=$(dirname $0);
+
+ if [ ! -f ${regression_testsdir}/tests/include.rc ]; then
+ echo "Seems like GlusterFS quality tests are corrupted..aborting!!"
+ exit 1
+ fi
+}
+
+function main()
+{
+ if [ $# -lt 1 ]; then
+ echo "Running all the regression test cases"
+ prove -rf --timer ${regression_testsdir}/tests;
+ else
+ ## TODO
+ echo "Running single regression test.."
+ echo "WARNING: yet to be implemented.. exiting safely"
+ exit 0
+ #export DEBUG=1;
+ #echo "Automatically setting up DEBUG=1 for this test $1";
+ fi
+}
+
+_init "$@" && main "$@"
diff --git a/tests/README b/tests/README.md
index 857230acb..2b5ed8dcd 100644
--- a/tests/README
+++ b/tests/README.md
@@ -1,26 +1,27 @@
-How to use test script framework.
-=================================
+Regression tests framework for GlusterFS
+========================================
+## Prereq
- Build and install the version of glusterfs with your changes. Make
sure the installed version is accessible from $PATH.
+## How-To
- To mount glusterfs, NEVER use 'mount -t glusterfs', instead use
'glusterfs -s ' method. This is because with the patch build setup
doesnot install the /sbin/mount.glusterfs necessary, where as the
glusterfs binary will be accessible with $PATH, and will pick the
right version.
-
- (optional) Set environment variables to specify location of
export directories and mount points. Unless you have special
requirements, the defaults should just work. The variables
themselves can be found at the top of tests/include.rc. All
of them can be overriden with environment variables.
-- Execute run-tests.sh in the top level directory as root.
+## Usage
+- Execute `/usr/share/glusterfs/run-tests.sh` as root.
-- If some test cases fail, you can execute the failed test case script
- directly bypassing run-tests.sh. At this time it might be
- useful to set the envrionment variable DEBUG=1 before running
- the individual test script directly by hand.
+- If some test cases fail, report to GlusterFS community at
+ `gluster-devel@nongnu.org`.
-- BE WARNED THAT THE TEST CASES DELETE /var/lib/glusterd/* !!!
+## Reminder
+- BE WARNED THAT THE TEST CASES DELETE /var/lib/glusterd/* !!! \ No newline at end of file
diff --git a/tests/basic/bd.t b/tests/basic/bd.t
index 3201b7460..eb6305414 100755
--- a/tests/basic/bd.t
+++ b/tests/basic/bd.t
@@ -2,9 +2,6 @@
. $(dirname $0)/../include.rc
-cleanup;
-
-
function execute()
{
cmd=$1
@@ -14,11 +11,10 @@ function execute()
function bd_cleanup()
{
- execute vgremove -f ${VG}
+ execute vgremove -f ${V0}
execute pvremove ${ld}
execute losetup -d ${ld}
execute rm ${BD_DISK}
- execute $CLI volume delete ${V0}
cleanup
}
@@ -31,9 +27,10 @@ function check()
fi
}
-VG=__bd_vg
SIZE=256 #in MB
+bd_cleanup;
+
## Configure environment needed for BD backend volumes
## Create a file with configured size and
## set it as a temporary loop device to create
@@ -56,23 +53,28 @@ function configure()
check losetup ${BD_DISK}
execute pvcreate -f ${ld}
check pvcreate ${ld}
- execute vgcreate ${VG} ${ld}
- check vgcreate ${VG}
+ execute vgcreate ${V0} ${ld}
+ check vgcreate ${V0}
+ execute lvcreate --thin ${V0}/pool --size 128M
}
function volinfo_field()
{
local vol=$1;
local field=$2;
-
$CLI volume info $vol | grep "^$field: " | sed 's/.*: //';
}
+function volume_type()
+{
+ getfattr -n volume.type $M0/. --only-values --absolute-names -e text
+}
+
TEST glusterd
TEST pidof glusterd
configure
-TEST $CLI volume create $V0 device vg ${H0}:/${VG}
+TEST $CLI volume create $V0 ${H0}:/$B0/$V0?${V0}
EXPECT "$V0" volinfo_field $V0 'Volume Name';
EXPECT 'Created' volinfo_field $V0 'Status';
@@ -80,38 +82,50 @@ EXPECT 'Created' volinfo_field $V0 'Status';
TEST $CLI volume start $V0;
EXPECT 'Started' volinfo_field $V0 'Status'
-TEST glusterfs --volfile-server=$H0 --volfile-id=$V0 $M0
+TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0
+EXPECT '1' volume_type
-## Create file (LV)
-TEST touch $M0/$VG/lv1
-TEST stat /dev/$VG/lv1
+## Create posix file
+TEST touch $M0/posix
-TEST rm $M0/$VG/lv1;
-TEST ! stat $M0/$VG/lv1;
+TEST touch $M0/lv
+gfid=`getfattr -n glusterfs.gfid.string $M0/lv --only-values --absolute-names`
+TEST setfattr -n user.glusterfs.bd -v "lv:4MB" $M0/lv
+# Check if LV is created
+TEST stat /dev/$V0/${gfid}
-TEST touch $M0/$VG/lv1
-TEST truncate -s64M $M0/$VG/lv1
+## Create filesystem
+sleep 1
+TEST mkfs.ext4 -qF $M0/lv
+# Cloning
+TEST touch $M0/lv_clone
+gfid=`getfattr -n glusterfs.gfid.string $M0/lv_clone --only-values --absolute-names`
+TEST setfattr -n clone -v ${gfid} $M0/lv
+TEST stat /dev/$V0/${gfid}
-TEST ln $M0/$VG/lv1 $M0/$VG/lv2
-TEST stat /dev/$VG/lv2
+sleep 1
+## Check mounting
+TEST mount -o loop $M0/lv $M1
+umount $M1
-rm $M0/$VG/lv1
-rm $M0/$VG/lv2
+# Snapshot
+TEST touch $M0/lv_sn
+gfid=`getfattr -n glusterfs.gfid.string $M0/lv_sn --only-values --absolute-names`
+TEST setfattr -n snapshot -v ${gfid} $M0/lv
+TEST stat /dev/$V0/${gfid}
-TEST $CLI bd create $V0:/$VG/lv1 4MB
-TEST stat /dev/$VG/lv1
+# Merge
+sleep 1
+TEST setfattr -n merge -v "$M0/lv_sn" $M0/lv_sn
+TEST ! stat $M0/lv_sn
+TEST ! stat /dev/$V0/${gfid}
-TEST $CLI bd clone $V0:/$VG/lv1 lv2
-TEST stat /dev/$VG/lv2
-TEST $CLI bd delete $V0:/$VG/lv2
-TEST $CLI bd snapshot $V0:/$VG/lv1 lv2 1
-TEST stat /dev/$VG/lv2
-rm $M0/$VG/lv2
-rm $M0/$VG/lv1
+rm $M0/* -f
TEST umount $M0
TEST $CLI volume stop ${V0}
+EXPECT 'Stopped' volinfo_field $V0 'Status';
TEST $CLI volume delete ${V0}
bd_cleanup
diff --git a/tests/basic/cdc.t b/tests/basic/cdc.t
new file mode 100755
index 000000000..4cd915aa9
--- /dev/null
+++ b/tests/basic/cdc.t
@@ -0,0 +1,135 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../volume.rc
+
+cleanup;
+
+TEST glusterd
+TEST pidof glusterd
+
+## Create a volume with one brick
+TEST $CLI volume create $V0 $H0:$B0/${V0}1;
+EXPECT "$V0" volinfo_field $V0 'Volume Name';
+EXPECT 'Created' volinfo_field $V0 'Status';
+EXPECT '1' brick_count $V0
+
+## Turn off performance translators
+## This is required for testing readv calls
+TEST $CLI volume set $V0 performance.io-cache off
+EXPECT 'off' volinfo_field $V0 'performance.io-cache'
+TEST $CLI volume set $V0 performance.quick-read off
+EXPECT 'off' volinfo_field $V0 'performance.quick-read'
+
+TEST $CLI volume set $V0 strict-write-ordering on
+EXPECT 'on' volinfo_field $V0 'performance.strict-write-ordering'
+
+## Turn on cdc xlator by setting features.compress to on
+TEST $CLI volume set $V0 compress on
+EXPECT 'on' volinfo_field $V0 'features.compress'
+EXPECT 'server' volinfo_field $V0 'compress.mode'
+
+## Make sure that user cannot change compress.mode
+## This would break the cdc xlator if allowed!
+TEST $CLI volume set $V0 compress.mode client
+EXPECT 'server' volinfo_field $V0 'compress.mode'
+
+## Turn on compress.debug option
+## This will dump compressed data onto disk as gzip file
+## This is used to check if compression actually happened
+TEST $CLI volume set $V0 compress.debug on
+EXPECT 'on' volinfo_field $V0 'compress.debug'
+
+## Start the volume
+TEST $CLI volume start $V0;
+EXPECT 'Started' volinfo_field $V0 'Status';
+
+## Mount FUSE with caching disabled
+TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0;
+
+####################
+## Testing writev ##
+####################
+
+## Create a 1K file locally and find the md5sum
+TEST dd if=/dev/zero of=/tmp/cdc-orig count=1 bs=1K 2>/dev/null
+checksum[original-file]=`md5sum /tmp/cdc-orig | cut -d' ' -f1`
+
+## Copy the file to mountpoint and find its md5sum on brick
+TEST dd if=/tmp/cdc-orig of=$M0/cdc-server count=1 bs=1K 2>/dev/null
+checksum[brick-file]=`md5sum $B0/${V0}1/cdc-server | cut -d' ' -f1`
+
+## Uncompress the gzip dump file and find its md5sum
+EXPECT '/tmp/cdcdump.gz: application/x-gzip; charset=binary' file -i /tmp/cdcdump.gz
+TEST gunzip -f /tmp/cdcdump.gz
+checksum[dump-file-writev]=`md5sum /tmp/cdcdump | cut -d' ' -f1`
+
+## Check if all 3 checksums are same
+TEST test ${checksum[original-file]} = ${checksum[brick-file]}
+TEST test ${checksum[brick-file]} = ${checksum[dump-file-writev]}
+
+## Cleanup files
+TEST rm -f /tmp/cdcdump.gz
+
+###################
+## Testing readv ##
+###################
+
+## Copy file from mount point to client and find checksum
+TEST dd if=$M0/cdc-server of=/tmp/cdc-client count=1 bs=1K 2>/dev/null
+checksum[client-file]=`md5sum /tmp/cdc-client | cut -d' ' -f1`
+
+## Uncompress the gzip dump file and find its md5sum
+EXPECT '/tmp/cdcdump.gz: application/x-gzip; charset=binary' file -i /tmp/cdcdump.gz
+TEST gunzip -f /tmp/cdcdump.gz
+checksum[dump-file-readv]=`md5sum /tmp/cdcdump | cut -d' ' -f1`
+
+## Check if all 3 checksums are same
+TEST test ${checksum[brick-file]} = ${checksum[client-file]}
+TEST test ${checksum[client-file]} = ${checksum[dump-file-readv]}
+
+## Cleanup files and unmount
+TEST rm -f /tmp/cdc* $M0/cdc*
+TEST umount $M0
+
+## Stop the volume
+TEST $CLI volume stop $V0;
+EXPECT 'Stopped' volinfo_field $V0 'Status';
+
+## Turn on compress.min-size and set it to 100 bytes
+## Compression should not take place if file size
+## is less than 100 bytes
+TEST $CLI volume set $V0 compress.min-size 100
+EXPECT '100' volinfo_field $V0 'compress.min-size'
+
+## Start the volume
+TEST $CLI volume start $V0;
+EXPECT 'Started' volinfo_field $V0 'Status';
+
+## Mount FUSE with caching disabled
+TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0;
+
+## Create a file of size 99 bytes on mountpoint
+## This is should not be compressed
+TEST dd if=/dev/zero of=$M0/cdc-small count=1 bs=99 2>/dev/null
+TEST ! test -e /tmp/cdcdump.gz
+
+## Cleanup files and unmount
+TEST rm -f /tmp/cdc* $M0/cdc*
+TEST umount $M0
+
+## Reset the compress options
+TEST $CLI volume reset $V0 compress.debug
+TEST $CLI volume reset $V0 compress.min-size
+TEST $CLI volume reset $V0 compress.mode
+TEST $CLI volume reset $V0 features.compress
+
+## Stop the volume
+TEST $CLI volume stop $V0;
+EXPECT 'Stopped' volinfo_field $V0 'Status';
+
+## Delete the volume
+TEST $CLI volume delete $V0;
+TEST ! $CLI volume info $V0;
+
+cleanup;
diff --git a/tests/basic/file-snapshot.t b/tests/basic/file-snapshot.t
index 93726f4b8..36908192b 100755
--- a/tests/basic/file-snapshot.t
+++ b/tests/basic/file-snapshot.t
@@ -27,6 +27,7 @@ TEST touch $M0/big-file;
TEST setfattr -n trusted.glusterfs.block-format -v qcow2:10GB $M0/big-file;
+TEST ls -al $M0 # test readdirplus
TEST [ `stat -c '%s' $M0/big-file` = 10737418240 ]
echo 'ABCDEFGHIJ' > $M0/data-file1
diff --git a/tests/basic/mgmt_v3-locks.t b/tests/basic/mgmt_v3-locks.t
new file mode 100755
index 000000000..22ca27b9f
--- /dev/null
+++ b/tests/basic/mgmt_v3-locks.t
@@ -0,0 +1,121 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../cluster.rc
+
+function check_peers {
+ $CLI_1 peer status | grep 'Peer in Cluster (Connected)' | wc -l
+}
+
+function volume_count {
+ local cli=$1;
+ if [ $cli -eq '1' ] ; then
+ $CLI_1 volume info | grep 'Volume Name' | wc -l;
+ else
+ $CLI_2 volume info | grep 'Volume Name' | wc -l;
+ fi
+}
+
+function volinfo_field()
+{
+ local vol=$1;
+ local field=$2;
+
+ $CLI_1 volume info $vol | grep "^$field: " | sed 's/.*: //';
+}
+
+function two_diff_vols_create {
+ # Both volume creates should be successful
+ $CLI_1 volume create $V0 $H1:$B1/$V0 $H2:$B2/$V0 $H3:$B3/$V0 &
+ PID_1=$!
+
+ $CLI_2 volume create $V1 $H1:$B1/$V1 $H2:$B2/$V1 $H3:$B3/$V1 &
+ PID_2=$!
+
+ wait $PID_1 $PID_2
+}
+
+function two_diff_vols_start {
+ # Both volume starts should be successful
+ $CLI_1 volume start $V0 &
+ PID_1=$!
+
+ $CLI_2 volume start $V1 &
+ PID_2=$!
+
+ wait $PID_1 $PID_2
+}
+
+function two_diff_vols_stop_force {
+ # Force stop, so that if rebalance from the
+ # remove bricks is in progress, stop can
+ # still go ahead. Both volume stops should
+ # be successful
+ $CLI_1 volume stop $V0 force &
+ PID_1=$!
+
+ $CLI_2 volume stop $V1 force &
+ PID_2=$!
+
+ wait $PID_1 $PID_2
+}
+
+function same_vol_remove_brick {
+
+ # Running two same vol commands at the same time can result in
+ # two success', two failures, or one success and one failure, all
+ # of which are valid. The only thing that shouldn't happen is a
+ # glusterd crash.
+
+ local vol=$1
+ local brick=$2
+ $CLI_1 volume remove-brick $1 $2 start &
+ $CLI_2 volume remove-brick $1 $2 start
+}
+
+cleanup;
+
+TEST launch_cluster 3;
+TEST $CLI_1 peer probe $H2;
+TEST $CLI_1 peer probe $H3;
+
+EXPECT_WITHIN 20 2 check_peers
+
+two_diff_vols_create
+EXPECT 'Created' volinfo_field $V0 'Status';
+EXPECT 'Created' volinfo_field $V1 'Status';
+
+two_diff_vols_start
+EXPECT 'Started' volinfo_field $V0 'Status';
+EXPECT 'Started' volinfo_field $V1 'Status';
+
+same_vol_remove_brick $V0 $H2:$B2/$V0
+# Checking glusterd crashed or not after same volume remove brick
+# on both nodes.
+EXPECT_WITHIN 20 2 check_peers
+
+same_vol_remove_brick $V1 $H2:$B2/$V1
+# Checking glusterd crashed or not after same volume remove brick
+# on both nodes.
+EXPECT_WITHIN 20 2 check_peers
+
+$CLI_1 volume set $V0 diagnostics.client-log-level DEBUG &
+$CLI_1 volume set $V1 diagnostics.client-log-level DEBUG
+kill_glusterd 3
+$CLI_1 volume status $V0
+$CLI_2 volume status $V1
+$CLI_1 peer status
+EXPECT_WITHIN 20 1 check_peers
+EXPECT 'Started' volinfo_field $V0 'Status';
+EXPECT 'Started' volinfo_field $V1 'Status';
+
+TEST $glusterd_3
+$CLI_1 volume status $V0
+$CLI_2 volume status $V1
+$CLI_1 peer status
+#EXPECT_WITHIN 20 2 check_peers
+#EXPECT 'Started' volinfo_field $V0 'Status';
+#EXPECT 'Started' volinfo_field $V1 'Status';
+#two_diff_vols_stop_force
+#EXPECT_WITHIN 20 2 check_peers
+cleanup;
diff --git a/tests/basic/rpm.t b/tests/basic/rpm.t
index ef4b5abf0..a577726a8 100755
--- a/tests/basic/rpm.t
+++ b/tests/basic/rpm.t
@@ -1,14 +1,29 @@
#!/bin/bash
+#
+# This test will run mock and rebuild the srpm for the latest two EPEL version.
+# By default, the results and the chroots are deleted.
+#
+# When debugging is needed, make sure to set DEBUG=1 in the environment or this
+# script. When debugging is enabled, the resulting log files and chroots are
+# kept. With debugging enabled, this test will fail the regression test, and
+# all output is saved to rpmbuild-mock.log. Tests are run in parallel, so the
+# logfile may be difficult to read.
+#
+# chroots are configured in /etc/mock/*.cfg, with site-defaults.cfg as main
+# configuration file. The default for chroots is /var/lib/mock, but this
+# depends on the 'basedir' configuration option set in the mentioned files.
+#
. $(dirname $0)/../include.rc
-RESULT_DIR=$(mktemp -d -p /var/tmp rpm-tests.XXXXXXXX)
-
# enable some extra debugging
if [ -n "${DEBUG}" -a "${DEBUG}" != "0" ]
then
- exec &> ${RESULT_DIR}/log
+ exec &> rpmbuild-mock.log
set -x
+ MOCK_CLEANUP='--no-cleanup-after'
+else
+ MOCK_CLEANUP='--cleanup-after'
fi
# detect the branch we're based off
@@ -20,20 +35,14 @@ else
GIT_PARENT=$(git describe --abbrev=0)
fi
-# check for changed files
-CHANGED_FILES=$(git diff --name-only ${GIT_PARENT})
-# filter out any files not affecting the build itself
-CHANGED_FILES=$(grep -E -v \
- -e '\.c$' \
- -e '\.h$' \
- -e '\.py$' \
- -e '^tests/' \
- <<< "${CHANGED_FILES}")
-if [ -z "${CHANGED_FILES}" ]
+# Filter out everything and what remains needs to be built
+BUILD_FILES=$(git diff --name-status ${GIT_PARENT} | grep -Ev '^M.*\.(c|h|py)' | awk {'print $2'})
+SELFTEST=$(grep -e 'tests/basic/rpm.t' <<< "${BUILD_FILES}")
+BUILD_FILES=$(grep -Ev '^tests/' <<< "${BUILD_FILES}")
+if [ -z "${BUILD_FILES}" -a -z "${SELFTEST}" ]
then
- # only contents of files were changed, no need to retest rpmbuild
+ # nothing affecting packaging changed, no need to retest rpmbuild
SKIP_TESTS
- rm -rf ${RESULT_DIR}
cleanup
exit 0
fi
@@ -41,8 +50,8 @@ fi
# checkout the sources to a new directory to execute ./configure and all
REPO=${PWD}
COMMIT=$(git describe)
-mkdir ${RESULT_DIR}/sources
-cd ${RESULT_DIR}/sources
+mkdir rpmbuild-mock.d
+pushd rpmbuild-mock.d 2>/dev/null
git clone -q -s file://${REPO} .
git checkout -q -b rpm-test ${COMMIT}
@@ -55,49 +64,46 @@ TEST make dist
ls extras
TEST make -C extras/LinuxRPM testsrpm
-chmod g=rwx ${RESULT_DIR}
-chown :mock ${RESULT_DIR}
-
# build for the last two Fedora EPEL releases (x86_64 only)
-# TAP/Prove aren't smart about loops
-TESTS_EXPECTED_IN_LOOP=2
for MOCK_CONF in $(ls -x1 /etc/mock/*.cfg | egrep -e 'epel-[0-9]+-x86_64.cfg$' | tail -n2)
do
EPEL_RELEASE=$(basename ${MOCK_CONF} .cfg)
- mkdir ${RESULT_DIR}/${EPEL_RELEASE}
- chmod g=rwx ${RESULT_DIR}/${EPEL_RELEASE}
- chown :mock ${RESULT_DIR}/${EPEL_RELEASE}
# expand the mock command line
- MOCK_CMD=$(echo /usr/bin/mock --cleanup-after \
- --resultdir=${RESULT_DIR}/${EPEL_RELEASE} \
- -r ${EPEL_RELEASE} --rebuild ${PWD}/*.src.rpm)
+ MOCK_CMD="/usr/bin/mock ${MOCK_CLEANUP} \
+ -r ${EPEL_RELEASE} --rebuild ${PWD}/*.src.rpm"
# write the mock command to a file, so that its easier to execute
- cat << EOF > ${RESULT_DIR}/${EPEL_RELEASE}/mock.sh
+ cat << EOF > mock-${EPEL_RELEASE}.sh
#!/bin/sh
${MOCK_CMD}
EOF
- chmod +x ${RESULT_DIR}/${EPEL_RELEASE}/mock.sh
+ chmod +x mock-${EPEL_RELEASE}.sh
# root can not run 'mock', it needs to drop priviledges
if (groups | grep -q mock)
then
# the current user is in group 'mock'
- RUNMOCK="${RESULT_DIR}/${EPEL_RELEASE}/mock.sh"
+ ${PWD}/mock-${EPEL_RELEASE}.sh &
else
- # switch to the user called 'mock'
- chown mock:mock ${RESULT_DIR}/${EPEL_RELEASE}
# "su" might not work, using sudo instead
- RUNMOCK="sudo -u mock -E ${RESULT_DIR}/${EPEL_RELEASE}/mock.sh"
+ sudo -u mock -E ${PWD}/mock-${EPEL_RELEASE}.sh &
fi
- TEST_IN_LOOP ${RUNMOCK}
+ sleep 5
+done
+
+# TAP and Prove aren't smart about loops
+TESTS_EXPECTED_IN_LOOP=2
+for mockjob in $(jobs -p)
+do
+ TEST_IN_LOOP wait ${mockjob}
done
# we could build for the last two Fedora releases too, but that is not
# possible on EPEL-5/6 installations, Fedora 17 and newer have unmet
# dependencies on the build-server :-/
-# only remove ${RESULT_DIR} if we're not debugging
-[ "${DEBUG}" = "0" ] && rm -rf ${RESULT_DIR}
+popd 2>/dev/null
+# only remove rpmbuild-mock.d if we're not debugging
+[ "${DEBUG}" = "0" ] && rm -rf rpmbuild-mock.d
cleanup
diff --git a/tests/basic/volume-snapshot.t b/tests/basic/volume-snapshot.t
new file mode 100755
index 000000000..35c748372
--- /dev/null
+++ b/tests/basic/volume-snapshot.t
@@ -0,0 +1,83 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../volume.rc
+. $(dirname $0)/../cluster.rc
+. $(dirname $0)/../snapshot.rc
+
+V1="patchy2"
+
+function create_volumes() {
+ $CLI_1 volume create $V0 $H1:$L1 &
+ PID_1=$!
+
+ $CLI_2 volume create $V1 $H2:$L2 $H3:$L3 &
+ PID_2=$!
+
+ wait $PID_1 $PID_2
+}
+
+function create_snapshots() {
+ $CLI_1 snapshot create ${V0}_snap ${V0}&
+ PID_1=$!
+
+ $CLI_1 snapshot create ${V1}_snap ${V1}&
+ PID_2=$!
+
+ wait $PID_1 $PID_2
+}
+
+function delete_snapshots() {
+ $CLI_1 snapshot delete ${V0}_snap &
+ PID_1=$!
+
+ $CLI_1 snapshot delete ${V1}_snap &
+ PID_2=$!
+
+ wait $PID_1 $PID_2
+}
+cleanup;
+
+#Create cluster with 3 nodes
+TEST launch_cluster 3;
+TEST setup_lvm 3
+
+TEST $CLI_1 peer probe $H2;
+TEST $CLI_1 peer probe $H3;
+EXPECT_WITHIN 20 2 peer_count;
+
+create_volumes
+EXPECT 'Created' volinfo_field $V0 'Status';
+EXPECT 'Created' volinfo_field $V1 'Status';
+
+start_volumes 2
+EXPECT 'Started' volinfo_field $V0 'Status';
+EXPECT 'Started' volinfo_field $V1 'Status';
+
+#Snapshot Operations
+create_snapshots
+TEST snapshot_exists $V0 ${V0}_snap
+TEST snapshot_exists $V1 ${V1}_snap
+
+TEST $CLI_1 snapshot config $V0 snap-max-hard-limit 100
+TEST $CLI_1 snapshot config $V1 snap-max-hard-limit 100
+
+TEST mount -t glusterfs $H1:/snaps/${V0}_snap/${V0} $M0
+TEST umount -f $M0
+TEST mount -t glusterfs $H2:/snaps/${V1}_snap/${V1} $M0
+TEST umount -f $M0
+
+#Clean up
+delete_snapshots
+TEST ! snapshot_exists $V0 ${V0}_snap
+TEST ! snapshot_exists $V1 ${V1}_snap
+
+stop_force_volumes 2
+EXPECT 'Stopped' volinfo_field $V0 'Status';
+EXPECT 'Stopped' volinfo_field $V1 'Status';
+
+delete_volumes 2
+TEST ! volume_exists $V0
+TEST ! volume_exists $V1
+
+cleanup;
diff --git a/tests/bugs/bug-1002556.t b/tests/bugs/bug-1002556.t
new file mode 100755
index 000000000..a57f455d4
--- /dev/null
+++ b/tests/bugs/bug-1002556.t
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../volume.rc
+
+cleanup;
+
+TEST glusterd
+TEST pidof glusterd
+
+TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1}
+TEST $CLI volume start $V0
+EXPECT '1 x 2 = 2' volinfo_field $V0 'Number of Bricks';
+
+TEST $CLI volume add-brick $V0 replica 3 $H0:$B0/${V0}2
+EXPECT '1 x 3 = 3' volinfo_field $V0 'Number of Bricks';
+
+TEST $CLI volume remove-brick $V0 replica 2 $H0:$B0/${V0}1 force
+EXPECT '1 x 2 = 2' volinfo_field $V0 'Number of Bricks';
+
+TEST killall glusterd
+TEST glusterd
+
+EXPECT '1 x 2 = 2' volinfo_field $V0 'Number of Bricks';
+cleanup
diff --git a/tests/bugs/bug-1004218.t b/tests/bugs/bug-1004218.t
new file mode 100644
index 000000000..17eb3c65b
--- /dev/null
+++ b/tests/bugs/bug-1004218.t
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Test if only a single xml document is generated by 'status all'
+# when a volume is not started
+
+. $(dirname $0)/../include.rc
+
+cleanup;
+
+TEST glusterd
+
+TEST $CLI volume create ${V0}1 $H0:$B0/${V0}1{1,2}
+TEST $CLI volume create ${V0}2 $H0:$B0/${V0}2{1,2}
+
+TEST $CLI volume start ${V0}1
+
+function test_status_all ()
+{
+ $CLI volume status all --xml | xmllint -format -
+}
+
+TEST test_status_all
+
+TEST $CLI volume stop ${V0}1
+
+cleanup
diff --git a/tests/bugs/bug-1004744.t b/tests/bugs/bug-1004744.t
new file mode 100644
index 000000000..0290119ef
--- /dev/null
+++ b/tests/bugs/bug-1004744.t
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+#Test case: After a rebalance fix-layout, check if the rebalance status command
+#displays the appropriate message at the CLI.
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../volume.rc
+
+cleanup;
+
+#Basic checks
+TEST glusterd
+TEST pidof glusterd
+TEST $CLI volume info
+
+#Create a 2x1 distributed volume
+TEST $CLI volume create $V0 $H0:$B0/${V0}{1,2};
+TEST $CLI volume start $V0
+
+# Mount FUSE and create file/directory
+TEST glusterfs -s $H0 --volfile-id $V0 $M0
+for i in `seq 1 10`;
+do
+ mkdir $M0/dir_$i
+ echo file>$M0/dir_$i/file_$i
+ for j in `seq 1 100`;
+ do
+ mkdir $M0/dir_$i/dir_$j
+ echo file>$M0/dir_$i/dir_$j/file_$j
+ done
+done
+
+#add 2 bricks
+TEST $CLI volume add-brick $V0 $H0:$B0/${V0}{3,4};
+
+#perform rebalance fix-layout
+TEST $CLI volume rebalance $V0 fix-layout start
+
+EXPECT_WITHIN 1 "fix-layout in progress" rebalance_status_field $V0;
+
+EXPECT_WITHIN 20 "fix-layout completed" rebalance_status_field $V0;
+
+TEST umount $M0
+TEST $CLI volume stop $V0
+TEST $CLI volume delete $V0;
+TEST ! $CLI volume info $V0;
+
+cleanup;
diff --git a/tests/bugs/bug-1015990-rep.t b/tests/bugs/bug-1015990-rep.t
new file mode 100755
index 000000000..f59bb2f75
--- /dev/null
+++ b/tests/bugs/bug-1015990-rep.t
@@ -0,0 +1,81 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../volume.rc
+. $(dirname $0)/../afr.rc
+cleanup;
+
+## Start and create a volume
+TEST glusterd;
+TEST pidof glusterd;
+TEST $CLI volume info;
+
+TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2,3,4};
+
+## Verify volume is is created
+EXPECT "$V0" volinfo_field $V0 'Volume Name';
+EXPECT 'Created' volinfo_field $V0 'Status';
+
+## Start volume and verify
+TEST $CLI volume start $V0;
+EXPECT 'Started' volinfo_field $V0 'Status';
+
+
+TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0
+
+
+
+TEST kill_brick $V0 $H0 $B0/$V0"1"
+sleep 5
+TEST kill_brick $V0 $H0 $B0/$V0"3"
+sleep 5
+
+for i in {1..100}; do echo "STRING" > $M0/File$i; done
+
+brick_2_sh_entries=$(count_sh_entries $B0/$V0"2")
+brick_4_sh_entries=$(count_sh_entries $B0/$V0"4")
+
+
+command_output=$(gluster volume heal $V0 statistics heal-count replica $H0:$B0/$V0"1")
+
+
+substring="Number of entries:"
+count=0
+while read -r line;
+do
+ if [[ "$line" == *$substring* ]]
+ then
+ value=$(echo $line | cut -f 2 -d :)
+ count=$(($count + $value))
+ fi
+
+done <<< "$command_output"
+
+brick_2_entries_count=$(($count-$value))
+
+EXPECT "0" echo $brick_2_entries_count
+
+brick_2_entries_count=$count
+
+
+xattrop_count_brick_2=$(count_sh_entries $B0/$V0"2")
+##Remove the count of the xattrop-gfid entry count as it does not contribute
+##to the number of files to be healed
+
+sub_val=1
+xattrop_count_brick_2=$(($xattrop_count_brick_2-$sub_val))
+
+ret=0
+if [ "$xattrop_count_brick_2" -eq "$brick_2_entries_count" ]
+ then
+ ret=$(($ret + $sub_val))
+fi
+
+EXPECT "1" echo $ret
+## Finish up
+TEST $CLI volume stop $V0;
+EXPECT 'Stopped' volinfo_field $V0 'Status';
+TEST $CLI volume delete $V0;
+TEST ! $CLI volume info $V0
+
+cleanup;
diff --git a/tests/bugs/bug-1015990.t b/tests/bugs/bug-1015990.t
new file mode 100755
index 000000000..165af5168
--- /dev/null
+++ b/tests/bugs/bug-1015990.t
@@ -0,0 +1,95 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../volume.rc
+. $(dirname $0)/../afr.rc
+cleanup;
+
+## Start and create a volume
+TEST glusterd;
+TEST pidof glusterd;
+TEST $CLI volume info;
+
+TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2,3,4};
+
+## Verify volume is is created
+EXPECT "$V0" volinfo_field $V0 'Volume Name';
+EXPECT 'Created' volinfo_field $V0 'Status';
+
+## Start volume and verify
+TEST $CLI volume start $V0;
+EXPECT 'Started' volinfo_field $V0 'Status';
+
+
+TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0
+
+
+
+TEST kill_brick $V0 $H0 $B0/$V0"1"
+sleep 5
+TEST kill_brick $V0 $H0 $B0/$V0"3"
+sleep 5
+
+for i in {1..100}; do echo "STRING" > $M0/File$i; done
+
+brick_2_sh_entries=$(count_sh_entries $B0/$V0"2")
+brick_4_sh_entries=$(count_sh_entries $B0/$V0"4")
+
+
+command_output=$(gluster volume heal $V0 statistics heal-count)
+
+
+substring="Number of entries:"
+count=0
+while read -r line;
+do
+ if [[ "$line" == *$substring* ]]
+ then
+ value=$(echo $line | cut -f 2 -d :)
+ count=$(($count + $value))
+ fi
+
+done <<< "$command_output"
+
+brick_2_entries_count=$(($count-$value))
+brick_4_entries_count=$value
+
+
+xattrop_count_brick_2=$(count_sh_entries $B0/$V0"2")
+##Remove the count of the xattrop-gfid entry count as it does not contribute
+##to the number of files to be healed
+
+sub_val=1
+xattrop_count_brick_2=$(($xattrop_count_brick_2-$sub_val))
+
+xattrop_count_brick_4=$(count_sh_entries $B0/$V0"4")
+##Remove xattrop-gfid entry count
+
+xattrop_count_brick_4=$(($xattrop_count_brick_4-$sub_val))
+
+
+ret=0
+if [ "$xattrop_count_brick_2" -eq "$brick_2_entries_count" ]
+ then
+ ret=$(($ret + $sub_val))
+fi
+
+EXPECT "1" echo $ret
+
+
+ret=0
+if [ "$xattrop_count_brick_4" -eq "$brick_4_entries_count" ]
+ then
+ ret=$(($ret + $sub_val))
+fi
+
+EXPECT "1" echo $ret
+
+## Finish up
+TEST $CLI volume stop $V0;
+EXPECT 'Stopped' volinfo_field $V0 'Status';
+TEST $CLI volume delete $V0;
+TEST ! $CLI volume info $V0
+
+cleanup;
+
diff --git a/tests/bugs/bug-1022055.t b/tests/bugs/bug-1022055.t
new file mode 100755
index 000000000..c2f4218bb
--- /dev/null
+++ b/tests/bugs/bug-1022055.t
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../cluster.rc
+
+function check_peers {
+ $CLI_1 peer status | grep 'Peer in Cluster (Connected)' | wc -l
+}
+
+cleanup;
+
+TEST launch_cluster 2;
+
+TEST $CLI_1 peer probe $H2;
+
+EXPECT_WITHIN 20 1 check_peers;
+
+TEST $CLI_1 volume create $V0 $H1:$B1/$V0 $H2:$B2/$V0;
+
+TEST $CLI_1 volume start $V0;
+
+TEST $CLI_1 volume log rotate $V0;
+
+TEST $CLI_1 volume status;
+
+cleanup;
diff --git a/tests/bugs/bug-1022905.t b/tests/bugs/bug-1022905.t
new file mode 100644
index 000000000..aef3395dd
--- /dev/null
+++ b/tests/bugs/bug-1022905.t
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+
+cleanup;
+
+## Create a volume
+TEST glusterd;
+TEST pidof glusterd
+TEST $CLI volume info;
+
+TEST $CLI volume create $V0 $H0:$B0/${V0}{1};
+EXPECT 'Created' volinfo_field $V0 'Status';
+
+## Volume start
+TEST $CLI volume start $V0;
+EXPECT 'Started' volinfo_field $V0 'Status';
+
+## Enable a protected and a resettable/unprotected option
+TEST $CLI volume quota $V0 enable
+TEST $CLI volume set $V0 diagnostics.client-log-level DEBUG
+
+## Reset cmd resets only unprotected option(s), succeeds.
+TEST $CLI volume reset $V0;
+
+## Reset should fail
+TEST ! $CLI volume reset $V0;
+
+## Set an unprotected option
+TEST $CLI volume set $V0 diagnostics.client-log-level DEBUG
+
+## Now 1 protected and 1 unprotected options are set
+## Reset force should succeed
+TEST $CLI volume reset $V0 force;
+
+TEST $CLI volume stop $V0
+TEST $CLI volume delete $V0
+
+cleanup;
diff --git a/tests/bugs/bug-1030208.t b/tests/bugs/bug-1030208.t
new file mode 100644
index 000000000..866999692
--- /dev/null
+++ b/tests/bugs/bug-1030208.t
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+#Test case: Hardlink test
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../volume.rc
+
+cleanup;
+
+#Basic checks
+TEST glusterd
+TEST pidof glusterd
+TEST $CLI volume info
+
+#Create a distributed volume
+TEST $CLI volume create $V0 $H0:$B0/${V0}{1..2};
+TEST $CLI volume start $V0
+
+# Mount FUSE
+TEST glusterfs -s $H0 --volfile-id $V0 $M0
+
+#Create a file and perform fop on a DIR
+TEST touch $M0/foo
+TEST ls $M0/
+
+#Create hardlink
+TEST ln $M0/foo $M0/bar
+
+
+TEST umount $M0
+TEST $CLI volume stop $V0
+TEST $CLI volume delete $V0;
+TEST ! $CLI volume info $V0;
+
+cleanup;
diff --git a/tests/bugs/bug-1040934.t b/tests/bugs/bug-1040934.t
new file mode 100644
index 000000000..3089d7ce1
--- /dev/null
+++ b/tests/bugs/bug-1040934.t
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../cluster.rc
+. $(dirname $0)/../snapshot.rc
+. $(dirname $0)/../volume.rc
+
+cleanup;
+
+TEST launch_cluster 2
+TEST setup_lvm 2
+
+TEST $CLI_1 peer probe $H2
+EXPECT_WITHIN 20 1 peer_count
+
+TEST $CLI_1 volume create $V0 replica 2 $H1:$L1 $H2:$L2
+EXPECT 'Created' volinfo_field $V0 'Status'
+
+TEST $CLI_1 volume start $V0
+EXPECT 'Started' volinfo_field $V0 'Status'
+
+TEST $CLI_1 snapshot create ${V0}_snap ${V0}
+PID_1=$!
+wait $PID_1
+
+TEST snapshot_exists ${V0}_snap
+TEST mount -t glusterfs $H1:/snaps/${V0}_snap/$V0 $M0
+cd $M0
+TEST ! touch a
+
+TEST $CLI_1 snapshot delete ${V0}_snap
+PID_1=$!
+wait $PID_1
+
+TEST ! snapshot_exists ${V0}_snap
+
+cleanup;
diff --git a/tests/bugs/bug-1045333.t b/tests/bugs/bug-1045333.t
new file mode 100644
index 000000000..d1f8069e8
--- /dev/null
+++ b/tests/bugs/bug-1045333.t
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../snapshot.rc
+
+cleanup;
+TEST glusterd;
+TEST pidof glusterd;
+
+TEST setup_lvm 1
+
+TEST $CLI volume create $V0 $H0:$L1
+TEST $CLI volume start $V0
+
+
+S1="${V0}-snap1" #Create snapshot with name contains hyphen(-)
+S2="-${V0}-snap2" #Create snapshot with name starts with hyphen(-)
+#Create snapshot with a long name
+S3="${V0}_single_gluster_volume_is_accessible_by_multiple_clients_offline_snapshot_is_a_long_name"
+
+TEST $CLI snapshot create $S1 $V0
+TEST snapshot_exists $S1
+
+TEST $CLI snapshot create $S2 $V0
+TEST snapshot_exists $S2
+
+TEST $CLI snapshot create $S3 $V0
+TEST snapshot_exists $S3
+
+
+TEST mount -t glusterfs $H0:/snaps/$S1/$V0 $M0
+TEST umount -f $M0
+
+TEST mount -t glusterfs $H0:/snaps/$S2/$V0 $M0
+TEST umount -f $M0
+
+TEST mount -t glusterfs $H0:/snaps/$S3/$V0 $M0
+TEST umount -f $M0
+
+#Clean up
+TEST $CLI snapshot delete $S1
+TEST $CLI snapshot delete $S2
+TEST $CLI snapshot delete $S3
+
+TEST $CLI volume stop $V0 force
+TEST $CLI volume delete $V0
+
+cleanup;
diff --git a/tests/bugs/bug-1049834.t b/tests/bugs/bug-1049834.t
new file mode 100755
index 000000000..6019a561c
--- /dev/null
+++ b/tests/bugs/bug-1049834.t
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../cluster.rc
+. $(dirname $0)/../snapshot.rc
+. $(dirname $0)/../volume.rc
+
+cleanup;
+
+TEST launch_cluster 2
+TEST setup_lvm 2
+
+TEST $CLI_1 peer probe $H2
+EXPECT_WITHIN 20 1 peer_count
+
+TEST $CLI_1 volume create $V0 $H1:$L1 $H2:$L2
+EXPECT 'Created' volinfo_field $V0 'Status'
+
+TEST $CLI_1 volume start $V0
+EXPECT 'Started' volinfo_field $V0 'Status'
+
+#Setting the snap-max-hard-limit to 4
+TEST $CLI_1 snapshot config $V0 snap-max-hard-limit 4
+PID_1=$!
+wait $PID_1
+
+#Creating 4 snapshots on the volume
+TEST create_n_snapshots $V0 4 $V0_snap
+TEST snapshot_n_exists $V0 4 $V0_snap
+
+#Creating the 5th snapshots on the volume and expecting it not to be created.
+TEST ! $CLI_1 snapshot create ${V0}_snap5 ${V0}
+TEST ! snapshot_exists ${V0}_snap5
+TEST ! $CLI_1 snapshot delete ${V0}_snap5
+
+#Deleting the 4 snaps
+TEST delete_n_snapshots $V0 4 $V0_snap
+TEST ! snapshot_n_exists $V0 4 $V0_snap
+
+cleanup;
diff --git a/tests/bugs/bug-1064768.t b/tests/bugs/bug-1064768.t
new file mode 100755
index 000000000..b87168150
--- /dev/null
+++ b/tests/bugs/bug-1064768.t
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+
+cleanup;
+
+TEST glusterd
+TEST pidof glusterd
+TEST $CLI volume create $V0 replica 2 $H0:$B0/brick0 $H0:$B0/brick1
+TEST $CLI volume start $V0
+EXPECT_WITHIN 15 'Started' volinfo_field $V0 'Status';
+
+TEST $CLI volume profile $V0 start
+TEST $CLI volume profile $V0 info
+TEST $CLI volume profile $V0 stop
+
+TEST $CLI volume status
+TEST $CLI volume stop $V0
+EXPECT_WITHIN 15 'Stopped' volinfo_field $V0 'Status';
+cleanup;
diff --git a/tests/bugs/bug-830665.t b/tests/bugs/bug-830665.t
index 0373ec6d7..0073ff1d9 100755
--- a/tests/bugs/bug-830665.t
+++ b/tests/bugs/bug-830665.t
@@ -35,6 +35,7 @@ TEST $CLI volume set $V0 performance.stat-prefetch off;
## Make sure automatic self-heal doesn't perturb our results.
TEST $CLI volume set $V0 cluster.self-heal-daemon off
+TEST $CLI volume set $V0 cluster.background-self-heal-count 0
## Start volume and verify
TEST $CLI volume start $V0;
diff --git a/tests/bugs/bug-853258.t b/tests/bugs/bug-853258.t
index 79cb88099..faa9d4465 100755
--- a/tests/bugs/bug-853258.t
+++ b/tests/bugs/bug-853258.t
@@ -20,7 +20,7 @@ EXPECT_WITHIN 15 'Started' volinfo_field $V0 'Status';
# Force assignment of initial ranges.
TEST $CLI volume rebalance $V0 fix-layout start
-EXPECT_WITHIN 15 "completed" rebalance_status_field $V0
+EXPECT_WITHIN 15 "fix-layout completed" rebalance_status_field $V0
# Get the original values.
xattrs=""
@@ -32,13 +32,13 @@ done
TEST $CLI volume add-brick $V0 $H0:$B0/${V0}3
# Force assignment of initial ranges.
TEST $CLI volume rebalance $V0 fix-layout start
-EXPECT_WITHIN 15 "completed" rebalance_status_field $V0
+EXPECT_WITHIN 15 "fix-layout completed" rebalance_status_field $V0
for i in $(seq 0 3); do
xattrs="$xattrs $(dht_get_layout $B0/${V0}$i)"
done
-overlap=$($(dirname $0)/overlap.py $xattrs)
+overlap=$(python2 $(dirname $0)/overlap.py $xattrs)
# 2863311531 = 0xaaaaaaab = 2/3 overlap
TEST [ "$overlap" -ge 2863311531 ]
diff --git a/tests/bugs/bug-857330/common.rc b/tests/bugs/bug-857330/common.rc
index 4e5a73a0b..e5a7cd79a 100644
--- a/tests/bugs/bug-857330/common.rc
+++ b/tests/bugs/bug-857330/common.rc
@@ -22,7 +22,7 @@ function check-and-store-task-id()
function get-task-id()
{
- $CLI $COMMAND | grep $PATTERN | grep -o -E "$UUID_REGEX"
+ $CLI $COMMAND | grep $PATTERN | grep -o -E "$UUID_REGEX" | tail -n1
}
diff --git a/tests/bugs/bug-857330/normal.t b/tests/bugs/bug-857330/normal.t
index 4455d1620..24dfe52c4 100755
--- a/tests/bugs/bug-857330/normal.t
+++ b/tests/bugs/bug-857330/normal.t
@@ -28,7 +28,7 @@ PATTERN="ID:"
TEST check-and-store-task-id
COMMAND="volume status $V0"
-PATTERN="Rebalance"
+PATTERN="ID"
EXPECT $TASK_ID get-task-id
COMMAND="volume rebalance $V0 status"
@@ -45,7 +45,7 @@ PATTERN="ID:"
TEST check-and-store-task-id
COMMAND="volume status $V0"
-PATTERN="Replace"
+PATTERN="ID"
EXPECT $TASK_ID get-task-id
COMMAND="volume replace-brick $V0 $REP_BRICK_PAIR status"
@@ -62,7 +62,7 @@ PATTERN="ID:"
TEST check-and-store-task-id
COMMAND="volume status $V0"
-PATTERN="Remove"
+PATTERN="ID"
EXPECT $TASK_ID get-task-id
COMMAND="volume remove-brick $V0 $H0:$B0/${V0}3 status"
diff --git a/tests/bugs/bug-907072.t b/tests/bugs/bug-907072.t
new file mode 100755
index 000000000..49b477767
--- /dev/null
+++ b/tests/bugs/bug-907072.t
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../fileio.rc
+. $(dirname $0)/../dht.rc
+
+cleanup;
+
+TEST glusterd;
+TEST pidof glusterd;
+
+TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1,2,3};
+TEST $CLI volume start $V0;
+
+TEST glusterfs -s $H0 --volfile-id $V0 $M0;
+
+TEST mkdir $M0/test;
+
+OLD_LAYOUT0=`get_layout $B0/${V0}0/test`;
+OLD_LAYOUT1=`get_layout $B0/${V0}1/test`;
+OLD_LAYOUT2=`get_layout $B0/${V0}2/test`;
+OLD_LAYOUT3=`get_layout $B0/${V0}3/test`;
+
+TEST killall glusterfsd;
+
+# Delete directory on one brick
+TEST rm -rf $B0/${V}1/test;
+
+# And only layout xattr on another brick
+TEST setfattr -x trusted.glusterfs.dht $B0/${V0}2/test;
+
+TEST $CLI volume start $V0 force;
+
+TEST umount $M0;
+TEST glusterfs -s $H0 --volfile-id $V0 $M0;
+TEST stat $M0/test;
+
+NEW_LAYOUT0=`get_layout $B0/${V0}0/test`;
+NEW_LAYOUT1=`get_layout $B0/${V0}1/test`;
+NEW_LAYOUT2=`get_layout $B0/${V0}2/test`;
+NEW_LAYOUT3=`get_layout $B0/${V0}3/test`;
+
+EXPECT $OLD_LAYOUT0 echo $NEW_LAYOUT0;
+EXPECT $OLD_LAYOUT1 echo $NEW_LAYOUT1;
+EXPECT $OLD_LAYOUT2 echo $NEW_LAYOUT2;
+EXPECT $OLD_LAYOUT3 echo $NEW_LAYOUT3;
diff --git a/tests/bugs/bug-948729/bug-948729-force.t b/tests/bugs/bug-948729/bug-948729-force.t
index 3a5df7916..d14e94061 100644
--- a/tests/bugs/bug-948729/bug-948729-force.t
+++ b/tests/bugs/bug-948729/bug-948729-force.t
@@ -16,7 +16,6 @@ V1=patchy1
V2=patchy2
TEST launch_cluster 2;
-cli1="gluster --remote-host=$H1"
TEST $CLI_1 peer probe $H2;
@@ -59,22 +58,22 @@ TEST mount -t xfs $LD5 $B5/$V0
TEST mount -t xfs $LD6 $B6/$V0
#Case 0: Parent directory of the brick is absent
-TEST ! $cli1 volume create $V0 $H1:$B1/$V0/nonexistent/b1 $H2:$B2/$V0/nonexistent/b2 force
+TEST ! $CLI1 volume create $V0 $H1:$B1/$V0/nonexistent/b1 $H2:$B2/$V0/nonexistent/b2 force
#Case 1: File system root is being used as brick directory
-TEST $cli1 volume create $V0 $H1:$B5/$V0 $H2:$B6/$V0 force
+TEST $CLI1 volume create $V0 $H1:$B5/$V0 $H2:$B6/$V0 force
#Case 2: Brick directory contains only one component
-TEST $cli1 volume create $V1 $H1:/$uuid1 $H2:/$uuid2 force
+TEST $CLI1 volume create $V1 $H1:/$uuid1 $H2:/$uuid2 force
#Case 3: Sub-directories of the backend FS being used as brick directory
-TEST $cli1 volume create $V2 $H1:$B1/$V0/brick1 $H2:$B2/$V0/brick2 force
+TEST $CLI1 volume create $V2 $H1:$B1/$V0/brick1 $H2:$B2/$V0/brick2 force
#add-brick tests
-TEST ! $cli1 volume add-brick $V0 $H1:$B3/$V0/nonexistent/brick3 force
-TEST $cli1 volume add-brick $V0 $H1:$B3/$V0 force
-TEST $cli1 volume add-brick $V1 $H1:/$uuid3 force
-TEST $cli1 volume add-brick $V2 $H1:$B4/$V0/brick3 force
+TEST ! $CLI1 volume add-brick $V0 $H1:$B3/$V0/nonexistent/brick3 force
+TEST $CLI1 volume add-brick $V0 $H1:$B3/$V0 force
+TEST $CLI1 volume add-brick $V1 $H1:/$uuid3 force
+TEST $CLI1 volume add-brick $V2 $H1:$B4/$V0/brick3 force
#####replace-brick tests
#FIX-ME: replace-brick does not work with the newly introduced cluster test
diff --git a/tests/bugs/bug-948729/bug-948729.t b/tests/bugs/bug-948729/bug-948729.t
index 288ae2bef..f94db1ea0 100644
--- a/tests/bugs/bug-948729/bug-948729.t
+++ b/tests/bugs/bug-948729/bug-948729.t
@@ -14,7 +14,6 @@ uuid2=`uuidgen`;
uuid3=`uuidgen`;
TEST launch_cluster 2;
-cli1="gluster --remote-host=$H1"
TEST $CLI_1 peer probe $H2;
@@ -42,7 +41,7 @@ TEST mount -t xfs $LD2 $B2/$V0
TEST mount -t xfs $LD3 $B3/$V0
#Tests without --mode=script option
-
+cli1=$(echo $CLI1 | sed 's/ --mode=script//')
#Case 0: Parent directory of the brick is absent
TEST ! $cli1 volume create $V0 $H1:$B1/$V0/nonexistent/b1 $H2:$B2/$V0/nonexistent/b2
diff --git a/tests/bugs/bug-983477.t b/tests/bugs/bug-983477.t
index 6384209e1..c19fa96c8 100755
--- a/tests/bugs/bug-983477.t
+++ b/tests/bugs/bug-983477.t
@@ -32,6 +32,13 @@ EXPECT_WITHIN 20 "0" get_use_readdirp_value $V0
TEST cd -
TEST umount $M0
+#Since args are optional on this argument just specifying "--use-readdirp" should also turn it `on` not `off`
+TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 --use-readdirp
+TEST cd $M0
+EXPECT_WITHIN 20 "1" get_use_readdirp_value $V0
+TEST cd -
+TEST umount $M0
+
#By default it is enabled.
TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0
TEST cd $M0
diff --git a/tests/bugs/bug-986429.t b/tests/bugs/bug-986429.t
new file mode 100644
index 000000000..6e43f72b7
--- /dev/null
+++ b/tests/bugs/bug-986429.t
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../volume.rc
+
+## This tests failover achieved by providing multiple
+## servers from the trusted pool for fetching volume
+## specification
+
+cleanup;
+
+TEST glusterd
+TEST pidof glusterd
+
+TEST $CLI volume create $V0 $H0:$B0/$V0
+TEST $CLI volume start $V0
+TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s non-existent -s $H0 --volfile-id=/$V0 $M0
+
+cleanup;
diff --git a/tests/cluster.rc b/tests/cluster.rc
index 1c06bca47..3b10d19f7 100755
--- a/tests/cluster.rc
+++ b/tests/cluster.rc
@@ -45,8 +45,10 @@ function define_glusterds() {
wopt="management.working-directory=${!b}/glusterd";
bopt="management.transport.socket.bind-address=${!h}";
popt="--pid-file=${!b}/glusterd.pid";
- eval "glusterd_$i='glusterd --xlator-option $wopt --xlator-option $bopt $popt'";
- eval "glusterd$i='glusterd --xlator-option $wopt --xlator-option $bopt $popt'";
+ sopt="management.glusterd-sockfile=${!b}/glusterd/gd.sock"
+ lopt="--log-file=${!b}/glusterd.log"
+ eval "glusterd_$i='glusterd --xlator-option $wopt --xlator-option $bopt --xlator-option $sopt $lopt $popt'";
+ eval "glusterd$i='glusterd --xlator-option $wopt --xlator-option $bopt --xlator-option $sopt $lopt $popt'";
done
}
@@ -98,9 +100,13 @@ function define_clis() {
local h;
for i in `seq 1 $count`; do
- h="H$i";
- eval "CLI_$i='$CLI --remote-host=${!h}'";
- eval "CLI$i='$CLI --remote-host=${!h}'";
+ b="B$i";
+ eval "CLI_$i='$CLI --glusterd-sock=${!b}/glusterd/gd.sock'";
+ eval "CLI$i='$CLI --glusterd-sock=${!b}/glusterd/gd.sock'";
done
+ CLI="$CLI_1"
}
+function peer_count() {
+ $CLI_1 peer status | grep 'Peer in Cluster (Connected)' | wc -l
+}
diff --git a/tests/include.rc b/tests/include.rc
index bb541eaa1..80457f124 100644
--- a/tests/include.rc
+++ b/tests/include.rc
@@ -3,6 +3,7 @@ M1=${M1:=/mnt/glusterfs/1}; # 1st mount point for FUSE
N0=${N0:=/mnt/nfs/0}; # 0th mount point for NFS
N1=${N1:=/mnt/nfs/1}; # 1st mount point for NFS
V0=${V0:=patchy}; # volume name to use in tests
+V1=${V1:=patchy1}; # volume name to use in tests
B0=${B0:=/d/backends}; # top level of brick directories
H0=${H0:=`hostname --fqdn`}; # hostname
DEBUG=${DEBUG:=0} # turn on debugging?
@@ -186,13 +187,14 @@ function cleanup()
killall -15 glusterfs glusterfsd glusterd 2>/dev/null || true;
killall -9 glusterfs glusterfsd glusterd 2>/dev/null || true;
+ type cleanup_lvm &>/dev/null && cleanup_lvm
+
MOUNTPOINTS=`mount | grep "$B0/" | awk '{print $3}'`
for m in $MOUNTPOINTS;
do
umount $m
done
-
LOOPDEVICES=`losetup -a | grep "$B0/" | awk '{print $1}' | tr -d :`
for l in $LOOPDEVICES;
do
@@ -206,6 +208,7 @@ function cleanup()
umount -l $M1 2>/dev/null || true;
umount -l $N0 2>/dev/null || true;
umount -l $N1 2>/dev/null || true;
+
}
function volinfo_field()
diff --git a/tests/snapshot.rc b/tests/snapshot.rc
new file mode 100755
index 000000000..a5b86f674
--- /dev/null
+++ b/tests/snapshot.rc
@@ -0,0 +1,251 @@
+#!/bin/bash
+
+LVM_DEFINED=0
+LVM_PREFIX="patchy_snap"
+LVM_COUNT=0
+VHD_SIZE="1G"
+
+function init_lvm() {
+ if [ "$1" == "" ]; then
+ echo "Error: Invalid argument supplied"
+ return 1
+ fi
+ LVM_COUNT=$1
+
+ if [ "$2" != "" ]; then
+ VHD_SIZE=$2
+ fi
+
+ local b
+ local i
+
+ if [ "$B1" = "" ]; then
+ B1=$B0
+ fi
+
+ for i in `seq 1 $LVM_COUNT`; do
+ b="B$i"
+ if [ "${!b}" = "" ]; then
+ echo "Error: $b not defined."
+ echo "Please run launch_cluster with atleast $LVM_COUNT nodes"
+ return 1
+ fi
+
+ eval "L$i=${!b}/${LVM_PREFIX}_mnt"
+ l="L$i"
+ mkdir -p ${!l}
+ if [ $? -ne 0 ]; then
+ echo "Error: failed to create dir ${!l}"
+ return 1
+ fi
+
+ eval "VG$i=${LVM_PREFIX}_vg_${i}"
+ done
+
+ LVM_DEFINED=1
+ return 0
+}
+
+function setup_lvm() {
+ init_lvm $@ || return 1
+ _setup_lvm
+ return 0
+}
+
+function cleanup_lvm() {
+ pkill gluster
+ sleep 2
+
+ if [ "$LVM_DEFINED" = "1" ]; then
+ _cleanup_lvm
+ fi
+
+ _cleanup_lvm_again >/dev/null 2>&1
+ return 0
+}
+
+########################################################
+# Private Functions
+########################################################
+function _setup_lvm() {
+ local count=$LVM_COUNT
+ local b
+ local i
+
+ for i in `seq 1 $count`; do
+ b="B$i"
+
+ _create_vhd ${!b} $i
+ _create_lv ${!b} $i
+ _mount_lv $i
+ done
+}
+
+function _cleanup_lvm() {
+ local count=$LVM_COUNT
+ local b
+ local i
+
+ for i in `seq 1 $count`; do
+ b="B$i"
+ _umount_lv $i
+ _remove_lv $i
+ _remove_vhd ${!b}
+ done
+}
+
+function _cleanup_lvm_again() {
+ local file
+
+ mount | grep $LVM_PREFIX | awk '{print $3}' | xargs -r umount -f
+
+ /sbin/vgs | grep $LVM_PREFIX | awk '{print $1}' | xargs -r vgremove -f
+
+ find $B0 -name "${LVM_PREFIX}_loop" | xargs -r losetup -d
+
+ find $B0 -name "${LVM_PREFIX}*" | xargs -r rm -rf
+
+ find /run/gluster/snaps -name "*${LVM_PREFIX}*" | xargs -r rm -rf
+
+ for file in `ls /run/gluster/snaps`; do
+ find /run/gluster/snaps/$file -mmin -2 | xargs -r rm -rf
+ done
+}
+
+########################################################
+########################################################
+function _create_vhd() {
+ local dir=$1
+ local num=$2
+ local loop_num=`expr $2 + 8`
+
+ fallocate -l${VHD_SIZE} $dir/${LVM_PREFIX}_vhd
+ mknod -m660 $dir/${LVM_PREFIX}_loop b 7 $loop_num
+ /sbin/losetup $dir/${LVM_PREFIX}_loop $dir/${LVM_PREFIX}_vhd
+}
+
+function _create_lv() {
+ local dir=$1
+ local num=$2
+ local vg="VG$num"
+
+ /sbin/pvcreate $dir/${LVM_PREFIX}_loop
+ /sbin/vgcreate ${!vg} $dir/${LVM_PREFIX}_loop
+
+ /sbin/lvcreate -l 100%FREE -T /dev/${!vg}/thinpool
+ /sbin/lvcreate -V $VHD_SIZE -T /dev/${!vg}/thinpool -n brick_lvm
+
+ mkfs.xfs -f /dev/${!vg}/brick_lvm
+}
+
+function _mount_lv() {
+ local num=$1
+ local vg="VG$num"
+ local l="L$num"
+
+ mount -t xfs -o nouuid /dev/${!vg}/brick_lvm ${!l}
+}
+
+function _umount_lv() {
+ local num=$1
+ local l="L$num"
+
+ umount -f ${!l} 2>/dev/null || true
+ rmdir ${!l} 2>/dev/null || true
+}
+
+function _remove_lv() {
+ local num=$1
+ local vg="VG$num"
+
+ vgremove -f ${!vg}
+}
+
+function _remove_vhd() {
+ local dir=$1
+
+ losetup -d $dir/${LVM_PREFIX}_loop
+ rm -f $dir/${LVM_PREFIX}_loop
+ rm -f $dir/${LVM_PREFIX}_vhd
+}
+
+########################################################
+# Utility Functions
+########################################################
+function snapshot_exists() {
+ local volname=$1
+ local snapname=$2
+ $CLI snapshot list $volname | egrep -q "^$snapname\$"
+ return $?
+}
+
+#Create N number of snaps in a given volume
+#Arg1 : <Volume Name>
+#Arg2 : <Count of snaps to be created>
+#Arg3 : <Snap Name Pattern>
+#Return: Returns 0 if all snaps are created ,
+# if not will return exit code of last failed
+# snap create command.
+function create_n_snapshots() {
+ local vol=$1
+ local snap_count=$2
+ local snap_name=$3
+ local ret=0
+ for i in `seq 1 $snap_count`; do
+ $CLI_1 snapshot create $snap_name$i ${vol}&
+ PID_1=$!
+ wait $PID_1
+ ret=$?
+ if [ "$ret" != "0" ]; then
+ break
+ fi
+ done
+ return $ret
+}
+
+
+#Delete N number of snaps in a given volume
+#Arg1 : <Volume Name>
+#Arg2 : <Count of snaps to be deleted>
+#Arg3 : <Snap Name Pattern>
+#Return: Returns 0 if all snaps are Delete,
+# if not will return exit code of last failed
+# snap delete command.
+function delete_n_snapshots() {
+ local vol=$1
+ local snap_count=$2
+ local snap_name=$3
+ local ret=0
+ for i in `seq 1 $snap_count`; do
+ $CLI_1 snapshot delete $snap_name$i &
+ PID_1=$!
+ wait $PID_1
+ temp=$?
+ if [ "$temp" != "0" ]; then
+ ret=$temp
+ fi
+ done
+ return $ret
+}
+
+#Check for the existance of N number of snaps in a given volume
+#Arg1 : <Volume Name>
+#Arg2 : <Count of snaps to be checked>
+#Arg3 : <Snap Name Pattern>
+#Return: Returns 0 if all snaps exists,
+# if not will return exit code of last failed
+# snapshot_exists().
+function snapshot_n_exists() {
+ local vol=$1
+ local snap_count=$2
+ local snap_name=$3
+ local ret=0
+ for i in `seq 1 $snap_count`; do
+ snapshot_exists $snap_name$i
+ ret=$?
+ if [ "$ret" != "0" ]; then
+ break
+ fi
+ done
+ return $ret
+}
diff --git a/tests/volume.rc b/tests/volume.rc
index 470fe9a7c..171f8d709 100644
--- a/tests/volume.rc
+++ b/tests/volume.rc
@@ -27,7 +27,12 @@ function volume_option()
}
function rebalance_status_field {
- $CLI volume rebalance $1 status | awk '{print $7}' | sed -n 3p
+ #The rebalance status can be upto 3 words, (ex:'fix-layout in progress'), hence the awk-print $7 thru $9.
+ #But if the status is less than 3 words, it also prints the next field i.e the run_time_in_secs.(ex:'completed 3.00').
+ #So we trim the numbers out with `tr`. Finally remove the trailing white spaces with sed. What we get is one of the
+ #strings in the 'cli_vol_task_status_str' char array of cli-rpc-ops.c
+
+ $CLI volume rebalance $1 status | awk '{print $7,$8,$9}' |sed -n 3p |tr -d '[^0-9+\.]'|sed 's/ *$//g'
}
function remove_brick_status_completed_field {
@@ -267,3 +272,54 @@ function get_backend_paths {
getfattr -m . -n trusted.glusterfs.pathinfo $path | tr ' ' '\n' | sed -n 's/<POSIX.*:.*:\(.*\)>.*/\1/p'
}
+
+function do_volume_operations() {
+ local operation=$1
+ local count=$2
+ local force=$3
+
+ local pids=()
+ local cli
+ local v
+
+ for i in `seq 1 $count`; do
+ cli="CLI_$i"
+ v="V`expr $i - 1`"
+ ${!cli} volume $operation ${!v} $force &
+ pids[$i]=$!
+ done
+
+ for i in `seq 1 $count`; do
+ wait ${pids[$i]}
+ done
+}
+
+function start_volumes() {
+ do_volume_operations start $1
+}
+
+function stop_volumes() {
+ do_volume_operations stop $1
+}
+
+function start_force_volumes() {
+ do_volume_operations start $1 force
+}
+
+function stop_force_volumes() {
+ do_volume_operations stop $1 force
+}
+
+function delete_volumes() {
+ do_volume_operations delete $1
+}
+
+function volume_exists() {
+ local volname=$1
+ $CLI volume info $volname 2>&1 | grep -q 'does not exist'
+ if [ $? -eq 0 ]; then
+ return 1
+ else
+ return 0
+ fi
+}
diff --git a/xlators/cluster/afr/src/afr-common.c b/xlators/cluster/afr/src/afr-common.c
index 37a782b31..af01f2ef2 100644
--- a/xlators/cluster/afr/src/afr-common.c
+++ b/xlators/cluster/afr/src/afr-common.c
@@ -51,7 +51,7 @@
#define AFR_ICTX_OPENDIR_DONE_MASK 0x0000000100000000ULL
#define AFR_ICTX_READ_CHILD_MASK 0x00000000FFFFFFFFULL
-
+#define AFR_STATISTICS_HISTORY_SIZE 50
int
afr_lookup_done_success_action (call_frame_t *frame, xlator_t *this,
gf_boolean_t fail_conflict);
@@ -1080,6 +1080,88 @@ afr_update_loc_gfids (loc_t *loc, struct iatt *buf, struct iatt *postparent)
uuid_copy (loc->pargfid, postparent->ia_gfid);
}
+/*
+ * Quota size xattrs are not maintained by afr. There is a
+ * possibility that they differ even when both the directory changelog xattrs
+ * suggest everything is fine. So if there is at least one 'source' check among
+ * the sources which has the maximum quota size. Otherwise check among all the
+ * available ones for maximum quota size. This way if there is a source and
+ * stale copies it always votes for the 'source'.
+ * */
+
+static void
+afr_handle_quota_size (afr_local_t *local, xlator_t *this,
+ dict_t *rsp_dict)
+{
+ int32_t *sources = NULL;
+ dict_t *xattr = NULL;
+ data_t *max_data = NULL;
+ int64_t max_quota_size = -1;
+ data_t *data = NULL;
+ int64_t *size = NULL;
+ int64_t quota_size = -1;
+ afr_private_t *priv = NULL;
+ int i = 0;
+ int ret = -1;
+ gf_boolean_t source_present = _gf_false;
+
+ priv = this->private;
+ sources = local->cont.lookup.sources;
+
+ if (rsp_dict == NULL) {
+ gf_log_callingfn (this->name, GF_LOG_ERROR, "%s: Invalid "
+ "response dictionary", local->loc.path);
+ return;
+ }
+
+ for (i = 0; i < priv->child_count; i++) {
+ if (sources[i]) {
+ source_present = _gf_true;
+ break;
+ }
+ }
+
+ for (i = 0; i < priv->child_count; i++) {
+ /*
+ * If there is at least one source lets check
+ * for maximum quota sizes among sources, otherwise take the
+ * maximum of the ones present to be on the safer side.
+ */
+ if (source_present && !sources[i])
+ continue;
+
+ xattr = local->cont.lookup.xattrs[i];
+ if (!xattr)
+ continue;
+
+ data = dict_get (xattr, QUOTA_SIZE_KEY);
+ if (!data)
+ continue;
+
+ size = (int64_t*)data->data;
+ quota_size = ntoh64(*size);
+ gf_log (this->name, GF_LOG_DEBUG, "%s: %d, size: %"PRId64,
+ local->loc.path, i, quota_size);
+ if (quota_size > max_quota_size) {
+ if (max_data)
+ data_unref (max_data);
+
+ max_quota_size = quota_size;
+ max_data = data_ref (data);
+ }
+ }
+
+ if (max_data) {
+ ret = dict_set (rsp_dict, QUOTA_SIZE_KEY, max_data);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "%s: Failed to set "
+ "quota size", local->loc.path);
+ }
+
+ data_unref (max_data);
+ }
+}
+
int
afr_lookup_build_response_params (afr_local_t *local, xlator_t *this)
{
@@ -1124,13 +1206,18 @@ afr_lookup_build_response_params (afr_local_t *local, xlator_t *this)
ret = -1;
goto out;
}
+
gf_log (this->name, GF_LOG_DEBUG, "Building lookup response from %d",
read_child);
if (!*xattr)
*xattr = dict_ref (local->cont.lookup.xattrs[read_child]);
+
*buf = local->cont.lookup.bufs[read_child];
*postparent = local->cont.lookup.postparents[read_child];
+ if (dict_get (local->xattr_req, QUOTA_SIZE_KEY))
+ afr_handle_quota_size (local, this, *xattr);
+
if (IA_INVAL == local->cont.lookup.inode->ia_type) {
/* fix for RT #602 */
local->cont.lookup.inode->ia_type = buf->ia_type;
@@ -1745,7 +1832,8 @@ afr_lookup_perform_self_heal (call_frame_t *frame, xlator_t *this,
afr_lookup_set_self_heal_params (local, this);
if (afr_can_self_heal_proceed (&local->self_heal, priv)) {
- if (afr_is_transaction_running (local))
+ if (afr_is_transaction_running (local) &&
+ (!local->allow_sh_for_running_transaction))
goto out;
reason = "lookup detected pending operations";
@@ -2340,7 +2428,7 @@ afr_lookup (call_frame_t *frame, xlator_t *this,
int call_count = 0;
uint64_t ctx = 0;
int32_t op_errno = 0;
-
+ int allow_sh = 0;
priv = this->private;
AFR_LOCAL_ALLOC_OR_GOTO (local, out);
@@ -2412,6 +2500,11 @@ afr_lookup (call_frame_t *frame, xlator_t *this,
/* By default assume ENOTCONN. On success it will be set to 0. */
local->op_errno = ENOTCONN;
+ ret = dict_get_int32 (xattr_req, "allow-sh-for-running-transaction",
+ &allow_sh);
+ dict_del (xattr_req, "allow-sh-for-running-transaction");
+ local->allow_sh_for_running_transaction = allow_sh;
+
ret = afr_lookup_xattr_req_prepare (local, this, xattr_req, &local->loc,
&gfid_req);
if (ret) {
@@ -2757,13 +2850,13 @@ afr_fsync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
local->op_ret = 0;
if (local->success_count == 0) {
- local->cont.fsync.prebuf = *prebuf;
- local->cont.fsync.postbuf = *postbuf;
+ local->cont.inode_wfop.prebuf = *prebuf;
+ local->cont.inode_wfop.postbuf = *postbuf;
}
if (child_index == read_child) {
- local->cont.fsync.prebuf = *prebuf;
- local->cont.fsync.postbuf = *postbuf;
+ local->cont.inode_wfop.prebuf = *prebuf;
+ local->cont.inode_wfop.postbuf = *postbuf;
}
local->success_count++;
@@ -2787,8 +2880,9 @@ afr_fsync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
*/
stub = fop_fsync_cbk_stub (frame, afr_fsync_unwind_cbk,
local->op_ret, local->op_errno,
- &local->cont.fsync.prebuf,
- &local->cont.fsync.postbuf, xdata);
+ &local->cont.inode_wfop.prebuf,
+ &local->cont.inode_wfop.postbuf,
+ xdata);
if (!stub) {
AFR_STACK_UNWIND (fsync, frame, -1, ENOMEM, 0, 0, 0);
return 0;
@@ -2860,495 +2954,6 @@ out:
/* }}} */
-/* {{{ fallocate */
-
-static int
-afr_fallocate_unwind (call_frame_t *frame, xlator_t *this)
-{
- afr_local_t * local = NULL;
- call_frame_t *main_frame = NULL;
-
- local = frame->local;
-
- LOCK (&frame->lock);
- {
- if (local->transaction.main_frame)
- main_frame = local->transaction.main_frame;
- local->transaction.main_frame = NULL;
- }
- UNLOCK (&frame->lock);
-
- if (main_frame) {
- AFR_STACK_UNWIND (fallocate, main_frame, local->op_ret,
- local->op_errno,
- &local->cont.fallocate.prebuf,
- &local->cont.fallocate.postbuf,
- NULL);
- }
- return 0;
-}
-
-static int
-afr_fallocate_wind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
- int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
- struct iatt *postbuf, dict_t *xdata)
-{
- afr_local_t * local = NULL;
- afr_private_t * priv = NULL;
- int child_index = (long) cookie;
- int call_count = -1;
- int need_unwind = 0;
- int read_child = 0;
-
- local = frame->local;
- priv = this->private;
-
- read_child = afr_inode_get_read_ctx (this, local->fd->inode, NULL);
-
- LOCK (&frame->lock);
- {
- if (child_index == read_child) {
- local->read_child_returned = _gf_true;
- }
-
- if (afr_fop_failed (op_ret, op_errno)) {
- afr_transaction_fop_failed (frame, this, child_index);
- local->child_errno[child_index] = op_errno;
- }
-
- if (op_ret != -1) {
- if (local->success_count == 0) {
- local->op_ret = op_ret;
- local->cont.fallocate.prebuf = *prebuf;
- local->cont.fallocate.postbuf = *postbuf;
- }
-
- if (child_index == read_child) {
- local->cont.fallocate.prebuf = *prebuf;
- local->cont.fallocate.postbuf = *postbuf;
- }
-
- local->success_count++;
-
- if ((local->success_count >= priv->wait_count)
- && local->read_child_returned) {
- need_unwind = 1;
- }
- }
- local->op_errno = op_errno;
- }
- UNLOCK (&frame->lock);
-
- if (need_unwind)
- local->transaction.unwind (frame, this);
-
- call_count = afr_frame_return (frame);
-
- if (call_count == 0) {
- local->transaction.resume (frame, this);
- }
-
- return 0;
-}
-
-static int
-afr_fallocate_wind (call_frame_t *frame, xlator_t *this)
-{
- afr_local_t *local = NULL;
- afr_private_t *priv = NULL;
- int call_count = -1;
- int i = 0;
-
- local = frame->local;
- priv = this->private;
-
- call_count = afr_pre_op_done_children_count (local->transaction.pre_op,
- priv->child_count);
-
- if (call_count == 0) {
- local->transaction.resume (frame, this);
- return 0;
- }
-
- local->call_count = call_count;
-
- for (i = 0; i < priv->child_count; i++) {
- if (local->transaction.pre_op[i]) {
- STACK_WIND_COOKIE (frame, afr_fallocate_wind_cbk,
- (void *) (long) i,
- priv->children[i],
- priv->children[i]->fops->fallocate,
- local->fd,
- local->cont.fallocate.mode,
- local->cont.fallocate.offset,
- local->cont.fallocate.len,
- NULL);
-
- if (!--call_count)
- break;
- }
- }
-
- return 0;
-}
-
-static int
-afr_fallocate_done (call_frame_t *frame, xlator_t *this)
-{
- afr_local_t *local = NULL;
-
- local = frame->local;
-
- local->transaction.unwind (frame, this);
-
- AFR_STACK_DESTROY (frame);
-
- return 0;
-}
-
-static int
-afr_do_fallocate(call_frame_t *frame, xlator_t *this)
-{
- call_frame_t * transaction_frame = NULL;
- afr_local_t * local = NULL;
- int op_ret = -1;
- int op_errno = 0;
-
- local = frame->local;
-
- transaction_frame = copy_frame (frame);
- if (!transaction_frame) {
- goto out;
- }
-
- transaction_frame->local = local;
- frame->local = NULL;
-
- local->op = GF_FOP_FALLOCATE;
-
- local->transaction.fop = afr_fallocate_wind;
- local->transaction.done = afr_fallocate_done;
- local->transaction.unwind = afr_fallocate_unwind;
-
- local->transaction.main_frame = frame;
-
- local->transaction.start = local->cont.fallocate.offset;
- local->transaction.len = 0;
-
- /* fallocate can modify the file size */
- op_ret = afr_transaction (transaction_frame, this, AFR_DATA_TRANSACTION);
- if (op_ret < 0) {
- op_errno = -op_ret;
- goto out;
- }
-
- op_ret = 0;
-out:
- if (op_ret < 0) {
- if (transaction_frame)
- AFR_STACK_DESTROY (transaction_frame);
- AFR_STACK_UNWIND (fallocate, frame, op_ret, op_errno, NULL,
- NULL, NULL);
- }
-
- return 0;
-}
-
-int
-afr_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t mode,
- off_t offset, size_t len, dict_t *xdata)
-{
- afr_private_t * priv = NULL;
- afr_local_t * local = NULL;
- call_frame_t *transaction_frame = NULL;
- int ret = -1;
- int op_errno = 0;
-
- VALIDATE_OR_GOTO (frame, out);
- VALIDATE_OR_GOTO (this, out);
- VALIDATE_OR_GOTO (this->private, out);
-
- priv = this->private;
-
- if (afr_is_split_brain (this, fd->inode)) {
- op_errno = EIO;
- goto out;
- }
- QUORUM_CHECK(fallocate,out);
-
- AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out);
- local = frame->local;
-
- ret = afr_local_init (local, priv, &op_errno);
- if (ret < 0)
- goto out;
-
- local->cont.fallocate.mode = mode;
- local->cont.fallocate.offset = offset;
- local->cont.fallocate.len = len;
-
- local->fd = fd_ref (fd);
-
- afr_open_fd_fix (fd, this);
-
- afr_do_fallocate (frame, this);
-
- ret = 0;
-out:
- if (ret < 0) {
- if (transaction_frame)
- AFR_STACK_DESTROY (transaction_frame);
- AFR_STACK_UNWIND (fallocate, frame, -1, op_errno, NULL, NULL, NULL);
- }
-
- return 0;
-}
-
-/* }}} */
-
-/* {{{ discard */
-
-static int
-afr_discard_unwind (call_frame_t *frame, xlator_t *this)
-{
- afr_local_t * local = NULL;
- call_frame_t *main_frame = NULL;
-
- local = frame->local;
-
- LOCK (&frame->lock);
- {
- if (local->transaction.main_frame)
- main_frame = local->transaction.main_frame;
- local->transaction.main_frame = NULL;
- }
- UNLOCK (&frame->lock);
-
- if (main_frame) {
- AFR_STACK_UNWIND (discard, main_frame, local->op_ret,
- local->op_errno,
- &local->cont.discard.prebuf,
- &local->cont.discard.postbuf,
- NULL);
- }
- return 0;
-}
-
-static int
-afr_discard_wind_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
- int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
- struct iatt *postbuf, dict_t *xdata)
-{
- afr_local_t * local = NULL;
- afr_private_t * priv = NULL;
- int child_index = (long) cookie;
- int call_count = -1;
- int need_unwind = 0;
- int read_child = 0;
-
- local = frame->local;
- priv = this->private;
-
- read_child = afr_inode_get_read_ctx (this, local->fd->inode, NULL);
-
- LOCK (&frame->lock);
- {
- if (child_index == read_child) {
- local->read_child_returned = _gf_true;
- }
-
- if (afr_fop_failed (op_ret, op_errno)) {
- afr_transaction_fop_failed (frame, this, child_index);
- local->child_errno[child_index] = op_errno;
- }
-
- if (op_ret != -1) {
- if (local->success_count == 0) {
- local->op_ret = op_ret;
- local->cont.discard.prebuf = *prebuf;
- local->cont.discard.postbuf = *postbuf;
- }
-
- if (child_index == read_child) {
- local->cont.discard.prebuf = *prebuf;
- local->cont.discard.postbuf = *postbuf;
- }
-
- local->success_count++;
-
- if ((local->success_count >= priv->wait_count)
- && local->read_child_returned) {
- need_unwind = 1;
- }
- }
- local->op_errno = op_errno;
- }
- UNLOCK (&frame->lock);
-
- if (need_unwind)
- local->transaction.unwind (frame, this);
-
- call_count = afr_frame_return (frame);
-
- if (call_count == 0) {
- local->transaction.resume (frame, this);
- }
-
- return 0;
-}
-
-static int
-afr_discard_wind (call_frame_t *frame, xlator_t *this)
-{
- afr_local_t *local = NULL;
- afr_private_t *priv = NULL;
- int call_count = -1;
- int i = 0;
-
- local = frame->local;
- priv = this->private;
-
- call_count = afr_pre_op_done_children_count (local->transaction.pre_op,
- priv->child_count);
-
- if (call_count == 0) {
- local->transaction.resume (frame, this);
- return 0;
- }
-
- local->call_count = call_count;
-
- for (i = 0; i < priv->child_count; i++) {
- if (local->transaction.pre_op[i]) {
- STACK_WIND_COOKIE (frame, afr_discard_wind_cbk,
- (void *) (long) i,
- priv->children[i],
- priv->children[i]->fops->discard,
- local->fd,
- local->cont.discard.offset,
- local->cont.discard.len,
- NULL);
-
- if (!--call_count)
- break;
- }
- }
-
- return 0;
-}
-
-static int
-afr_discard_done (call_frame_t *frame, xlator_t *this)
-{
- afr_local_t *local = NULL;
-
- local = frame->local;
-
- local->transaction.unwind (frame, this);
-
- AFR_STACK_DESTROY (frame);
-
- return 0;
-}
-
-static int
-afr_do_discard(call_frame_t *frame, xlator_t *this)
-{
- call_frame_t * transaction_frame = NULL;
- afr_local_t * local = NULL;
- int op_ret = -1;
- int op_errno = 0;
-
- local = frame->local;
-
- transaction_frame = copy_frame (frame);
- if (!transaction_frame) {
- goto out;
- }
-
- transaction_frame->local = local;
- frame->local = NULL;
-
- local->op = GF_FOP_DISCARD;
-
- local->transaction.fop = afr_discard_wind;
- local->transaction.done = afr_discard_done;
- local->transaction.unwind = afr_discard_unwind;
-
- local->transaction.main_frame = frame;
-
- local->transaction.start = local->cont.discard.offset;
- local->transaction.len = 0;
-
- op_ret = afr_transaction (transaction_frame, this, AFR_DATA_TRANSACTION);
- if (op_ret < 0) {
- op_errno = -op_ret;
- goto out;
- }
-
- op_ret = 0;
-out:
- if (op_ret < 0) {
- if (transaction_frame)
- AFR_STACK_DESTROY (transaction_frame);
- AFR_STACK_UNWIND (discard, frame, op_ret, op_errno, NULL,
- NULL, NULL);
- }
-
- return 0;
-}
-
-int
-afr_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
- size_t len, dict_t *xdata)
-{
- afr_private_t * priv = NULL;
- afr_local_t * local = NULL;
- call_frame_t *transaction_frame = NULL;
- int ret = -1;
- int op_errno = 0;
-
- VALIDATE_OR_GOTO (frame, out);
- VALIDATE_OR_GOTO (this, out);
- VALIDATE_OR_GOTO (this->private, out);
-
- priv = this->private;
-
- if (afr_is_split_brain (this, fd->inode)) {
- op_errno = EIO;
- goto out;
- }
- QUORUM_CHECK(discard, out);
-
- AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out);
- local = frame->local;
-
- ret = afr_local_init (local, priv, &op_errno);
- if (ret < 0)
- goto out;
-
- local->cont.discard.offset = offset;
- local->cont.discard.len = len;
-
- local->fd = fd_ref (fd);
-
- afr_open_fd_fix (fd, this);
-
- afr_do_discard(frame, this);
-
- ret = 0;
-out:
- if (ret < 0) {
- if (transaction_frame)
- AFR_STACK_DESTROY (transaction_frame);
- AFR_STACK_UNWIND (discard, frame, -1, op_errno, NULL, NULL, NULL);
- }
-
- return 0;
-}
-
-/* }}} */
-
/* {{{ fsync */
int32_t
@@ -4826,6 +4431,16 @@ afr_priv_destroy (afr_private_t *priv)
if (priv->shd.split_brain)
eh_destroy (priv->shd.split_brain);
+ for (i = 0; i < priv->child_count; i++)
+ {
+ if (priv->shd.statistics[i])
+ eh_destroy (priv->shd.statistics[i]);
+ }
+
+ GF_FREE (priv->shd.statistics);
+
+ GF_FREE (priv->shd.crawl_events);
+
GF_FREE (priv->last_event);
if (priv->pending_key) {
for (i = 0; i < priv->child_count; i++)
@@ -4929,3 +4544,48 @@ afr_handle_open_fd_count (call_frame_t *frame, xlator_t *this)
}
UNLOCK (&inode->lock);
}
+
+int
+afr_initialise_statistics (xlator_t *this)
+{
+ afr_private_t *priv = NULL;
+ int ret = -1;
+ int i = 0;
+ int child_count = 0;
+ eh_t *stats_per_brick = NULL;
+ shd_crawl_event_t ***shd_crawl_events = NULL;
+ priv = this->private;
+
+ priv->shd.statistics = GF_CALLOC (sizeof(eh_t *), priv->child_count,
+ gf_common_mt_eh_t);
+ if (!priv->shd.statistics) {
+ ret = -1;
+ goto out;
+ }
+ child_count = priv->child_count;
+ for (i=0; i < child_count ; i++) {
+ stats_per_brick = eh_new (AFR_STATISTICS_HISTORY_SIZE,
+ _gf_false,
+ _destroy_crawl_event_data);
+ if (!stats_per_brick) {
+ ret = -1;
+ goto out;
+ }
+ priv->shd.statistics[i] = stats_per_brick;
+
+ }
+
+ shd_crawl_events = (shd_crawl_event_t***)(&priv->shd.crawl_events);
+ *shd_crawl_events = GF_CALLOC (sizeof(shd_crawl_event_t*),
+ priv->child_count,
+ gf_afr_mt_shd_crawl_event_t);
+
+ if (!priv->shd.crawl_events) {
+ ret = -1;
+ goto out;
+ }
+ ret = 0;
+out:
+ return ret;
+
+}
diff --git a/xlators/cluster/afr/src/afr-inode-read.c b/xlators/cluster/afr/src/afr-inode-read.c
index 00dd22214..e06e3b2f2 100644
--- a/xlators/cluster/afr/src/afr-inode-read.c
+++ b/xlators/cluster/afr/src/afr-inode-read.c
@@ -117,6 +117,8 @@ afr_access (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t mask,
children = priv->children;
+ AFR_SBRAIN_CHECK_LOC (loc, out);
+
AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out);
local = frame->local;
@@ -232,6 +234,8 @@ afr_stat (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
children = priv->children;
+ AFR_SBRAIN_CHECK_LOC (loc, out);
+
AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out);
local = frame->local;
@@ -348,10 +352,7 @@ afr_fstat (call_frame_t *frame, xlator_t *this,
VALIDATE_OR_GOTO (fd->inode, out);
- if (afr_is_split_brain (this, fd->inode)) {
- op_errno = EIO;
- goto out;
- }
+ AFR_SBRAIN_CHECK_FD (fd, out);
AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out);
local = frame->local;
@@ -472,6 +473,8 @@ afr_readlink (call_frame_t *frame, xlator_t *this,
children = priv->children;
+ AFR_SBRAIN_CHECK_LOC (loc, out);
+
AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out);
local = frame->local;
@@ -1472,6 +1475,8 @@ afr_getxattr (call_frame_t *frame, xlator_t *this,
children = priv->children;
+ AFR_SBRAIN_CHECK_LOC (loc, out);
+
AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out);
local = frame->local;
@@ -1727,10 +1732,8 @@ afr_fgetxattr (call_frame_t *frame, xlator_t *this,
children = priv->children;
- if (afr_is_split_brain (this, fd->inode)) {
- op_errno = EIO;
- goto out;
- }
+ AFR_SBRAIN_CHECK_FD (fd, out);
+
AFR_LOCAL_ALLOC_OR_GOTO (local, out);
frame->local = local;
@@ -1886,10 +1889,7 @@ afr_readv (call_frame_t *frame, xlator_t *this,
priv = this->private;
children = priv->children;
- if (afr_is_split_brain (this, fd->inode)) {
- op_errno = EIO;
- goto out;
- }
+ AFR_SBRAIN_CHECK_FD (fd, out);
AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out);
local = frame->local;
diff --git a/xlators/cluster/afr/src/afr-inode-write.c b/xlators/cluster/afr/src/afr-inode-write.c
index a3090e4db..c1ec69a55 100644
--- a/xlators/cluster/afr/src/afr-inode-write.c
+++ b/xlators/cluster/afr/src/afr-inode-write.c
@@ -39,6 +39,46 @@
#include "afr-transaction.h"
#include "afr-self-heal-common.h"
+void
+__inode_write_fop_cbk (call_frame_t *frame, int child_index, int read_child,
+ xlator_t *this, int32_t *op_ret, int32_t *op_errno,
+ struct iatt *prebuf, struct iatt *postbuf, dict_t *xdata)
+{
+ afr_local_t *local = NULL;
+
+ local = frame->local;
+
+ if (afr_fop_failed (*op_ret, *op_errno)) {
+ local->child_errno[child_index] = *op_errno;
+
+ switch (local->op) {
+ case GF_FOP_TRUNCATE:
+ case GF_FOP_FTRUNCATE:
+ if (*op_errno != EFBIG)
+ afr_transaction_fop_failed (frame, this,
+ child_index);
+ break;
+ default:
+ afr_transaction_fop_failed (frame, this, child_index);
+ break;
+ }
+ local->op_errno = *op_errno;
+ goto out;
+ }
+
+ if ((local->success_count == 0) || (read_child == child_index)) {
+ local->op_ret = *op_ret;
+ if (prebuf)
+ local->cont.inode_wfop.prebuf = *prebuf;
+ if (postbuf)
+ local->cont.inode_wfop.postbuf = *postbuf;
+ }
+
+ local->success_count++;
+out:
+ return;
+}
+
/* {{{ writev */
void
@@ -52,8 +92,8 @@ afr_writev_copy_outvars (call_frame_t *src_frame, call_frame_t *dst_frame)
dst_local->op_ret = src_local->op_ret;
dst_local->op_errno = src_local->op_errno;
- dst_local->cont.writev.prebuf = src_local->cont.writev.prebuf;
- dst_local->cont.writev.postbuf = src_local->cont.writev.postbuf;
+ dst_local->cont.inode_wfop.prebuf = src_local->cont.inode_wfop.prebuf;
+ dst_local->cont.inode_wfop.postbuf = src_local->cont.inode_wfop.postbuf;
}
void
@@ -64,8 +104,8 @@ afr_writev_unwind (call_frame_t *frame, xlator_t *this)
AFR_STACK_UNWIND (writev, frame,
local->op_ret, local->op_errno,
- &local->cont.writev.prebuf,
- &local->cont.writev.postbuf,
+ &local->cont.inode_wfop.prebuf,
+ &local->cont.inode_wfop.postbuf,
NULL);
}
@@ -153,14 +193,14 @@ afr_writev_wind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
local->read_child_returned = _gf_true;
}
+ __inode_write_fop_cbk (frame, child_index, read_child, this,
+ &op_ret, &op_errno, prebuf, postbuf,
+ xdata);
+
local->replies[child_index].valid = 1;
local->replies[child_index].op_ret = op_ret;
local->replies[child_index].op_errno = op_errno;
- if (afr_fop_failed (op_ret, op_errno)) {
- afr_transaction_fop_failed (frame, this, child_index);
- local->child_errno[child_index] = op_errno;
- }
/* stage the best case return value for unwind */
if ((local->success_count == 0) || (op_ret > local->op_ret)) {
@@ -187,12 +227,6 @@ afr_writev_wind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
local->append_write = _gf_false;
}
- if ((local->success_count == 0) ||
- (child_index == read_child)) {
- local->cont.writev.prebuf = *prebuf;
- local->cont.writev.postbuf = *postbuf;
- }
- local->success_count++;
}
}
UNLOCK (&frame->lock);
@@ -572,8 +606,8 @@ afr_truncate_unwind (call_frame_t *frame, xlator_t *this)
if (main_frame) {
AFR_STACK_UNWIND (truncate, main_frame, local->op_ret,
local->op_errno,
- &local->cont.truncate.prebuf,
- &local->cont.truncate.postbuf,
+ &local->cont.inode_wfop.prebuf,
+ &local->cont.inode_wfop.postbuf,
NULL);
}
@@ -601,29 +635,13 @@ afr_truncate_wind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
local->read_child_returned = _gf_true;
}
- if (afr_fop_failed (op_ret, op_errno) && op_errno != EFBIG) {
- afr_transaction_fop_failed (frame, this, child_index);
- local->child_errno[child_index] = op_errno;
- }
-
if (op_ret != -1) {
if (prebuf->ia_size != postbuf->ia_size)
local->stable_write = _gf_false;
-
- if (local->success_count == 0) {
- local->op_ret = op_ret;
- local->cont.truncate.prebuf = *prebuf;
- local->cont.truncate.postbuf = *postbuf;
- }
-
- if (child_index == read_child) {
- local->cont.truncate.prebuf = *prebuf;
- local->cont.truncate.postbuf = *postbuf;
- }
-
- local->success_count++;
}
- local->op_errno = op_errno;
+ __inode_write_fop_cbk (frame, child_index, read_child, this,
+ &op_ret, &op_errno, prebuf, postbuf,
+ xdata);
}
UNLOCK (&frame->lock);
@@ -781,8 +799,8 @@ afr_ftruncate_unwind (call_frame_t *frame, xlator_t *this)
if (main_frame) {
AFR_STACK_UNWIND (ftruncate, main_frame, local->op_ret,
local->op_errno,
- &local->cont.ftruncate.prebuf,
- &local->cont.ftruncate.postbuf,
+ &local->cont.inode_wfop.prebuf,
+ &local->cont.inode_wfop.postbuf,
NULL);
}
return 0;
@@ -809,29 +827,13 @@ afr_ftruncate_wind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
local->read_child_returned = _gf_true;
}
- if (afr_fop_failed (op_ret, op_errno)) {
- afr_transaction_fop_failed (frame, this, child_index);
- local->child_errno[child_index] = op_errno;
- }
-
if (op_ret != -1) {
if (prebuf->ia_size != postbuf->ia_size)
local->stable_write = _gf_false;
-
- if (local->success_count == 0) {
- local->op_ret = op_ret;
- local->cont.ftruncate.prebuf = *prebuf;
- local->cont.ftruncate.postbuf = *postbuf;
- }
-
- if (child_index == read_child) {
- local->cont.ftruncate.prebuf = *prebuf;
- local->cont.ftruncate.postbuf = *postbuf;
- }
-
- local->success_count++;
}
- local->op_errno = op_errno;
+ __inode_write_fop_cbk (frame, child_index, read_child, this,
+ &op_ret, &op_errno, prebuf, postbuf,
+ xdata);
}
UNLOCK (&frame->lock);
@@ -1023,8 +1025,8 @@ afr_setattr_unwind (call_frame_t *frame, xlator_t *this)
if (main_frame) {
AFR_STACK_UNWIND (setattr, main_frame, local->op_ret,
local->op_errno,
- &local->cont.setattr.preop_buf,
- &local->cont.setattr.postop_buf,
+ &local->cont.inode_wfop.prebuf,
+ &local->cont.inode_wfop.postbuf,
NULL);
}
@@ -1055,29 +1057,14 @@ afr_setattr_wind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
local->read_child_returned = _gf_true;
}
- if (afr_fop_failed (op_ret, op_errno))
- afr_transaction_fop_failed (frame, this, child_index);
-
- if (op_ret != -1) {
- if (local->success_count == 0) {
- local->op_ret = op_ret;
- local->cont.setattr.preop_buf = *preop;
- local->cont.setattr.postop_buf = *postop;
- }
-
- if (child_index == read_child) {
- local->cont.setattr.preop_buf = *preop;
- local->cont.setattr.postop_buf = *postop;
- }
-
- local->success_count++;
+ __inode_write_fop_cbk (frame, child_index, read_child, this,
+ &op_ret, &op_errno, preop, postop,
+ xdata);
- if ((local->success_count >= priv->wait_count)
- && local->read_child_returned) {
- need_unwind = 1;
- }
+ if ((local->success_count >= priv->wait_count)
+ && local->read_child_returned) {
+ need_unwind = 1;
}
- local->op_errno = op_errno;
}
UNLOCK (&frame->lock);
@@ -1232,8 +1219,8 @@ afr_fsetattr_unwind (call_frame_t *frame, xlator_t *this)
if (main_frame) {
AFR_STACK_UNWIND (fsetattr, main_frame, local->op_ret,
local->op_errno,
- &local->cont.fsetattr.preop_buf,
- &local->cont.fsetattr.postop_buf,
+ &local->cont.inode_wfop.prebuf,
+ &local->cont.inode_wfop.postbuf,
NULL);
}
@@ -1264,29 +1251,14 @@ afr_fsetattr_wind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
local->read_child_returned = _gf_true;
}
- if (afr_fop_failed (op_ret, op_errno))
- afr_transaction_fop_failed (frame, this, child_index);
+ __inode_write_fop_cbk (frame, child_index, read_child, this,
+ &op_ret, &op_errno, preop, postop,
+ xdata);
- if (op_ret != -1) {
- if (local->success_count == 0) {
- local->op_ret = op_ret;
- local->cont.fsetattr.preop_buf = *preop;
- local->cont.fsetattr.postop_buf = *postop;
- }
-
- if (child_index == read_child) {
- local->cont.fsetattr.preop_buf = *preop;
- local->cont.fsetattr.postop_buf = *postop;
- }
-
- local->success_count++;
-
- if ((local->success_count >= priv->wait_count)
- && local->read_child_returned) {
- need_unwind = 1;
- }
+ if ((local->success_count >= priv->wait_count)
+ && local->read_child_returned) {
+ need_unwind = 1;
}
- local->op_errno = op_errno;
}
UNLOCK (&frame->lock);
@@ -1459,28 +1431,23 @@ int
afr_setxattr_wind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, dict_t *xdata)
{
- afr_local_t *local = NULL;
- afr_private_t *priv = NULL;
- int call_count = -1;
- int need_unwind = 0;
+ afr_local_t *local = NULL;
+ afr_private_t *priv = NULL;
+ int call_count = -1;
+ int need_unwind = 0;
+ int child_index = (long) cookie;
local = frame->local;
priv = this->private;
LOCK (&frame->lock);
{
- if (op_ret != -1) {
- if (local->success_count == 0) {
- local->op_ret = op_ret;
- }
- local->success_count++;
-
- if (local->success_count == priv->child_count) {
- need_unwind = 1;
- }
+ __inode_write_fop_cbk (frame, child_index, -1, this,
+ &op_ret, &op_errno, NULL, NULL,
+ xdata);
+ if (local->success_count == priv->child_count) {
+ need_unwind = 1;
}
-
- local->op_errno = op_errno;
}
UNLOCK (&frame->lock);
@@ -1649,28 +1616,24 @@ int
afr_fsetxattr_wind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, dict_t *xdata)
{
- afr_local_t *local = NULL;
- afr_private_t *priv = NULL;
- int call_count = -1;
- int need_unwind = 0;
+ afr_local_t *local = NULL;
+ afr_private_t *priv = NULL;
+ int call_count = -1;
+ int need_unwind = 0;
+ int child_index = (long) cookie;
local = frame->local;
priv = this->private;
LOCK (&frame->lock);
{
- if (op_ret != -1) {
- if (local->success_count == 0) {
- local->op_ret = op_ret;
- }
- local->success_count++;
- if (local->success_count == priv->child_count) {
- need_unwind = 1;
- }
+ __inode_write_fop_cbk (frame, child_index, -1, this,
+ &op_ret, &op_errno, NULL, NULL,
+ xdata);
+ if (local->success_count == priv->child_count) {
+ need_unwind = 1;
}
-
- local->op_errno = op_errno;
}
UNLOCK (&frame->lock);
@@ -1849,28 +1812,23 @@ int
afr_removexattr_wind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, dict_t *xdata)
{
- afr_local_t * local = NULL;
- afr_private_t * priv = NULL;
- int call_count = -1;
- int need_unwind = 0;
+ afr_local_t *local = NULL;
+ afr_private_t *priv = NULL;
+ int call_count = -1;
+ int need_unwind = 0;
+ int child_index = (long) cookie;
local = frame->local;
priv = this->private;
LOCK (&frame->lock);
{
- if (op_ret != -1) {
- if (local->success_count == 0) {
- local->op_ret = op_ret;
- }
- local->success_count++;
-
- if (local->success_count == priv->wait_count) {
- need_unwind = 1;
- }
+ __inode_write_fop_cbk (frame, child_index, -1, this,
+ &op_ret, &op_errno, NULL, NULL,
+ xdata);
+ if (local->success_count == priv->wait_count) {
+ need_unwind = 1;
}
-
- local->op_errno = op_errno;
}
UNLOCK (&frame->lock);
@@ -2038,28 +1996,24 @@ int
afr_fremovexattr_wind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, dict_t *xdata)
{
- afr_local_t * local = NULL;
- afr_private_t * priv = NULL;
- int call_count = -1;
- int need_unwind = 0;
+ afr_local_t * local = NULL;
+ afr_private_t * priv = NULL;
+ int call_count = -1;
+ int need_unwind = 0;
+ int child_index = (long) cookie;
local = frame->local;
priv = this->private;
LOCK (&frame->lock);
{
- if (op_ret != -1) {
- if (local->success_count == 0) {
- local->op_ret = op_ret;
- }
- local->success_count++;
+ __inode_write_fop_cbk (frame, child_index, -1, this,
+ &op_ret, &op_errno, NULL, NULL,
+ xdata);
- if (local->success_count == priv->wait_count) {
- need_unwind = 1;
- }
+ if (local->success_count == priv->wait_count) {
+ need_unwind = 1;
}
-
- local->op_errno = op_errno;
}
UNLOCK (&frame->lock);
@@ -2204,3 +2158,704 @@ out:
return 0;
}
+
+static int
+afr_fallocate_unwind (call_frame_t *frame, xlator_t *this)
+{
+ afr_local_t * local = NULL;
+ call_frame_t *main_frame = NULL;
+
+ local = frame->local;
+
+ LOCK (&frame->lock);
+ {
+ if (local->transaction.main_frame)
+ main_frame = local->transaction.main_frame;
+ local->transaction.main_frame = NULL;
+ }
+ UNLOCK (&frame->lock);
+
+ if (main_frame) {
+ AFR_STACK_UNWIND (fallocate, main_frame, local->op_ret,
+ local->op_errno,
+ &local->cont.inode_wfop.prebuf,
+ &local->cont.inode_wfop.postbuf,
+ NULL);
+ }
+ return 0;
+}
+
+static int
+afr_fallocate_wind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
+ struct iatt *postbuf, dict_t *xdata)
+{
+ afr_local_t * local = NULL;
+ afr_private_t * priv = NULL;
+ int child_index = (long) cookie;
+ int call_count = -1;
+ int need_unwind = 0;
+ int read_child = 0;
+
+ local = frame->local;
+ priv = this->private;
+
+ read_child = afr_inode_get_read_ctx (this, local->fd->inode, NULL);
+
+ LOCK (&frame->lock);
+ {
+ if (child_index == read_child) {
+ local->read_child_returned = _gf_true;
+ }
+
+ __inode_write_fop_cbk (frame, child_index, read_child, this,
+ &op_ret, &op_errno, prebuf, postbuf,
+ xdata);
+
+ if ((local->success_count >= priv->wait_count)
+ && local->read_child_returned) {
+ need_unwind = 1;
+ }
+ }
+ UNLOCK (&frame->lock);
+
+ if (need_unwind)
+ local->transaction.unwind (frame, this);
+
+ call_count = afr_frame_return (frame);
+
+ if (call_count == 0) {
+ local->transaction.resume (frame, this);
+ }
+
+ return 0;
+}
+
+static int
+afr_fallocate_wind (call_frame_t *frame, xlator_t *this)
+{
+ afr_local_t *local = NULL;
+ afr_private_t *priv = NULL;
+ int call_count = -1;
+ int i = 0;
+
+ local = frame->local;
+ priv = this->private;
+
+ call_count = afr_pre_op_done_children_count (local->transaction.pre_op,
+ priv->child_count);
+
+ if (call_count == 0) {
+ local->transaction.resume (frame, this);
+ return 0;
+ }
+
+ local->call_count = call_count;
+
+ for (i = 0; i < priv->child_count; i++) {
+ if (local->transaction.pre_op[i]) {
+ STACK_WIND_COOKIE (frame, afr_fallocate_wind_cbk,
+ (void *) (long) i,
+ priv->children[i],
+ priv->children[i]->fops->fallocate,
+ local->fd,
+ local->cont.fallocate.mode,
+ local->cont.fallocate.offset,
+ local->cont.fallocate.len,
+ NULL);
+
+ if (!--call_count)
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int
+afr_fallocate_done (call_frame_t *frame, xlator_t *this)
+{
+ afr_local_t *local = NULL;
+
+ local = frame->local;
+
+ local->transaction.unwind (frame, this);
+
+ AFR_STACK_DESTROY (frame);
+
+ return 0;
+}
+
+static int
+afr_do_fallocate (call_frame_t *frame, xlator_t *this)
+{
+ call_frame_t * transaction_frame = NULL;
+ afr_local_t * local = NULL;
+ int op_ret = -1;
+ int op_errno = 0;
+
+ local = frame->local;
+
+ transaction_frame = copy_frame (frame);
+ if (!transaction_frame) {
+ goto out;
+ }
+
+ transaction_frame->local = local;
+ frame->local = NULL;
+
+ local->op = GF_FOP_FALLOCATE;
+
+ local->transaction.fop = afr_fallocate_wind;
+ local->transaction.done = afr_fallocate_done;
+ local->transaction.unwind = afr_fallocate_unwind;
+
+ local->transaction.main_frame = frame;
+
+ local->transaction.start = local->cont.fallocate.offset;
+ local->transaction.len = 0;
+
+ /* fallocate can modify the file size */
+ op_ret = afr_transaction (transaction_frame, this, AFR_DATA_TRANSACTION);
+ if (op_ret < 0) {
+ op_errno = -op_ret;
+ goto out;
+ }
+
+ op_ret = 0;
+out:
+ if (op_ret < 0) {
+ if (transaction_frame)
+ AFR_STACK_DESTROY (transaction_frame);
+ AFR_STACK_UNWIND (fallocate, frame, op_ret, op_errno, NULL,
+ NULL, NULL);
+ }
+
+ return 0;
+}
+
+int
+afr_fallocate (call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t mode,
+ off_t offset, size_t len, dict_t *xdata)
+{
+ afr_private_t * priv = NULL;
+ afr_local_t * local = NULL;
+ call_frame_t *transaction_frame = NULL;
+ int ret = -1;
+ int op_errno = 0;
+
+ VALIDATE_OR_GOTO (frame, out);
+ VALIDATE_OR_GOTO (this, out);
+ VALIDATE_OR_GOTO (this->private, out);
+
+ priv = this->private;
+
+ if (afr_is_split_brain (this, fd->inode)) {
+ op_errno = EIO;
+ goto out;
+ }
+ QUORUM_CHECK(fallocate,out);
+
+ AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out);
+ local = frame->local;
+
+ ret = afr_local_init (local, priv, &op_errno);
+ if (ret < 0)
+ goto out;
+
+ local->cont.fallocate.mode = mode;
+ local->cont.fallocate.offset = offset;
+ local->cont.fallocate.len = len;
+
+ local->fd = fd_ref (fd);
+
+ afr_open_fd_fix (fd, this);
+
+ afr_do_fallocate (frame, this);
+
+ ret = 0;
+out:
+ if (ret < 0) {
+ if (transaction_frame)
+ AFR_STACK_DESTROY (transaction_frame);
+ AFR_STACK_UNWIND (fallocate, frame, -1, op_errno, NULL, NULL, NULL);
+ }
+
+ return 0;
+}
+
+/* }}} */
+
+/* {{{ discard */
+
+static int
+afr_discard_unwind (call_frame_t *frame, xlator_t *this)
+{
+ afr_local_t * local = NULL;
+ call_frame_t *main_frame = NULL;
+
+ local = frame->local;
+
+ LOCK (&frame->lock);
+ {
+ if (local->transaction.main_frame)
+ main_frame = local->transaction.main_frame;
+ local->transaction.main_frame = NULL;
+ }
+ UNLOCK (&frame->lock);
+
+ if (main_frame) {
+ AFR_STACK_UNWIND (discard, main_frame, local->op_ret,
+ local->op_errno,
+ &local->cont.inode_wfop.prebuf,
+ &local->cont.inode_wfop.postbuf,
+ NULL);
+ }
+ return 0;
+}
+
+static int
+afr_discard_wind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
+ struct iatt *postbuf, dict_t *xdata)
+{
+ afr_local_t * local = NULL;
+ afr_private_t * priv = NULL;
+ int child_index = (long) cookie;
+ int call_count = -1;
+ int need_unwind = 0;
+ int read_child = 0;
+
+ local = frame->local;
+ priv = this->private;
+
+ read_child = afr_inode_get_read_ctx (this, local->fd->inode, NULL);
+
+ LOCK (&frame->lock);
+ {
+ if (child_index == read_child) {
+ local->read_child_returned = _gf_true;
+ }
+
+ __inode_write_fop_cbk (frame, child_index, read_child, this,
+ &op_ret, &op_errno, prebuf, postbuf,
+ xdata);
+
+ if ((local->success_count >= priv->wait_count)
+ && local->read_child_returned) {
+ need_unwind = 1;
+ }
+ }
+ UNLOCK (&frame->lock);
+
+ if (need_unwind)
+ local->transaction.unwind (frame, this);
+
+ call_count = afr_frame_return (frame);
+
+ if (call_count == 0) {
+ local->transaction.resume (frame, this);
+ }
+
+ return 0;
+}
+
+static int
+afr_discard_wind (call_frame_t *frame, xlator_t *this)
+{
+ afr_local_t *local = NULL;
+ afr_private_t *priv = NULL;
+ int call_count = -1;
+ int i = 0;
+
+ local = frame->local;
+ priv = this->private;
+
+ call_count = afr_pre_op_done_children_count (local->transaction.pre_op,
+ priv->child_count);
+
+ if (call_count == 0) {
+ local->transaction.resume (frame, this);
+ return 0;
+ }
+
+ local->call_count = call_count;
+
+ for (i = 0; i < priv->child_count; i++) {
+ if (local->transaction.pre_op[i]) {
+ STACK_WIND_COOKIE (frame, afr_discard_wind_cbk,
+ (void *) (long) i,
+ priv->children[i],
+ priv->children[i]->fops->discard,
+ local->fd,
+ local->cont.discard.offset,
+ local->cont.discard.len,
+ NULL);
+
+ if (!--call_count)
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int
+afr_discard_done (call_frame_t *frame, xlator_t *this)
+{
+ afr_local_t *local = NULL;
+
+ local = frame->local;
+
+ local->transaction.unwind (frame, this);
+
+ AFR_STACK_DESTROY (frame);
+
+ return 0;
+}
+
+static int
+afr_do_discard (call_frame_t *frame, xlator_t *this)
+{
+ call_frame_t * transaction_frame = NULL;
+ afr_local_t * local = NULL;
+ int op_ret = -1;
+ int op_errno = 0;
+
+ local = frame->local;
+
+ transaction_frame = copy_frame (frame);
+ if (!transaction_frame) {
+ goto out;
+ }
+
+ transaction_frame->local = local;
+ frame->local = NULL;
+
+ local->op = GF_FOP_DISCARD;
+
+ local->transaction.fop = afr_discard_wind;
+ local->transaction.done = afr_discard_done;
+ local->transaction.unwind = afr_discard_unwind;
+
+ local->transaction.main_frame = frame;
+
+ local->transaction.start = local->cont.discard.offset;
+ local->transaction.len = 0;
+
+ op_ret = afr_transaction (transaction_frame, this, AFR_DATA_TRANSACTION);
+ if (op_ret < 0) {
+ op_errno = -op_ret;
+ goto out;
+ }
+
+ op_ret = 0;
+out:
+ if (op_ret < 0) {
+ if (transaction_frame)
+ AFR_STACK_DESTROY (transaction_frame);
+ AFR_STACK_UNWIND (discard, frame, op_ret, op_errno, NULL,
+ NULL, NULL);
+ }
+
+ return 0;
+}
+
+int
+afr_discard (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
+ size_t len, dict_t *xdata)
+{
+ afr_private_t * priv = NULL;
+ afr_local_t * local = NULL;
+ call_frame_t *transaction_frame = NULL;
+ int ret = -1;
+ int op_errno = 0;
+
+ VALIDATE_OR_GOTO (frame, out);
+ VALIDATE_OR_GOTO (this, out);
+ VALIDATE_OR_GOTO (this->private, out);
+
+ priv = this->private;
+
+ if (afr_is_split_brain (this, fd->inode)) {
+ op_errno = EIO;
+ goto out;
+ }
+ QUORUM_CHECK(discard, out);
+
+ AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out);
+ local = frame->local;
+
+ ret = afr_local_init (local, priv, &op_errno);
+ if (ret < 0)
+ goto out;
+
+ local->cont.discard.offset = offset;
+ local->cont.discard.len = len;
+
+ local->fd = fd_ref (fd);
+
+ afr_open_fd_fix (fd, this);
+
+ afr_do_discard(frame, this);
+
+ ret = 0;
+out:
+ if (ret < 0) {
+ if (transaction_frame)
+ AFR_STACK_DESTROY (transaction_frame);
+ AFR_STACK_UNWIND (discard, frame, -1, op_errno, NULL, NULL, NULL);
+ }
+
+ return 0;
+}
+
+
+/* {{{ zerofill */
+
+static int
+afr_zerofill_unwind (call_frame_t *frame, xlator_t *this)
+{
+ afr_local_t *local = NULL;
+ call_frame_t *main_frame = NULL;
+
+ local = frame->local;
+
+ LOCK (&frame->lock);
+ {
+ if (local->transaction.main_frame) {
+ main_frame = local->transaction.main_frame;
+ }
+ local->transaction.main_frame = NULL;
+ }
+ UNLOCK (&frame->lock);
+
+ if (main_frame) {
+ AFR_STACK_UNWIND (zerofill, main_frame, local->op_ret,
+ local->op_errno,
+ &local->cont.zerofill.prebuf,
+ &local->cont.zerofill.postbuf,
+ NULL);
+ }
+ return 0;
+}
+
+static int
+afr_zerofill_wind_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
+ struct iatt *postbuf, dict_t *xdata)
+{
+ afr_local_t *local = NULL;
+ afr_private_t *priv = NULL;
+ int child_index = (long) cookie;
+ int call_count = -1;
+ int need_unwind = 0;
+ int read_child = 0;
+
+ local = frame->local;
+ priv = this->private;
+
+ read_child = afr_inode_get_read_ctx (this, local->fd->inode, NULL);
+
+ LOCK (&frame->lock);
+ {
+ if (child_index == read_child) {
+ local->read_child_returned = _gf_true;
+ }
+
+ if (afr_fop_failed (op_ret, op_errno)) {
+ afr_transaction_fop_failed (frame, this, child_index);
+ }
+
+ if (op_ret != -1) {
+ if (local->success_count == 0) {
+ local->op_ret = op_ret;
+ local->cont.zerofill.prebuf = *prebuf;
+ local->cont.zerofill.postbuf = *postbuf;
+ }
+
+ if (child_index == read_child) {
+ local->cont.zerofill.prebuf = *prebuf;
+ local->cont.zerofill.postbuf = *postbuf;
+ }
+
+ local->success_count++;
+
+ if ((local->success_count >= priv->wait_count)
+ && local->read_child_returned) {
+ need_unwind = 1;
+ }
+ }
+ local->op_errno = op_errno;
+ }
+ UNLOCK (&frame->lock);
+
+ if (need_unwind) {
+ local->transaction.unwind (frame, this);
+ }
+ call_count = afr_frame_return (frame);
+
+ if (call_count == 0) {
+ local->transaction.resume (frame, this);
+ }
+
+ return 0;
+}
+
+static int
+afr_zerofill_wind (call_frame_t *frame, xlator_t *this)
+{
+ afr_local_t *local = NULL;
+ afr_private_t *priv = NULL;
+ int call_count = -1;
+ int i = 0;
+
+ local = frame->local;
+ priv = this->private;
+
+ call_count = afr_pre_op_done_children_count (local->transaction.pre_op,
+ priv->child_count);
+
+ if (call_count == 0) {
+ local->transaction.resume (frame, this);
+ return 0;
+ }
+
+ local->call_count = call_count;
+
+ for (i = 0; i < priv->child_count; i++) {
+ if (local->transaction.pre_op[i]) {
+ STACK_WIND_COOKIE (frame, afr_zerofill_wind_cbk,
+ (void *) (long) i,
+ priv->children[i],
+ priv->children[i]->fops->zerofill,
+ local->fd,
+ local->cont.zerofill.offset,
+ local->cont.zerofill.len,
+ NULL);
+
+ if (!--call_count)
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int
+afr_zerofill_done (call_frame_t *frame, xlator_t *this)
+{
+ afr_local_t *local = NULL;
+
+ local = frame->local;
+
+ local->transaction.unwind (frame, this);
+
+ AFR_STACK_DESTROY (frame);
+
+ return 0;
+}
+
+static int
+afr_do_zerofill(call_frame_t *frame, xlator_t *this)
+{
+ call_frame_t *transaction_frame = NULL;
+ afr_local_t *local = NULL;
+ int op_ret = -1;
+ int op_errno = 0;
+
+ local = frame->local;
+
+ transaction_frame = copy_frame (frame);
+ if (!transaction_frame) {
+ goto out;
+ }
+
+ transaction_frame->local = local;
+ frame->local = NULL;
+
+ local->op = GF_FOP_ZEROFILL;
+
+ local->transaction.fop = afr_zerofill_wind;
+ local->transaction.done = afr_zerofill_done;
+ local->transaction.unwind = afr_zerofill_unwind;
+
+ local->transaction.main_frame = frame;
+
+ local->transaction.start = local->cont.zerofill.offset;
+ local->transaction.len = 0;
+
+ op_ret = afr_transaction (transaction_frame, this,
+ AFR_DATA_TRANSACTION);
+ if (op_ret < 0) {
+ op_errno = -op_ret;
+ goto out;
+ }
+
+ op_ret = 0;
+out:
+ if (op_ret < 0) {
+ if (transaction_frame) {
+ AFR_STACK_DESTROY (transaction_frame);
+ }
+ AFR_STACK_UNWIND (zerofill, frame, op_ret, op_errno, NULL,
+ NULL, NULL);
+ }
+
+ return 0;
+}
+
+int
+afr_zerofill (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
+ size_t len, dict_t *xdata)
+{
+ afr_private_t *priv = NULL;
+ afr_local_t *local = NULL;
+ call_frame_t *transaction_frame = NULL;
+ int ret = -1;
+ int op_errno = 0;
+
+ VALIDATE_OR_GOTO (frame, out);
+ VALIDATE_OR_GOTO (this, out);
+ VALIDATE_OR_GOTO (this->private, out);
+
+ priv = this->private;
+
+ if (afr_is_split_brain (this, fd->inode)) {
+ op_errno = EIO;
+ goto out;
+ }
+ QUORUM_CHECK(zerofill, out);
+
+ AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out);
+ local = frame->local;
+
+ ret = afr_local_init (local, priv, &op_errno);
+ if (ret < 0) {
+ goto out;
+ }
+ local->cont.zerofill.offset = offset;
+ local->cont.zerofill.len = len;
+
+ local->fd = fd_ref (fd);
+
+ afr_open_fd_fix (fd, this);
+
+ afr_do_zerofill(frame, this);
+
+ ret = 0;
+out:
+ if (ret < 0) {
+ if (transaction_frame) {
+ AFR_STACK_DESTROY (transaction_frame);
+ }
+ AFR_STACK_UNWIND (zerofill, frame, -1, op_errno, NULL,
+ NULL, NULL);
+ }
+
+ return 0;
+}
+
+/* }}} */
+
+
diff --git a/xlators/cluster/afr/src/afr-inode-write.h b/xlators/cluster/afr/src/afr-inode-write.h
index ed11079fd..8e93ca44a 100644
--- a/xlators/cluster/afr/src/afr-inode-write.h
+++ b/xlators/cluster/afr/src/afr-inode-write.h
@@ -68,4 +68,15 @@ int32_t
afr_fremovexattr (call_frame_t *frame, xlator_t *this,
fd_t *fd, const char *name, dict_t *xdata);
+int
+afr_discard (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
+ size_t len, dict_t *xdata);
+
+int
+afr_fallocate (call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t mode,
+ off_t offset, size_t len, dict_t *xdata);
+
+int
+afr_zerofill(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
+ size_t len, dict_t *xdata);
#endif /* __INODE_WRITE_H__ */
diff --git a/xlators/cluster/afr/src/afr-lk-common.c b/xlators/cluster/afr/src/afr-lk-common.c
index e2136089b..060d78f35 100644
--- a/xlators/cluster/afr/src/afr-lk-common.c
+++ b/xlators/cluster/afr/src/afr-lk-common.c
@@ -658,6 +658,7 @@ afr_unlock_inodelk_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
afr_internal_lock_t *int_lock = NULL;
afr_inodelk_t *inodelk = NULL;
int32_t child_index = (long)cookie;
+ afr_private_t *priv = NULL;
local = frame->local;
int_lock = &local->internal_lock;
@@ -666,9 +667,12 @@ afr_unlock_inodelk_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
AFR_UNLOCK_OP, NULL, op_ret,
op_errno, child_index);
+ priv = this->private;
+
if (op_ret < 0 && op_errno != ENOTCONN && op_errno != EBADFD) {
- gf_log (this->name, GF_LOG_INFO, "%s: unlock failed on %d "
- "unlock by %s", local->loc.path, child_index,
+ gf_log (this->name, GF_LOG_INFO, "%s: unlock failed on subvolume %s "
+ "with lock owner %s", local->loc.path,
+ priv->children[child_index]->name,
lkowner_utoa (&frame->root->lk_owner));
}
diff --git a/xlators/cluster/afr/src/afr-mem-types.h b/xlators/cluster/afr/src/afr-mem-types.h
index e01ab366f..73594f265 100644
--- a/xlators/cluster/afr/src/afr-mem-types.h
+++ b/xlators/cluster/afr/src/afr-mem-types.h
@@ -41,7 +41,10 @@ enum gf_afr_mem_types_ {
gf_afr_mt_shd_event_t,
gf_afr_mt_time_t,
gf_afr_mt_pos_data_t,
- gf_afr_mt_reply_t,
+ gf_afr_mt_reply_t,
+ gf_afr_mt_stats_t,
+ gf_afr_mt_shd_crawl_event_t,
+ gf_afr_mt_uint64_t,
gf_afr_mt_end
};
#endif
diff --git a/xlators/cluster/afr/src/afr-self-heald.c b/xlators/cluster/afr/src/afr-self-heald.c
index f33b04eed..1b48a1bca 100644
--- a/xlators/cluster/afr/src/afr-self-heald.c
+++ b/xlators/cluster/afr/src/afr-self-heald.c
@@ -25,7 +25,8 @@ typedef enum {
typedef enum {
HEAL = 1,
- INFO
+ INFO,
+ STATISTICS_TO_BE_HEALED,
} shd_crawl_op;
typedef struct shd_dump {
@@ -84,6 +85,33 @@ _loc_assign_gfid_path (loc_t *loc)
}
void
+_destroy_crawl_event_data (void *data)
+{
+ shd_crawl_event_t *crawl_event = NULL;
+
+ if (!data)
+ goto out;
+
+ crawl_event = (shd_crawl_event_t *)data;
+ GF_FREE (crawl_event->start_time_str);
+ GF_FREE (crawl_event->end_time_str);
+
+out:
+ return;
+}
+
+void
+_destroy_shd_event_data (void *data)
+{
+ shd_event_t *event = NULL;
+ if (!data)
+ goto out;
+ event = (shd_event_t*)data;
+ GF_FREE (event->path);
+out:
+ return;
+}
+void
shd_cleanup_event (void *event)
{
shd_event_t *shd_event = event;
@@ -128,6 +156,123 @@ _build_index_loc (xlator_t *this, loc_t *loc, char *name, loc_t *parent)
}
int
+_add_crawl_stats_to_dict (xlator_t *this, dict_t *output, int child,
+ shd_crawl_event_t *shd_event, struct timeval *tv)
+{
+ int ret = 0;
+ uint64_t count = 0;
+ char key[256] = {0};
+ int xl_id = 0;
+ uint64_t healed_count = 0;
+ uint64_t split_brain_count = 0;
+ uint64_t heal_failed_count = 0;
+ char *start_time_str = NULL;
+ char *end_time_str = NULL;
+ char *crawl_type = NULL;
+ int progress = -1;
+
+ healed_count = shd_event->healed_count;
+ split_brain_count = shd_event->split_brain_count;
+ heal_failed_count = shd_event->heal_failed_count;
+ start_time_str = shd_event->start_time_str;
+ end_time_str = shd_event->end_time_str;
+ crawl_type = shd_event->crawl_type;
+
+ if (!start_time_str) {
+ ret = -1;
+ goto out;
+ }
+
+
+ ret = dict_get_int32 (output, this->name, &xl_id);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "xl does not have id");
+ goto out;
+ }
+
+ snprintf (key, sizeof (key), "statistics-%d-%d-count", xl_id, child);
+ ret = dict_get_uint64 (output, key, &count);
+
+ snprintf (key, sizeof (key), "statistics_healed_cnt-%d-%d-%"PRIu64,
+ xl_id, child, count);
+ ret = dict_set_uint64(output, key, healed_count);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Could not add statistics_"
+ "healed_count to outout");
+ goto out;
+ }
+ snprintf (key, sizeof (key), "statistics_sb_cnt-%d-%d-%"PRIu64,
+ xl_id, child, count);
+ ret = dict_set_uint64 (output, key, split_brain_count);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Could not add statistics_"
+ "split_brain_count to outout");
+ goto out;
+ }
+ snprintf (key, sizeof (key), "statistics_crawl_type-%d-%d-%"PRIu64,
+ xl_id, child, count);
+ ret = dict_set_dynstr (output, key, gf_strdup (crawl_type));
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Could not add statistics_"
+ "crawl_type to output");
+ goto out;
+ }
+ snprintf (key, sizeof (key), "statistics_heal_failed_cnt-%d-%d-%"PRIu64,
+ xl_id, child, count);
+ ret = dict_set_uint64 (output, key, heal_failed_count);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Could not add statistics_"
+ "healed_failed_count to outout");
+ goto out;
+ }
+ snprintf (key, sizeof (key), "statistics_strt_time-%d-%d-%"PRIu64,
+ xl_id, child, count);
+ ret = dict_set_dynstr (output, key, gf_strdup(start_time_str));
+
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Could not add statistics_"
+ "crawl_start_time to outout");
+ goto out;
+ }
+
+ snprintf (key, sizeof (key), "statistics_end_time-%d-%d-%"PRIu64,
+ xl_id, child, count);
+
+ if (!end_time_str)
+ end_time_str = "Could not determine the end time";
+ ret = dict_set_dynstr (output, key, gf_strdup(end_time_str));
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Could not add statistics_"
+ "crawl_end_time to outout");
+ goto out;
+ }
+ snprintf (key, sizeof (key), "statistics_inprogress-%d-%d-%"PRIu64,
+ xl_id, child, count);
+
+ if (shd_event->crawl_inprogress == _gf_true)
+ progress = 1;
+ else
+ progress = 0;
+
+ ret = dict_set_int32 (output, key, progress);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Could not add statistics_"
+ "inprogress to outout");
+ goto out;
+ }
+
+ snprintf (key, sizeof (key), "statistics-%d-%d-count",xl_id, child);
+ ret = dict_set_uint64 (output, key, count + 1);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Could not increment the "
+ "counter.");
+ goto out;
+ }
+out:
+ return ret;
+}
+
+int
_add_path_to_dict (xlator_t *this, dict_t *output, int child, char *path,
struct timeval *tv, gf_boolean_t dyn)
{
@@ -233,6 +378,20 @@ out:
}
int
+_add_crawl_event_statistics_to_dict (circular_buffer_t *cb, void *data)
+{
+ int ret = 0;
+ shd_dump_t *dump_data = NULL;
+ shd_crawl_event_t *shd_event = NULL;
+
+ dump_data = data;
+ shd_event = cb->data;
+ ret = _add_crawl_stats_to_dict (dump_data->this, dump_data->dict,
+ dump_data->child, shd_event, &cb->tv);
+ return ret;
+}
+
+int
_add_eh_to_dict (xlator_t *this, eh_t *eh, dict_t *dict, int child)
{
shd_dump_t dump_data = {0};
@@ -244,6 +403,26 @@ _add_eh_to_dict (xlator_t *this, eh_t *eh, dict_t *dict, int child)
return 0;
}
+
+int
+_add_statistics_to_dict (xlator_t *this, dict_t *dict, int child)
+{
+ shd_dump_t dump_data = {0};
+ afr_private_t *priv = NULL;
+ afr_self_heald_t *shd = NULL;
+
+ priv = this->private;
+ shd = &priv->shd;
+
+ dump_data.this = this;
+ dump_data.dict = dict;
+ dump_data.child = child;
+ eh_dump (shd->statistics[child], &dump_data,
+ _add_crawl_event_statistics_to_dict);
+ return 0;
+
+}
+
void
_remove_stale_index (xlator_t *this, xlator_t *readdir_xl,
loc_t *parent, char *fname)
@@ -269,6 +448,46 @@ out:
}
int
+_count_hard_links_under_base_indices_dir (xlator_t *this,
+ afr_crawl_data_t *crawl_data,
+ gf_dirent_t *entry, loc_t *childloc,
+ loc_t *parentloc, struct iatt *iattr)
+{
+ xlator_t *readdir_xl = crawl_data->readdir_xl;
+ struct iatt parent = {0};
+ int ret = 0;
+ dict_t *output = NULL;
+ int xl_id = 0;
+ char key[256] = {0};
+ int child = -1;
+ uint64_t hardlinks = 0;
+
+ output = crawl_data->op_data;
+ child = crawl_data->child;
+
+ ret = syncop_lookup (readdir_xl, childloc, NULL, iattr, NULL, &parent);
+ if (ret)
+ goto out;
+
+ ret = dict_get_int32 (output, this->name, &xl_id);
+ if (ret)
+ goto out;
+
+ snprintf (key, sizeof (key), "%d-%d-hardlinks", xl_id, child);
+ ret = dict_get_uint64 (output, key, &hardlinks);
+
+ /*Removing the count of base_entry under indices/base_indicies and
+ * entry under indices/xattrop */
+ hardlinks = hardlinks + iattr->ia_nlink - 2;
+ ret = dict_set_uint64 (output, key, hardlinks);
+ if (ret)
+ goto out;
+
+out:
+ return ret;
+}
+
+int
_add_summary_to_dict (xlator_t *this, afr_crawl_data_t *crawl_data,
gf_dirent_t *entry,
loc_t *childloc, loc_t *parentloc, struct iatt *iattr)
@@ -307,16 +526,18 @@ _crawl_post_sh_action (xlator_t *this, loc_t *parent, loc_t *child,
int32_t op_ret, int32_t op_errno, dict_t *xattr_rsp,
afr_crawl_data_t *crawl_data)
{
- int ret = 0;
- afr_private_t *priv = NULL;
- afr_self_heald_t *shd = NULL;
- eh_t *eh = NULL;
- char *path = NULL;
- char gfid_str[64] = {0};
- shd_event_t *event = NULL;
- int32_t sh_failed = 0;
- gf_boolean_t split_brain = 0;
- int32_t actual_sh_done = 0;
+ int ret = 0;
+ afr_private_t *priv = NULL;
+ afr_self_heald_t *shd = NULL;
+ eh_t *eh = NULL;
+ char *path = NULL;
+ char gfid_str[64] = {0};
+ shd_event_t *event = NULL;
+ int32_t sh_failed = 0;
+ gf_boolean_t split_brain = 0;
+ int32_t actual_sh_done = 0;
+ shd_crawl_event_t **shd_crawl_event = NULL;
+
priv = this->private;
shd = &priv->shd;
if (crawl_data->crawl == INDEX) {
@@ -343,16 +564,19 @@ _crawl_post_sh_action (xlator_t *this, loc_t *parent, loc_t *child,
ret = dict_get_int32 (xattr_rsp, "actual-sh-done", &actual_sh_done);
}
- split_brain = afr_is_split_brain (this, child->inode);
+ shd_crawl_event = (shd_crawl_event_t**)(shd->crawl_events);
+ split_brain = afr_is_split_brain (this, child->inode);
if ((op_ret < 0 && op_errno == EIO) || split_brain) {
eh = shd->split_brain;
+ shd_crawl_event[crawl_data->child]->split_brain_count += 1;
} else if ((op_ret < 0) || sh_failed) {
eh = shd->heal_failed;
+ shd_crawl_event[crawl_data->child]->heal_failed_count += 1;
} else if (actual_sh_done == 1) {
- eh = shd->healed;
+ eh = shd->healed;
+ shd_crawl_event[crawl_data->child]->healed_count += 1;
}
-
ret = -1;
if (eh != NULL) {
@@ -408,10 +632,20 @@ _self_heal_entry (xlator_t *this, afr_crawl_data_t *crawl_data, gf_dirent_t *ent
struct iatt parentbuf = {0};
int ret = 0;
dict_t *xattr_rsp = NULL;
+ dict_t *xattr_req = NULL;
+
+ xattr_req = dict_new ();
+ if (!xattr_req) {
+ errno = ENOMEM;
+ ret = -1;
+ goto out;
+ }
+
+ ret = dict_set_int32 (xattr_req, "allow-sh-for-running-transaction", 1);
gf_log (this->name, GF_LOG_DEBUG, "lookup %s", child->path);
- ret = syncop_lookup (this, child, NULL,
+ ret = syncop_lookup (this, child, xattr_req,
iattr, &xattr_rsp, &parentbuf);
_crawl_post_sh_action (this, parent, child, ret, errno, xattr_rsp,
crawl_data);
@@ -420,6 +654,9 @@ _self_heal_entry (xlator_t *this, afr_crawl_data_t *crawl_data, gf_dirent_t *ent
if (ret == 0)
ret = _link_inode_update_loc (this, child, iattr);
+out:
+ if (xattr_req)
+ dict_unref(xattr_req);
return ret;
}
@@ -528,12 +765,20 @@ _do_crawl_op_on_local_subvols (xlator_t *this, afr_crawl_type_t crawl,
status = "Started self-heal";
_do_self_heal_on_subvol (this, i,
crawl);
- } else if (output) {
+ } else if (output && (op == INFO)) {
status = "";
afr_start_crawl (this, i, INDEX,
_add_summary_to_dict,
output, _gf_false, 0,
NULL);
+ } else if (output &&
+ (op == STATISTICS_TO_BE_HEALED)) {
+ status = "";
+ afr_start_crawl (this, i,
+ INDEX_TO_BE_HEALED,
+ _count_hard_links_under_base_indices_dir,
+ output, _gf_false,
+ 0, NULL);
}
}
if (output) {
@@ -567,8 +812,103 @@ _get_index_summary_on_local_subvols (xlator_t *this, dict_t *output)
return _do_crawl_op_on_local_subvols (this, INDEX, INFO, output);
}
+void
+afr_fill_completed_crawl_statistics_to_dict (xlator_t *this, dict_t *dict)
+{
+ afr_private_t *priv = NULL;
+ afr_self_heald_t *shd = NULL;
+ int i = 0;
+ priv = this->private;
+ shd= &priv->shd;
+ for (i = 0; i < priv->child_count; i++) {
+ if (shd->pos[i] != AFR_POS_LOCAL)
+ continue;
+ _add_statistics_to_dict (this, dict, i);
+ }
+
+ return ;
+}
+
+static void
+reset_crawl_event (shd_crawl_event_t *crawl_event)
+{
+ crawl_event->healed_count = 0;
+ crawl_event->split_brain_count = 0;
+ crawl_event->heal_failed_count = 0;
+ GF_FREE (crawl_event->start_time_str);
+ crawl_event->start_time_str = NULL;
+ crawl_event->end_time_str = NULL;
+ crawl_event->crawl_type = NULL;
+ crawl_event->crawl_inprogress = _gf_false;
+ return;
+}
+
+static void
+afr_copy_crawl_event_struct (shd_crawl_event_t *src, shd_crawl_event_t *dst)
+{
+ dst->healed_count = src->healed_count;
+ dst->split_brain_count = src->split_brain_count;
+ dst->heal_failed_count = src->heal_failed_count;
+ dst->start_time_str = gf_strdup (src->start_time_str);
+ dst->end_time_str = "Crawl is already in progress";
+ dst->crawl_type = src->crawl_type;
+ dst->crawl_inprogress = _gf_true;
+ return;
+}
+
+static int
+afr_fill_crawl_statistics_of_running_crawl(xlator_t *this, dict_t *dict)
+{
+ shd_crawl_event_t *evnt = NULL;
+ int ret = 0;
+ afr_private_t *priv = NULL;
+ afr_self_heald_t *shd = NULL;
+ int i = 0;
+ priv = this->private;
+ shd = &priv->shd;
+
+ evnt = GF_CALLOC (1, sizeof (shd_crawl_event_t),
+ gf_afr_mt_shd_crawl_event_t);
+ if (!evnt) {
+ ret = -1;
+ goto out;
+ }
+ LOCK (&priv->lock);
+ {
+ for (i = 0; i < priv->child_count; i++) {
+ if (shd->pos[i] != AFR_POS_LOCAL)
+ continue;
+
+ reset_crawl_event (evnt);
+
+ if (!shd->crawl_events[i]) {
+ continue;
+ }
+
+ afr_copy_crawl_event_struct (shd->crawl_events[i],
+ evnt);
+ _add_crawl_stats_to_dict (this, dict, i, evnt, NULL);
+
+ }
+ }
+ UNLOCK (&priv->lock);
+ reset_crawl_event (evnt);
+ GF_FREE (evnt);
+
+out:
+ return ret;
+}
+
+static int
+_add_local_subvols_crawl_statistics_to_dict (xlator_t *this, dict_t *dict)
+{
+ int ret = 0;
+ afr_fill_completed_crawl_statistics_to_dict (this, dict);
+ ret = afr_fill_crawl_statistics_of_running_crawl (this, dict);
+ return ret;
+}
int
-_add_all_subvols_eh_to_dict (xlator_t *this, eh_t *eh, dict_t *dict)
+_add_local_subvols_eh_to_dict (xlator_t *this, eh_t *eh, dict_t *dict)
{
afr_private_t *priv = NULL;
afr_self_heald_t *shd = NULL;
@@ -618,16 +958,25 @@ afr_xl_op (xlator_t *this, dict_t *input, dict_t *output)
ret = 0;
break;
case GF_AFR_OP_HEALED_FILES:
- ret = _add_all_subvols_eh_to_dict (this, shd->healed, output);
+ ret = _add_local_subvols_eh_to_dict (this, shd->healed, output);
break;
case GF_AFR_OP_HEAL_FAILED_FILES:
- ret = _add_all_subvols_eh_to_dict (this, shd->heal_failed,
+ ret = _add_local_subvols_eh_to_dict (this, shd->heal_failed,
output);
break;
case GF_AFR_OP_SPLIT_BRAIN_FILES:
- ret = _add_all_subvols_eh_to_dict (this, shd->split_brain,
+ ret = _add_local_subvols_eh_to_dict (this, shd->split_brain,
output);
break;
+ case GF_AFR_OP_STATISTICS:
+ ret = _add_local_subvols_crawl_statistics_to_dict (this, output);
+ break;
+ case GF_AFR_OP_STATISTICS_HEAL_COUNT:
+ case GF_AFR_OP_STATISTICS_HEAL_COUNT_PER_REPLICA:
+ ret = _do_crawl_op_on_local_subvols (this, INDEX_TO_BE_HEALED,
+ STATISTICS_TO_BE_HEALED,
+ output);
+ break;
default:
gf_log (this->name, GF_LOG_ERROR, "Unknown set op %d", op);
break;
@@ -642,7 +991,7 @@ afr_poll_self_heal (void *data)
{
afr_private_t *priv = NULL;
afr_self_heald_t *shd = NULL;
- struct timeval timeout = {0};
+ struct timespec timeout = {0};
xlator_t *this = NULL;
long child = (long)data;
gf_timer_t *old_timer = NULL;
@@ -666,7 +1015,7 @@ afr_poll_self_heal (void *data)
if (shd->enabled && (shd->pos[child] == AFR_POS_LOCAL))
_do_self_heal_on_subvol (this, child, INDEX);
timeout.tv_sec = shd->timeout;
- timeout.tv_usec = 0;
+ timeout.tv_nsec = 0;
//notify and previous timer should be synchronized.
LOCK (&priv->lock);
{
@@ -800,6 +1149,7 @@ afr_crawl_build_start_loc (xlator_t *this, afr_crawl_data_t *crawl_data,
afr_private_t *priv = NULL;
dict_t *xattr = NULL;
void *index_gfid = NULL;
+ void *base_indices_holder_vgfid = NULL;
loc_t rootloc = {0};
struct iatt iattr = {0};
struct iatt parent = {0};
@@ -809,7 +1159,7 @@ afr_crawl_build_start_loc (xlator_t *this, afr_crawl_data_t *crawl_data,
priv = this->private;
if (crawl_data->crawl == FULL) {
afr_build_root_loc (this, dirloc);
- } else {
+ } else if (crawl_data->crawl == INDEX) {
afr_build_root_loc (this, &rootloc);
ret = syncop_getxattr (readdir_xl, &rootloc, &xattr,
GF_XATTROP_INDEX_GFID);
@@ -843,6 +1193,47 @@ afr_crawl_build_start_loc (xlator_t *this, afr_crawl_data_t *crawl_data,
ret = _link_inode_update_loc (this, dirloc, &iattr);
if (ret)
goto out;
+ } else if (crawl_data->crawl == INDEX_TO_BE_HEALED) {
+ afr_build_root_loc (this, &rootloc);
+ ret = syncop_getxattr (readdir_xl, &rootloc, &xattr,
+ GF_BASE_INDICES_HOLDER_GFID);
+ if (ret < 0)
+ goto out;
+ ret = dict_get_ptr (xattr, GF_BASE_INDICES_HOLDER_GFID,
+ &base_indices_holder_vgfid);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR, "index gfid empty "
+ "on %s", readdir_xl->name);
+ ret = -1;
+ goto out;
+ }
+ if (!base_indices_holder_vgfid) {
+ gf_log (this->name, GF_LOG_ERROR, "Base indices holder"
+ "virtual gfid is null on %s", readdir_xl->name);
+ ret = -1;
+ goto out;
+ }
+ uuid_copy (dirloc->gfid, base_indices_holder_vgfid);
+ dirloc->path = "";
+ dirloc->inode = inode_new (priv->root_inode->table);
+ ret = syncop_lookup (readdir_xl, dirloc, NULL, &iattr, NULL,
+ &parent);
+ if (ret < 0) {
+ if (errno != ENOENT) {
+ gf_log (this->name, GF_LOG_ERROR, "lookup "
+ "failed for base_indices_holder dir"
+ " on %s - (%s)", readdir_xl->name,
+ strerror (errno));
+
+ } else {
+ gf_log (this->name, GF_LOG_ERROR, "base_indices"
+ "_holder is not yet created.");
+ }
+ goto out;
+ }
+ ret = _link_inode_update_loc (this, dirloc, &iattr);
+ if (ret)
+ goto out;
}
ret = 0;
out:
@@ -907,6 +1298,16 @@ afr_crawl_build_child_loc (xlator_t *this, loc_t *child, loc_t *parent,
priv = this->private;
if (crawl_data->crawl == FULL) {
ret = afr_build_child_loc (this, child, parent, entry->d_name);
+ } else if (crawl_data->crawl == INDEX_TO_BE_HEALED) {
+ ret = _build_index_loc (this, child, entry->d_name, parent);
+ if (ret)
+ goto out;
+ child->inode = inode_new (priv->root_inode->table);
+ if (!child->inode) {
+ ret = -1;
+ goto out;
+ }
+ child->path = NULL;
} else {
child->inode = inode_new (priv->root_inode->table);
if (!child->inode)
@@ -956,10 +1357,14 @@ _process_entries (xlator_t *this, loc_t *parentloc, gf_dirent_t *entries,
ret = crawl_data->process_entry (this, crawl_data, entry,
&entry_loc, parentloc, &iattr);
- if (ret)
+ if (crawl_data->crawl == INDEX_TO_BE_HEALED && ret) {
+ goto out;
+ } else if (ret) {
continue;
+ }
- if (crawl_data->crawl == INDEX)
+ if ((crawl_data->crawl == INDEX) ||
+ (crawl_data->crawl == INDEX_TO_BE_HEALED))
continue;
if (!IA_ISDIR (iattr.ia_type))
@@ -974,6 +1379,10 @@ _process_entries (xlator_t *this, loc_t *parentloc, gf_dirent_t *entries,
}
ret = 0;
out:
+ if ((crawl_data->crawl == INDEX_TO_BE_HEALED) && ret) {
+ gf_log (this->name, GF_LOG_ERROR,"Failed to get the hardlink "
+ "count");
+ }
loc_wipe (&entry_loc);
return ret;
}
@@ -1021,6 +1430,9 @@ _crawl_directory (fd_t *fd, loc_t *loc, afr_crawl_data_t *crawl_data)
ret = _process_entries (this, loc, &entries, &offset,
crawl_data);
+ if ((ret < 0) && (crawl_data->crawl == INDEX_TO_BE_HEALED)) {
+ goto out;
+ }
gf_dirent_free (&entries);
free_entries = _gf_false;
}
@@ -1126,8 +1538,13 @@ afr_dir_crawl (void *data)
goto out;
ret = afr_crawl_opendir (this, crawl_data, &fd, &dirloc);
- if (ret)
+ if (ret) {
+ if (crawl_data->crawl == INDEX_TO_BE_HEALED) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to open base_"
+ "indices_holder");
+ }
goto out;
+ }
ret = _crawl_directory (fd, &dirloc, crawl_data);
if (ret)
@@ -1141,12 +1558,102 @@ afr_dir_crawl (void *data)
out:
if (fd)
fd_unref (fd);
- if (crawl_data->crawl == INDEX)
+ if ((crawl_data->crawl == INDEX) ||
+ (crawl_data->crawl == INDEX_TO_BE_HEALED ))
dirloc.path = NULL;
loc_wipe (&dirloc);
return ret;
}
+char *
+get_crawl_type_in_string (afr_crawl_type_t crawl)
+{
+ char *index = "INDEX";
+ char *full = "FULL";
+ char *crawl_type = NULL;
+
+ if (crawl == INDEX){
+ crawl_type = index;
+ } else if (crawl == FULL) {
+ crawl_type = full;
+ }
+
+ return crawl_type;
+}
+
+static int
+afr_allocate_crawl_event (xlator_t *this, int child, afr_crawl_type_t crawl)
+{
+ afr_private_t *priv = NULL;
+ afr_self_heald_t *shd = NULL;
+ int ret = 0;
+ shd_crawl_event_t *crawl_event = NULL;
+ time_t get_time = 0;
+
+ priv = this->private;
+ shd = &priv->shd;
+
+ crawl_event = GF_CALLOC (sizeof (shd_crawl_event_t), 1,
+ gf_afr_mt_shd_crawl_event_t);
+ if (!crawl_event) {
+ ret = -1;
+ goto out;
+ }
+
+ get_time = time(NULL);
+ if (get_time == ((time_t)-1)) {
+ ret = -1;
+ goto out;
+ }
+
+ crawl_event->start_time_str = gf_strdup (ctime(&get_time));
+
+ crawl_event->crawl_type = get_crawl_type_in_string (crawl);
+ if (!crawl_event->crawl_type) {
+ ret = -1;
+ goto out;
+ }
+ LOCK (&priv->lock);
+ {
+ shd->crawl_events[child] = crawl_event;
+ }
+ UNLOCK (&priv->lock);
+ ret = 0;
+out:
+ return ret;
+
+}
+
+static int
+afr_put_crawl_event_in_eh (xlator_t *this, int child)
+{
+ afr_private_t *priv = NULL;
+ afr_self_heald_t *shd = NULL;
+ int ret = 0;
+ time_t get_time = 0;
+ shd_crawl_event_t **crawl_event = NULL;
+
+ priv = this->private;
+ shd = &priv->shd;
+
+ get_time = time(NULL);
+ if (get_time == ((time_t)-1)) {
+ ret = -1;
+ goto out;
+ }
+ crawl_event = (shd_crawl_event_t**)shd->crawl_events;
+ LOCK (&priv->lock);
+ {
+ crawl_event[child]->end_time_str = gf_strdup (ctime(&get_time));
+ ret = eh_save_history (shd->statistics[child],
+ crawl_event[child]);
+ crawl_event[child] = NULL;
+ }
+ UNLOCK (&priv->lock);
+out:
+ return ret;
+}
+
static int
afr_dir_exclusive_crawl (void *data)
{
@@ -1182,7 +1689,15 @@ afr_dir_exclusive_crawl (void *data)
}
do {
+ ret = afr_allocate_crawl_event (this, child, crawl_data->crawl);
+ if (ret)
+ goto out;
afr_dir_crawl (data);
+
+ ret = afr_put_crawl_event_in_eh (this, child);
+ if (ret < 0)
+ goto out;
+
LOCK (&priv->lock);
{
if (shd->pending[child] != NONE) {
@@ -1270,4 +1785,3 @@ afr_set_root_gfid (dict_t *dict)
return ret;
}
-
diff --git a/xlators/cluster/afr/src/afr-self-heald.h b/xlators/cluster/afr/src/afr-self-heald.h
index 32a8aaca5..e0c083754 100644
--- a/xlators/cluster/afr/src/afr-self-heald.h
+++ b/xlators/cluster/afr/src/afr-self-heald.h
@@ -29,6 +29,19 @@ typedef struct afr_crawl_data_ {
struct iatt *iattr);
} afr_crawl_data_t;
+typedef struct crawl_event_stats_ {
+ uint64_t healed_count;
+ uint64_t split_brain_count;
+ uint64_t heal_failed_count;
+ char *start_time_str;
+ char *end_time_str;
+ char *crawl_type;
+ gf_boolean_t crawl_inprogress;
+} shd_crawl_event_t;
+
+void _destroy_crawl_event_data (void *data);
+void _destroy_shd_event_data (void *data);
+
typedef int (*process_entry_cbk_t) (xlator_t *this, afr_crawl_data_t *crawl_data,
gf_dirent_t *entry, loc_t *child, loc_t *parent,
struct iatt *iattr);
diff --git a/xlators/cluster/afr/src/afr-transaction.c b/xlators/cluster/afr/src/afr-transaction.c
index 0b91f466e..20306e469 100644
--- a/xlators/cluster/afr/src/afr-transaction.c
+++ b/xlators/cluster/afr/src/afr-transaction.c
@@ -1699,7 +1699,7 @@ afr_delayed_changelog_post_op (xlator_t *this, call_frame_t *frame, fd_t *fd,
{
afr_fd_ctx_t *fd_ctx = NULL;
call_frame_t *prev_frame = NULL;
- struct timeval delta = {0, };
+ struct timespec delta = {0, };
afr_private_t *priv = NULL;
afr_local_t *local = NULL;
@@ -1710,7 +1710,7 @@ afr_delayed_changelog_post_op (xlator_t *this, call_frame_t *frame, fd_t *fd,
goto out;
delta.tv_sec = priv->post_op_delay_secs;
- delta.tv_usec = 0;
+ delta.tv_nsec = 0;
pthread_mutex_lock (&fd_ctx->delay_lock);
{
diff --git a/xlators/cluster/afr/src/afr.c b/xlators/cluster/afr/src/afr.c
index 4338b799a..c724eb2ae 100644
--- a/xlators/cluster/afr/src/afr.c
+++ b/xlators/cluster/afr/src/afr.c
@@ -388,7 +388,8 @@ init (xlator_t *this)
i++;
}
- ret = gf_asprintf (&priv->sh_domain, "%s-self-heal", this->name);
+ ret = gf_asprintf (&priv->sh_domain, AFR_SH_DATA_DOMAIN_FMT,
+ this->name);
if (-1 == ret) {
ret = -ENOMEM;
goto out;
@@ -438,15 +439,18 @@ init (xlator_t *this)
if (!priv->shd.timer)
goto out;
- priv->shd.healed = eh_new (AFR_EH_HEALED_LIMIT, _gf_false);
+ priv->shd.healed = eh_new (AFR_EH_HEALED_LIMIT, _gf_false,
+ _destroy_shd_event_data);
if (!priv->shd.healed)
goto out;
- priv->shd.heal_failed = eh_new (AFR_EH_HEAL_FAIL_LIMIT, _gf_false);
+ priv->shd.heal_failed = eh_new (AFR_EH_HEAL_FAIL_LIMIT, _gf_false,
+ _destroy_shd_event_data);
if (!priv->shd.heal_failed)
goto out;
- priv->shd.split_brain = eh_new (AFR_EH_SPLIT_BRAIN_LIMIT, _gf_false);
+ priv->shd.split_brain = eh_new (AFR_EH_SPLIT_BRAIN_LIMIT, _gf_false,
+ _destroy_shd_event_data);
if (!priv->shd.split_brain)
goto out;
@@ -456,7 +460,9 @@ init (xlator_t *this)
priv->root_inode = inode_ref (this->itable->root);
GF_OPTION_INIT ("node-uuid", priv->shd.node_uuid, str, out);
GF_OPTION_INIT ("heal-timeout", priv->shd.timeout, int32, out);
-
+ ret = afr_initialise_statistics (this);
+ if (ret)
+ goto out;
ret = 0;
out:
return ret;
@@ -493,6 +499,7 @@ struct xlator_fops fops = {
.fentrylk = afr_fentrylk,
.fallocate = afr_fallocate,
.discard = afr_discard,
+ .zerofill = afr_zerofill,
/* inode read */
.access = afr_access,
diff --git a/xlators/cluster/afr/src/afr.h b/xlators/cluster/afr/src/afr.h
index 70c5a96a7..21064db58 100644
--- a/xlators/cluster/afr/src/afr.h
+++ b/xlators/cluster/afr/src/afr.h
@@ -28,6 +28,7 @@
#define AFR_XATTR_PREFIX "trusted.afr"
#define AFR_PATHINFO_HEADER "REPLICATE:"
#define AFR_SH_READDIR_SIZE_KEY "self-heal-readdir-size"
+#define AFR_SH_DATA_DOMAIN_FMT "%s:self-heal"
#define AFR_LOCKEE_COUNT_MAX 3
#define AFR_DOM_COUNT_MAX 3
@@ -93,21 +94,24 @@ typedef struct afr_inode_ctx_ {
typedef enum {
NONE,
INDEX,
+ INDEX_TO_BE_HEALED,
FULL,
} afr_crawl_type_t;
typedef struct afr_self_heald_ {
- gf_boolean_t enabled;
- gf_boolean_t iamshd;
- afr_crawl_type_t *pending;
- gf_boolean_t *inprogress;
- afr_child_pos_t *pos;
- gf_timer_t **timer;
- eh_t *healed;
- eh_t *heal_failed;
- eh_t *split_brain;
- char *node_uuid;
- int timeout;
+ gf_boolean_t enabled;
+ gf_boolean_t iamshd;
+ afr_crawl_type_t *pending;
+ gf_boolean_t *inprogress;
+ afr_child_pos_t *pos;
+ gf_timer_t **timer;
+ eh_t *healed;
+ eh_t *heal_failed;
+ eh_t *split_brain;
+ eh_t **statistics;
+ void **crawl_events;
+ char *node_uuid;
+ int timeout;
} afr_self_heald_t;
typedef struct _afr_private {
@@ -493,20 +497,23 @@ typedef struct _afr_local {
int optimistic_change_log;
gf_boolean_t delayed_post_op;
+
/* Is the current writev() going to perform a stable write?
i.e, is fd->flags or @flags writev param have O_SYNC or
O_DSYNC?
*/
- gf_boolean_t stable_write;
+ gf_boolean_t stable_write;
- /* This write appended to the file. Nnot necessarily O_APPEND,
- just means the offset of write was at the end of file.
- */
- gf_boolean_t append_write;
+ /* This write appended to the file. Nnot necessarily O_APPEND,
+ just means the offset of write was at the end of file.
+ */
+ gf_boolean_t append_write;
- /*
- This struct contains the arguments for the "continuation"
- (scheme-like) of fops
+ int allow_sh_for_running_transaction;
+
+
+ /* This struct contains the arguments for the "continuation"
+ (scheme-like) of fops
*/
int op;
@@ -602,7 +609,9 @@ typedef struct _afr_local {
struct {
struct iatt prebuf;
struct iatt postbuf;
+ } inode_wfop; //common structure for all inode-write-fops
+ struct {
int32_t op_ret;
struct iovec *vector;
@@ -613,34 +622,21 @@ typedef struct _afr_local {
} writev;
struct {
- struct iatt prebuf;
- struct iatt postbuf;
- } fsync;
-
- struct {
off_t offset;
- struct iatt prebuf;
- struct iatt postbuf;
} truncate;
struct {
off_t offset;
- struct iatt prebuf;
- struct iatt postbuf;
} ftruncate;
struct {
struct iatt in_buf;
int32_t valid;
- struct iatt preop_buf;
- struct iatt postop_buf;
} setattr;
struct {
struct iatt in_buf;
int32_t valid;
- struct iatt preop_buf;
- struct iatt postop_buf;
} fsetattr;
struct {
@@ -707,17 +703,21 @@ typedef struct _afr_local {
int32_t mode;
off_t offset;
size_t len;
- struct iatt prebuf;
- struct iatt postbuf;
} fallocate;
struct {
off_t offset;
size_t len;
- struct iatt prebuf;
- struct iatt postbuf;
} discard;
+ struct {
+ off_t offset;
+ size_t len;
+ struct iatt prebuf;
+ struct iatt postbuf;
+ } zerofill;
+
+
} cont;
struct {
@@ -1170,6 +1170,27 @@ afr_xattr_array_destroy (dict_t **xattr, unsigned int child_count);
} while (0);
+#define AFR_SBRAIN_MSG "Failed on %s as split-brain is seen. Returning EIO."
+
+#define AFR_SBRAIN_CHECK_FD(fd, label) do { \
+ if (fd->inode && afr_is_split_brain (this, fd->inode)) { \
+ op_errno = EIO; \
+ gf_log (this->name, GF_LOG_WARNING, \
+ AFR_SBRAIN_MSG ,uuid_utoa (fd->inode->gfid)); \
+ goto label; \
+ } \
+} while (0)
+
+#define AFR_SBRAIN_CHECK_LOC(loc, label) do { \
+ if (loc->inode && afr_is_split_brain (this, loc->inode)) { \
+ op_errno = EIO; \
+ loc_path (loc, NULL); \
+ gf_log (this->name, GF_LOG_WARNING, \
+ AFR_SBRAIN_MSG , loc->path); \
+ goto label; \
+ } \
+} while (0)
+
int
afr_fd_report_unstable_write (xlator_t *this, fd_t *fd);
diff --git a/xlators/cluster/dht/src/dht-common.c b/xlators/cluster/dht/src/dht-common.c
index b1fee655b..8f61339e6 100644
--- a/xlators/cluster/dht/src/dht-common.c
+++ b/xlators/cluster/dht/src/dht-common.c
@@ -22,6 +22,7 @@
#include "dht-common.h"
#include "defaults.h"
#include "byte-order.h"
+#include "glusterfs-acl.h"
#include <sys/time.h>
#include <libgen.h>
@@ -154,7 +155,6 @@ dht_discover_complete (xlator_t *this, call_frame_t *discover_frame)
int ret = -1;
dht_layout_t *layout = NULL;
dht_conf_t *conf = NULL;
- uint32_t missing = 0;
local = discover_frame->local;
layout = local->layout;
@@ -191,33 +191,20 @@ dht_discover_complete (xlator_t *this, call_frame_t *discover_frame)
goto out;
}
} else {
- ret = dht_layout_normalize (this, &local->loc, layout,
- &missing);
- if (ret < 0) {
- gf_log (this->name, GF_LOG_DEBUG,
- "normalizing failed on %s (internal error)",
- local->loc.path);
- op_errno = EIO;
- goto out;
- }
- if (missing == conf->subvolume_cnt) {
+ ret = dht_layout_normalize (this, &local->loc, layout);
+ if ((ret < 0) || ((ret > 0) && (local->op_ret != 0))) {
+ /* either the layout is incorrect or the directory is
+ * not found even in one subvolume.
+ */
gf_log (this->name, GF_LOG_DEBUG,
- "normalizing failed on %s, ENOENT errors: %u)",
- local->loc.path, missing);
- op_errno = ENOENT;