| /* |
| * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
| * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. |
| * |
| * This copyrighted material is made available to anyone wishing to use, |
| * modify, copy, or redistribute it subject to the terms and conditions |
| * of the GNU General Public License v.2. |
| */ |
| |
| #include <linux/sched.h> |
| #include <linux/slab.h> |
| #include <linux/spinlock.h> |
| #include <linux/completion.h> |
| #include <linux/buffer_head.h> |
| #include <linux/delay.h> |
| #include <linux/gfs2_ondisk.h> |
| #include <asm/semaphore.h> |
| |
| #include "gfs2.h" |
| #include "lm_interface.h" |
| #include "incore.h" |
| #include "glock.h" |
| #include "lm.h" |
| #include "super.h" |
| #include "util.h" |
| #include "lvb.h" |
| |
| /** |
| * gfs2_lm_mount - mount a locking protocol |
| * @sdp: the filesystem |
| * @args: mount arguements |
| * @silent: if 1, don't complain if the FS isn't a GFS2 fs |
| * |
| * Returns: errno |
| */ |
| |
| int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) |
| { |
| char *proto = sdp->sd_proto_name; |
| char *table = sdp->sd_table_name; |
| int flags = 0; |
| int error; |
| |
| if (sdp->sd_args.ar_spectator) |
| flags |= LM_MFLAG_SPECTATOR; |
| |
| fs_info(sdp, "Trying to join cluster \"%s\", \"%s\"\n", proto, table); |
| |
| error = gfs2_mount_lockproto(proto, table, sdp->sd_args.ar_hostdata, |
| gfs2_glock_cb, sdp, |
| GFS2_MIN_LVB_SIZE, flags, |
| &sdp->sd_lockstruct, &sdp->sd_kobj); |
| if (error) { |
| fs_info(sdp, "can't mount proto=%s, table=%s, hostdata=%s\n", |
| proto, table, sdp->sd_args.ar_hostdata); |
| goto out; |
| } |
| |
| if (gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lockspace) || |
| gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_ops) || |
| gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lvb_size >= |
| GFS2_MIN_LVB_SIZE)) { |
| gfs2_unmount_lockproto(&sdp->sd_lockstruct); |
| goto out; |
| } |
| |
| if (sdp->sd_args.ar_spectator) |
| snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s", table); |
| else |
| snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table, |
| sdp->sd_lockstruct.ls_jid); |
| |
| fs_info(sdp, "Joined cluster. Now mounting FS...\n"); |
| |
| if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) && |
| !sdp->sd_args.ar_ignore_local_fs) { |
| sdp->sd_args.ar_localflocks = 1; |
| sdp->sd_args.ar_localcaching = 1; |
| } |
| |
| out: |
| return error; |
| } |
| |
| void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp) |
| { |
| if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| sdp->sd_lockstruct.ls_ops->lm_others_may_mount( |
| sdp->sd_lockstruct.ls_lockspace); |
| } |
| |
| void gfs2_lm_unmount(struct gfs2_sbd *sdp) |
| { |
| if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| gfs2_unmount_lockproto(&sdp->sd_lockstruct); |
| } |
| |
| int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) |
| { |
| va_list args; |
| |
| if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags)) |
| return 0; |
| |
| va_start(args, fmt); |
| vprintk(fmt, args); |
| va_end(args); |
| |
| fs_err(sdp, "about to withdraw from the cluster\n"); |
| BUG_ON(sdp->sd_args.ar_debug); |
| |
| |
| fs_err(sdp, "waiting for outstanding I/O\n"); |
| |
| /* FIXME: suspend dm device so oustanding bio's complete |
| and all further io requests fail */ |
| |
| fs_err(sdp, "telling LM to withdraw\n"); |
| gfs2_withdraw_lockproto(&sdp->sd_lockstruct); |
| fs_err(sdp, "withdrawn\n"); |
| dump_stack(); |
| |
| return -1; |
| } |
| |
| int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name, |
| lm_lock_t **lockp) |
| { |
| int error; |
| if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| error = -EIO; |
| else |
| error = sdp->sd_lockstruct.ls_ops->lm_get_lock( |
| sdp->sd_lockstruct.ls_lockspace, name, lockp); |
| return error; |
| } |
| |
| void gfs2_lm_put_lock(struct gfs2_sbd *sdp, lm_lock_t *lock) |
| { |
| if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| sdp->sd_lockstruct.ls_ops->lm_put_lock(lock); |
| } |
| |
| unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, lm_lock_t *lock, |
| unsigned int cur_state, unsigned int req_state, |
| unsigned int flags) |
| { |
| int ret; |
| if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| ret = 0; |
| else |
| ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, |
| cur_state, |
| req_state, flags); |
| return ret; |
| } |
| |
| unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, lm_lock_t *lock, |
| unsigned int cur_state) |
| { |
| int ret; |
| if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| ret = 0; |
| else |
| ret = sdp->sd_lockstruct.ls_ops->lm_unlock(lock, cur_state); |
| return ret; |
| } |
| |
| void gfs2_lm_cancel(struct gfs2_sbd *sdp, lm_lock_t *lock) |
| { |
| if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| sdp->sd_lockstruct.ls_ops->lm_cancel(lock); |
| } |
| |
| int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char **lvbp) |
| { |
| int error; |
| if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| error = -EIO; |
| else |
| error = sdp->sd_lockstruct.ls_ops->lm_hold_lvb(lock, lvbp); |
| return error; |
| } |
| |
| void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char *lvb) |
| { |
| if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(lock, lvb); |
| } |
| |
| void gfs2_lm_sync_lvb(struct gfs2_sbd *sdp, lm_lock_t *lock, char *lvb) |
| { |
| if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| sdp->sd_lockstruct.ls_ops->lm_sync_lvb(lock, lvb); |
| } |
| |
| int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name, |
| struct file *file, struct file_lock *fl) |
| { |
| int error; |
| if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| error = -EIO; |
| else |
| error = sdp->sd_lockstruct.ls_ops->lm_plock_get( |
| sdp->sd_lockstruct.ls_lockspace, |
| name, file, fl); |
| return error; |
| } |
| |
| int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name, |
| struct file *file, int cmd, struct file_lock *fl) |
| { |
| int error; |
| if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| error = -EIO; |
| else |
| error = sdp->sd_lockstruct.ls_ops->lm_plock( |
| sdp->sd_lockstruct.ls_lockspace, |
| name, file, cmd, fl); |
| return error; |
| } |
| |
| int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name, |
| struct file *file, struct file_lock *fl) |
| { |
| int error; |
| if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| error = -EIO; |
| else |
| error = sdp->sd_lockstruct.ls_ops->lm_punlock( |
| sdp->sd_lockstruct.ls_lockspace, |
| name, file, fl); |
| return error; |
| } |
| |
| void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid, |
| unsigned int message) |
| { |
| if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
| sdp->sd_lockstruct.ls_ops->lm_recovery_done( |
| sdp->sd_lockstruct.ls_lockspace, jid, message); |
| } |
| |