Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
locks.c
Go to the documentation of this file.
2 
3 #include <linux/file.h>
4 #include <linux/namei.h>
5 
6 #include "super.h"
7 #include "mds_client.h"
8 #include <linux/ceph/pagelist.h>
9 
13 static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
14  int cmd, u8 wait, struct file_lock *fl)
15 {
16  struct inode *inode = file->f_dentry->d_inode;
17  struct ceph_mds_client *mdsc =
18  ceph_sb_to_client(inode->i_sb)->mdsc;
19  struct ceph_mds_request *req;
20  int err;
21  u64 length = 0;
22 
23  req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS);
24  if (IS_ERR(req))
25  return PTR_ERR(req);
26  req->r_inode = inode;
27  ihold(inode);
28 
29  /* mds requires start and length rather than start and end */
30  if (LLONG_MAX == fl->fl_end)
31  length = 0;
32  else
33  length = fl->fl_end - fl->fl_start + 1;
34 
35  dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, "
36  "length: %llu, wait: %d, type: %d", (int)lock_type,
37  (int)operation, (u64)fl->fl_pid, fl->fl_start,
38  length, wait, fl->fl_type);
39 
40  req->r_args.filelock_change.rule = lock_type;
41  req->r_args.filelock_change.type = cmd;
42  req->r_args.filelock_change.pid = cpu_to_le64((u64)fl->fl_pid);
43  /* This should be adjusted, but I'm not sure if
44  namespaces actually get id numbers*/
45  req->r_args.filelock_change.pid_namespace =
46  cpu_to_le64((u64)(unsigned long)fl->fl_nspid);
47  req->r_args.filelock_change.start = cpu_to_le64(fl->fl_start);
48  req->r_args.filelock_change.length = cpu_to_le64(length);
49  req->r_args.filelock_change.wait = wait;
50 
51  err = ceph_mdsc_do_request(mdsc, inode, req);
52 
53  if ( operation == CEPH_MDS_OP_GETFILELOCK){
54  fl->fl_pid = le64_to_cpu(req->r_reply_info.filelock_reply->pid);
55  if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type)
56  fl->fl_type = F_RDLCK;
57  else if (CEPH_LOCK_EXCL == req->r_reply_info.filelock_reply->type)
58  fl->fl_type = F_WRLCK;
59  else
60  fl->fl_type = F_UNLCK;
61 
62  fl->fl_start = le64_to_cpu(req->r_reply_info.filelock_reply->start);
63  length = le64_to_cpu(req->r_reply_info.filelock_reply->start) +
64  le64_to_cpu(req->r_reply_info.filelock_reply->length);
65  if (length >= 1)
66  fl->fl_end = length -1;
67  else
68  fl->fl_end = 0;
69 
70  }
71  ceph_mdsc_put_request(req);
72  dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, "
73  "length: %llu, wait: %d, type: %d, err code %d", (int)lock_type,
74  (int)operation, (u64)fl->fl_pid, fl->fl_start,
75  length, wait, fl->fl_type, err);
76  return err;
77 }
78 
83 int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
84 {
85  u8 lock_cmd;
86  int err;
87  u8 wait = 0;
89 
90  fl->fl_nspid = get_pid(task_tgid(current));
91  dout("ceph_lock, fl_pid:%d", fl->fl_pid);
92 
93  /* set wait bit as appropriate, then make command as Ceph expects it*/
94  if (F_SETLKW == cmd)
95  wait = 1;
96  if (F_GETLK == cmd)
98 
99  if (F_RDLCK == fl->fl_type)
100  lock_cmd = CEPH_LOCK_SHARED;
101  else if (F_WRLCK == fl->fl_type)
102  lock_cmd = CEPH_LOCK_EXCL;
103  else
104  lock_cmd = CEPH_LOCK_UNLOCK;
105 
106  err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, lock_cmd, wait, fl);
107  if (!err) {
108  if ( op != CEPH_MDS_OP_GETFILELOCK ){
109  dout("mds locked, locking locally");
110  err = posix_lock_file(file, fl, NULL);
111  if (err && (CEPH_MDS_OP_SETFILELOCK == op)) {
112  /* undo! This should only happen if
113  * the kernel detects local
114  * deadlock. */
115  ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
116  CEPH_LOCK_UNLOCK, 0, fl);
117  dout("got %d on posix_lock_file, undid lock",
118  err);
119  }
120  }
121 
122  } else if (err == -ERESTARTSYS) {
123  dout("undoing lock\n");
124  ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
125  CEPH_LOCK_UNLOCK, 0, fl);
126  }
127  return err;
128 }
129 
130 int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
131 {
132  u8 lock_cmd;
133  int err;
134  u8 wait = 1;
135 
136  fl->fl_nspid = get_pid(task_tgid(current));
137  dout("ceph_flock, fl_pid:%d", fl->fl_pid);
138 
139  /* set wait bit, then clear it out of cmd*/
140  if (cmd & LOCK_NB)
141  wait = 0;
142  cmd = cmd & (LOCK_SH | LOCK_EX | LOCK_UN);
143  /* set command sequence that Ceph wants to see:
144  shared lock, exclusive lock, or unlock */
145  if (LOCK_SH == cmd)
146  lock_cmd = CEPH_LOCK_SHARED;
147  else if (LOCK_EX == cmd)
148  lock_cmd = CEPH_LOCK_EXCL;
149  else
150  lock_cmd = CEPH_LOCK_UNLOCK;
151 
152  err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK,
153  file, lock_cmd, wait, fl);
154  if (!err) {
155  err = flock_lock_file_wait(file, fl);
156  if (err) {
157  ceph_lock_message(CEPH_LOCK_FLOCK,
159  file, CEPH_LOCK_UNLOCK, 0, fl);
160  dout("got %d on flock_lock_file_wait, undid lock", err);
161  }
162  } else if (err == -ERESTARTSYS) {
163  dout("undoing lock\n");
164  ceph_lock_message(CEPH_LOCK_FLOCK,
166  file, CEPH_LOCK_UNLOCK, 0, fl);
167  }
168  return err;
169 }
170 
176 void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
177 {
178  struct file_lock *lock;
179 
180  *fcntl_count = 0;
181  *flock_count = 0;
182 
183  for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
184  if (lock->fl_flags & FL_POSIX)
185  ++(*fcntl_count);
186  else if (lock->fl_flags & FL_FLOCK)
187  ++(*flock_count);
188  }
189  dout("counted %d flock locks and %d fcntl locks",
190  *flock_count, *fcntl_count);
191 }
192 
201 int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist,
202  int num_fcntl_locks, int num_flock_locks)
203 {
204  struct file_lock *lock;
205  struct ceph_filelock cephlock;
206  int err = 0;
207  int seen_fcntl = 0;
208  int seen_flock = 0;
209 
210  dout("encoding %d flock and %d fcntl locks", num_flock_locks,
211  num_fcntl_locks);
212  err = ceph_pagelist_append(pagelist, &num_fcntl_locks, sizeof(u32));
213  if (err)
214  goto fail;
215  for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
216  if (lock->fl_flags & FL_POSIX) {
217  ++seen_fcntl;
218  if (seen_fcntl > num_fcntl_locks) {
219  err = -ENOSPC;
220  goto fail;
221  }
222  err = lock_to_ceph_filelock(lock, &cephlock);
223  if (err)
224  goto fail;
225  err = ceph_pagelist_append(pagelist, &cephlock,
226  sizeof(struct ceph_filelock));
227  }
228  if (err)
229  goto fail;
230  }
231 
232  err = ceph_pagelist_append(pagelist, &num_flock_locks, sizeof(u32));
233  if (err)
234  goto fail;
235  for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
236  if (lock->fl_flags & FL_FLOCK) {
237  ++seen_flock;
238  if (seen_flock > num_flock_locks) {
239  err = -ENOSPC;
240  goto fail;
241  }
242  err = lock_to_ceph_filelock(lock, &cephlock);
243  if (err)
244  goto fail;
245  err = ceph_pagelist_append(pagelist, &cephlock,
246  sizeof(struct ceph_filelock));
247  }
248  if (err)
249  goto fail;
250  }
251 fail:
252  return err;
253 }
254 
255 /*
256  * Given a pointer to a lock, convert it to a ceph filelock
257  */
259  struct ceph_filelock *cephlock)
260 {
261  int err = 0;
262 
263  cephlock->start = cpu_to_le64(lock->fl_start);
264  cephlock->length = cpu_to_le64(lock->fl_end - lock->fl_start + 1);
265  cephlock->client = cpu_to_le64(0);
266  cephlock->pid = cpu_to_le64(lock->fl_pid);
267  cephlock->pid_namespace =
268  cpu_to_le64((u64)(unsigned long)lock->fl_nspid);
269 
270  switch (lock->fl_type) {
271  case F_RDLCK:
272  cephlock->type = CEPH_LOCK_SHARED;
273  break;
274  case F_WRLCK:
275  cephlock->type = CEPH_LOCK_EXCL;
276  break;
277  case F_UNLCK:
278  cephlock->type = CEPH_LOCK_UNLOCK;
279  break;
280  default:
281  dout("Have unknown lock type %d", lock->fl_type);
282  err = -EINVAL;
283  }
284 
285  return err;
286 }