Blame view

fs/ceph/file.c 23.6 KB
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
1
  #include <linux/ceph/ceph_debug.h>
124e68e74   Sage Weil   ceph: file operat...
2

3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
3
  #include <linux/module.h>
124e68e74   Sage Weil   ceph: file operat...
4
  #include <linux/sched.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
5
  #include <linux/slab.h>
124e68e74   Sage Weil   ceph: file operat...
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
  #include <linux/file.h>
  #include <linux/namei.h>
  #include <linux/writeback.h>
  
  #include "super.h"
  #include "mds_client.h"
  
  /*
   * Ceph file operations
   *
   * Implement basic open/close functionality, and implement
   * read/write.
   *
   * We implement three modes of file I/O:
   *  - buffered uses the generic_file_aio_{read,write} helpers
   *
   *  - synchronous is used when there is multi-client read/write
   *    sharing, avoids the page cache, and synchronously waits for an
   *    ack from the OSD.
   *
   *  - direct io takes the variant of the sync path that references
   *    user pages directly.
   *
   * fsync() flushes and waits on dirty pages, but just queues metadata
   * for writeback: since the MDS can recover size and mtime there is no
   * need to wait for MDS acknowledgement.
   */
  
  
  /*
   * Prepare an open request.  Preallocate ceph_cap to avoid an
   * inopportune ENOMEM later.
   */
  static struct ceph_mds_request *
  prepare_open_request(struct super_block *sb, int flags, int create_mode)
  {
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
42
43
  	struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
  	struct ceph_mds_client *mdsc = fsc->mdsc;
124e68e74   Sage Weil   ceph: file operat...
44
45
46
47
48
49
50
51
52
53
54
55
56
  	struct ceph_mds_request *req;
  	int want_auth = USE_ANY_MDS;
  	int op = (flags & O_CREAT) ? CEPH_MDS_OP_CREATE : CEPH_MDS_OP_OPEN;
  
  	if (flags & (O_WRONLY|O_RDWR|O_CREAT|O_TRUNC))
  		want_auth = USE_AUTH_MDS;
  
  	req = ceph_mdsc_create_request(mdsc, op, want_auth);
  	if (IS_ERR(req))
  		goto out;
  	req->r_fmode = ceph_flags_to_mode(flags);
  	req->r_args.open.flags = cpu_to_le32(flags);
  	req->r_args.open.mode = cpu_to_le32(create_mode);
6a18be16f   Sage Weil   ceph: fix sparse ...
57
  	req->r_args.open.preferred = cpu_to_le32(-1);
124e68e74   Sage Weil   ceph: file operat...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  out:
  	return req;
  }
  
  /*
   * initialize private struct file data.
   * if we fail, clean up by dropping fmode reference on the ceph_inode
   */
  static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
  {
  	struct ceph_file_info *cf;
  	int ret = 0;
  
  	switch (inode->i_mode & S_IFMT) {
  	case S_IFREG:
  	case S_IFDIR:
  		dout("init_file %p %p 0%o (regular)
  ", inode, file,
  		     inode->i_mode);
  		cf = kmem_cache_alloc(ceph_file_cachep, GFP_NOFS | __GFP_ZERO);
  		if (cf == NULL) {
  			ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
  			return -ENOMEM;
  		}
  		cf->fmode = fmode;
  		cf->next_offset = 2;
  		file->private_data = cf;
  		BUG_ON(inode->i_fop->release != ceph_release);
  		break;
  
  	case S_IFLNK:
  		dout("init_file %p %p 0%o (symlink)
  ", inode, file,
  		     inode->i_mode);
  		ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
  		break;
  
  	default:
  		dout("init_file %p %p 0%o (special)
  ", inode, file,
  		     inode->i_mode);
  		/*
  		 * we need to drop the open ref now, since we don't
  		 * have .release set to ceph_release.
  		 */
  		ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
  		BUG_ON(inode->i_fop->release == ceph_release);
  
  		/* call the proper open fop */
  		ret = inode->i_fop->open(inode, file);
  	}
  	return ret;
  }
  
  /*
   * If the filp already has private_data, that means the file was
   * already opened by intent during lookup, and we do nothing.
   *
   * If we already have the requisite capabilities, we can satisfy
   * the open request locally (no need to request new caps from the
   * MDS).  We do, however, need to inform the MDS (asynchronously)
   * if our wanted caps set expands.
   */
  int ceph_open(struct inode *inode, struct file *file)
  {
  	struct ceph_inode_info *ci = ceph_inode(inode);
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
124
125
  	struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb);
  	struct ceph_mds_client *mdsc = fsc->mdsc;
124e68e74   Sage Weil   ceph: file operat...
126
127
  	struct ceph_mds_request *req;
  	struct ceph_file_info *cf = file->private_data;
5f21c96dd   Sage Weil   ceph: protect acc...
128
  	struct inode *parent_inode = NULL;
