diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-10 16:56:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-10 16:56:13 -0400 |
commit | 1b21f458ddbc8fb6fceeb68158e9e04b2571dabd (patch) | |
tree | 6ad7a02eba52a17e7a5d2e5de07b2918705c97bb /fs/dlm/user.c | |
parent | 01370f0603f8435d415a19f7e62d1bab826c3589 (diff) | |
parent | 3ebf44902f77537b5784eb5059c2b78d8b5a920a (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw
* git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw: (57 commits)
[GFS2] Accept old format NFS filehandles
[GFS2] Small fixes to logging code
[DLM] dump more lock values
[GFS2] Remove i_mode passing from NFS File Handle
[GFS2] Obtaining no_formal_ino from directory entry
[GFS2] git-gfs2-nmw-build-fix
[GFS2] System won't suspend with GFS2 file system mounted
[GFS2] remounting w/o acl option leaves acls enabled
[GFS2] inode size inconsistency
[DLM] Telnet to port 21064 can stop all lockspaces
[GFS2] Fix gfs2_block_truncate_page err return
[GFS2] Addendum to the journaled file/unmount patch
[GFS2] Simplify multiple glock aquisition
[GFS2] assertion failure after writing to journaled file, umount
[GFS2] Use zero_user_page() in stuffed_readpage()
[GFS2] Remove bogus '\0' in rgrp.c
[GFS2] Journaled file write/unstuff bug
[DLM] don't require FS flag on all nodes
[GFS2] Fix deallocation issues
[GFS2] return conflicts for GETLK
...
Diffstat (limited to 'fs/dlm/user.c')
-rw-r--r-- | fs/dlm/user.c | 129 |
1 files changed, 99 insertions, 30 deletions
diff --git a/fs/dlm/user.c b/fs/dlm/user.c index b0201ec325a7..6438941ab1f8 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c | |||
@@ -33,16 +33,17 @@ static const struct file_operations device_fops; | |||
33 | struct dlm_lock_params32 { | 33 | struct dlm_lock_params32 { |
34 | __u8 mode; | 34 | __u8 mode; |
35 | __u8 namelen; | 35 | __u8 namelen; |
36 | __u16 flags; | 36 | __u16 unused; |
37 | __u32 flags; | ||
37 | __u32 lkid; | 38 | __u32 lkid; |
38 | __u32 parent; | 39 | __u32 parent; |
39 | 40 | __u64 xid; | |
41 | __u64 timeout; | ||
40 | __u32 castparam; | 42 | __u32 castparam; |
41 | __u32 castaddr; | 43 | __u32 castaddr; |
42 | __u32 bastparam; | 44 | __u32 bastparam; |
43 | __u32 bastaddr; | 45 | __u32 bastaddr; |
44 | __u32 lksb; | 46 | __u32 lksb; |
45 | |||
46 | char lvb[DLM_USER_LVB_LEN]; | 47 | char lvb[DLM_USER_LVB_LEN]; |
47 | char name[0]; | 48 | char name[0]; |
48 | }; | 49 | }; |
@@ -68,6 +69,7 @@ struct dlm_lksb32 { | |||
68 | }; | 69 | }; |
69 | 70 | ||
70 | struct dlm_lock_result32 { | 71 | struct dlm_lock_result32 { |
72 | __u32 version[3]; | ||
71 | __u32 length; | 73 | __u32 length; |
72 | __u32 user_astaddr; | 74 | __u32 user_astaddr; |
73 | __u32 user_astparam; | 75 | __u32 user_astparam; |
@@ -102,6 +104,8 @@ static void compat_input(struct dlm_write_request *kb, | |||
102 | kb->i.lock.flags = kb32->i.lock.flags; | 104 | kb->i.lock.flags = kb32->i.lock.flags; |
103 | kb->i.lock.lkid = kb32->i.lock.lkid; | 105 | kb->i.lock.lkid = kb32->i.lock.lkid; |
104 | kb->i.lock.parent = kb32->i.lock.parent; | 106 | kb->i.lock.parent = kb32->i.lock.parent; |
107 | kb->i.lock.xid = kb32->i.lock.xid; | ||
108 | kb->i.lock.timeout = kb32->i.lock.timeout; | ||
105 | kb->i.lock.castparam = (void *)(long)kb32->i.lock.castparam; | 109 | kb->i.lock.castparam = (void *)(long)kb32->i.lock.castparam; |
106 | kb->i.lock.castaddr = (void *)(long)kb32->i.lock.castaddr; | 110 | kb->i.lock.castaddr = (void *)(long)kb32->i.lock.castaddr; |
107 | kb->i.lock.bastparam = (void *)(long)kb32->i.lock.bastparam; | 111 | kb->i.lock.bastparam = (void *)(long)kb32->i.lock.bastparam; |
@@ -115,6 +119,10 @@ static void compat_input(struct dlm_write_request *kb, | |||
115 | static void compat_output(struct dlm_lock_result *res, | 119 | static void compat_output(struct dlm_lock_result *res, |
116 | struct dlm_lock_result32 *res32) | 120 | struct dlm_lock_result32 *res32) |
117 | { | 121 | { |
122 | res32->version[0] = res->version[0]; | ||
123 | res32->version[1] = res->version[1]; | ||
124 | res32->version[2] = res->version[2]; | ||
125 | |||
118 | res32->user_astaddr = (__u32)(long)res->user_astaddr; | 126 | res32->user_astaddr = (__u32)(long)res->user_astaddr; |
119 | res32->user_astparam = (__u32)(long)res->user_astparam; | 127 | res32->user_astparam = (__u32)(long)res->user_astparam; |
120 | res32->user_lksb = (__u32)(long)res->user_lksb; | 128 | res32->user_lksb = (__u32)(long)res->user_lksb; |
@@ -130,6 +138,36 @@ static void compat_output(struct dlm_lock_result *res, | |||
130 | } | 138 | } |
131 | #endif | 139 | #endif |
132 | 140 | ||
141 | /* Figure out if this lock is at the end of its life and no longer | ||
142 | available for the application to use. The lkb still exists until | ||
143 | the final ast is read. A lock becomes EOL in three situations: | ||
144 | 1. a noqueue request fails with EAGAIN | ||
145 | 2. an unlock completes with EUNLOCK | ||
146 | 3. a cancel of a waiting request completes with ECANCEL/EDEADLK | ||
147 | An EOL lock needs to be removed from the process's list of locks. | ||
148 | And we can't allow any new operation on an EOL lock. This is | ||
149 | not related to the lifetime of the lkb struct which is managed | ||
150 | entirely by refcount. */ | ||
151 | |||
152 | static int lkb_is_endoflife(struct dlm_lkb *lkb, int sb_status, int type) | ||
153 | { | ||
154 | switch (sb_status) { | ||
155 | case -DLM_EUNLOCK: | ||
156 | return 1; | ||
157 | case -DLM_ECANCEL: | ||
158 | case -ETIMEDOUT: | ||
159 | case -EDEADLK: | ||
160 | if (lkb->lkb_grmode == DLM_LOCK_IV) | ||
161 | return 1; | ||
162 | break; | ||
163 | case -EAGAIN: | ||
164 | if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV) | ||
165 | return 1; | ||
166 | break; | ||
167 | } | ||
168 | return 0; | ||
169 | } | ||
170 | |||
133 | /* we could possibly check if the cancel of an orphan has resulted in the lkb | 171 | /* we could possibly check if the cancel of an orphan has resulted in the lkb |
134 | being removed and then remove that lkb from the orphans list and free it */ | 172 | being removed and then remove that lkb from the orphans list and free it */ |
135 | 173 | ||
@@ -176,25 +214,7 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type) | |||
176 | log_debug(ls, "ast overlap %x status %x %x", | 214 | log_debug(ls, "ast overlap %x status %x %x", |
177 | lkb->lkb_id, ua->lksb.sb_status, lkb->lkb_flags); | 215 | lkb->lkb_id, ua->lksb.sb_status, lkb->lkb_flags); |
178 | 216 | ||
179 | /* Figure out if this lock is at the end of its life and no longer | 217 | eol = lkb_is_endoflife(lkb, ua->lksb.sb_status, type); |
180 | available for the application to use. The lkb still exists until | ||
181 | the final ast is read. A lock becomes EOL in three situations: | ||
182 | 1. a noqueue request fails with EAGAIN | ||
183 | 2. an unlock completes with EUNLOCK | ||
184 | 3. a cancel of a waiting request completes with ECANCEL | ||
185 | An EOL lock needs to be removed from the process's list of locks. | ||
186 | And we can't allow any new operation on an EOL lock. This is | ||
187 | not related to the lifetime of the lkb struct which is managed | ||
188 | entirely by refcount. */ | ||
189 | |||
190 | if (type == AST_COMP && | ||
191 | lkb->lkb_grmode == DLM_LOCK_IV && | ||
192 | ua->lksb.sb_status == -EAGAIN) | ||
193 | eol = 1; | ||
194 | else if (ua->lksb.sb_status == -DLM_EUNLOCK || | ||
195 | (ua->lksb.sb_status == -DLM_ECANCEL && | ||
196 | lkb->lkb_grmode == DLM_LOCK_IV)) | ||
197 | eol = 1; | ||
198 | if (eol) { | 218 | if (eol) { |
199 | lkb->lkb_ast_type &= ~AST_BAST; | 219 | lkb->lkb_ast_type &= ~AST_BAST; |
200 | lkb->lkb_flags |= DLM_IFL_ENDOFLIFE; | 220 | lkb->lkb_flags |= DLM_IFL_ENDOFLIFE; |
@@ -252,16 +272,18 @@ static int device_user_lock(struct dlm_user_proc *proc, | |||
252 | ua->castaddr = params->castaddr; | 272 | ua->castaddr = params->castaddr; |
253 | ua->bastparam = params->bastparam; | 273 | ua->bastparam = params->bastparam; |
254 | ua->bastaddr = params->bastaddr; | 274 | ua->bastaddr = params->bastaddr; |
275 | ua->xid = params->xid; | ||
255 | 276 | ||
256 | if (params->flags & DLM_LKF_CONVERT) | 277 | if (params->flags & DLM_LKF_CONVERT) |
257 | error = dlm_user_convert(ls, ua, | 278 | error = dlm_user_convert(ls, ua, |
258 | params->mode, params->flags, | 279 | params->mode, params->flags, |
259 | params->lkid, params->lvb); | 280 | params->lkid, params->lvb, |
281 | (unsigned long) params->timeout); | ||
260 | else { | 282 | else { |
261 | error = dlm_user_request(ls, ua, | 283 | error = dlm_user_request(ls, ua, |
262 | params->mode, params->flags, | 284 | params->mode, params->flags, |
263 | params->name, params->namelen, | 285 | params->name, params->namelen, |
264 | params->parent); | 286 | (unsigned long) params->timeout); |
265 | if (!error) | 287 | if (!error) |
266 | error = ua->lksb.sb_lkid; | 288 | error = ua->lksb.sb_lkid; |
267 | } | 289 | } |
@@ -299,6 +321,22 @@ static int device_user_unlock(struct dlm_user_proc *proc, | |||
299 | return error; | 321 | return error; |
300 | } | 322 | } |
301 | 323 | ||
324 | static int device_user_deadlock(struct dlm_user_proc *proc, | ||
325 | struct dlm_lock_params *params) | ||
326 | { | ||
327 | struct dlm_ls *ls; | ||
328 | int error; | ||
329 | |||
330 | ls = dlm_find_lockspace_local(proc->lockspace); | ||
331 | if (!ls) | ||
332 | return -ENOENT; | ||
333 | |||
334 | error = dlm_user_deadlock(ls, params->flags, params->lkid); | ||
335 | |||
336 | dlm_put_lockspace(ls); | ||
337 | return error; | ||
338 | } | ||
339 | |||
302 | static int create_misc_device(struct dlm_ls *ls, char *name) | 340 | static int create_misc_device(struct dlm_ls *ls, char *name) |
303 | { | 341 | { |
304 | int error, len; | 342 | int error, len; |
@@ -348,7 +386,7 @@ static int device_create_lockspace(struct dlm_lspace_params *params) | |||
348 | return -EPERM; | 386 | return -EPERM; |
349 | 387 | ||
350 | error = dlm_new_lockspace(params->name, strlen(params->name), | 388 | error = dlm_new_lockspace(params->name, strlen(params->name), |
351 | &lockspace, 0, DLM_USER_LVB_LEN); | 389 | &lockspace, params->flags, DLM_USER_LVB_LEN); |
352 | if (error) | 390 | if (error) |
353 | return error; | 391 | return error; |
354 | 392 | ||
@@ -524,6 +562,14 @@ static ssize_t device_write(struct file *file, const char __user *buf, | |||
524 | error = device_user_unlock(proc, &kbuf->i.lock); | 562 | error = device_user_unlock(proc, &kbuf->i.lock); |
525 | break; | 563 | break; |
526 | 564 | ||
565 | case DLM_USER_DEADLOCK: | ||
566 | if (!proc) { | ||
567 | log_print("no locking on control device"); | ||
568 | goto out_sig; | ||
569 | } | ||
570 | error = device_user_deadlock(proc, &kbuf->i.lock); | ||
571 | break; | ||
572 | |||
527 | case DLM_USER_CREATE_LOCKSPACE: | 573 | case DLM_USER_CREATE_LOCKSPACE: |
528 | if (proc) { | 574 | if (proc) { |
529 | log_print("create/remove only on control device"); | 575 | log_print("create/remove only on control device"); |
@@ -641,6 +687,9 @@ static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type, | |||
641 | int struct_len; | 687 | int struct_len; |
642 | 688 | ||
643 | memset(&result, 0, sizeof(struct dlm_lock_result)); | 689 | memset(&result, 0, sizeof(struct dlm_lock_result)); |
690 | result.version[0] = DLM_DEVICE_VERSION_MAJOR; | ||
691 | result.version[1] = DLM_DEVICE_VERSION_MINOR; | ||
692 | result.version[2] = DLM_DEVICE_VERSION_PATCH; | ||
644 | memcpy(&result.lksb, &ua->lksb, sizeof(struct dlm_lksb)); | 693 | memcpy(&result.lksb, &ua->lksb, sizeof(struct dlm_lksb)); |
645 | result.user_lksb = ua->user_lksb; | 694 | result.user_lksb = ua->user_lksb; |
646 | 695 | ||
@@ -699,6 +748,20 @@ static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type, | |||
699 | return error; | 748 | return error; |
700 | } | 749 | } |
701 | 750 | ||
751 | static int copy_version_to_user(char __user *buf, size_t count) | ||
752 | { | ||
753 | struct dlm_device_version ver; | ||
754 | |||
755 | memset(&ver, 0, sizeof(struct dlm_device_version)); | ||
756 | ver.version[0] = DLM_DEVICE_VERSION_MAJOR; | ||
757 | ver.version[1] = DLM_DEVICE_VERSION_MINOR; | ||
758 | ver.version[2] = DLM_DEVICE_VERSION_PATCH; | ||
759 | |||
760 | if (copy_to_user(buf, &ver, sizeof(struct dlm_device_version))) | ||
761 | return -EFAULT; | ||
762 | return sizeof(struct dlm_device_version); | ||
763 | } | ||
764 | |||
702 | /* a read returns a single ast described in a struct dlm_lock_result */ | 765 | /* a read returns a single ast described in a struct dlm_lock_result */ |
703 | 766 | ||
704 | static ssize_t device_read(struct file *file, char __user *buf, size_t count, | 767 | static ssize_t device_read(struct file *file, char __user *buf, size_t count, |
@@ -710,6 +773,16 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, | |||
710 | DECLARE_WAITQUEUE(wait, current); | 773 | DECLARE_WAITQUEUE(wait, current); |
711 | int error, type=0, bmode=0, removed = 0; | 774 | int error, type=0, bmode=0, removed = 0; |
712 | 775 | ||
776 | if (count == sizeof(struct dlm_device_version)) { | ||
777 | error = copy_version_to_user(buf, count); | ||
778 | return error; | ||
779 | } | ||
780 | |||
781 | if (!proc) { | ||
782 | log_print("non-version read from control device %zu", count); | ||
783 | return -EINVAL; | ||
784 | } | ||
785 | |||
713 | #ifdef CONFIG_COMPAT | 786 | #ifdef CONFIG_COMPAT |
714 | if (count < sizeof(struct dlm_lock_result32)) | 787 | if (count < sizeof(struct dlm_lock_result32)) |
715 | #else | 788 | #else |
@@ -747,11 +820,6 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, | |||
747 | } | 820 | } |
748 | } | 821 | } |
749 | 822 | ||
750 | if (list_empty(&proc->asts)) { | ||
751 | spin_unlock(&proc->asts_spin); | ||
752 | return -EAGAIN; | ||
753 | } | ||
754 | |||
755 | /* there may be both completion and blocking asts to return for | 823 | /* there may be both completion and blocking asts to return for |
756 | the lkb, don't remove lkb from asts list unless no asts remain */ | 824 | the lkb, don't remove lkb from asts list unless no asts remain */ |
757 | 825 | ||
@@ -823,6 +891,7 @@ static const struct file_operations device_fops = { | |||
823 | static const struct file_operations ctl_device_fops = { | 891 | static const struct file_operations ctl_device_fops = { |
824 | .open = ctl_device_open, | 892 | .open = ctl_device_open, |
825 | .release = ctl_device_close, | 893 | .release = ctl_device_close, |
894 | .read = device_read, | ||
826 | .write = device_write, | 895 | .write = device_write, |
827 | .owner = THIS_MODULE, | 896 | .owner = THIS_MODULE, |
828 | }; | 897 | }; |