124e68e74   Sage Weil   ceph: file operat...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  	int err;
  	int flags, fmode, wanted;
  
  	if (cf) {
  		dout("open file %p is already opened
  ", file);
  		return 0;
  	}
  
  	/* filter out O_CREAT|O_EXCL; vfs did that already.  yuck. */
  	flags = file->f_flags & ~(O_CREAT|O_EXCL);
  	if (S_ISDIR(inode->i_mode))
  		flags = O_DIRECTORY;  /* mds likes to know */
  
  	dout("open inode %p ino %llx.%llx file %p flags %d (%d)
  ", inode,
  	     ceph_vinop(inode), file, flags, file->f_flags);
  	fmode = ceph_flags_to_mode(flags);
  	wanted = ceph_caps_for_mode(fmode);
  
  	/* snapped files are read-only */
  	if (ceph_snap(inode) != CEPH_NOSNAP && (file->f_mode & FMODE_WRITE))
  		return -EROFS;
  
  	/* trivially open snapdir */
  	if (ceph_snap(inode) == CEPH_SNAPDIR) {
be655596b   Sage Weil   ceph: use i_ceph_...
155
  		spin_lock(&ci->i_ceph_lock);
124e68e74   Sage Weil   ceph: file operat...
156
  		__ceph_get_fmode(ci, fmode);
be655596b   Sage Weil   ceph: use i_ceph_...
157
  		spin_unlock(&ci->i_ceph_lock);
124e68e74   Sage Weil   ceph: file operat...
158
159
160
161
  		return ceph_init_file(inode, file, fmode);
  	}
  
  	/*
7421ab804   Sage Weil   ceph: fix open fo...
162
163
  	 * No need to block if we have caps on the auth MDS (for
  	 * write) or any MDS (for read).  Update wanted set
124e68e74   Sage Weil   ceph: file operat...
164
165
  	 * asynchronously.
  	 */
be655596b   Sage Weil   ceph: use i_ceph_...
166
  	spin_lock(&ci->i_ceph_lock);
7421ab804   Sage Weil   ceph: fix open fo...
167
168
  	if (__ceph_is_any_real_caps(ci) &&
  	    (((fmode & CEPH_FILE_MODE_WR) == 0) || ci->i_auth_cap)) {
124e68e74   Sage Weil   ceph: file operat...
169
170
171
172
173
174
175
176
  		int mds_wanted = __ceph_caps_mds_wanted(ci);
  		int issued = __ceph_caps_issued(ci, NULL);
  
  		dout("open %p fmode %d want %s issued %s using existing
  ",
  		     inode, fmode, ceph_cap_string(wanted),
  		     ceph_cap_string(issued));
  		__ceph_get_fmode(ci, fmode);
be655596b   Sage Weil   ceph: use i_ceph_...
177
  		spin_unlock(&ci->i_ceph_lock);
124e68e74   Sage Weil   ceph: file operat...
178
179
180
181
182
183
184
185
186
187
188
  
  		/* adjust wanted? */
  		if ((issued & wanted) != wanted &&
  		    (mds_wanted & wanted) != wanted &&
  		    ceph_snap(inode) != CEPH_SNAPDIR)
  			ceph_check_caps(ci, 0, NULL);
  
  		return ceph_init_file(inode, file, fmode);
  	} else if (ceph_snap(inode) != CEPH_NOSNAP &&
  		   (ci->i_snap_caps & wanted) == wanted) {
  		__ceph_get_fmode(ci, fmode);
be655596b   Sage Weil   ceph: use i_ceph_...
189
  		spin_unlock(&ci->i_ceph_lock);
124e68e74   Sage Weil   ceph: file operat...
190
191
  		return ceph_init_file(inode, file, fmode);
  	}
be655596b   Sage Weil   ceph: use i_ceph_...
192
  	spin_unlock(&ci->i_ceph_lock);
124e68e74   Sage Weil   ceph: file operat...
193
194
195
196
197
198
199
200
  
  	dout("open fmode %d wants %s
  ", fmode, ceph_cap_string(wanted));
  	req = prepare_open_request(inode->i_sb, flags, 0);
  	if (IS_ERR(req)) {
  		err = PTR_ERR(req);
  		goto out;
  	}
70b666c3b   Sage Weil   ceph: use ihold w...
201
202
  	req->r_inode = inode;
  	ihold(inode);
124e68e74   Sage Weil   ceph: file operat...
203
  	req->r_num_caps = 1;
5f21c96dd   Sage Weil   ceph: protect acc...
204
205
  	if (flags & (O_CREAT|O_TRUNC))
  		parent_inode = ceph_get_dentry_parent_inode(file->f_dentry);
124e68e74   Sage Weil   ceph: file operat...
206
  	err = ceph_mdsc_do_request(mdsc, parent_inode, req);
5f21c96dd   Sage Weil   ceph: protect acc...
207
  	iput(parent_inode);
124e68e74   Sage Weil   ceph: file operat...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  	if (!err)
  		err = ceph_init_file(inode, file, req->r_fmode);
  	ceph_mdsc_put_request(req);
  	dout("open result=%d on %llx.%llx
  ", err, ceph_vinop(inode));
  out:
  	return err;
  }
  
  
  /*
   * Do a lookup + open with a single request.
   *
   * If this succeeds, but some subsequent check in the vfs
   * may_open() fails, the struct *file gets cleaned up (i.e.
   * ceph_release gets called).  So fear not!
   */
  /*
   * flags
   *  path_lookup_open   -> LOOKUP_OPEN
   *  path_lookup_create -> LOOKUP_OPEN|LOOKUP_CREATE
   */
  struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
  				struct nameidata *nd, int mode,
  				int locked_dir)
  {
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
234
235
  	struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
  	struct ceph_mds_client *mdsc = fsc->mdsc;
468640e32   Sage Weil   ceph: fix ceph_lo...
236
  	struct file *file;
124e68e74   Sage Weil   ceph: file operat...
237
  	struct ceph_mds_request *req;
468640e32   Sage Weil   ceph: fix ceph_lo...
238
  	struct dentry *ret;
124e68e74   Sage Weil   ceph: file operat...
239
  	int err;
8a5e929dd   Al Viro   don't translitera...
240
  	int flags = nd->intent.open.flags;
124e68e74   Sage Weil   ceph: file operat...
241
242
243
244
245
246
247
248
  
  	dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o
  ",
  	     dentry, dentry->d_name.len, dentry->d_name.name, flags, mode);
  
  	/* do the open */
  	req = prepare_open_request(dir->i_sb, flags, mode);
  	if (IS_ERR(req))
7e34bc524   Julia Lawall   fs/ceph: Use ERR_...
249
  		return ERR_CAST(req);
124e68e74   Sage Weil   ceph: file operat...
250
251
252
253
254
255
256
  	req->r_dentry = dget(dentry);
  	req->r_num_caps = 2;
  	if (flags & O_CREAT) {
  		req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
  		req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
  	}
  	req->r_locked_dir = dir;           /* caller holds dir->i_mutex */
acda76578   Sage Weil   ceph: fix bad par...
257
258
259
  	err = ceph_mdsc_do_request(mdsc,
  				   (flags & (O_CREAT|O_TRUNC)) ? dir : NULL,
  				   req);
468640e32   Sage Weil   ceph: fix ceph_lo...
260
261
262
263
  	err = ceph_handle_snapdir(req, dentry, err);
  	if (err)
  		goto out;
  	if ((flags & O_CREAT) && !req->r_reply_info.head->is_dentry)
124e68e74   Sage Weil   ceph: file operat...
264
  		err = ceph_handle_notrace_create(dir, dentry);
468640e32   Sage Weil   ceph: fix ceph_lo...
265
266
267
268
269
270
271
  	if (err)
  		goto out;
  	file = lookup_instantiate_filp(nd, req->r_dentry, ceph_open);
  	if (IS_ERR(file))
  		err = PTR_ERR(file);
  out:
  	ret = ceph_finish_lookup(req, dentry, err);
124e68e74   Sage Weil   ceph: file operat...
272
  	ceph_mdsc_put_request(req);
468640e32   Sage Weil   ceph: fix ceph_lo...
273
274
275
  	dout("ceph_lookup_open result=%p
  ", ret);
  	return ret;
124e68e74   Sage Weil   ceph: file operat...
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  }
  
  int ceph_release(struct inode *inode, struct file *file)
  {
  	struct ceph_inode_info *ci = ceph_inode(inode);
  	struct ceph_file_info *cf = file->private_data;
  
  	dout("release inode %p file %p
  ", inode, file);
  	ceph_put_fmode(ci, cf->fmode);
  	if (cf->last_readdir)
  		ceph_mdsc_put_request(cf->last_readdir);
  	kfree(cf->last_name);
  	kfree(cf->dir_info);
  	dput(cf->dentry);
  	kmem_cache_free(ceph_file_cachep, cf);
195d3ce2c   Sage Weil   ceph: return EBAD...
292
293
  
  	/* wake up anyone waiting for caps on this inode */
03066f234   Yehuda Sadeh   ceph: use complet...
294
  	wake_up_all(&ci->i_cap_wq);
124e68e74   Sage Weil   ceph: file operat...
295
296
297
298
  	return 0;
  }
  
  /*
124e68e74   Sage Weil   ceph: file operat...
299
300
301
302
303
304
305
306
   * Read a range of bytes striped over one or more objects.  Iterate over
   * objects we stripe over.  (That's not atomic, but good enough for now.)
   *
   * If we get a short result from the OSD, check against i_size; we need to
   * only return a short read to the caller if we hit EOF.
   */
  static int striped_read(struct inode *inode,
  			u64 off, u64 len,
6a026589b   Sage Weil   ceph: fix sync re...
307
  			struct page **pages, int num_pages,
c3cd62839   Sage Weil   ceph: fix short s...
308
  			int *checkeof, bool o_direct,
ab226e21a   Henry C Chang   ceph: fix direct-...
309
  			unsigned long buf_align)
124e68e74   Sage Weil   ceph: file operat...
310
  {
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
311
  	struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
124e68e74   Sage Weil   ceph: file operat...
312
313
  	struct ceph_inode_info *ci = ceph_inode(inode);
  	u64 pos, this_len;
b7495fc2f   Sage Weil   ceph: make page a...
314
  	int io_align, page_align;
124e68e74   Sage Weil   ceph: file operat...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
  	int left, pages_left;
  	int read;
  	struct page **page_pos;
  	int ret;
  	bool hit_stripe, was_short;
  
  	/*
  	 * we may need to do multiple reads.  not atomic, unfortunately.
  	 */
  	pos = off;
  	left = len;
  	page_pos = pages;
  	pages_left = num_pages;
  	read = 0;
b7495fc2f   Sage Weil   ceph: make page a...
329
  	io_align = off & ~PAGE_MASK;
124e68e74   Sage Weil   ceph: file operat...
330
331
  
  more:
c3cd62839   Sage Weil   ceph: fix short s...
332
  	if (o_direct)
ab226e21a   Henry C Chang   ceph: fix direct-...
333
  		page_align = (pos - io_align + buf_align) & ~PAGE_MASK;
b7495fc2f   Sage Weil   ceph: make page a...
334
335
  	else
  		page_align = pos & ~PAGE_MASK;
124e68e74   Sage Weil   ceph: file operat...
336
  	this_len = left;
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
337
  	ret = ceph_osdc_readpages(&fsc->client->osdc, ceph_vino(inode),
124e68e74   Sage Weil   ceph: file operat...
338
339
340
  				  &ci->i_layout, pos, &this_len,
  				  ci->i_truncate_seq,
  				  ci->i_truncate_size,
b7495fc2f   Sage Weil   ceph: make page a...
341
  				  page_pos, pages_left, page_align);
124e68e74   Sage Weil   ceph: file operat...
342
343
  	if (ret == -ENOENT)
  		ret = 0;
0e98728fa   Sage Weil   ceph: fix ENOENT ...
344
345
  	hit_stripe = this_len < left;
  	was_short = ret >= 0 && ret < this_len;
124e68e74   Sage Weil   ceph: file operat...
346
347
348
349
350
  	dout("striped_read %llu~%u (read %u) got %d%s%s
  ", pos, left, read,
  	     ret, hit_stripe ? " HITSTRIPE" : "", was_short ? " SHORT" : "");
  
  	if (ret > 0) {
773e9b442   Sage Weil   ceph: fix page al...
351
  		int didpages = (page_align + ret) >> PAGE_CACHE_SHIFT;
124e68e74   Sage Weil   ceph: file operat...
352
353
354
355
  
  		if (read < pos - off) {
  			dout(" zero gap %llu to %llu
  ", off + read, pos);
773e9b442   Sage Weil   ceph: fix page al...
356
  			ceph_zero_page_vector_range(page_align + read,
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
357
  						    pos - off - read, pages);
124e68e74   Sage Weil   ceph: file operat...
358
359
360
361
362
363
364
365
366
367
368
369
370
  		}
  		pos += ret;
  		read = pos - off;
  		left -= ret;
  		page_pos += didpages;
  		pages_left -= didpages;
  
  		/* hit stripe? */
  		if (left && hit_stripe)
  			goto more;
  	}
  
  	if (was_short) {
c3cd62839   Sage Weil   ceph: fix short s...
371
372
373
374
375
376
377
378
379
380
381
  		/* did we bounce off eof? */
  		if (pos + left > inode->i_size)
  			*checkeof = 1;
  
  		/* zero trailing bytes (inside i_size) */
  		if (left > 0 && pos < inode->i_size) {
  			if (pos + left > inode->i_size)
  				left = inode->i_size - pos;
  
  			dout("zero tail %d
  ", left);
773e9b442   Sage Weil   ceph: fix page al...
382
  			ceph_zero_page_vector_range(page_align + read, left,
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
383
  						    pages);
c3cd62839   Sage Weil   ceph: fix short s...
384
  			read += left;
124e68e74   Sage Weil   ceph: file operat...
385
  		}
124e68e74   Sage Weil   ceph: file operat...
386
  	}
124e68e74   Sage Weil   ceph: file operat...
387
388
389
390
391
392
393
394
395
396
397
398
399
400
  	if (ret >= 0)
  		ret = read;
  	dout("striped_read returns %d
  ", ret);
  	return ret;
  }
  
  /*
   * Completely synchronous read and write methods.  Direct from __user
   * buffer to osd, or directly to user pages (if O_DIRECT).
   *
   * If the read spans object boundary, just do multiple reads.
   */
  static ssize_t ceph_sync_read(struct file *file, char __user *data,
6a026589b   Sage Weil   ceph: fix sync re...
401
  			      unsigned len, loff_t *poff, int *checkeof)
124e68e74   Sage Weil   ceph: file operat...
402
403
404
405
  {
  	struct inode *inode = file->f_dentry->d_inode;
  	struct page **pages;
  	u64 off = *poff;
ab226e21a   Henry C Chang   ceph: fix direct-...
406
  	int num_pages, ret;
124e68e74   Sage Weil   ceph: file operat...
407
408
409
410
  
  	dout("sync_read on file %p %llu~%u %s
  ", file, off, len,
  	     (file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
ab226e21a   Henry C Chang   ceph: fix direct-...
411
412
  	if (file->f_flags & O_DIRECT) {
  		num_pages = calc_pages_for((unsigned long)data, len);
b6aa5901c   Henry C Chang   ceph: mark user p...
413
  		pages = ceph_get_direct_page_vector(data, num_pages, true);
ab226e21a   Henry C Chang   ceph: fix direct-...
414
415
  	} else {
  		num_pages = calc_pages_for(off, len);
34d23762d   Yehuda Sadeh   ceph: all allocat...
416
  		pages = ceph_alloc_page_vector(num_pages, GFP_NOFS);
ab226e21a   Henry C Chang   ceph: fix direct-...
417
  	}
124e68e74   Sage Weil   ceph: file operat...
418
419
  	if (IS_ERR(pages))
  		return PTR_ERR(pages);
e98b6fed8   Sage Weil   ceph: fix comment...
420
421
422
423
424
425
  	/*
  	 * flush any page cache pages in this range.  this
  	 * will make concurrent normal and sync io slow,
  	 * but it will at least behave sensibly when they are
  	 * in sequence.
  	 */
29065a513   Yehuda Sadeh   ceph: sync read/w...
426
427
428
  	ret = filemap_write_and_wait(inode->i_mapping);
  	if (ret < 0)
  		goto done;
b7495fc2f   Sage Weil   ceph: make page a...
429
  	ret = striped_read(inode, off, len, pages, num_pages, checkeof,
ab226e21a   Henry C Chang   ceph: fix direct-...
430
431
  			   file->f_flags & O_DIRECT,
  			   (unsigned long)data & ~PAGE_MASK);
124e68e74   Sage Weil   ceph: file operat...
432
433
  
  	if (ret >= 0 && (file->f_flags & O_DIRECT) == 0)
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
434
  		ret = ceph_copy_page_vector_to_user(pages, data, off, ret);
124e68e74   Sage Weil   ceph: file operat...
435
436
  	if (ret >= 0)
  		*poff = off + ret;
29065a513   Yehuda Sadeh   ceph: sync read/w...
437
  done:
124e68e74   Sage Weil   ceph: file operat...
438
  	if (file->f_flags & O_DIRECT)
b6aa5901c   Henry C Chang   ceph: mark user p...
439
  		ceph_put_page_vector(pages, num_pages, true);
124e68e74   Sage Weil   ceph: file operat...
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
  	else
  		ceph_release_page_vector(pages, num_pages);
  	dout("sync_read result %d
  ", ret);
  	return ret;
  }
  
  /*
   * Write commit callback, called if we requested both an ACK and
   * ONDISK commit reply from the OSD.
   */
  static void sync_write_commit(struct ceph_osd_request *req,
  			      struct ceph_msg *msg)
  {
  	struct ceph_inode_info *ci = ceph_inode(req->r_inode);
  
  	dout("sync_write_commit %p tid %llu
  ", req, req->r_tid);
  	spin_lock(&ci->i_unsafe_lock);
  	list_del_init(&req->r_unsafe_item);
  	spin_unlock(&ci->i_unsafe_lock);
  	ceph_put_cap_refs(ci, CEPH_CAP_FILE_WR);
  }
  
  /*
   * Synchronous write, straight from __user pointer or user pages (if
   * O_DIRECT).
   *
   * If write spans object boundary, just do multiple writes.  (For a
   * correct atomic write, we should e.g. take write locks on all
   * objects, rollback on failure, etc.)
   */
  static ssize_t ceph_sync_write(struct file *file, const char __user *data,
  			       size_t left, loff_t *offset)
  {
  	struct inode *inode = file->f_dentry->d_inode;
  	struct ceph_inode_info *ci = ceph_inode(inode);
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
477
  	struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
124e68e74   Sage Weil   ceph: file operat...
478
479
480
481
482
483
484
485
486
  	struct ceph_osd_request *req;
  	struct page **pages;
  	int num_pages;
  	long long unsigned pos;
  	u64 len;
  	int written = 0;
  	int flags;
  	int do_sync = 0;
  	int check_caps = 0;
b7495fc2f   Sage Weil   ceph: make page a...
487
  	int page_align, io_align;
ab226e21a   Henry C Chang   ceph: fix direct-...
488
  	unsigned long buf_align;
124e68e74   Sage Weil   ceph: file operat...
489
490
491
492
493
494
495
496
497
498
499
500
501
502
  	int ret;
  	struct timespec mtime = CURRENT_TIME;
  
  	if (ceph_snap(file->f_dentry->d_inode) != CEPH_NOSNAP)
  		return -EROFS;
  
  	dout("sync_write on file %p %lld~%u %s
  ", file, *offset,
  	     (unsigned)left, (file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
  
  	if (file->f_flags & O_APPEND)
  		pos = i_size_read(inode);
  	else
  		pos = *offset;
29065a513   Yehuda Sadeh   ceph: sync read/w...
503
504
505
506
507
508
509
510
511
512
  	ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left);
  	if (ret < 0)
  		return ret;
  
  	ret = invalidate_inode_pages2_range(inode->i_mapping,
  					    pos >> PAGE_CACHE_SHIFT,
  					    (pos + left) >> PAGE_CACHE_SHIFT);
  	if (ret < 0)
  		dout("invalidate_inode_pages2_range returned %d
  ", ret);
124e68e74   Sage Weil   ceph: file operat...
513
514
515
516
517
518
519
520
521
522
523
524
525
  	flags = CEPH_OSD_FLAG_ORDERSNAP |
  		CEPH_OSD_FLAG_ONDISK |
  		CEPH_OSD_FLAG_WRITE;
  	if ((file->f_flags & (O_SYNC|O_DIRECT)) == 0)
  		flags |= CEPH_OSD_FLAG_ACK;
  	else
  		do_sync = 1;
  
  	/*
  	 * we may need to do multiple writes here if we span an object
  	 * boundary.  this isn't atomic, unfortunately.  :(
  	 */
  more:
d7f124f12   Sage Weil   ceph: fix sync an...
526
527
  	io_align = pos & ~PAGE_MASK;
  	buf_align = (unsigned long)data & ~PAGE_MASK;
124e68e74   Sage Weil   ceph: file operat...
528
  	len = left;
ab226e21a   Henry C Chang   ceph: fix direct-...
529
  	if (file->f_flags & O_DIRECT) {
b7495fc2f   Sage Weil   ceph: make page a...
530
531
  		/* write from beginning of first page, regardless of
  		   io alignment */
ab226e21a   Henry C Chang   ceph: fix direct-...
532
533
534
  		page_align = (pos - io_align + buf_align) & ~PAGE_MASK;
  		num_pages = calc_pages_for((unsigned long)data, len);
  	} else {
b7495fc2f   Sage Weil   ceph: make page a...
535
  		page_align = pos & ~PAGE_MASK;
ab226e21a   Henry C Chang   ceph: fix direct-...
536
537
  		num_pages = calc_pages_for(pos, len);
  	}
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
538
  	req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
124e68e74   Sage Weil   ceph: file operat...
539
540
541
542
543
  				    ceph_vino(inode), pos, &len,
  				    CEPH_OSD_OP_WRITE, flags,
  				    ci->i_snap_realm->cached_context,
  				    do_sync,
  				    ci->i_truncate_seq, ci->i_truncate_size,
b7495fc2f   Sage Weil   ceph: make page a...
544
  				    &mtime, false, 2, page_align);
a79832f26   Sage Weil   ceph: make ceph_m...
545
546
  	if (!req)
  		return -ENOMEM;
124e68e74   Sage Weil   ceph: file operat...
547

124e68e74   Sage Weil   ceph: file operat...
548
  	if (file->f_flags & O_DIRECT) {
b6aa5901c   Henry C Chang   ceph: mark user p...
549
  		pages = ceph_get_direct_page_vector(data, num_pages, false);
124e68e74   Sage Weil   ceph: file operat...
550
551
552
553
554
555
556
557
558
  		if (IS_ERR(pages)) {
  			ret = PTR_ERR(pages);
  			goto out;
  		}
  
  		/*
  		 * throw out any page cache pages in this range. this
  		 * may block.
  		 */
213c99ee0   Sage Weil   ceph: whitespace ...
559
  		truncate_inode_pages_range(inode->i_mapping, pos,
5c6a2cdb4   Sage Weil   ceph: fix direct ...
560
  					   (pos+len) | (PAGE_CACHE_SIZE-1));
124e68e74   Sage Weil   ceph: file operat...
561
  	} else {
34d23762d   Yehuda Sadeh   ceph: all allocat...
562
  		pages = ceph_alloc_page_vector(num_pages, GFP_NOFS);
124e68e74   Sage Weil   ceph: file operat...
563
564
565
566
  		if (IS_ERR(pages)) {
  			ret = PTR_ERR(pages);
  			goto out;
  		}
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
567
  		ret = ceph_copy_user_to_page_vector(pages, data, pos, len);
124e68e74   Sage Weil   ceph: file operat...
568
569
570
571
572
573
574
575
576
577
578
579
580
581
  		if (ret < 0) {
  			ceph_release_page_vector(pages, num_pages);
  			goto out;
  		}
  
  		if ((file->f_flags & O_SYNC) == 0) {
  			/* get a second commit callback */
  			req->r_safe_callback = sync_write_commit;
  			req->r_own_pages = 1;
  		}
  	}
  	req->r_pages = pages;
  	req->r_num_pages = num_pages;
  	req->r_inode = inode;
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
582
  	ret = ceph_osdc_start_request(&fsc->client->osdc, req, false);
124e68e74   Sage Weil   ceph: file operat...
583
584
585
586
587
588
589
  	if (!ret) {
  		if (req->r_safe_callback) {
  			/*
  			 * Add to inode unsafe list only after we
  			 * start_request so that a tid has been assigned.
  			 */
  			spin_lock(&ci->i_unsafe_lock);
49bcb9323   Henry C Chang   ceph: add request...
590
591
  			list_add_tail(&req->r_unsafe_item,
  				      &ci->i_unsafe_writes);
124e68e74   Sage Weil   ceph: file operat...
592
593
594
  			spin_unlock(&ci->i_unsafe_lock);
  			ceph_get_cap_refs(ci, CEPH_CAP_FILE_WR);
  		}
78a255654   Henry C Chang   ceph: remove requ...
595
  		
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
596
  		ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
78a255654   Henry C Chang   ceph: remove requ...
597
598
599
600
601
602
  		if (ret < 0 && req->r_safe_callback) {
  			spin_lock(&ci->i_unsafe_lock);
  			list_del_init(&req->r_unsafe_item);
  			spin_unlock(&ci->i_unsafe_lock);
  			ceph_put_cap_refs(ci, CEPH_CAP_FILE_WR);
  		}
124e68e74   Sage Weil   ceph: file operat...
603
604
605
  	}
  
  	if (file->f_flags & O_DIRECT)
b6aa5901c   Henry C Chang   ceph: mark user p...
606
  		ceph_put_page_vector(pages, num_pages, false);
124e68e74   Sage Weil   ceph: file operat...
607
608
609
610
611
612
613
614
615
  	else if (file->f_flags & O_SYNC)
  		ceph_release_page_vector(pages, num_pages);
  
  out:
  	ceph_osdc_put_request(req);
  	if (ret == 0) {
  		pos += len;
  		written += len;
  		left -= len;
d7f124f12   Sage Weil   ceph: fix sync an...
616
  		data += written;
124e68e74   Sage Weil   ceph: file operat...
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
  		if (left)
  			goto more;
  
  		ret = written;
  		*offset = pos;
  		if (pos > i_size_read(inode))
  			check_caps = ceph_inode_set_size(inode, pos);
  		if (check_caps)
  			ceph_check_caps(ceph_inode(inode), CHECK_CAPS_AUTHONLY,
  					NULL);
  	}
  	return ret;
  }
  
  /*
   * Wrap generic_file_aio_read with checks for cap bits on the inode.
   * Atomically grab references, so that those bits are not released
   * back to the MDS mid-read.
   *
   * Hmm, the sync read case isn't actually async... should it be?
   */
  static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov,
  			     unsigned long nr_segs, loff_t pos)
  {
  	struct file *filp = iocb->ki_filp;
2962507ca   Sage Weil   ceph: perform laz...
642
  	struct ceph_file_info *fi = filp->private_data;
124e68e74   Sage Weil   ceph: file operat...
643
644
645
646
  	loff_t *ppos = &iocb->ki_pos;
  	size_t len = iov->iov_len;
  	struct inode *inode = filp->f_dentry->d_inode;
  	struct ceph_inode_info *ci = ceph_inode(inode);
cd84db6e4   Yehuda Sadeh   ceph: code cleanup
647
  	void __user *base = iov->iov_base;
124e68e74   Sage Weil   ceph: file operat...
648
  	ssize_t ret;
2962507ca   Sage Weil   ceph: perform laz...
649
  	int want, got = 0;
6a026589b   Sage Weil   ceph: fix sync re...
650
  	int checkeof = 0, read = 0;
124e68e74   Sage Weil   ceph: file operat...
651
652
653
654
  
  	dout("aio_read %p %llx.%llx %llu~%u trying to get caps on %p
  ",
  	     inode, ceph_vinop(inode), pos, (unsigned)len, inode);
6a026589b   Sage Weil   ceph: fix sync re...
655
  again:
124e68e74   Sage Weil   ceph: file operat...
656
  	__ceph_do_pending_vmtruncate(inode);
2962507ca   Sage Weil   ceph: perform laz...
657
658
659
660
661
  	if (fi->fmode & CEPH_FILE_MODE_LAZY)
  		want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO;
  	else
  		want = CEPH_CAP_FILE_CACHE;
  	ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, want, &got, -1);
124e68e74   Sage Weil   ceph: file operat...
662
663
664
665
666
667
  	if (ret < 0)
  		goto out;
  	dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s
  ",
  	     inode, ceph_vinop(inode), pos, (unsigned)len,
  	     ceph_cap_string(got));
2962507ca   Sage Weil   ceph: perform laz...
668
  	if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 ||
124e68e74   Sage Weil   ceph: file operat...
669
  	    (iocb->ki_filp->f_flags & O_DIRECT) ||
4918b6d14   Sage Weil   ceph: add F_SYNC ...
670
671
  	    (inode->i_sb->s_flags & MS_SYNCHRONOUS) ||
  	    (fi->flags & CEPH_F_SYNC))
124e68e74   Sage Weil   ceph: file operat...
672
  		/* hmm, this isn't really async... */
6a026589b   Sage Weil   ceph: fix sync re...
673
  		ret = ceph_sync_read(filp, base, len, ppos, &checkeof);
124e68e74   Sage Weil   ceph: file operat...
674
675
676
677
678
679
680
681
  	else
  		ret = generic_file_aio_read(iocb, iov, nr_segs, pos);
  
  out:
  	dout("aio_read %p %llx.%llx dropping cap refs on %s = %d
  ",
  	     inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret);
  	ceph_put_cap_refs(ci, got);
6a026589b   Sage Weil   ceph: fix sync re...
682
683
684
685
686
687
  
  	if (checkeof && ret >= 0) {
  		int statret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE);
  
  		/* hit EOF or hole? */
  		if (statret == 0 && *ppos < inode->i_size) {
c3cd62839   Sage Weil   ceph: fix short s...
688
689
  			dout("aio_read sync_read hit hole, ppos %lld < size %lld, reading more
  ", *ppos, inode->i_size);
6a026589b   Sage Weil   ceph: fix sync re...
690
691
692
693
694
695
696
697
698
  			read += ret;
  			base += ret;
  			len -= ret;
  			checkeof = 0;
  			goto again;
  		}
  	}
  	if (ret >= 0)
  		ret += read;
124e68e74   Sage Weil   ceph: file operat...
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
  	return ret;
  }
  
  /*
   * Take cap references to avoid releasing caps to MDS mid-write.
   *
   * If we are synchronous, and write with an old snap context, the OSD
   * may return EOLDSNAPC.  In that case, retry the write.. _after_
   * dropping our cap refs and allowing the pending snap to logically
   * complete _before_ this write occurs.
   *
   * If we are near ENOSPC, write synchronously.
   */
  static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
  		       unsigned long nr_segs, loff_t pos)
  {
  	struct file *file = iocb->ki_filp;
33caad324   Sage Weil   ceph: perform laz...
716
  	struct ceph_file_info *fi = file->private_data;
124e68e74   Sage Weil   ceph: file operat...
717
718
  	struct inode *inode = file->f_dentry->d_inode;
  	struct ceph_inode_info *ci = ceph_inode(inode);
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
719
720
  	struct ceph_osd_client *osdc =
  		&ceph_sb_to_client(inode->i_sb)->client->osdc;
124e68e74   Sage Weil   ceph: file operat...
721
  	loff_t endoff = pos + iov->iov_len;
33caad324   Sage Weil   ceph: perform laz...
722
  	int want, got = 0;
88d892a37   Yehuda Sadeh   ceph: don't clobb...
723
  	int ret, err;
124e68e74   Sage Weil   ceph: file operat...
724
725
726
727
728
729
730
731
732
733
734
735
  
  	if (ceph_snap(inode) != CEPH_NOSNAP)
  		return -EROFS;
  
  retry_snap:
  	if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL))
  		return -ENOSPC;
  	__ceph_do_pending_vmtruncate(inode);
  	dout("aio_write %p %llx.%llx %llu~%u getting caps. i_size %llu
  ",
  	     inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
  	     inode->i_size);
33caad324   Sage Weil   ceph: perform laz...
736
737
738
739
740
  	if (fi->fmode & CEPH_FILE_MODE_LAZY)
  		want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO;
  	else
  		want = CEPH_CAP_FILE_BUFFER;
  	ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, &got, endoff);
124e68e74   Sage Weil   ceph: file operat...
741
  	if (ret < 0)
d8de9ab63   Sage Weil   ceph: avoid carry...
742
  		goto out_put;
124e68e74   Sage Weil   ceph: file operat...
743
744
745
746
747
  
  	dout("aio_write %p %llx.%llx %llu~%u  got cap refs on %s
  ",
  	     inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
  	     ceph_cap_string(got));
33caad324   Sage Weil   ceph: perform laz...
748
  	if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 ||
124e68e74   Sage Weil   ceph: file operat...
749
  	    (iocb->ki_filp->f_flags & O_DIRECT) ||
4918b6d14   Sage Weil   ceph: add F_SYNC ...
750
751
  	    (inode->i_sb->s_flags & MS_SYNCHRONOUS) ||
  	    (fi->flags & CEPH_F_SYNC)) {
124e68e74   Sage Weil   ceph: file operat...
752
753
754
  		ret = ceph_sync_write(file, iov->iov_base, iov->iov_len,
  			&iocb->ki_pos);
  	} else {
d8de9ab63   Sage Weil   ceph: avoid carry...
755
756
757
758
759
  		/*
  		 * buffered write; drop Fw early to avoid slow
  		 * revocation if we get stuck on balance_dirty_pages
  		 */
  		int dirty;
124e68e74   Sage Weil   ceph: file operat...
760

be655596b   Sage Weil   ceph: use i_ceph_...
761
  		spin_lock(&ci->i_ceph_lock);
d8de9ab63   Sage Weil   ceph: avoid carry...
762
  		dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR);
be655596b   Sage Weil   ceph: use i_ceph_...
763
  		spin_unlock(&ci->i_ceph_lock);
d8de9ab63   Sage Weil   ceph: avoid carry...
764
  		ceph_put_cap_refs(ci, got);
124e68e74   Sage Weil   ceph: file operat...
765

d8de9ab63   Sage Weil   ceph: avoid carry...
766
  		ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
124e68e74   Sage Weil   ceph: file operat...
767
768
  		if ((ret >= 0 || ret == -EIOCBQUEUED) &&
  		    ((file->f_flags & O_SYNC) || IS_SYNC(file->f_mapping->host)
88d892a37   Yehuda Sadeh   ceph: don't clobb...
769
  		     || ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_NEARFULL))) {
8018ab057   Christoph Hellwig   sanitize vfs_fsyn...
770
  			err = vfs_fsync_range(file, pos, pos + ret - 1, 1);
88d892a37   Yehuda Sadeh   ceph: don't clobb...
771
772
773
  			if (err < 0)
  				ret = err;
  		}
d8de9ab63   Sage Weil   ceph: avoid carry...
774
775
776
777
  
  		if (dirty)
  			__mark_inode_dirty(inode, dirty);
  		goto out;
124e68e74   Sage Weil   ceph: file operat...
778
  	}
d8de9ab63   Sage Weil   ceph: avoid carry...
779

124e68e74   Sage Weil   ceph: file operat...
780
  	if (ret >= 0) {
fca65b4ad   Sage Weil   ceph: do not call...
781
  		int dirty;
be655596b   Sage Weil   ceph: use i_ceph_...
782
  		spin_lock(&ci->i_ceph_lock);
fca65b4ad   Sage Weil   ceph: do not call...
783
  		dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR);
be655596b   Sage Weil   ceph: use i_ceph_...
784
  		spin_unlock(&ci->i_ceph_lock);
fca65b4ad   Sage Weil   ceph: do not call...
785
786
  		if (dirty)
  			__mark_inode_dirty(inode, dirty);
124e68e74   Sage Weil   ceph: file operat...
787
  	}
d8de9ab63   Sage Weil   ceph: avoid carry...
788
  out_put:
124e68e74   Sage Weil   ceph: file operat...
789
790
791
792
793
  	dout("aio_write %p %llx.%llx %llu~%u  dropping cap refs on %s
  ",
  	     inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
  	     ceph_cap_string(got));
  	ceph_put_cap_refs(ci, got);
d8de9ab63   Sage Weil   ceph: avoid carry...
794
  out:
124e68e74   Sage Weil   ceph: file operat...
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
  	if (ret == -EOLDSNAPC) {
  		dout("aio_write %p %llx.%llx %llu~%u got EOLDSNAPC, retrying
  ",
  		     inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len);
  		goto retry_snap;
  	}
  
  	return ret;
  }
  
  /*
   * llseek.  be sure to verify file size on SEEK_END.
   */
  static loff_t ceph_llseek(struct file *file, loff_t offset, int origin)
  {
  	struct inode *inode = file->f_mapping->host;
  	int ret;
  
  	mutex_lock(&inode->i_mutex);
  	__ceph_do_pending_vmtruncate(inode);
6a82c47aa   Sage Weil   ceph: fix SEEK_CU...
815
816
  
  	if (origin == SEEK_END || origin == SEEK_DATA || origin == SEEK_HOLE) {
124e68e74   Sage Weil   ceph: file operat...
817
818
819
820
821
  		ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE);
  		if (ret < 0) {
  			offset = ret;
  			goto out;
  		}
06222e491   Josef Bacik   fs: handle SEEK_H...
822
823
824
825
  	}
  
  	switch (origin) {
  	case SEEK_END:
124e68e74   Sage Weil   ceph: file operat...
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
  		offset += inode->i_size;
  		break;
  	case SEEK_CUR:
  		/*
  		 * Here we special-case the lseek(fd, 0, SEEK_CUR)
  		 * position-querying operation.  Avoid rewriting the "same"
  		 * f_pos value back to the file because a concurrent read(),
  		 * write() or lseek() might have altered it
  		 */
  		if (offset == 0) {
  			offset = file->f_pos;
  			goto out;
  		}
  		offset += file->f_pos;
  		break;
06222e491   Josef Bacik   fs: handle SEEK_H...
841
842
843
844
845
846
847
848
849
850
851
852
853
  	case SEEK_DATA:
  		if (offset >= inode->i_size) {
  			ret = -ENXIO;
  			goto out;
  		}
  		break;
  	case SEEK_HOLE:
  		if (offset >= inode->i_size) {
  			ret = -ENXIO;
  			goto out;
  		}
  		offset = inode->i_size;
  		break;
124e68e74   Sage Weil   ceph: file operat...
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
  	}
  
  	if (offset < 0 || offset > inode->i_sb->s_maxbytes) {
  		offset = -EINVAL;
  		goto out;
  	}
  
  	/* Special lock needed here? */
  	if (offset != file->f_pos) {
  		file->f_pos = offset;
  		file->f_version = 0;
  	}
  
  out:
  	mutex_unlock(&inode->i_mutex);
  	return offset;
  }
  
  const struct file_operations ceph_file_fops = {
  	.open = ceph_open,
  	.release = ceph_release,
  	.llseek = ceph_llseek,
  	.read = do_sync_read,
  	.write = do_sync_write,
  	.aio_read = ceph_aio_read,
  	.aio_write = ceph_aio_write,
  	.mmap = ceph_mmap,
  	.fsync = ceph_fsync,
40819f6fb   Greg Farnum   ceph: add flock/f...
882
883
  	.lock = ceph_lock,
  	.flock = ceph_flock,
124e68e74   Sage Weil   ceph: file operat...
884
885
886
887
888
  	.splice_read = generic_file_splice_read,
  	.splice_write = generic_file_splice_write,
  	.unlocked_ioctl = ceph_ioctl,
  	.compat_ioctl	= ceph_ioctl,
  };