]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.25/patches.suse/xfs-dmapi-xfs-enable
Updated xen patches taken from suse.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.suse / xfs-dmapi-xfs-enable
1 Date: Thu, 09 Oct 2008 17:11:53 +1100
2 From: Donald Douwsma <donaldd@sgi.com>
3 Subject: DMAPI support for xfs
4 Patch-mainline: ?
5 References: bnc#450658
6
7 Acked-by: Jan Kara <jack@suse.cz>
8
9 ---
10 fs/xfs/Kconfig | 13
11 fs/xfs/Makefile | 5
12 fs/xfs/dmapi/Makefile | 28
13 fs/xfs/dmapi/xfs_dm.c | 3337 +++++++++++++++++++++++++++++++++++++++++++
14 fs/xfs/dmapi/xfs_dm.h | 23
15 fs/xfs/linux-2.6/xfs_file.c | 76
16 fs/xfs/linux-2.6/xfs_ksyms.c | 99 +
17 fs/xfs/linux-2.6/xfs_linux.h | 4
18 fs/xfs/linux-2.6/xfs_super.c | 13
19 fs/xfs/xfs_dmops.c | 20
20 fs/xfs/xfs_mount.h | 1
21 11 files changed, 3613 insertions(+), 6 deletions(-)
22
23 Index: linux-2.6.27/fs/xfs/dmapi/Makefile
24 ===================================================================
25 --- /dev/null
26 +++ linux-2.6.27/fs/xfs/dmapi/Makefile
27 @@ -0,0 +1,28 @@
28 +#
29 +# Copyright (c) 2006 Silicon Graphics, Inc.
30 +# All Rights Reserved.
31 +#
32 +# This program is free software; you can redistribute it and/or
33 +# modify it under the terms of the GNU General Public License as
34 +# published by the Free Software Foundation.
35 +#
36 +# This program is distributed in the hope that it would be useful,
37 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
38 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 +# GNU General Public License for more details.
40 +#
41 +# You should have received a copy of the GNU General Public License
42 +# along with this program; if not, write the Free Software Foundation,
43 +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
44 +#
45 +
46 +EXTRA_CFLAGS += -I$(src)/.. -I$(src)/../linux-2.6
47 +EXTRA_CFLAGS += -I$(TOPDIR)/fs/dmapi
48 +
49 +ifeq ($(CONFIG_XFS_DEBUG),y)
50 + EXTRA_CFLAGS += -g -DDEBUG
51 +endif
52 +
53 +obj-$(CONFIG_XFS_DMAPI) += xfs_dmapi.o
54 +
55 +xfs_dmapi-y += xfs_dm.o
56 Index: linux-2.6.27/fs/xfs/dmapi/xfs_dm.c
57 ===================================================================
58 --- /dev/null
59 +++ linux-2.6.27/fs/xfs/dmapi/xfs_dm.c
60 @@ -0,0 +1,3337 @@
61 +/*
62 + * Copyright (c) 2000-2006 Silicon Graphics, Inc.
63 + * All Rights Reserved.
64 + *
65 + * This program is free software; you can redistribute it and/or
66 + * modify it under the terms of the GNU General Public License as
67 + * published by the Free Software Foundation.
68 + *
69 + * This program is distributed in the hope that it would be useful,
70 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
71 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
72 + * GNU General Public License for more details.
73 + *
74 + * You should have received a copy of the GNU General Public License
75 + * along with this program; if not, write the Free Software Foundation,
76 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
77 + */
78 +#include "xfs.h"
79 +#include "xfs_fs.h"
80 +#include "xfs_types.h"
81 +#include "xfs_bit.h"
82 +#include "xfs_log.h"
83 +#include "xfs_inum.h"
84 +#include "xfs_clnt.h"
85 +#include "xfs_trans.h"
86 +#include "xfs_sb.h"
87 +#include "xfs_ag.h"
88 +#include "xfs_dir2.h"
89 +#include "xfs_alloc.h"
90 +#include "xfs_dmapi.h"
91 +#include "xfs_mount.h"
92 +#include "xfs_da_btree.h"
93 +#include "xfs_bmap_btree.h"
94 +#include "xfs_alloc_btree.h"
95 +#include "xfs_ialloc_btree.h"
96 +#include "xfs_dir2_sf.h"
97 +#include "xfs_attr_sf.h"
98 +#include "xfs_dinode.h"
99 +#include "xfs_inode.h"
100 +#include "xfs_btree.h"
101 +#include "xfs_ialloc.h"
102 +#include "xfs_itable.h"
103 +#include "xfs_bmap.h"
104 +#include "xfs_rw.h"
105 +#include "xfs_acl.h"
106 +#include "xfs_attr.h"
107 +#include "xfs_attr_leaf.h"
108 +#include "xfs_inode_item.h"
109 +#include "xfs_vfsops.h"
110 +#include "xfs_vnodeops.h"
111 +#include <dmapi.h>
112 +#include <dmapi_kern.h>
113 +#include "xfs_dm.h"
114 +
115 +#include <linux/mount.h>
116 +
117 +#define MAXNAMLEN MAXNAMELEN
118 +
119 +#define MIN_DIO_SIZE(mp) ((mp)->m_sb.sb_sectsize)
120 +#define MAX_DIO_SIZE(mp) (INT_MAX & ~(MIN_DIO_SIZE(mp) - 1))
121 +
122 +static void up_rw_sems(struct inode *ip, int flags)
123 +{
124 + if (flags & DM_FLAGS_IALLOCSEM_WR)
125 + up_write(&ip->i_alloc_sem);
126 + if (flags & DM_FLAGS_IMUX)
127 + mutex_unlock(&ip->i_mutex);
128 +}
129 +
130 +static void down_rw_sems(struct inode *ip, int flags)
131 +{
132 + if (flags & DM_FLAGS_IMUX)
133 + mutex_lock(&ip->i_mutex);
134 + if (flags & DM_FLAGS_IALLOCSEM_WR)
135 + down_write(&ip->i_alloc_sem);
136 +}
137 +
138 +
139 +/* Structure used to hold the on-disk version of a dm_attrname_t. All
140 + on-disk attribute names start with the 8-byte string "SGI_DMI_".
141 +*/
142 +
143 +typedef struct {
144 + char dan_chars[DMATTR_PREFIXLEN + DM_ATTR_NAME_SIZE + 1];
145 +} dm_dkattrname_t;
146 +
147 +/* Structure used by xfs_dm_get_bulkall(), used as the "private_data"
148 + * that we want xfs_bulkstat to send to our formatter.
149 + */
150 +typedef struct {
151 + dm_fsid_t fsid;
152 + void __user *laststruct;
153 + dm_dkattrname_t attrname;
154 +} dm_bulkstat_one_t;
155 +
156 +/* In the on-disk inode, DMAPI attribute names consist of the user-provided
157 + name with the DMATTR_PREFIXSTRING pre-pended. This string must NEVER be
158 + changed!
159 +*/
160 +
161 +static const char dmattr_prefix[DMATTR_PREFIXLEN + 1] = DMATTR_PREFIXSTRING;
162 +
163 +static dm_size_t dm_min_dio_xfer = 0; /* direct I/O disabled for now */
164 +
165 +
166 +/* See xfs_dm_get_dmattr() for a description of why this is needed. */
167 +
168 +#define XFS_BUG_KLUDGE 256 /* max size of an in-inode attribute value */
169 +
170 +#define DM_MAX_ATTR_BYTES_ON_DESTROY 256
171 +
172 +#define DM_STAT_SIZE(dmtype,namelen) \
173 + (sizeof(dmtype) + sizeof(dm_handle_t) + namelen)
174 +
175 +#define DM_STAT_ALIGN (sizeof(__uint64_t))
176 +
177 +/* DMAPI's E2BIG == EA's ERANGE */
178 +#define DM_EA_XLATE_ERR(err) { if (err == ERANGE) err = E2BIG; }
179 +
180 +static inline size_t dm_stat_align(size_t size)
181 +{
182 + return (size + (DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1);
183 +}
184 +
185 +static inline size_t dm_stat_size(size_t namelen)
186 +{
187 + return dm_stat_align(sizeof(dm_stat_t) + sizeof(dm_handle_t) + namelen);
188 +}
189 +
190 +/*
191 + * xfs_dm_send_data_event()
192 + *
193 + * Send data event to DMAPI. Drop IO lock (if specified) before
194 + * the dm_send_data_event() call and reacquire it afterwards.
195 + */
196 +int
197 +xfs_dm_send_data_event(
198 + dm_eventtype_t event,
199 + xfs_inode_t *ip,
200 + xfs_off_t offset,
201 + size_t length,
202 + int flags,
203 + int *lock_flags)
204 +{
205 + struct inode *inode = ip->i_vnode;
206 + int error;
207 + uint16_t dmstate;
208 +
209 + /* Returns positive errors to XFS */
210 +
211 + do {
212 + dmstate = ip->i_d.di_dmstate;
213 + if (lock_flags)
214 + xfs_iunlock(ip, *lock_flags);
215 +
216 + up_rw_sems(inode, flags);
217 +
218 + error = dm_send_data_event(event, inode, DM_RIGHT_NULL,
219 + offset, length, flags);
220 + error = -error; /* DMAPI returns negative errors */
221 +
222 + down_rw_sems(inode, flags);
223 +
224 + if (lock_flags)
225 + xfs_ilock(ip, *lock_flags);
226 + } while (!error && (ip->i_d.di_dmstate != dmstate));
227 +
228 + return error;
229 +}
230 +
231 +/* prohibited_mr_events
232 + *
233 + * Return event bits representing any events which cannot have managed
234 + * region events set due to memory mapping of the file. If the maximum
235 + * protection allowed in any pregion includes PROT_WRITE, and the region
236 + * is shared and not text, then neither READ nor WRITE events can be set.
237 + * Otherwise if the file is memory mapped, no READ event can be set.
238 + *
239 + */
240 +STATIC int
241 +prohibited_mr_events(
242 + struct address_space *mapping)
243 +{
244 + int prohibited = (1 << DM_EVENT_READ);
245 +
246 + if (!mapping_mapped(mapping))
247 + return 0;
248 +
249 + spin_lock(&mapping->i_mmap_lock);
250 + if (mapping_writably_mapped(mapping))
251 + prohibited |= (1 << DM_EVENT_WRITE);
252 + spin_unlock(&mapping->i_mmap_lock);
253 +
254 + return prohibited;
255 +}
256 +
257 +#ifdef DEBUG_RIGHTS
258 +STATIC int
259 +xfs_vp_to_hexhandle(
260 + struct inode *inode,
261 + u_int type,
262 + char *buffer)
263 +{
264 + dm_handle_t handle;
265 + u_char *ip;
266 + int length;
267 + int error;
268 + int i;
269 +
270 + /*
271 + * XXX: dm_vp_to_handle doesn't exist.
272 + * Looks like this debug code is rather dead.
273 + */
274 + if ((error = dm_vp_to_handle(inode, &handle)))
275 + return(error);
276 +
277 + if (type == DM_FSYS_OBJ) { /* a filesystem handle */
278 + length = DM_FSHSIZE;
279 + } else {
280 + length = DM_HSIZE(handle);
281 + }
282 + for (ip = (u_char *)&handle, i = 0; i < length; i++) {
283 + *buffer++ = "0123456789abcdef"[ip[i] >> 4];
284 + *buffer++ = "0123456789abcdef"[ip[i] & 0xf];
285 + }
286 + *buffer = '\0';
287 + return(0);
288 +}
289 +#endif /* DEBUG_RIGHTS */
290 +
291 +
292 +
293 +
294 +/* Copy in and validate an attribute name from user space. It should be a
295 + string of at least one and at most DM_ATTR_NAME_SIZE characters. Because
296 + the dm_attrname_t structure doesn't provide room for the trailing NULL
297 + byte, we just copy in one extra character and then zero it if it
298 + happens to be non-NULL.
299 +*/
300 +
301 +STATIC int
302 +xfs_copyin_attrname(
303 + dm_attrname_t __user *from, /* dm_attrname_t in user space */
304 + dm_dkattrname_t *to) /* name buffer in kernel space */
305 +{
306 + int error = 0;
307 + size_t len;
308 +
309 + strcpy(to->dan_chars, dmattr_prefix);
310 +
311 + len = strnlen_user((char __user *)from, DM_ATTR_NAME_SIZE);
312 + if (len == 0)
313 + error = EFAULT;
314 + else {
315 + if (copy_from_user(&to->dan_chars[DMATTR_PREFIXLEN], from, len))
316 + to->dan_chars[sizeof(to->dan_chars) - 1] = '\0';
317 + else if (to->dan_chars[DMATTR_PREFIXLEN] == '\0')
318 + error = EINVAL;
319 + else
320 + to->dan_chars[DMATTR_PREFIXLEN + len - 1] = '\0';
321 + }
322 +
323 + return error;
324 +}
325 +
326 +
327 +/*
328 + * Convert the XFS flags into their DMAPI flag equivalent for export
329 + */
330 +STATIC uint
331 +_xfs_dic2dmflags(
332 + __uint16_t di_flags)
333 +{
334 + uint flags = 0;
335 +
336 + if (di_flags & XFS_DIFLAG_ANY) {
337 + if (di_flags & XFS_DIFLAG_REALTIME)
338 + flags |= DM_XFLAG_REALTIME;
339 + if (di_flags & XFS_DIFLAG_PREALLOC)
340 + flags |= DM_XFLAG_PREALLOC;
341 + if (di_flags & XFS_DIFLAG_IMMUTABLE)
342 + flags |= DM_XFLAG_IMMUTABLE;
343 + if (di_flags & XFS_DIFLAG_APPEND)
344 + flags |= DM_XFLAG_APPEND;
345 + if (di_flags & XFS_DIFLAG_SYNC)
346 + flags |= DM_XFLAG_SYNC;
347 + if (di_flags & XFS_DIFLAG_NOATIME)
348 + flags |= DM_XFLAG_NOATIME;
349 + if (di_flags & XFS_DIFLAG_NODUMP)
350 + flags |= DM_XFLAG_NODUMP;
351 + }
352 + return flags;
353 +}
354 +
355 +STATIC uint
356 +xfs_ip2dmflags(
357 + xfs_inode_t *ip)
358 +{
359 + return _xfs_dic2dmflags(ip->i_d.di_flags) |
360 + (XFS_IFORK_Q(ip) ? DM_XFLAG_HASATTR : 0);
361 +}
362 +
363 +STATIC uint
364 +xfs_dic2dmflags(
365 + xfs_dinode_t *dip)
366 +{
367 + return _xfs_dic2dmflags(be16_to_cpu(dip->di_core.di_flags)) |
368 + (XFS_DFORK_Q(dip) ? DM_XFLAG_HASATTR : 0);
369 +}
370 +
371 +/*
372 + * This copies selected fields in an inode into a dm_stat structure. Because
373 + * these fields must return the same values as they would in stat(), the
374 + * majority of this code was copied directly from xfs_getattr(). Any future
375 + * changes to xfs_gettattr() must also be reflected here.
376 + */
377 +STATIC void
378 +xfs_dip_to_stat(
379 + xfs_mount_t *mp,
380 + xfs_ino_t ino,
381 + xfs_dinode_t *dip,
382 + dm_stat_t *buf)
383 +{
384 + xfs_dinode_core_t *dic = &dip->di_core;
385 +
386 + /*
387 + * The inode format changed when we moved the link count and
388 + * made it 32 bits long. If this is an old format inode,
389 + * convert it in memory to look like a new one. If it gets
390 + * flushed to disk we will convert back before flushing or
391 + * logging it. We zero out the new projid field and the old link
392 + * count field. We'll handle clearing the pad field (the remains
393 + * of the old uuid field) when we actually convert the inode to
394 + * the new format. We don't change the version number so that we
395 + * can distinguish this from a real new format inode.
396 + */
397 + if (dic->di_version == XFS_DINODE_VERSION_1) {
398 + buf->dt_nlink = be16_to_cpu(dic->di_onlink);
399 + /*buf->dt_xfs_projid = 0;*/
400 + } else {
401 + buf->dt_nlink = be32_to_cpu(dic->di_nlink);
402 + /*buf->dt_xfs_projid = be16_to_cpu(dic->di_projid);*/
403 + }
404 + buf->dt_ino = ino;
405 + buf->dt_dev = new_encode_dev(mp->m_ddev_targp->bt_dev);
406 + buf->dt_mode = be16_to_cpu(dic->di_mode);
407 + buf->dt_uid = be32_to_cpu(dic->di_uid);
408 + buf->dt_gid = be32_to_cpu(dic->di_gid);
409 + buf->dt_size = be64_to_cpu(dic->di_size);
410 + buf->dt_atime = be32_to_cpu(dic->di_atime.t_sec);
411 + buf->dt_mtime = be32_to_cpu(dic->di_mtime.t_sec);
412 + buf->dt_ctime = be32_to_cpu(dic->di_ctime.t_sec);
413 + buf->dt_xfs_xflags = xfs_dic2dmflags(dip);
414 + buf->dt_xfs_extsize =
415 + be32_to_cpu(dic->di_extsize) << mp->m_sb.sb_blocklog;
416 + buf->dt_xfs_extents = be32_to_cpu(dic->di_nextents);
417 + buf->dt_xfs_aextents = be16_to_cpu(dic->di_anextents);
418 + buf->dt_xfs_igen = be32_to_cpu(dic->di_gen);
419 + buf->dt_xfs_dmstate = be16_to_cpu(dic->di_dmstate);
420 +
421 + switch (dic->di_format) {
422 + case XFS_DINODE_FMT_DEV:
423 + buf->dt_rdev = be32_to_cpu(dip->di_u.di_dev);
424 + buf->dt_blksize = BLKDEV_IOSIZE;
425 + buf->dt_blocks = 0;
426 + break;
427 + case XFS_DINODE_FMT_LOCAL:
428 + case XFS_DINODE_FMT_UUID:
429 + buf->dt_rdev = 0;
430 + buf->dt_blksize = mp->m_sb.sb_blocksize;
431 + buf->dt_blocks = 0;
432 + break;
433 + case XFS_DINODE_FMT_EXTENTS:
434 + case XFS_DINODE_FMT_BTREE:
435 + buf->dt_rdev = 0;
436 + buf->dt_blksize = mp->m_sb.sb_blocksize;
437 + buf->dt_blocks =
438 + XFS_FSB_TO_BB(mp, be64_to_cpu(dic->di_nblocks));
439 + break;
440 + }
441 +
442 + memset(&buf->dt_pad1, 0, sizeof(buf->dt_pad1));
443 + memset(&buf->dt_pad2, 0, sizeof(buf->dt_pad2));
444 + memset(&buf->dt_pad3, 0, sizeof(buf->dt_pad3));
445 +
446 + /* Finally fill in the DMAPI specific fields */
447 + buf->dt_pers = 0;
448 + buf->dt_change = 0;
449 + buf->dt_nevents = DM_EVENT_MAX;
450 + buf->dt_emask = be32_to_cpu(dic->di_dmevmask);
451 + buf->dt_dtime = be32_to_cpu(dic->di_ctime.t_sec);
452 + /* Set if one of READ, WRITE or TRUNCATE bits is set in emask */
453 + buf->dt_pmanreg = (DMEV_ISSET(DM_EVENT_READ, buf->dt_emask) ||
454 + DMEV_ISSET(DM_EVENT_WRITE, buf->dt_emask) ||
455 + DMEV_ISSET(DM_EVENT_TRUNCATE, buf->dt_emask)) ? 1 : 0;
456 +}
457 +
458 +/*
459 + * Pull out both ondisk and incore fields, incore has preference.
460 + * The inode must be kept locked SHARED by the caller.
461 + */
462 +STATIC void
463 +xfs_ip_to_stat(
464 + xfs_mount_t *mp,
465 + xfs_ino_t ino,
466 + xfs_inode_t *ip,
467 + dm_stat_t *buf)
468 +{
469 + xfs_icdinode_t *dic = &ip->i_d;
470 +
471 + buf->dt_ino = ino;
472 + buf->dt_nlink = dic->di_nlink;
473 + /*buf->dt_xfs_projid = dic->di_projid;*/
474 + buf->dt_mode = dic->di_mode;
475 + buf->dt_uid = dic->di_uid;
476 + buf->dt_gid = dic->di_gid;
477 + buf->dt_size = XFS_ISIZE(ip);
478 + buf->dt_dev = new_encode_dev(mp->m_ddev_targp->bt_dev);
479 + vn_atime_to_time_t(VFS_I(ip), &buf->dt_atime);
480 + buf->dt_mtime = dic->di_mtime.t_sec;
481 + buf->dt_ctime = dic->di_ctime.t_sec;
482 + buf->dt_xfs_xflags = xfs_ip2dmflags(ip);
483 + buf->dt_xfs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog;
484 + buf->dt_xfs_extents = dic->di_nextents;
485 + buf->dt_xfs_aextents = dic->di_anextents;
486 + buf->dt_xfs_igen = dic->di_gen;
487 + buf->dt_xfs_dmstate = dic->di_dmstate;
488 +
489 + switch (dic->di_format) {
490 + case XFS_DINODE_FMT_DEV:
491 + buf->dt_rdev = ip->i_df.if_u2.if_rdev;
492 + buf->dt_blksize = BLKDEV_IOSIZE;
493 + buf->dt_blocks = 0;
494 + break;
495 + case XFS_DINODE_FMT_LOCAL:
496 + case XFS_DINODE_FMT_UUID:
497 + buf->dt_rdev = 0;
498 + buf->dt_blksize = mp->m_sb.sb_blocksize;
499 + buf->dt_blocks = 0;
500 + break;
501 + case XFS_DINODE_FMT_EXTENTS:
502 + case XFS_DINODE_FMT_BTREE:
503 + buf->dt_rdev = 0;
504 + buf->dt_blksize = mp->m_sb.sb_blocksize;
505 + buf->dt_blocks = XFS_FSB_TO_BB(mp,
506 + (dic->di_nblocks + ip->i_delayed_blks));
507 + break;
508 + }
509 +
510 + memset(&buf->dt_pad1, 0, sizeof(buf->dt_pad1));
511 + memset(&buf->dt_pad2, 0, sizeof(buf->dt_pad2));
512 + memset(&buf->dt_pad3, 0, sizeof(buf->dt_pad3));
513 +
514 + /* Finally fill in the DMAPI specific fields */
515 + buf->dt_pers = 0;
516 + buf->dt_change = 0;
517 + buf->dt_nevents = DM_EVENT_MAX;
518 + buf->dt_emask = dic->di_dmevmask;
519 + buf->dt_dtime = dic->di_ctime.t_sec;
520 + /* Set if one of READ, WRITE or TRUNCATE bits is set in emask */
521 + buf->dt_pmanreg = (DMEV_ISSET(DM_EVENT_READ, buf->dt_emask) ||
522 + DMEV_ISSET(DM_EVENT_WRITE, buf->dt_emask) ||
523 + DMEV_ISSET(DM_EVENT_TRUNCATE, buf->dt_emask)) ? 1 : 0;
524 +}
525 +
526 +/*
527 + * Take the handle and put it at the end of a dm_xstat buffer.
528 + * dt_compname is unused in bulkstat - so we zero it out.
529 + * Finally, update link in dm_xstat_t to point to next struct.
530 + */
531 +STATIC void
532 +xfs_dm_handle_to_xstat(
533 + dm_xstat_t *xbuf,
534 + size_t xstat_sz,
535 + dm_handle_t *handle,
536 + size_t handle_sz)
537 +{
538 + dm_stat_t *sbuf = &xbuf->dx_statinfo;
539 +
540 + memcpy(xbuf + 1, handle, handle_sz);
541 + sbuf->dt_handle.vd_offset = (ssize_t) sizeof(dm_xstat_t);
542 + sbuf->dt_handle.vd_length = (size_t) DM_HSIZE(*handle);
543 + memset(&sbuf->dt_compname, 0, sizeof(dm_vardata_t));
544 + sbuf->_link = xstat_sz;
545 +}
546 +
547 +STATIC int
548 +xfs_dm_bulkall_iget_one(
549 + xfs_mount_t *mp,
550 + xfs_ino_t ino,
551 + xfs_daddr_t bno,
552 + int *value_lenp,
553 + dm_xstat_t *xbuf,
554 + u_int *xstat_szp,
555 + char *attr_name,
556 + caddr_t attr_buf)
557 +{
558 + xfs_inode_t *ip;
559 + dm_handle_t handle;
560 + u_int xstat_sz = *xstat_szp;
561 + int value_len = *value_lenp;
562 + int error;
563 +
564 + error = xfs_iget(mp, NULL, ino,
565 + XFS_IGET_BULKSTAT, XFS_ILOCK_SHARED, &ip, bno);
566 + if (error)
567 + return error;
568 +
569 + xfs_ip_to_stat(mp, ino, ip, &xbuf->dx_statinfo);
570 + dm_ip_to_handle(ip->i_vnode, &handle);
571 + xfs_dm_handle_to_xstat(xbuf, xstat_sz, &handle, sizeof(handle));
572 +
573 + /* Drop ILOCK_SHARED for call to xfs_attr_get */
574 + xfs_iunlock(ip, XFS_ILOCK_SHARED);
575 +
576 + memset(&xbuf->dx_attrdata, 0, sizeof(dm_vardata_t));
577 + error = xfs_attr_get(ip, attr_name, attr_buf, &value_len, ATTR_ROOT);
578 + iput(ip->i_vnode);
579 +
580 + DM_EA_XLATE_ERR(error);
581 + if (error && (error != ENOATTR)) {
582 + if (error == E2BIG)
583 + error = ENOMEM;
584 + return error;
585 + }
586 +
587 + /* How much space was in the attr? */
588 + if (error != ENOATTR) {
589 + xbuf->dx_attrdata.vd_offset = xstat_sz;
590 + xbuf->dx_attrdata.vd_length = value_len;
591 + xstat_sz += (value_len+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1);
592 + }
593 + *xstat_szp = xbuf->dx_statinfo._link = xstat_sz;
594 + *value_lenp = value_len;
595 + return 0;
596 +}
597 +
598 +
599 +STATIC int
600 +xfs_dm_inline_attr(
601 + xfs_mount_t *mp,
602 + xfs_dinode_t *dip,
603 + char *attr_name,
604 + caddr_t attr_buf,
605 + int *value_lenp)
606 +{
607 + if (dip->di_core.di_aformat == XFS_DINODE_FMT_LOCAL) {
608 + xfs_attr_shortform_t *sf;
609 + xfs_attr_sf_entry_t *sfe;
610 + unsigned int namelen = strlen(attr_name);
611 + unsigned int valuelen = *value_lenp;
612 + int i;
613 +
614 + sf = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
615 + sfe = &sf->list[0];
616 + for (i = 0; i < sf->hdr.count;
617 + sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
618 + if (sfe->namelen != namelen)
619 + continue;
620 + if (!(sfe->flags & XFS_ATTR_ROOT))
621 + continue;
622 + if (memcmp(attr_name, sfe->nameval, namelen) != 0)
623 + continue;
624 + if (valuelen < sfe->valuelen)
625 + return ERANGE;
626 + valuelen = sfe->valuelen;
627 + memcpy(attr_buf, &sfe->nameval[namelen], valuelen);
628 + *value_lenp = valuelen;
629 + return 0;
630 + }
631 + }
632 + *value_lenp = 0;
633 + return ENOATTR;
634 +}
635 +
636 +STATIC void
637 +dm_dip_to_handle(
638 + xfs_ino_t ino,
639 + xfs_dinode_t *dip,
640 + dm_fsid_t *fsid,
641 + dm_handle_t *handlep)
642 +{
643 + dm_fid_t fid;
644 + int hsize;
645 +
646 + fid.dm_fid_len = sizeof(struct dm_fid) - sizeof(fid.dm_fid_len);
647 + fid.dm_fid_pad = 0;
648 + fid.dm_fid_ino = ino;
649 + fid.dm_fid_gen = be32_to_cpu(dip->di_core.di_gen);
650 +
651 + memcpy(&handlep->ha_fsid, fsid, sizeof(*fsid));
652 + memcpy(&handlep->ha_fid, &fid, fid.dm_fid_len + sizeof(fid.dm_fid_len));
653 + hsize = DM_HSIZE(*handlep);
654 + memset((char *)handlep + hsize, 0, sizeof(*handlep) - hsize);
655 +}
656 +
657 +STATIC int
658 +xfs_dm_bulkall_inline_one(
659 + xfs_mount_t *mp,
660 + xfs_ino_t ino,
661 + xfs_dinode_t *dip,
662 + dm_fsid_t *fsid,
663 + int *value_lenp,
664 + dm_xstat_t *xbuf,
665 + u_int *xstat_szp,
666 + char *attr_name,
667 + caddr_t attr_buf)
668 +{
669 + dm_handle_t handle;
670 + u_int xstat_sz = *xstat_szp;
671 + int value_len = *value_lenp;
672 + int error;
673 +
674 + if (dip->di_core.di_mode == 0)
675 + return ENOENT;
676 +
677 + xfs_dip_to_stat(mp, ino, dip, &xbuf->dx_statinfo);
678 + dm_dip_to_handle(ino, dip, fsid, &handle);
679 + xfs_dm_handle_to_xstat(xbuf, xstat_sz, &handle, sizeof(handle));
680 +
681 + memset(&xbuf->dx_attrdata, 0, sizeof(dm_vardata_t));
682 + error = xfs_dm_inline_attr(mp, dip, attr_name, attr_buf, &value_len);
683 + DM_EA_XLATE_ERR(error);
684 + if (error && (error != ENOATTR)) {
685 + if (error == E2BIG)
686 + error = ENOMEM;
687 + return error;
688 + }
689 +
690 + /* How much space was in the attr? */
691 + if (error != ENOATTR) {
692 + xbuf->dx_attrdata.vd_offset = xstat_sz;
693 + xbuf->dx_attrdata.vd_length = value_len;
694 + xstat_sz += (value_len+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1);
695 + }
696 + *xstat_szp = xbuf->dx_statinfo._link = xstat_sz;
697 + *value_lenp = value_len;
698 + return 0;
699 +}
700 +
701 +/*
702 + * This is used by dm_get_bulkall().
703 + * Given a inumber, it igets the inode and fills the given buffer
704 + * with the dm_xstat structure for the file.
705 + */
706 +STATIC int
707 +xfs_dm_bulkall_one(
708 + xfs_mount_t *mp, /* mount point for filesystem */
709 + xfs_ino_t ino, /* inode number to get data for */
710 + void __user *buffer, /* buffer to place output in */
711 + int ubsize, /* size of buffer */
712 + void *private_data, /* my private data */
713 + xfs_daddr_t bno, /* starting block of inode cluster */
714 + int *ubused, /* amount of buffer we used */
715 + void *dibuff, /* on-disk inode buffer */
716 + int *res) /* bulkstat result code */
717 +{
718 + dm_xstat_t *xbuf;
719 + u_int xstat_sz;
720 + int error;
721 + int value_len;
722 + int kern_buf_sz;
723 + int attr_buf_sz;
724 + caddr_t attr_buf;
725 + void __user *attr_user_buf;
726 + dm_bulkstat_one_t *dmb = (dm_bulkstat_one_t*)private_data;
727 +
728 + /* Returns positive errors to XFS */
729 +
730 + *res = BULKSTAT_RV_NOTHING;
731 +
732 + if (!buffer || xfs_internal_inum(mp, ino))
733 + return EINVAL;
734 +
735 + xstat_sz = DM_STAT_SIZE(*xbuf, 0);
736 + xstat_sz = (xstat_sz + (DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1);
737 + if (xstat_sz > ubsize)
738 + return ENOMEM;
739 +
740 + kern_buf_sz = xstat_sz;
741 + xbuf = kmem_alloc(kern_buf_sz, KM_SLEEP);
742 +
743 + /* Determine place to drop attr value, and available space. */
744 + value_len = ubsize - xstat_sz;
745 + if (value_len > ATTR_MAX_VALUELEN)
746 + value_len = ATTR_MAX_VALUELEN;
747 +
748 + attr_user_buf = buffer + xstat_sz;
749 + attr_buf_sz = value_len;
750 + attr_buf = kmem_alloc(attr_buf_sz, KM_SLEEP);
751 +
752 + if (!dibuff)
753 + error = xfs_dm_bulkall_iget_one(mp, ino, bno,
754 + &value_len, xbuf, &xstat_sz,
755 + dmb->attrname.dan_chars,
756 + attr_buf);
757 + else
758 + error = xfs_dm_bulkall_inline_one(mp, ino,
759 + (xfs_dinode_t *)dibuff,
760 + &dmb->fsid,
761 + &value_len, xbuf, &xstat_sz,
762 + dmb->attrname.dan_chars,
763 + attr_buf);
764 + if (error)
765 + goto out_free_buffers;
766 +
767 + if (copy_to_user(buffer, xbuf, kern_buf_sz)) {
768 + error = EFAULT;
769 + goto out_free_buffers;
770 + }
771 + if (copy_to_user(attr_user_buf, attr_buf, value_len)) {
772 + error = EFAULT;
773 + goto out_free_buffers;
774 + }
775 +
776 + kmem_free(attr_buf);
777 + kmem_free(xbuf);
778 +
779 + *res = BULKSTAT_RV_DIDONE;
780 + if (ubused)
781 + *ubused = xstat_sz;
782 + dmb->laststruct = buffer;
783 + return 0;
784 +
785 + out_free_buffers:
786 + kmem_free(attr_buf);
787 + kmem_free(xbuf);
788 + return error;
789 +}
790 +
791 +/*
792 + * Take the handle and put it at the end of a dm_stat buffer.
793 + * dt_compname is unused in bulkstat - so we zero it out.
794 + * Finally, update link in dm_stat_t to point to next struct.
795 + */
796 +STATIC void
797 +xfs_dm_handle_to_stat(
798 + dm_stat_t *sbuf,
799 + size_t stat_sz,
800 + dm_handle_t *handle,
801 + size_t handle_sz)
802 +{
803 + memcpy(sbuf + 1, handle, handle_sz);
804 + sbuf->dt_handle.vd_offset = (ssize_t) sizeof(dm_stat_t);
805 + sbuf->dt_handle.vd_length = (size_t) DM_HSIZE(*handle);
806 + memset(&sbuf->dt_compname, 0, sizeof(dm_vardata_t));
807 + sbuf->_link = stat_sz;
808 +}
809 +
810 +STATIC int
811 +xfs_dm_bulkattr_iget_one(
812 + xfs_mount_t *mp,
813 + xfs_ino_t ino,
814 + xfs_daddr_t bno,
815 + dm_stat_t *sbuf,
816 + u_int stat_sz)
817 +{
818 + xfs_inode_t *ip;
819 + dm_handle_t handle;
820 + int error;
821 +
822 + error = xfs_iget(mp, NULL, ino,
823 + XFS_IGET_BULKSTAT, XFS_ILOCK_SHARED, &ip, bno);
824 + if (error)
825 + return error;
826 +
827 + xfs_ip_to_stat(mp, ino, ip, sbuf);
828 + dm_ip_to_handle(ip->i_vnode, &handle);
829 + xfs_dm_handle_to_stat(sbuf, stat_sz, &handle, sizeof(handle));
830 +
831 + xfs_iput(ip, XFS_ILOCK_SHARED);
832 + return 0;
833 +}
834 +
835 +STATIC int
836 +xfs_dm_bulkattr_inline_one(
837 + xfs_mount_t *mp,
838 + xfs_ino_t ino,
839 + xfs_dinode_t *dip,
840 + dm_fsid_t *fsid,
841 + dm_stat_t *sbuf,
842 + u_int stat_sz)
843 +{
844 + dm_handle_t handle;
845 +
846 + if (dip->di_core.di_mode == 0)
847 + return ENOENT;
848 + xfs_dip_to_stat(mp, ino, dip, sbuf);
849 + dm_dip_to_handle(ino, dip, fsid, &handle);
850 + xfs_dm_handle_to_stat(sbuf, stat_sz, &handle, sizeof(handle));
851 + return 0;
852 +}
853 +
854 +/*
855 + * This is used by dm_get_bulkattr().
856 + * Given a inumber, it igets the inode and fills the given buffer
857 + * with the dm_stat structure for the file.
858 + */
859 +STATIC int
860 +xfs_dm_bulkattr_one(
861 + xfs_mount_t *mp, /* mount point for filesystem */
862 + xfs_ino_t ino, /* inode number to get data for */
863 + void __user *buffer, /* buffer to place output in */
864 + int ubsize, /* size of buffer */
865 + void *private_data, /* my private data */
866 + xfs_daddr_t bno, /* starting block of inode cluster */
867 + int *ubused, /* amount of buffer we used */
868 + void *dibuff, /* on-disk inode buffer */
869 + int *res) /* bulkstat result code */
870 +{
871 + dm_stat_t *sbuf;
872 + u_int stat_sz;
873 + int error;
874 + dm_bulkstat_one_t *dmb = (dm_bulkstat_one_t*)private_data;
875 +
876 + /* Returns positive errors to XFS */
877 +
878 + *res = BULKSTAT_RV_NOTHING;
879 +
880 + if (!buffer || xfs_internal_inum(mp, ino))
881 + return EINVAL;
882 +
883 + stat_sz = DM_STAT_SIZE(*sbuf, 0);
884 + stat_sz = (stat_sz+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1);
885 + if (stat_sz > ubsize)
886 + return ENOMEM;
887 +
888 + sbuf = kmem_alloc(stat_sz, KM_SLEEP);
889 +
890 + if (!dibuff)
891 + error = xfs_dm_bulkattr_iget_one(mp, ino, bno, sbuf, stat_sz);
892 + else
893 + error = xfs_dm_bulkattr_inline_one(mp, ino,
894 + (xfs_dinode_t *)dibuff,
895 + &dmb->fsid, sbuf, stat_sz);
896 + if (error)
897 + goto out_free_buffer;
898 +
899 + if (copy_to_user(buffer, sbuf, stat_sz)) {
900 + error = EFAULT;
901 + goto out_free_buffer;
902 + }
903 +
904 + kmem_free(sbuf);
905 + *res = BULKSTAT_RV_DIDONE;
906 + if (ubused)
907 + *ubused = stat_sz;
908 + dmb->laststruct = buffer;
909 + return 0;
910 +
911 + out_free_buffer:
912 + kmem_free(sbuf);
913 + return error;
914 +}
915 +
916 +/* xfs_dm_f_get_eventlist - return the dm_eventset_t mask for inode ip. */
917 +
918 +STATIC int
919 +xfs_dm_f_get_eventlist(
920 + xfs_inode_t *ip,
921 + dm_right_t right,
922 + u_int nelem,
923 + dm_eventset_t *eventsetp, /* in kernel space! */
924 + u_int *nelemp) /* in kernel space! */
925 +{
926 + dm_eventset_t eventset;
927 +
928 + if (right < DM_RIGHT_SHARED)
929 + return(EACCES);
930 +
931 + /* Note that we MUST return a regular file's managed region bits as
932 + part of the mask because dm_get_eventlist is supposed to return the
933 + union of all managed region flags in those bits. Since we only
934 + support one region, we can just return the bits as they are. For
935 + all other object types, the bits will already be zero. Handy, huh?
936 + */
937 +
938 + eventset = ip->i_d.di_dmevmask;
939 +
940 + /* Now copy the event mask and event count back to the caller. We
941 + return the lesser of nelem and DM_EVENT_MAX.
942 + */
943 +
944 + if (nelem > DM_EVENT_MAX)
945 + nelem = DM_EVENT_MAX;
946 + eventset &= (1 << nelem) - 1;
947 +
948 + *eventsetp = eventset;
949 + *nelemp = nelem;
950 + return(0);
951 +}
952 +
953 +
954 +/* xfs_dm_f_set_eventlist - update the dm_eventset_t mask in the inode vp. Only the
955 + bits from zero to maxevent-1 are being replaced; higher bits are preserved.
956 +*/
957 +
958 +STATIC int
959 +xfs_dm_f_set_eventlist(
960 + xfs_inode_t *ip,
961 + dm_right_t right,
962 + dm_eventset_t *eventsetp, /* in kernel space! */
963 + u_int maxevent)
964 +{
965 + dm_eventset_t eventset;
966 + dm_eventset_t max_mask;
967 + dm_eventset_t valid_events;
968 + xfs_trans_t *tp;
969 + xfs_mount_t *mp;
970 + int error;
971 +
972 + if (right < DM_RIGHT_EXCL)
973 + return(EACCES);
974 +
975 + eventset = *eventsetp;
976 + if (maxevent >= sizeof(ip->i_d.di_dmevmask) * NBBY)
977 + return(EINVAL);
978 + max_mask = (1 << maxevent) - 1;
979 +
980 + if (S_ISDIR(ip->i_d.di_mode)) {
981 + valid_events = DM_XFS_VALID_DIRECTORY_EVENTS;
982 + } else { /* file or symlink */
983 + valid_events = DM_XFS_VALID_FILE_EVENTS;
984 + }
985 + if ((eventset & max_mask) & ~valid_events)
986 + return(EINVAL);
987 +
988 + /* Adjust the event mask so that the managed region bits will not
989 + be altered.
990 + */
991 +
992 + max_mask &= ~(1 <<DM_EVENT_READ); /* preserve current MR bits */
993 + max_mask &= ~(1 <<DM_EVENT_WRITE);
994 + max_mask &= ~(1 <<DM_EVENT_TRUNCATE);
995 +
996 + mp = ip->i_mount;
997 + tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS);
998 + error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0);
999 + if (error) {
1000 + xfs_trans_cancel(tp, 0);
1001 + return(error);
1002 + }
1003 + xfs_ilock(ip, XFS_ILOCK_EXCL);
1004 + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
1005 +
1006 + ip->i_d.di_dmevmask = (eventset & max_mask) | (ip->i_d.di_dmevmask & ~max_mask);
1007 +
1008 + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
1009 + igrab(ip->i_vnode);
1010 + xfs_trans_commit(tp, 0);
1011 +
1012 + return(0);
1013 +}
1014 +
1015 +
1016 +/* xfs_dm_fs_get_eventlist - return the dm_eventset_t mask for filesystem vfsp. */
1017 +
1018 +STATIC int
1019 +xfs_dm_fs_get_eventlist(
1020 + xfs_mount_t *mp,
1021 + dm_right_t right,
1022 + u_int nelem,
1023 + dm_eventset_t *eventsetp, /* in kernel space! */
1024 + u_int *nelemp) /* in kernel space! */
1025 +{
1026 + dm_eventset_t eventset;
1027 +
1028 + if (right < DM_RIGHT_SHARED)
1029 + return(EACCES);
1030 +
1031 + eventset = mp->m_dmevmask;
1032 +
1033 + /* Now copy the event mask and event count back to the caller. We
1034 + return the lesser of nelem and DM_EVENT_MAX.
1035 + */
1036 +
1037 + if (nelem > DM_EVENT_MAX)
1038 + nelem = DM_EVENT_MAX;
1039 + eventset &= (1 << nelem) - 1;
1040 +
1041 + *eventsetp = eventset;
1042 + *nelemp = nelem;
1043 + return(0);
1044 +}
1045 +
1046 +
1047 +/* xfs_dm_fs_set_eventlist - update the dm_eventset_t mask in the mount structure for
1048 + filesystem vfsp. Only the bits from zero to maxevent-1 are being replaced;
1049 + higher bits are preserved.
1050 +*/
1051 +
1052 +STATIC int
1053 +xfs_dm_fs_set_eventlist(
1054 + xfs_mount_t *mp,
1055 + dm_right_t right,
1056 + dm_eventset_t *eventsetp, /* in kernel space! */
1057 + u_int maxevent)
1058 +{
1059 + dm_eventset_t eventset;
1060 + dm_eventset_t max_mask;
1061 +
1062 + if (right < DM_RIGHT_EXCL)
1063 + return(EACCES);
1064 +
1065 + eventset = *eventsetp;
1066 +
1067 + if (maxevent >= sizeof(mp->m_dmevmask) * NBBY)
1068 + return(EINVAL);
1069 + max_mask = (1 << maxevent) - 1;
1070 +
1071 + if ((eventset & max_mask) & ~DM_XFS_VALID_FS_EVENTS)
1072 + return(EINVAL);
1073 +
1074 + mp->m_dmevmask = (eventset & max_mask) | (mp->m_dmevmask & ~max_mask);
1075 + return(0);
1076 +}
1077 +
1078 +
1079 +/* Code in this routine must exactly match the logic in xfs_diordwr() in
1080 + order for this to work!
1081 +*/
1082 +
1083 +STATIC int
1084 +xfs_dm_direct_ok(
1085 + xfs_inode_t *ip,
1086 + dm_off_t off,
1087 + dm_size_t len,
1088 + void __user *bufp)
1089 +{
1090 + xfs_mount_t *mp;
1091 +
1092 + mp = ip->i_mount;
1093 +
1094 + /* Realtime files can ONLY do direct I/O. */
1095 +
1096 + if (XFS_IS_REALTIME_INODE(ip))
1097 + return(1);
1098 +
1099 + /* If direct I/O is disabled, or if the request is too small, use
1100 + buffered I/O.
1101 + */
1102 +
1103 + if (!dm_min_dio_xfer || len < dm_min_dio_xfer)
1104 + return(0);
1105 +
1106 +#if 0
1107 + /* If the request is not well-formed or is too large, use
1108 + buffered I/O.
1109 + */
1110 +
1111 + if ((__psint_t)bufp & scache_linemask) /* if buffer not aligned */
1112 + return(0);
1113 + if (off & mp->m_blockmask) /* if file offset not aligned */
1114 + return(0);
1115 + if (len & mp->m_blockmask) /* if xfer length not aligned */
1116 + return(0);
1117 + if (len > ctooff(v.v_maxdmasz - 1)) /* if transfer too large */
1118 + return(0);
1119 +
1120 + /* A valid direct I/O candidate. */
1121 +
1122 + return(1);
1123 +#else
1124 + return(0);
1125 +#endif
1126 +}
1127 +
1128 +
1129 +/* We need to be able to select various combinations of O_NONBLOCK,
1130 + O_DIRECT, and O_SYNC, yet we don't have a file descriptor and we don't have
1131 + the file's pathname. All we have is a handle.
1132 +*/
1133 +
1134 +STATIC int
1135 +xfs_dm_rdwr(
1136 + struct inode *inode,
1137 + uint fflag,
1138 + mode_t fmode,
1139 + dm_off_t off,
1140 + dm_size_t len,
1141 + void __user *bufp,
1142 + int *rvp)
1143 +{
1144 + xfs_inode_t *ip = XFS_I(inode);
1145 + int error;
1146 + int oflags;
1147 + ssize_t xfer;
1148 + struct file *file;
1149 + struct dentry *dentry;
1150 +
1151 + if ((off < 0) || (off > i_size_read(inode)) || !S_ISREG(inode->i_mode))
1152 + return EINVAL;
1153 +
1154 + if (fmode & FMODE_READ) {
1155 + oflags = O_RDONLY;
1156 + } else {
1157 + oflags = O_WRONLY;
1158 + }
1159 +
1160 + /*
1161 + * Build file descriptor flags and I/O flags. O_NONBLOCK is needed so
1162 + * that we don't block on mandatory file locks. This is an invisible IO,
1163 + * don't change the atime.
1164 + */
1165 +
1166 + oflags |= O_LARGEFILE | O_NONBLOCK | O_NOATIME;
1167 + if (xfs_dm_direct_ok(ip, off, len, bufp))
1168 + oflags |= O_DIRECT;
1169 +
1170 + if (fflag & O_SYNC)
1171 + oflags |= O_SYNC;
1172 +
1173 + if (inode->i_fop == NULL) {
1174 + /* no iput; caller did get, and will do put */
1175 + return EINVAL;
1176 + }
1177 +
1178 + igrab(inode);
1179 +
1180 + dentry = d_alloc_anon(inode);
1181 + if (dentry == NULL) {
1182 + iput(inode);
1183 + return ENOMEM;
1184 + }
1185 +
1186 + file = dentry_open(dentry, mntget(ip->i_mount->m_vfsmount), oflags);
1187 + if (IS_ERR(file)) {
1188 + return -PTR_ERR(file);
1189 + }
1190 + file->f_op = &xfs_invis_file_operations;
1191 +
1192 + if (fmode & FMODE_READ) {
1193 + xfer = file->f_op->read(file, bufp, len, (loff_t*)&off);
1194 + } else {
1195 + xfer = file->f_op->write(file, bufp, len, (loff_t*)&off);
1196 + }
1197 +
1198 + if (xfer >= 0) {
1199 + *rvp = xfer;
1200 + error = 0;
1201 + } else {
1202 + /* xfs_read/xfs_write return negative error--flip it */
1203 + error = -(int)xfer;
1204 + }
1205 +
1206 + fput(file);
1207 + return error;
1208 +}
1209 +
1210 +/* ARGSUSED */
1211 +STATIC int
1212 +xfs_dm_clear_inherit(
1213 + struct inode *inode,
1214 + dm_right_t right,
1215 + dm_attrname_t __user *attrnamep)
1216 +{
1217 + return(-ENOSYS); /* Return negative error to DMAPI */
1218 +}
1219 +
1220 +
1221 +/* ARGSUSED */
1222 +STATIC int
1223 +xfs_dm_create_by_handle(
1224 + struct inode *inode,
1225 + dm_right_t right,
1226 + void __user *hanp,
1227 + size_t hlen,
1228 + char __user *cname)
1229 +{
1230 + return(-ENOSYS); /* Return negative error to DMAPI */
1231 +}
1232 +
1233 +
1234 +/* ARGSUSED */
1235 +STATIC int
1236 +xfs_dm_downgrade_right(
1237 + struct inode *inode,
1238 + dm_right_t right,
1239 + u_int type) /* DM_FSYS_OBJ or zero */
1240 +{
1241 +#ifdef DEBUG_RIGHTS
1242 + char buffer[sizeof(dm_handle_t) * 2 + 1];
1243 +
1244 + if (!xfs_vp_to_hexhandle(inode, type, buffer)) {
1245 + printf("dm_downgrade_right: old %d new %d type %d handle %s\n",
1246 + right, DM_RIGHT_SHARED, type, buffer);
1247 + } else {
1248 + printf("dm_downgrade_right: old %d new %d type %d handle "
1249 + "<INVALID>\n", right, DM_RIGHT_SHARED, type);
1250 + }
1251 +#endif /* DEBUG_RIGHTS */
1252 + return(0);
1253 +}
1254 +
1255 +
1256 +/* Note: xfs_dm_get_allocinfo() makes no attempt to coalesce two adjacent
1257 + extents when both are of type DM_EXTENT_RES; this is left to the caller.
1258 + XFS guarantees that there will never be two adjacent DM_EXTENT_HOLE extents.
1259 +
1260 + In order to provide the caller with all extents in a file including
1261 + those beyond the file's last byte offset, we have to use the xfs_bmapi()
1262 + interface.
1263 +*/
1264 +
1265 +STATIC int
1266 +xfs_dm_get_allocinfo_rvp(
1267 + struct inode *inode,
1268 + dm_right_t right,
1269 + dm_off_t __user *offp,
1270 + u_int nelem,
1271 + dm_extent_t __user *extentp,
1272 + u_int __user *nelemp,
1273 + int *rvp)
1274 +{
1275 + xfs_inode_t *ip = XFS_I(inode);
1276 + xfs_mount_t *mp; /* file system mount point */
1277 + xfs_fileoff_t fsb_offset;
1278 + xfs_filblks_t fsb_length;
1279 + dm_off_t startoff;
1280 + int elem;
1281 + xfs_bmbt_irec_t *bmp = NULL;
1282 + u_int bmpcnt = 50;
1283 + u_int bmpsz = sizeof(xfs_bmbt_irec_t) * bmpcnt;
1284 + int error = 0;
1285 +
1286 + /* Returns negative errors to DMAPI */
1287 +
1288 + if (right < DM_RIGHT_SHARED)
1289 + return(-EACCES);
1290 +
1291 + if ((inode->i_mode & S_IFMT) != S_IFREG)
1292 + return(-EINVAL);
1293 +
1294 + if (copy_from_user( &startoff, offp, sizeof(startoff)))
1295 + return(-EFAULT);
1296 +
1297 + mp = ip->i_mount;
1298 + ASSERT(mp);
1299 +
1300 + if (startoff > XFS_MAXIOFFSET(mp))
1301 + return(-EINVAL);
1302 +
1303 + if (nelem == 0)
1304 + return(-EINVAL);
1305 +
1306 + /* Convert the caller's starting offset into filesystem allocation
1307 + units as required by xfs_bmapi(). Round the offset down so that
1308 + it is sure to be included in the reply.
1309 + */
1310 +
1311 + fsb_offset = XFS_B_TO_FSBT(mp, startoff);
1312 + fsb_length = XFS_B_TO_FSB(mp, XFS_MAXIOFFSET(mp)) - fsb_offset;
1313 + elem = 0;
1314 +
1315 + if (fsb_length)
1316 + bmp = kmem_alloc(bmpsz, KM_SLEEP);
1317 +
1318 + while (fsb_length && elem < nelem) {
1319 + dm_extent_t extent;
1320 + xfs_filblks_t fsb_bias;
1321 + dm_size_t bias;
1322 + int lock;
1323 + int num;
1324 + int i;
1325 +
1326 + /* Compute how many getbmap structures to use on the xfs_bmapi
1327 + call.
1328 + */
1329 +
1330 + num = MIN((u_int)(nelem - elem), bmpcnt);
1331 +
1332 + xfs_ilock(ip, XFS_IOLOCK_SHARED);
1333 + lock = xfs_ilock_map_shared(ip);
1334 +
1335 + error = xfs_bmapi(NULL, ip, fsb_offset, fsb_length,
1336 + XFS_BMAPI_ENTIRE, NULL, 0, bmp, &num, NULL, NULL);
1337 +
1338 + xfs_iunlock_map_shared(ip, lock);
1339 + xfs_iunlock(ip, XFS_IOLOCK_SHARED);
1340 +
1341 + if (error) {
1342 + error = -error; /* Return negative error to DMAPI */
1343 + goto finish_out;
1344 + }
1345 +
1346 + /* Fill in the caller's extents, adjusting the bias in the
1347 + first entry if necessary.
1348 + */
1349 +
1350 + for (i = 0; i < num; i++, extentp++) {
1351 + bias = startoff - XFS_FSB_TO_B(mp, bmp[i].br_startoff);
1352 + extent.ex_offset = startoff;
1353 + extent.ex_length =
1354 + XFS_FSB_TO_B(mp, bmp[i].br_blockcount) - bias;
1355 + if (bmp[i].br_startblock == HOLESTARTBLOCK) {
1356 + extent.ex_type = DM_EXTENT_HOLE;
1357 + } else {
1358 + extent.ex_type = DM_EXTENT_RES;
1359 + }
1360 + startoff = extent.ex_offset + extent.ex_length;
1361 +
1362 + if (copy_to_user( extentp, &extent, sizeof(extent))) {
1363 + error = -EFAULT;
1364 + goto finish_out;
1365 + }
1366 +
1367 + fsb_bias = fsb_offset - bmp[i].br_startoff;
1368 + fsb_offset += bmp[i].br_blockcount - fsb_bias;
1369 + fsb_length -= bmp[i].br_blockcount - fsb_bias;
1370 + elem++;
1371 + }
1372 + }
1373 +
1374 + if (fsb_length == 0) {
1375 + startoff = 0;
1376 + }
1377 + if (copy_to_user( offp, &startoff, sizeof(startoff))) {
1378 + error = -EFAULT;
1379 + goto finish_out;
1380 + }
1381 +
1382 + if (copy_to_user( nelemp, &elem, sizeof(elem))) {
1383 + error = -EFAULT;
1384 + goto finish_out;
1385 + }
1386 +
1387 + *rvp = (fsb_length == 0 ? 0 : 1);
1388 +
1389 +finish_out:
1390 + if (bmp)
1391 + kmem_free(bmp);
1392 + return(error);
1393 +}
1394 +
1395 +
1396 +STATIC int
1397 +xfs_dm_zero_xstatinfo_link(
1398 + dm_xstat_t __user *dxs)
1399 +{
1400 + dm_xstat_t *ldxs;
1401 + int error = 0;
1402 +
1403 + if (!dxs)
1404 + return 0;
1405 + ldxs = kmalloc(sizeof(*ldxs), GFP_KERNEL);
1406 + if (!ldxs)
1407 + return -ENOMEM;
1408 + if (copy_from_user(ldxs, dxs, sizeof(*dxs))) {
1409 + error = -EFAULT;
1410 + } else {
1411 + ldxs->dx_statinfo._link = 0;
1412 + if (copy_to_user(dxs, ldxs, sizeof(*dxs)))
1413 + error = -EFAULT;
1414 + }
1415 + kfree(ldxs);
1416 + return error;
1417 +}
1418 +
1419 +/* ARGSUSED */
1420 +STATIC int
1421 +xfs_dm_get_bulkall_rvp(
1422 + struct inode *inode,
1423 + dm_right_t right,
1424 + u_int mask,
1425 + dm_attrname_t __user *attrnamep,
1426 + dm_attrloc_t __user *locp,
1427 + size_t buflen,
1428 + void __user *bufp, /* address of buffer in user space */
1429 + size_t __user *rlenp, /* user space address */
1430 + int *rvalp)
1431 +{
1432 + int error, done;
1433 + int nelems;
1434 + u_int statstruct_sz;
1435 + dm_attrloc_t loc;
1436 + xfs_mount_t *mp = XFS_I(inode)->i_mount;
1437 + dm_attrname_t attrname;
1438 + dm_bulkstat_one_t dmb;
1439 +
1440 + /* Returns negative errors to DMAPI */
1441 +
1442 + if (copy_from_user(&attrname, attrnamep, sizeof(attrname)) ||
1443 + copy_from_user(&loc, locp, sizeof(loc)))
1444 + return -EFAULT;
1445 +
1446 + if (attrname.an_chars[0] == '\0')
1447 + return(-EINVAL);
1448 +
1449 + if (right < DM_RIGHT_SHARED)
1450 + return(-EACCES);
1451 +
1452 + /* Because we will write directly to the user's buffer, make sure that
1453 + the buffer is properly aligned.
1454 + */
1455 +
1456 + if (((unsigned long)bufp & (DM_STAT_ALIGN - 1)) != 0)
1457 + return(-EFAULT);
1458 +
1459 + /* Size of the handle is constant for this function.
1460 + * If there are no files with attributes, then this will be the
1461 + * maximum number of inodes we can get.
1462 + */
1463 +
1464 + statstruct_sz = DM_STAT_SIZE(dm_xstat_t, 0);
1465 + statstruct_sz = (statstruct_sz+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1);
1466 +
1467 + nelems = buflen / statstruct_sz;
1468 + if (nelems < 1) {
1469 + if (put_user( statstruct_sz, rlenp ))
1470 + return(-EFAULT);
1471 + return(-E2BIG);
1472 + }
1473 +
1474 + /* Build the on-disk version of the attribute name. */
1475 + strcpy(dmb.attrname.dan_chars, dmattr_prefix);
1476 + strncpy(&dmb.attrname.dan_chars[DMATTR_PREFIXLEN],
1477 + attrname.an_chars, DM_ATTR_NAME_SIZE + 1);
1478 + dmb.attrname.dan_chars[sizeof(dmb.attrname.dan_chars) - 1] = '\0';
1479 +
1480 + /*
1481 + * fill the buffer with dm_xstat_t's
1482 + */
1483 +
1484 + dmb.laststruct = NULL;
1485 + memcpy(&dmb.fsid, mp->m_fixedfsid, sizeof(dm_fsid_t));
1486 + error = xfs_bulkstat(mp, (xfs_ino_t *)&loc, &nelems,
1487 + xfs_dm_bulkall_one, (void*)&dmb, statstruct_sz,
1488 + bufp, BULKSTAT_FG_INLINE, &done);
1489 + if (error)
1490 + return(-error); /* Return negative error to DMAPI */
1491 +
1492 + *rvalp = !done ? 1 : 0;
1493 +
1494 + if (put_user( statstruct_sz * nelems, rlenp ))
1495 + return(-EFAULT);
1496 +
1497 + if (copy_to_user( locp, &loc, sizeof(loc)))
1498 + return(-EFAULT);
1499 + /*
1500 + * If we didn't do any, we must not have any more to do.
1501 + */
1502 + if (nelems < 1)
1503 + return(0);
1504 + /*
1505 + * Set _link in the last struct to zero
1506 + */
1507 + return xfs_dm_zero_xstatinfo_link((dm_xstat_t __user *)dmb.laststruct);
1508 +}
1509 +
1510 +
1511 +STATIC int
1512 +xfs_dm_zero_statinfo_link(
1513 + dm_stat_t __user *dxs)
1514 +{
1515 + dm_stat_t *ldxs;
1516 + int error = 0;
1517 +
1518 + if (!dxs)
1519 + return 0;
1520 + ldxs = kmalloc(sizeof(*ldxs), GFP_KERNEL);
1521 + if (!ldxs)
1522 + return -ENOMEM;
1523 + if (copy_from_user(ldxs, dxs, sizeof(*dxs))) {
1524 + error = -EFAULT;
1525 + } else {
1526 + ldxs->_link = 0;
1527 + if (copy_to_user(dxs, ldxs, sizeof(*dxs)))
1528 + error = -EFAULT;
1529 + }
1530 + kfree(ldxs);
1531 + return error;
1532 +}
1533 +
1534 +/* ARGSUSED */
1535 +STATIC int
1536 +xfs_dm_get_bulkattr_rvp(
1537 + struct inode *inode,
1538 + dm_right_t right,
1539 + u_int mask,
1540 + dm_attrloc_t __user *locp,
1541 + size_t buflen,
1542 + void __user *bufp,
1543 + size_t __user *rlenp,
1544 + int *rvalp)
1545 +{
1546 + int error, done;
1547 + int nelems;
1548 + u_int statstruct_sz;
1549 + dm_attrloc_t loc;
1550 + xfs_mount_t *mp = XFS_I(inode)->i_mount;
1551 + dm_bulkstat_one_t dmb;
1552 +
1553 + /* Returns negative errors to DMAPI */
1554 +
1555 + if (right < DM_RIGHT_SHARED)
1556 + return(-EACCES);
1557 +
1558 + if (copy_from_user( &loc, locp, sizeof(loc)))
1559 + return(-EFAULT);
1560 +
1561 + /* Because we will write directly to the user's buffer, make sure that
1562 + the buffer is properly aligned.
1563 + */
1564 +
1565 + if (((unsigned long)bufp & (DM_STAT_ALIGN - 1)) != 0)
1566 + return(-EFAULT);
1567 +
1568 + /* size of the handle is constant for this function */
1569 +
1570 + statstruct_sz = DM_STAT_SIZE(dm_stat_t, 0);
1571 + statstruct_sz = (statstruct_sz+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1);
1572 +
1573 + nelems = buflen / statstruct_sz;
1574 + if (nelems < 1) {
1575 + if (put_user( statstruct_sz, rlenp ))
1576 + return(-EFAULT);
1577 + return(-E2BIG);
1578 + }
1579 +
1580 + dmb.laststruct = NULL;
1581 + memcpy(&dmb.fsid, mp->m_fixedfsid, sizeof(dm_fsid_t));
1582 + error = xfs_bulkstat(mp, (xfs_ino_t *)&loc, &nelems,
1583 + xfs_dm_bulkattr_one, (void*)&dmb,
1584 + statstruct_sz, bufp, BULKSTAT_FG_INLINE, &done);
1585 + if (error)
1586 + return(-error); /* Return negative error to DMAPI */
1587 +
1588 + *rvalp = !done ? 1 : 0;
1589 +
1590 + if (put_user( statstruct_sz * nelems, rlenp ))
1591 + return(-EFAULT);
1592 +
1593 + if (copy_to_user( locp, &loc, sizeof(loc)))
1594 + return(-EFAULT);
1595 +
1596 + /*
1597 + * If we didn't do any, we must not have any more to do.
1598 + */
1599 + if (nelems < 1)
1600 + return(0);
1601 + /*
1602 + * Set _link in the last struct to zero
1603 + */
1604 + return xfs_dm_zero_statinfo_link((dm_stat_t __user *)dmb.laststruct);
1605 +}
1606 +
1607 +
1608 +/* ARGSUSED */
1609 +STATIC int
1610 +xfs_dm_get_config(
1611 + struct inode *inode,
1612 + dm_right_t right,
1613 + dm_config_t flagname,
1614 + dm_size_t __user *retvalp)
1615 +{
1616 + dm_size_t retval;
1617 +
1618 + /* Returns negative errors to DMAPI */
1619 +
1620 + switch (flagname) {
1621 + case DM_CONFIG_DTIME_OVERLOAD:
1622 + case DM_CONFIG_PERS_ATTRIBUTES:
1623 + case DM_CONFIG_PERS_EVENTS:
1624 + case DM_CONFIG_PERS_MANAGED_REGIONS:
1625 + case DM_CONFIG_PUNCH_HOLE:
1626 + case DM_CONFIG_WILL_RETRY:
1627 + retval = DM_TRUE;
1628 + break;
1629 +
1630 + case DM_CONFIG_CREATE_BY_HANDLE: /* these will never be done */
1631 + case DM_CONFIG_LOCK_UPGRADE:
1632 + case DM_CONFIG_PERS_INHERIT_ATTRIBS:
1633 + retval = DM_FALSE;
1634 + break;
1635 +
1636 + case DM_CONFIG_BULKALL:
1637 + retval = DM_TRUE;
1638 + break;
1639 + case DM_CONFIG_MAX_ATTR_ON_DESTROY:
1640 + retval = DM_MAX_ATTR_BYTES_ON_DESTROY;
1641 + break;
1642 +
1643 + case DM_CONFIG_MAX_ATTRIBUTE_SIZE:
1644 + retval = ATTR_MAX_VALUELEN;
1645 + break;
1646 +
1647 + case DM_CONFIG_MAX_HANDLE_SIZE:
1648 + retval = DM_MAX_HANDLE_SIZE;
1649 + break;
1650 +
1651 + case DM_CONFIG_MAX_MANAGED_REGIONS:
1652 + retval = 1;
1653 + break;
1654 +
1655 + case DM_CONFIG_TOTAL_ATTRIBUTE_SPACE:
1656 + retval = 0x7fffffff; /* actually it's unlimited */
1657 + break;
1658 +
1659 + default:
1660 + return(-EINVAL);
1661 + }
1662 +
1663 + /* Copy the results back to the user. */
1664 +
1665 + if (copy_to_user( retvalp, &retval, sizeof(retval)))
1666 + return(-EFAULT);
1667 + return(0);
1668 +}
1669 +
1670 +
1671 +/* ARGSUSED */
1672 +STATIC int
1673 +xfs_dm_get_config_events(
1674 + struct inode *inode,
1675 + dm_right_t right,
1676 + u_int nelem,
1677 + dm_eventset_t __user *eventsetp,
1678 + u_int __user *nelemp)
1679 +{
1680 + dm_eventset_t eventset;
1681 +
1682 + /* Returns negative errors to DMAPI */
1683 +
1684 + if (nelem == 0)
1685 + return(-EINVAL);
1686 +
1687 + eventset = DM_XFS_SUPPORTED_EVENTS;
1688 +
1689 + /* Now copy the event mask and event count back to the caller. We
1690 + return the lesser of nelem and DM_EVENT_MAX.
1691 + */
1692 +
1693 + if (nelem > DM_EVENT_MAX)
1694 + nelem = DM_EVENT_MAX;
1695 + eventset &= (1 << nelem) - 1;
1696 +
1697 + if (copy_to_user( eventsetp, &eventset, sizeof(eventset)))
1698 + return(-EFAULT);
1699 +
1700 + if (put_user(nelem, nelemp))
1701 + return(-EFAULT);
1702 + return(0);
1703 +}
1704 +
1705 +
1706 +/* ARGSUSED */
1707 +STATIC int
1708 +xfs_dm_get_destroy_dmattr(
1709 + struct inode *inode,
1710 + dm_right_t right,
1711 + dm_attrname_t *attrnamep,
1712 + char **valuepp,
1713 + int *vlenp)
1714 +{
1715 + dm_dkattrname_t dkattrname;
1716 + int alloc_size;
1717 + int value_len;
1718 + char *value;
1719 + int error;
1720 +
1721 + /* Returns negative errors to DMAPI */
1722 +
1723 + *vlenp = -1; /* assume failure by default */
1724 +
1725 + if (attrnamep->an_chars[0] == '\0')
1726 + return(-EINVAL);
1727 +
1728 + /* Build the on-disk version of the attribute name. */
1729 +
1730 + strcpy(dkattrname.dan_chars, dmattr_prefix);
1731 + strncpy(&dkattrname.dan_chars[DMATTR_PREFIXLEN],
1732 + (char *)attrnamep->an_chars, DM_ATTR_NAME_SIZE + 1);
1733 + dkattrname.dan_chars[sizeof(dkattrname.dan_chars) - 1] = '\0';
1734 +
1735 + /* xfs_attr_get will not return anything if the buffer is too small,
1736 + and we don't know how big to make the buffer, so this may take
1737 + two tries to get it right. The initial try must use a buffer of
1738 + at least XFS_BUG_KLUDGE bytes to prevent buffer overflow because
1739 + of a bug in XFS.
1740 + */
1741 +
1742 + alloc_size = XFS_BUG_KLUDGE;
1743 + value = kmalloc(alloc_size, GFP_KERNEL);
1744 + if (value == NULL)
1745 + return(-ENOMEM);
1746 +
1747 + error = xfs_attr_get(XFS_I(inode), dkattrname.dan_chars, value,
1748 + &value_len, ATTR_ROOT);
1749 + if (error == ERANGE) {
1750 + kfree(value);
1751 + alloc_size = value_len;
1752 + value = kmalloc(alloc_size, GFP_KERNEL);
1753 + if (value == NULL)
1754 + return(-ENOMEM);
1755 +
1756 + error = xfs_attr_get(XFS_I(inode), dkattrname.dan_chars, value,
1757 + &value_len, ATTR_ROOT);
1758 + }
1759 + if (error) {
1760 + kfree(value);
1761 + DM_EA_XLATE_ERR(error);
1762 + return(-error); /* Return negative error to DMAPI */
1763 + }
1764 +
1765 + /* The attribute exists and has a value. Note that a value_len of
1766 + zero is valid!
1767 + */
1768 +
1769 + if (value_len == 0) {
1770 + kfree(value);
1771 + *vlenp = 0;
1772 + return(0);
1773 + } else if (value_len > DM_MAX_ATTR_BYTES_ON_DESTROY) {
1774 + char *value2;
1775 +
1776 + value2 = kmalloc(DM_MAX_ATTR_BYTES_ON_DESTROY, GFP_KERNEL);
1777 + if (value2 == NULL) {
1778 + kfree(value);
1779 + return(-ENOMEM);
1780 + }
1781 + memcpy(value2, value, DM_MAX_ATTR_BYTES_ON_DESTROY);
1782 + kfree(value);
1783 + value = value2;
1784 + value_len = DM_MAX_ATTR_BYTES_ON_DESTROY;
1785 + }
1786 + *vlenp = value_len;
1787 + *valuepp = value;
1788 + return(0);
1789 +}
1790 +
1791 +/* This code was taken from xfs_fcntl(F_DIOINFO) and modified slightly because
1792 + we don't have a flags parameter (no open file).
1793 + Taken from xfs_ioctl(XFS_IOC_DIOINFO) on Linux.
1794 +*/
1795 +
1796 +STATIC int
1797 +xfs_dm_get_dioinfo(
1798 + struct inode *inode,
1799 + dm_right_t right,
1800 + dm_dioinfo_t __user *diop)
1801 +{
1802 + dm_dioinfo_t dio;
1803 + xfs_mount_t *mp;
1804 + xfs_inode_t *ip = XFS_I(inode);
1805 +
1806 + /* Returns negative errors to DMAPI */
1807 +
1808 + if (right < DM_RIGHT_SHARED)
1809 + return(-EACCES);
1810 +
1811 + mp = ip->i_mount;
1812 +
1813 + dio.d_miniosz = dio.d_mem = MIN_DIO_SIZE(mp);
1814 + dio.d_maxiosz = MAX_DIO_SIZE(mp);
1815 + dio.d_dio_only = DM_FALSE;
1816 +
1817 + if (copy_to_user(diop, &dio, sizeof(dio)))
1818 + return(-EFAULT);
1819 + return(0);
1820 +}
1821 +
1822 +typedef struct dm_readdir_cb {
1823 + xfs_mount_t *mp;
1824 + char __user *ubuf;
1825 + dm_stat_t __user *lastbuf;
1826 + size_t spaceleft;
1827 + size_t nwritten;
1828 + int error;
1829 + dm_stat_t kstat;
1830 +} dm_readdir_cb_t;
1831 +
1832 +STATIC int
1833 +dm_filldir(void *__buf, const char *name, int namelen, loff_t offset,
1834 + u64 ino, unsigned int d_type)
1835 +{
1836 + dm_readdir_cb_t *cb = __buf;
1837 + dm_stat_t *statp = &cb->kstat;
1838 + size_t len;
1839 + int error;
1840 + int needed;
1841 +
1842 + /*
1843 + * Make sure we have enough space.
1844 + */
1845 + needed = dm_stat_size(namelen + 1);
1846 + if (cb->spaceleft < needed) {
1847 + cb->spaceleft = 0;
1848 + return -ENOSPC;
1849 + }
1850 +
1851 + error = -EINVAL;
1852 + if (xfs_internal_inum(cb->mp, ino))
1853 + goto out_err;
1854 +
1855 + memset(statp, 0, dm_stat_size(MAXNAMLEN));
1856 + error = -xfs_dm_bulkattr_iget_one(cb->mp, ino, 0,
1857 + statp, needed);
1858 + if (error)
1859 + goto out_err;
1860 +
1861 + /*
1862 + * On return from bulkstat_one(), stap->_link points
1863 + * at the end of the handle in the stat structure.
1864 + */
1865 + statp->dt_compname.vd_offset = statp->_link;
1866 + statp->dt_compname.vd_length = namelen + 1;
1867 +
1868 + len = statp->_link;
1869 +
1870 + /* Word-align the record */
1871 + statp->_link = dm_stat_align(len + namelen + 1);
1872 +
1873 + error = -EFAULT;
1874 + if (copy_to_user(cb->ubuf, statp, len))
1875 + goto out_err;
1876 + if (copy_to_user(cb->ubuf + len, name, namelen))
1877 + goto out_err;
1878 + if (put_user(0, cb->ubuf + len + namelen))
1879 + goto out_err;
1880 +
1881 + cb->lastbuf = (dm_stat_t __user *)cb->ubuf;
1882 + cb->spaceleft -= statp->_link;
1883 + cb->nwritten += statp->_link;
1884 + cb->ubuf += statp->_link;
1885 +
1886 + return 0;
1887 +
1888 + out_err:
1889 + cb->error = error;
1890 + return error;
1891 +}
1892 +
1893 +/* Returns negative errors to DMAPI */
1894 +STATIC int
1895 +xfs_dm_get_dirattrs_rvp(
1896 + struct inode *inode,
1897 + dm_right_t right,
1898 + u_int mask,
1899 + dm_attrloc_t __user *locp,
1900 + size_t buflen,
1901 + void __user *bufp,
1902 + size_t __user *rlenp,
1903 + int *rvp)
1904 +{
1905 + xfs_inode_t *dp = XFS_I(inode);
1906 + xfs_mount_t *mp = dp->i_mount;
1907 + dm_readdir_cb_t *cb;
1908 + dm_attrloc_t loc;
1909 + int error;
1910 +
1911 + if (right < DM_RIGHT_SHARED)
1912 + return -EACCES;
1913 +
1914 + /*
1915 + * Make sure that the buffer is properly aligned.
1916 + */
1917 + if (((unsigned long)bufp & (DM_STAT_ALIGN - 1)) != 0)
1918 + return -EFAULT;
1919 +
1920 + if (mask & ~(DM_AT_HANDLE|DM_AT_EMASK|DM_AT_PMANR|DM_AT_PATTR|
1921 + DM_AT_DTIME|DM_AT_CFLAG|DM_AT_STAT))
1922 + return -EINVAL;
1923 +
1924 + if (!S_ISDIR(inode->i_mode))
1925 + return -EINVAL;
1926 +
1927 + /*
1928 + * bufp should be able to fit at least one dm_stat entry including
1929 + * dt_handle and full size MAXNAMLEN dt_compname.
1930 + */
1931 + if (buflen < dm_stat_size(MAXNAMLEN))
1932 + return -ENOMEM;
1933 +
1934 + if (copy_from_user(&loc, locp, sizeof(loc)))
1935 + return -EFAULT;
1936 +
1937 + cb = kzalloc(sizeof(*cb) + dm_stat_size(MAXNAMLEN), GFP_KERNEL);
1938 + if (!cb)
1939 + return -ENOMEM;
1940 +
1941 + cb->mp = mp;
1942 + cb->spaceleft = buflen;
1943 + cb->ubuf = bufp;
1944 +
1945 + mutex_lock(&inode->i_mutex);
1946 + error = -ENOENT;
1947 + if (!IS_DEADDIR(inode)) {
1948 + error = -xfs_readdir(dp, cb, dp->i_size,
1949 + (xfs_off_t *)&loc, dm_filldir);
1950 + }
1951 + mutex_unlock(&inode->i_mutex);
1952 +
1953 + if (error)
1954 + goto out_kfree;
1955 + if (cb->error) {
1956 + error = cb->error;
1957 + goto out_kfree;
1958 + }
1959 +
1960 + error = -EFAULT;
1961 + if (cb->lastbuf && put_user(0, &cb->lastbuf->_link))
1962 + goto out_kfree;
1963 + if (put_user(cb->nwritten, rlenp))
1964 + goto out_kfree;
1965 + if (copy_to_user(locp, &loc, sizeof(loc)))
1966 + goto out_kfree;
1967 +
1968 + if (cb->nwritten)
1969 + *rvp = 1;
1970 + else
1971 + *rvp = 0;
1972 + error = 0;
1973 +
1974 + out_kfree:
1975 + kfree(cb);
1976 + return error;
1977 +}
1978 +
1979 +STATIC int
1980 +xfs_dm_get_dmattr(
1981 + struct inode *inode,
1982 + dm_right_t right,
1983 + dm_attrname_t __user *attrnamep,
1984 + size_t buflen,
1985 + void __user *bufp,
1986 + size_t __user *rlenp)
1987 +{
1988 + dm_dkattrname_t name;
1989 + char *value;
1990 + int value_len;
1991 + int alloc_size;
1992 + int error;
1993 +
1994 + /* Returns negative errors to DMAPI */
1995 +
1996 + if (right < DM_RIGHT_SHARED)
1997 + return(-EACCES);
1998 +
1999 + if ((error = xfs_copyin_attrname(attrnamep, &name)) != 0)
2000 + return(-error); /* Return negative error to DMAPI */
2001 +
2002 + /* Allocate a buffer to receive the attribute's value. We allocate
2003 + at least one byte even if the caller specified a buflen of zero.
2004 + (A buflen of zero is considered valid.)
2005 +
2006 + Allocating a minimum of XFS_BUG_KLUDGE bytes temporarily works
2007 + around a bug within XFS in which in-inode attribute values are not
2008 + checked to see if they will fit in the buffer before they are
2009 + copied. Since no in-core attribute value can be larger than 256
2010 + bytes (an 8-bit size field), we allocate that minimum size here to
2011 + prevent buffer overrun in both the kernel's and user's buffers.
2012 + */
2013 +
2014 + alloc_size = buflen;
2015 + if (alloc_size < XFS_BUG_KLUDGE)
2016 + alloc_size = XFS_BUG_KLUDGE;
2017 + if (alloc_size > ATTR_MAX_VALUELEN)
2018 + alloc_size = ATTR_MAX_VALUELEN;
2019 + value = kmem_alloc(alloc_size, KM_SLEEP | KM_LARGE);
2020 +
2021 + /* Get the attribute's value. */
2022 +
2023 + value_len = alloc_size; /* in/out parameter */
2024 +
2025 + error = xfs_attr_get(XFS_I(inode), name.dan_chars, value, &value_len,
2026 + ATTR_ROOT);
2027 + DM_EA_XLATE_ERR(error);
2028 +
2029 + /* DMAPI requires an errno of ENOENT if an attribute does not exist,
2030 + so remap ENOATTR here.
2031 + */
2032 +
2033 + if (error == ENOATTR)
2034 + error = ENOENT;
2035 + if (!error && value_len > buflen)
2036 + error = E2BIG;
2037 + if (!error && copy_to_user(bufp, value, value_len))
2038 + error = EFAULT;
2039 + if (!error || error == E2BIG) {
2040 + if (put_user(value_len, rlenp))
2041 + error = EFAULT;
2042 + }
2043 +
2044 + kmem_free(value);
2045 + return(-error); /* Return negative error to DMAPI */
2046 +}
2047 +
2048 +STATIC int
2049 +xfs_dm_get_eventlist(
2050 + struct inode *inode,
2051 + dm_right_t right,
2052 + u_int type,
2053 + u_int nelem,
2054 + dm_eventset_t *eventsetp,
2055 + u_int *nelemp)
2056 +{
2057 + int error;
2058 + xfs_inode_t *ip = XFS_I(inode);
2059 +
2060 + /* Returns negative errors to DMAPI */
2061 +
2062 + if (type == DM_FSYS_OBJ) {
2063 + error = xfs_dm_fs_get_eventlist(ip->i_mount, right, nelem,
2064 + eventsetp, nelemp);
2065 + } else {
2066 + error = xfs_dm_f_get_eventlist(ip, right, nelem,
2067 + eventsetp, nelemp);
2068 + }
2069 + return(-error); /* Returns negative error to DMAPI */
2070 +}
2071 +
2072 +
2073 +/* ARGSUSED */
2074 +STATIC int
2075 +xfs_dm_get_fileattr(
2076 + struct inode *inode,
2077 + dm_right_t right,
2078 + u_int mask, /* not used; always return everything */
2079 + dm_stat_t __user *statp)
2080 +{
2081 + dm_stat_t stat;
2082 + xfs_inode_t *ip = XFS_I(inode);
2083 + xfs_mount_t *mp;
2084 +
2085 + /* Returns negative errors to DMAPI */
2086 +
2087 + if (right < DM_RIGHT_SHARED)
2088 + return(-EACCES);
2089 +
2090 + /* Find the mount point. */
2091 +
2092 + mp = ip->i_mount;
2093 +
2094 + xfs_ilock(ip, XFS_ILOCK_SHARED);
2095 + xfs_ip_to_stat(mp, ip->i_ino, ip, &stat);
2096 + xfs_iunlock(ip, XFS_ILOCK_SHARED);
2097 +
2098 + if (copy_to_user( statp, &stat, sizeof(stat)))
2099 + return(-EFAULT);
2100 + return(0);
2101 +}
2102 +
2103 +
2104 +/* We currently only support a maximum of one managed region per file, and
2105 + use the DM_EVENT_READ, DM_EVENT_WRITE, and DM_EVENT_TRUNCATE events in
2106 + the file's dm_eventset_t event mask to implement the DM_REGION_READ,
2107 + DM_REGION_WRITE, and DM_REGION_TRUNCATE flags for that single region.
2108 +*/
2109 +
2110 +STATIC int
2111 +xfs_dm_get_region(
2112 + struct inode *inode,
2113 + dm_right_t right,
2114 + u_int nelem,
2115 + dm_region_t __user *regbufp,
2116 + u_int __user *nelemp)
2117 +{
2118 + dm_eventset_t evmask;
2119 + dm_region_t region;
2120 + xfs_inode_t *ip = XFS_I(inode);
2121 + u_int elem;
2122 +
2123 + /* Returns negative errors to DMAPI */
2124 +
2125 + if (right < DM_RIGHT_SHARED)
2126 + return(-EACCES);
2127 +
2128 + evmask = ip->i_d.di_dmevmask; /* read the mask "atomically" */
2129 +
2130 + /* Get the file's current managed region flags out of the
2131 + dm_eventset_t mask and use them to build a managed region that
2132 + covers the entire file, i.e. set rg_offset and rg_size to zero.
2133 + */
2134 +
2135 + memset((char *)&region, 0, sizeof(region));
2136 +
2137 + if (evmask & (1 << DM_EVENT_READ))
2138 + region.rg_flags |= DM_REGION_READ;
2139 + if (evmask & (1 << DM_EVENT_WRITE))
2140 + region.rg_flags |= DM_REGION_WRITE;
2141 + if (evmask & (1 << DM_EVENT_TRUNCATE))
2142 + region.rg_flags |= DM_REGION_TRUNCATE;
2143 +
2144 + elem = (region.rg_flags ? 1 : 0);
2145 +
2146 + if (copy_to_user( nelemp, &elem, sizeof(elem)))
2147 + return(-EFAULT);
2148 + if (elem > nelem)
2149 + return(-E2BIG);
2150 + if (elem && copy_to_user(regbufp, &region, sizeof(region)))
2151 + return(-EFAULT);
2152 + return(0);
2153 +}
2154 +
2155 +
2156 +STATIC int
2157 +xfs_dm_getall_dmattr(
2158 + struct inode *inode,
2159 + dm_right_t right,
2160 + size_t buflen,
2161 + void __user *bufp,
2162 + size_t __user *rlenp)
2163 +{
2164 + attrlist_cursor_kern_t cursor;
2165 + attrlist_t *attrlist;
2166 + dm_attrlist_t __user *ulist;
2167 + int *last_link;
2168 + int alignment;
2169 + int total_size;
2170 + int list_size = 8192; /* should be big enough */
2171 + int error;
2172 +
2173 + /* Returns negative errors to DMAPI */
2174 +
2175 + if (right < DM_RIGHT_SHARED)
2176 + return(-EACCES);
2177 +
2178 + /* Verify that the user gave us a buffer that is 4-byte aligned, lock
2179 + it down, and work directly within that buffer. As a side-effect,
2180 + values of buflen < sizeof(int) return EINVAL.
2181 + */
2182 +
2183 + alignment = sizeof(int) - 1;
2184 + if ((((__psint_t)bufp & alignment) != 0) ||
2185 + !access_ok(VERIFY_WRITE, bufp, buflen)) {
2186 + return(-EFAULT);
2187 + }
2188 + buflen &= ~alignment; /* round down the alignment */
2189 +
2190 + /* Initialize all the structures and variables for the main loop. */
2191 +
2192 + memset(&cursor, 0, sizeof(cursor));
2193 + attrlist = (attrlist_t *)kmem_alloc(list_size, KM_SLEEP);
2194 + total_size = 0;
2195 + ulist = (dm_attrlist_t *)bufp;
2196 + last_link = NULL;
2197 +
2198 + /* Use vop_attr_list to get the names of DMAPI attributes, and use
2199 + vop_attr_get to get their values. There is a risk here that the
2200 + DMAPI attributes could change between the vop_attr_list and
2201 + vop_attr_get calls. If we can detect it, we return EIO to notify
2202 + the user.
2203 + */
2204 +
2205 + do {
2206 + int i;
2207 +
2208 + /* Get a buffer full of attribute names. If there aren't any
2209 + more or if we encounter an error, then finish up.
2210 + */
2211 +
2212 + error = xfs_attr_list(XFS_I(inode), (char *)attrlist, list_size,
2213 + ATTR_ROOT, &cursor);
2214 + DM_EA_XLATE_ERR(error);
2215 +
2216 + if (error || attrlist->al_count == 0)
2217 + break;
2218 +
2219 + for (i = 0; i < attrlist->al_count; i++) {
2220 + attrlist_ent_t *entry;
2221 + char *user_name;
2222 + int size_needed;
2223 + int value_len;
2224 +
2225 + /* Skip over all non-DMAPI attributes. If the
2226 + attribute name is too long, we assume it is
2227 + non-DMAPI even if it starts with the correct
2228 + prefix.
2229 + */
2230 +
2231 + entry = ATTR_ENTRY(attrlist, i);
2232 + if (strncmp(entry->a_name, dmattr_prefix, DMATTR_PREFIXLEN))
2233 + continue;
2234 + user_name = &entry->a_name[DMATTR_PREFIXLEN];
2235 + if (strlen(user_name) > DM_ATTR_NAME_SIZE)
2236 + continue;
2237 +
2238 + /* We have a valid DMAPI attribute to return. If it
2239 + won't fit in the user's buffer, we still need to
2240 + keep track of the number of bytes for the user's
2241 + next call.
2242 + */
2243 +
2244 +
2245 + size_needed = sizeof(*ulist) + entry->a_valuelen;
2246 + size_needed = (size_needed + alignment) & ~alignment;
2247 +
2248 + total_size += size_needed;
2249 + if (total_size > buflen)
2250 + continue;
2251 +
2252 + /* Start by filling in all the fields in the
2253 + dm_attrlist_t structure.
2254 + */
2255 +
2256 + strncpy((char *)ulist->al_name.an_chars, user_name,
2257 + DM_ATTR_NAME_SIZE);
2258 + ulist->al_data.vd_offset = sizeof(*ulist);
2259 + ulist->al_data.vd_length = entry->a_valuelen;
2260 + ulist->_link = size_needed;
2261 + last_link = &ulist->_link;
2262 +
2263 + /* Next read the attribute's value into its correct
2264 + location after the dm_attrlist structure. Any sort
2265 + of error indicates that the data is moving under us,
2266 + so we return EIO to let the user know.
2267 + */
2268 +
2269 + value_len = entry->a_valuelen;
2270 +
2271 + error = xfs_attr_get(XFS_I(inode), entry->a_name,
2272 + (void *)(ulist + 1), &value_len,
2273 + ATTR_ROOT);
2274 + DM_EA_XLATE_ERR(error);
2275 +
2276 + if (error || value_len != entry->a_valuelen) {
2277 + error = EIO;
2278 + break;
2279 + }
2280 +
2281 + ulist = (dm_attrlist_t *)((char *)ulist + ulist->_link);
2282 + }
2283 + } while (!error && attrlist->al_more);
2284 + if (last_link)
2285 + *last_link = 0;
2286 +
2287 + if (!error && total_size > buflen)
2288 + error = E2BIG;
2289 + if (!error || error == E2BIG) {
2290 + if (put_user(total_size, rlenp))
2291 + error = EFAULT;
2292 + }
2293 +
2294 + kmem_free(attrlist);
2295 + return(-error); /* Return negative error to DMAPI */
2296 +}
2297 +
2298 +
2299 +/* ARGSUSED */
2300 +STATIC int
2301 +xfs_dm_getall_inherit(
2302 + struct inode *inode,
2303 + dm_right_t right,
2304 + u_int nelem,
2305 + dm_inherit_t __user *inheritbufp,
2306 + u_int __user *nelemp)
2307 +{
2308 + return(-ENOSYS); /* Return negative error to DMAPI */
2309 +}
2310 +
2311 +
2312 +/* Initialize location pointer for subsequent dm_get_dirattrs,
2313 + dm_get_bulkattr, and dm_get_bulkall calls. The same initialization must
2314 + work for inode-based routines (dm_get_dirattrs) and filesystem-based
2315 + routines (dm_get_bulkattr and dm_get_bulkall). Filesystem-based functions
2316 + call this routine using the filesystem's root inode.
2317 +*/
2318 +
2319 +/* ARGSUSED */
2320 +STATIC int
2321 +xfs_dm_init_attrloc(
2322 + struct inode *inode,
2323 + dm_right_t right,
2324 + dm_attrloc_t __user *locp)
2325 +{
2326 + dm_attrloc_t loc = 0;
2327 +
2328 + /* Returns negative errors to DMAPI */
2329 +
2330 + if (right < DM_RIGHT_SHARED)
2331 + return(-EACCES);
2332 +
2333 + if (copy_to_user( locp, &loc, sizeof(loc)))
2334 + return(-EFAULT);
2335 + return(0);
2336 +}
2337 +
2338 +
2339 +/* ARGSUSED */
2340 +STATIC int
2341 +xfs_dm_mkdir_by_handle(
2342 + struct inode *inode,
2343 + dm_right_t right,
2344 + void __user *hanp,
2345 + size_t hlen,
2346 + char __user *cname)
2347 +{
2348 + return(-ENOSYS); /* Return negative error to DMAPI */
2349 +}
2350 +
2351 +
2352 +/*
2353 + * Probe and Punch
2354 + *
2355 + * Hole punching alignment is based on the underlying device base
2356 + * allocation size. Because it is not defined in the DMAPI spec, we
2357 + * can align how we choose here. Round inwards (offset up and length
2358 + * down) to the block, extent or page size whichever is bigger. Our
2359 + * DMAPI implementation rounds the hole geometry strictly inwards. If
2360 + * this is not possible, return EINVAL for both for xfs_dm_probe_hole
2361 + * and xfs_dm_punch_hole which differs from the DMAPI spec. Note that
2362 + * length = 0 is special - it means "punch to EOF" and at that point
2363 + * we treat the punch as remove everything past offset (including
2364 + * preallocation past EOF).
2365 + */
2366 +
2367 +STATIC int
2368 +xfs_dm_round_hole(
2369 + dm_off_t offset,
2370 + dm_size_t length,
2371 + dm_size_t align,
2372 + xfs_fsize_t filesize,
2373 + dm_off_t *roff,
2374 + dm_size_t *rlen)
2375 +{
2376 +
2377 + dm_off_t off = offset;
2378 + dm_size_t len = length;
2379 +
2380 + /* Try to round offset up to the nearest boundary */
2381 + *roff = roundup_64(off, align);
2382 + if ((*roff >= filesize) || (len && (len < align)))
2383 + return -EINVAL;
2384 +
2385 + if ((len == 0) || ((off + len) == filesize)) {
2386 + /* punch to EOF */
2387 + *rlen = 0;
2388 + } else {
2389 + /* Round length down to the nearest boundary. */
2390 + ASSERT(len >= align);
2391 + ASSERT(align > (*roff - off));
2392 + len -= *roff - off;
2393 + *rlen = len - do_mod(len, align);
2394 + if (*rlen == 0)
2395 + return -EINVAL; /* requested length is too small */
2396 + }
2397 +#ifdef CONFIG_DMAPI_DEBUG
2398 + printk("xfs_dm_round_hole: off %lu, len %ld, align %lu, "
2399 + "filesize %llu, roff %ld, rlen %ld\n",
2400 + offset, length, align, filesize, *roff, *rlen);
2401 +#endif
2402 + return 0; /* hole geometry successfully rounded */
2403 +}
2404 +
2405 +/* ARGSUSED */
2406 +STATIC int
2407 +xfs_dm_probe_hole(
2408 + struct inode *inode,
2409 + dm_right_t right,
2410 + dm_off_t off,
2411 + dm_size_t len,
2412 + dm_off_t __user *roffp,
2413 + dm_size_t __user *rlenp)
2414 +{
2415 + dm_off_t roff;
2416 + dm_size_t rlen;
2417 + xfs_inode_t *ip = XFS_I(inode);
2418 + xfs_mount_t *mp;
2419 + uint lock_flags;
2420 + xfs_fsize_t realsize;
2421 + dm_size_t align;
2422 + int error;
2423 +
2424 + /* Returns negative errors to DMAPI */
2425 +
2426 + if (right < DM_RIGHT_SHARED)
2427 + return -EACCES;
2428 +
2429 + if ((ip->i_d.di_mode & S_IFMT) != S_IFREG)
2430 + return -EINVAL;
2431 +
2432 + mp = ip->i_mount;
2433 + lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL;
2434 + xfs_ilock(ip, lock_flags);
2435 + realsize = ip->i_size;
2436 + xfs_iunlock(ip, lock_flags);
2437 +
2438 + if ((off + len) > realsize)
2439 + return -E2BIG;
2440 +
2441 + align = 1 << mp->m_sb.sb_blocklog;
2442 +
2443 + error = xfs_dm_round_hole(off, len, align, realsize, &roff, &rlen);
2444 + if (error)
2445 + return error;
2446 +
2447 + if (copy_to_user( roffp, &roff, sizeof(roff)))
2448 + return -EFAULT;
2449 + if (copy_to_user( rlenp, &rlen, sizeof(rlen)))
2450 + return -EFAULT;
2451 + return(0);
2452 +}
2453 +
2454 +
2455 +STATIC int
2456 +xfs_dm_punch_hole(
2457 + struct inode *inode,
2458 + dm_right_t right,
2459 + dm_off_t off,
2460 + dm_size_t len)
2461 +{
2462 + xfs_flock64_t bf;
2463 + int error = 0;
2464 + xfs_inode_t *ip = XFS_I(inode);
2465 + xfs_mount_t *mp;
2466 + dm_size_t align;
2467 + xfs_fsize_t realsize;
2468 + dm_off_t roff;
2469 + dm_size_t rlen;
2470 +
2471 + /* Returns negative errors to DMAPI */
2472 +
2473 + if (right < DM_RIGHT_EXCL)
2474 + return -EACCES;
2475 +
2476 + /* Make sure there are no leases. */
2477 + error = break_lease(inode, FMODE_WRITE);
2478 + if (error)
2479 + return -EBUSY;
2480 +
2481 + error = get_write_access(inode);
2482 + if (error)
2483 + return -EBUSY;
2484 +
2485 + mp = ip->i_mount;
2486 +
2487 + down_rw_sems(inode, DM_SEM_FLAG_WR);
2488 +
2489 + xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
2490 + realsize = ip->i_size;
2491 + xfs_iunlock(ip, XFS_ILOCK_EXCL);
2492 + align = xfs_get_extsz_hint(ip);
2493 + if (align == 0)
2494 + align = 1;
2495 +
2496 + align <<= mp->m_sb.sb_blocklog;
2497 +
2498 + if ((off + len) > realsize) {
2499 + xfs_iunlock(ip, XFS_IOLOCK_EXCL);
2500 + error = -E2BIG;
2501 + goto up_and_out;
2502 + }
2503 +
2504 + if ((off + len) == realsize)
2505 + len = 0;
2506 +
2507 + error = xfs_dm_round_hole(off, len, align, realsize, &roff, &rlen);
2508 + if (error || (off != roff) || (len != rlen)) {
2509 + xfs_iunlock(ip, XFS_IOLOCK_EXCL);
2510 + error = -EINVAL;
2511 + goto up_and_out;
2512 + }
2513 +
2514 + bf.l_type = 0;
2515 + bf.l_whence = 0;
2516 + bf.l_start = (xfs_off_t)off;
2517 + if (len) {
2518 + bf.l_len = len;
2519 + }
2520 + else {
2521 + /*
2522 + * When we are punching to EOF, we have to make sure we punch
2523 + * the last partial block that contains EOF. Round up
2524 + * the length to make sure we punch the block and not just
2525 + * zero it.
2526 + */
2527 + bf.l_len = roundup_64((realsize - off), mp->m_sb.sb_blocksize);
2528 + }
2529 +
2530 +#ifdef CONFIG_DMAPI_DEBUG
2531 + printk("xfs_dm_punch_hole: off %lu, len %ld, align %lu\n",
2532 + off, len, align);
2533 +#endif
2534 +
2535 + error = xfs_change_file_space(ip, XFS_IOC_UNRESVSP, &bf,
2536 + (xfs_off_t)off, sys_cred,
2537 + XFS_ATTR_DMI|XFS_ATTR_NOLOCK);
2538 +
2539 + /*
2540 + * if punching to end of file, kill any blocks past EOF that
2541 + * may have been (speculatively) preallocated. No point in
2542 + * leaving them around if we are migrating the file....
2543 + */
2544 + if (!error && (len == 0)) {
2545 + error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_NOLOCK);
2546 + }
2547 +
2548 + /*
2549 + * negate the error for return here as core XFS functions return
2550 + * positive error numbers
2551 + */
2552 + if (error)
2553 + error = -error;
2554 +
2555 + /* Let threads in send_data_event know we punched the file. */
2556 + ip->i_d.di_dmstate++;
2557 + xfs_iunlock(ip, XFS_IOLOCK_EXCL);
2558 + xfs_iflags_set(ip, XFS_IMODIFIED);
2559 +
2560 +up_and_out:
2561 + up_rw_sems(inode, DM_SEM_FLAG_WR);
2562 + put_write_access(inode);
2563 +
2564 + return error;
2565 +}
2566 +
2567 +
2568 +STATIC int
2569 +xfs_dm_read_invis_rvp(
2570 + struct inode *inode,
2571 + dm_right_t right,
2572 + dm_off_t off,
2573 + dm_size_t len,
2574 + void __user *bufp,
2575 + int *rvp)
2576 +{
2577 + /* Returns negative errors to DMAPI */
2578 +
2579 + if (right < DM_RIGHT_SHARED)
2580 + return(-EACCES);
2581 +
2582 + return(-xfs_dm_rdwr(inode, 0, FMODE_READ, off, len, bufp, rvp));
2583 +}
2584 +
2585 +
2586 +/* ARGSUSED */
2587 +STATIC int
2588 +xfs_dm_release_right(
2589 + struct inode *inode,
2590 + dm_right_t right,
2591 + u_int type) /* DM_FSYS_OBJ or zero */
2592 +{
2593 +#ifdef DEBUG_RIGHTS
2594 + char buffer[sizeof(dm_handle_t) * 2 + 1];
2595 +
2596 + if (!xfs_vp_to_hexhandle(inode, type, buffer)) {
2597 + printf("dm_release_right: old %d type %d handle %s\n",
2598 + right, type, buffer);
2599 + } else {
2600 + printf("dm_release_right: old %d type %d handle "
2601 + " <INVALID>\n", right, type);
2602 + }
2603 +#endif /* DEBUG_RIGHTS */
2604 + return(0);
2605 +}
2606 +
2607 +
2608 +STATIC int
2609 +xfs_dm_remove_dmattr(
2610 + struct inode *inode,
2611 + dm_right_t right,
2612 + int setdtime,
2613 + dm_attrname_t __user *attrnamep)
2614 +{
2615 + dm_dkattrname_t name;
2616 + int error;
2617 +
2618 + /* Returns negative errors to DMAPI */
2619 +
2620 + if (right < DM_RIGHT_EXCL)
2621 + return(-EACCES);
2622 +
2623 + if ((error = xfs_copyin_attrname(attrnamep, &name)) != 0)
2624 + return(-error); /* Return negative error to DMAPI */
2625 +
2626 + /* Remove the attribute from the object. */
2627 +
2628 + error = xfs_attr_remove(XFS_I(inode), name.dan_chars, setdtime ?
2629 + ATTR_ROOT : (ATTR_ROOT|ATTR_KERNOTIME));
2630 + DM_EA_XLATE_ERR(error);
2631 +
2632 + if (error == ENOATTR)
2633 + error = ENOENT;
2634 + return(-error); /* Return negative error to DMAPI */
2635 +}
2636 +
2637 +
2638 +/* ARGSUSED */
2639 +STATIC int
2640 +xfs_dm_request_right(
2641 + struct inode *inode,
2642 + dm_right_t right,
2643 + u_int type, /* DM_FSYS_OBJ or zero */
2644 + u_int flags,
2645 + dm_right_t newright)
2646 +{
2647 +#ifdef DEBUG_RIGHTS
2648 + char buffer[sizeof(dm_handle_t) * 2 + 1];
2649 +
2650 + if (!xfs_vp_to_hexhandle(inode, type, buffer)) {
2651 + printf("dm_request_right: old %d new %d type %d flags 0x%x "
2652 + "handle %s\n", right, newright, type, flags, buffer);
2653 + } else {
2654 + printf("dm_request_right: old %d new %d type %d flags 0x%x "
2655 + "handle <INVALID>\n", right, newright, type, flags);
2656 + }
2657 +#endif /* DEBUG_RIGHTS */
2658 + return(0);
2659 +}
2660 +
2661 +
2662 +STATIC int
2663 +xfs_dm_set_dmattr(
2664 + struct inode *inode,
2665 + dm_right_t right,
2666 + dm_attrname_t __user *attrnamep,
2667 + int setdtime,
2668 + size_t buflen,
2669 + void __user *bufp)
2670 +{
2671 + dm_dkattrname_t name;
2672 + char *value;
2673 + int alloc_size;
2674 + int error;
2675 +
2676 + /* Returns negative errors to DMAPI */
2677 +
2678 + if (right < DM_RIGHT_EXCL)
2679 + return(-EACCES);
2680 +
2681 + if ((error = xfs_copyin_attrname(attrnamep, &name)) != 0)
2682 + return(-error); /* Return negative error to DMAPI */
2683 + if (buflen > ATTR_MAX_VALUELEN)
2684 + return(-E2BIG);
2685 +
2686 + /* Copy in the attribute's value and store the <name,value> pair in
2687 + the object. We allocate a buffer of at least one byte even if the
2688 + caller specified a buflen of zero. (A buflen of zero is considered
2689 + valid.)
2690 + */
2691 +
2692 + alloc_size = (buflen == 0) ? 1 : buflen;
2693 + value = kmem_alloc(alloc_size, KM_SLEEP);
2694 + if (copy_from_user( value, bufp, buflen)) {
2695 + error = EFAULT;
2696 + } else {
2697 + error = xfs_attr_set(XFS_I(inode), name.dan_chars, value, buflen,
2698 + setdtime ? ATTR_ROOT :
2699 + (ATTR_ROOT|ATTR_KERNOTIME));
2700 + DM_EA_XLATE_ERR(error);
2701 + }
2702 + kmem_free(value);
2703 + return(-error); /* Return negative error to DMAPI */
2704 +}
2705 +
2706 +STATIC int
2707 +xfs_dm_set_eventlist(
2708 + struct inode *inode,
2709 + dm_right_t right,
2710 + u_int type,
2711 + dm_eventset_t *eventsetp, /* in kernel space! */
2712 + u_int maxevent)
2713 +{
2714 + int error;
2715 + xfs_inode_t *ip = XFS_I(inode);
2716 +
2717 + /* Returns negative errors to DMAPI */
2718 +
2719 + if (type == DM_FSYS_OBJ) {
2720 + error = xfs_dm_fs_set_eventlist(ip->i_mount, right, eventsetp, maxevent);
2721 + } else {
2722 + error = xfs_dm_f_set_eventlist(ip, right, eventsetp, maxevent);
2723 + }
2724 + return(-error); /* Return negative error to DMAPI */
2725 +}
2726 +
2727 +
2728 +/*
2729 + * This turned out not XFS-specific, but leave it here with get_fileattr.
2730 + */
2731 +
2732 +STATIC int
2733 +xfs_dm_set_fileattr(
2734 + struct inode *inode,
2735 + dm_right_t right,
2736 + u_int mask,
2737 + dm_fileattr_t __user *statp)
2738 +{
2739 + dm_fileattr_t stat;
2740 + struct iattr iattr;
2741 +
2742 + /* Returns negative errors to DMAPI */
2743 +
2744 + if (right < DM_RIGHT_EXCL)
2745 + return(-EACCES);
2746 +
2747 + if (copy_from_user( &stat, statp, sizeof(stat)))
2748 + return(-EFAULT);
2749 +
2750 + iattr.ia_valid = 0;
2751 +
2752 + if (mask & DM_AT_MODE) {
2753 + iattr.ia_valid |= ATTR_MODE;
2754 + iattr.ia_mode = stat.fa_mode;
2755 + }
2756 + if (mask & DM_AT_UID) {
2757 + iattr.ia_valid |= ATTR_UID;
2758 + iattr.ia_uid = stat.fa_uid;
2759 + }
2760 + if (mask & DM_AT_GID) {
2761 + iattr.ia_valid |= ATTR_GID;
2762 + iattr.ia_gid = stat.fa_gid;
2763 + }
2764 + if (mask & DM_AT_ATIME) {
2765 + iattr.ia_valid |= ATTR_ATIME;
2766 + iattr.ia_atime.tv_sec = stat.fa_atime;
2767 + iattr.ia_atime.tv_nsec = 0;
2768 + inode->i_atime.tv_sec = stat.fa_atime;
2769 + }
2770 + if (mask & DM_AT_MTIME) {
2771 + iattr.ia_valid |= ATTR_MTIME;
2772 + iattr.ia_mtime.tv_sec = stat.fa_mtime;
2773 + iattr.ia_mtime.tv_nsec = 0;
2774 + }
2775 + if (mask & DM_AT_CTIME) {
2776 + iattr.ia_valid |= ATTR_CTIME;
2777 + iattr.ia_ctime.tv_sec = stat.fa_ctime;
2778 + iattr.ia_ctime.tv_nsec = 0;
2779 + }
2780 +
2781 + /*
2782 + * DM_AT_DTIME only takes effect if DM_AT_CTIME is not specified. We
2783 + * overload ctime to also act as dtime, i.e. DM_CONFIG_DTIME_OVERLOAD.
2784 + */
2785 + if ((mask & DM_AT_DTIME) && !(mask & DM_AT_CTIME)) {
2786 + iattr.ia_valid |= ATTR_CTIME;
2787 + iattr.ia_ctime.tv_sec = stat.fa_dtime;
2788 + iattr.ia_ctime.tv_nsec = 0;
2789 + }
2790 + if (mask & DM_AT_SIZE) {
2791 + iattr.ia_valid |= ATTR_SIZE;
2792 + iattr.ia_size = stat.fa_size;
2793 + }
2794 +
2795 + return -xfs_setattr(XFS_I(inode), &iattr, XFS_ATTR_DMI, NULL);
2796 +}
2797 +
2798 +
2799 +/* ARGSUSED */
2800 +STATIC int
2801 +xfs_dm_set_inherit(
2802 + struct inode *inode,
2803 + dm_right_t right,
2804 + dm_attrname_t __user *attrnamep,
2805 + mode_t mode)
2806 +{
2807 + return(-ENOSYS); /* Return negative error to DMAPI */
2808 +}
2809 +
2810 +
2811 +STATIC int
2812 +xfs_dm_set_region(
2813 + struct inode *inode,
2814 + dm_right_t right,
2815 + u_int nelem,
2816 + dm_region_t __user *regbufp,
2817 + dm_boolean_t __user *exactflagp)
2818 +{
2819 + xfs_inode_t *ip = XFS_I(inode);
2820 + xfs_trans_t *tp;
2821 + xfs_mount_t *mp;
2822 + dm_region_t region;
2823 + dm_eventset_t new_mask;
2824 + dm_eventset_t mr_mask;
2825 + int error;
2826 + u_int exactflag;
2827 +
2828 + /* Returns negative errors to DMAPI */
2829 +
2830 + if (right < DM_RIGHT_EXCL)
2831 + return(-EACCES);
2832 +
2833 + /* If the caller gave us more than one dm_region_t structure, complain.
2834 + (He has to call dm_get_config() to find out what our limit is.)
2835 + */
2836 +
2837 + if (nelem > 1)
2838 + return(-E2BIG);
2839 +
2840 + /* If the user provided a dm_region_t structure, then copy it in,
2841 + validate it, and convert its flags to the corresponding bits in a
2842 + dm_set_eventlist() event mask. A call with zero regions is
2843 + equivalent to clearing all region flags.
2844 + */
2845 +
2846 + new_mask = 0;
2847 + if (nelem == 1) {
2848 + if (copy_from_user( &region, regbufp, sizeof(region)))
2849 + return(-EFAULT);
2850 +
2851 + if (region.rg_flags & ~(DM_REGION_READ|DM_REGION_WRITE|DM_REGION_TRUNCATE))
2852 + return(-EINVAL);
2853 + if (region.rg_flags & DM_REGION_READ)
2854 + new_mask |= 1 << DM_EVENT_READ;
2855 + if (region.rg_flags & DM_REGION_WRITE)
2856 + new_mask |= 1 << DM_EVENT_WRITE;
2857 + if (region.rg_flags & DM_REGION_TRUNCATE)
2858 + new_mask |= 1 << DM_EVENT_TRUNCATE;
2859 + }
2860 + mr_mask = (1 << DM_EVENT_READ) | (1 << DM_EVENT_WRITE) | (1 << DM_EVENT_TRUNCATE);
2861 +
2862 + /* Get the file's existing event mask, clear the old managed region
2863 + bits, add in the new ones, and update the file's mask.
2864 + */
2865 +
2866 + if (new_mask & prohibited_mr_events(inode->i_mapping)) {
2867 + /* If the change is simply to remove the READ
2868 + * bit, then that's always okay. Otherwise, it's busy.
2869 + */
2870 + dm_eventset_t m1;
2871 + m1 = ip->i_d.di_dmevmask & ((1 << DM_EVENT_WRITE) | (1 << DM_EVENT_TRUNCATE));
2872 + if (m1 != new_mask) {
2873 + return -EBUSY;
2874 + }
2875 + }
2876 +
2877 + mp = ip->i_mount;
2878 + tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS);
2879 + error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES (mp), 0, 0, 0);
2880 + if (error) {
2881 + xfs_trans_cancel(tp, 0);
2882 + return(-error); /* Return negative error to DMAPI */
2883 + }
2884 + xfs_ilock(ip, XFS_ILOCK_EXCL);
2885 + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
2886 +
2887 + ip->i_d.di_dmevmask = (ip->i_d.di_dmevmask & ~mr_mask) | new_mask;
2888 +
2889 + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
2890 + igrab(inode);
2891 + xfs_trans_commit(tp, 0);
2892 +
2893 + /* Return the proper value for *exactflagp depending upon whether or not
2894 + we "changed" the user's managed region. In other words, if the user
2895 + specified a non-zero value for either rg_offset or rg_size, we
2896 + round each of those values back to zero.
2897 + */
2898 +
2899 + if (nelem && (region.rg_offset || region.rg_size)) {
2900 + exactflag = DM_FALSE; /* user region was changed */
2901 + } else {
2902 + exactflag = DM_TRUE; /* user region was unchanged */
2903 + }
2904 + if (copy_to_user( exactflagp, &exactflag, sizeof(exactflag)))
2905 + return(-EFAULT);
2906 + return(0);
2907 +}
2908 +
2909 +
2910 +/* ARGSUSED */
2911 +STATIC int
2912 +xfs_dm_symlink_by_handle(
2913 + struct inode *inode,
2914 + dm_right_t right,
2915 + void __user *hanp,
2916 + size_t hlen,
2917 + char __user *cname,
2918 + char __user *path)
2919 +{
2920 + return(-ENOSYS); /* Return negative errors to DMAPI */
2921 +}
2922 +
2923 +
2924 +/*
2925 + * xfs_dm_sync_by_handle needs to do the same thing as sys_fsync()
2926 + */
2927 +STATIC int
2928 +xfs_dm_sync_by_handle(
2929 + struct inode *inode,
2930 + dm_right_t right)
2931 +{
2932 + int err, ret;
2933 + xfs_inode_t *ip = XFS_I(inode);
2934 +
2935 + /* Returns negative errors to DMAPI */
2936 + if (right < DM_RIGHT_EXCL)
2937 + return(-EACCES);
2938 +
2939 + /* We need to protect against concurrent writers.. */
2940 + ret = filemap_fdatawrite(inode->i_mapping);
2941 + down_rw_sems(inode, DM_FLAGS_IMUX);
2942 + err = -xfs_fsync(ip);
2943 + if (!ret)
2944 + ret = err;
2945 + up_rw_sems(inode, DM_FLAGS_IMUX);
2946 + err = filemap_fdatawait(inode->i_mapping);
2947 + if (!ret)
2948 + ret = err;
2949 + xfs_iflags_clear(ip, XFS_ITRUNCATED);
2950 + return ret;
2951 +}
2952 +
2953 +
2954 +/* ARGSUSED */
2955 +STATIC int
2956 +xfs_dm_upgrade_right(
2957 + struct inode *inode,
2958 + dm_right_t right,
2959 + u_int type) /* DM_FSYS_OBJ or zero */
2960 +{
2961 +#ifdef DEBUG_RIGHTS
2962 + char buffer[sizeof(dm_handle_t) * 2 + 1];
2963 +
2964 + if (!xfs_vp_to_hexhandle(inode, type, buffer)) {
2965 + printf("dm_upgrade_right: old %d new %d type %d handle %s\n",
2966 + right, DM_RIGHT_EXCL, type, buffer);
2967 + } else {
2968 + printf("dm_upgrade_right: old %d new %d type %d handle "
2969 + "<INVALID>\n", right, DM_RIGHT_EXCL, type);
2970 + }
2971 +#endif /* DEBUG_RIGHTS */
2972 + return(0);
2973 +}
2974 +
2975 +
2976 +STATIC int
2977 +xfs_dm_write_invis_rvp(
2978 + struct inode *inode,
2979 + dm_right_t right,
2980 + int flags,
2981 + dm_off_t off,
2982 + dm_size_t len,
2983 + void __user *bufp,
2984 + int *rvp)
2985 +{
2986 + int fflag = 0;
2987 +
2988 + /* Returns negative errors to DMAPI */
2989 +
2990 + if (right < DM_RIGHT_EXCL)
2991 + return(-EACCES);
2992 +
2993 + if (flags & DM_WRITE_SYNC)
2994 + fflag |= O_SYNC;
2995 + return(-xfs_dm_rdwr(inode, fflag, FMODE_WRITE, off, len, bufp, rvp));
2996 +}
2997 +
2998 +
2999 +STATIC void
3000 +xfs_dm_obj_ref_hold(
3001 + struct inode *inode)
3002 +{
3003 + igrab(inode);
3004 +}
3005 +
3006 +
3007 +static fsys_function_vector_t xfs_fsys_vector[DM_FSYS_MAX];
3008 +
3009 +
3010 +STATIC int
3011 +xfs_dm_get_dmapiops(
3012 + struct super_block *sb,
3013 + void *addr)
3014 +{
3015 + static int initialized = 0;
3016 + dm_fcntl_vector_t *vecrq;
3017 + fsys_function_vector_t *vecp;
3018 + int i = 0;
3019 +
3020 + vecrq = (dm_fcntl_vector_t *)addr;
3021 + vecrq->count =
3022 + sizeof(xfs_fsys_vector) / sizeof(xfs_fsys_vector[0]);
3023 + vecrq->vecp = xfs_fsys_vector;
3024 + if (initialized)
3025 + return(0);
3026 + vecrq->code_level = DM_CLVL_XOPEN;
3027 + vecp = xfs_fsys_vector;
3028 +
3029 + vecp[i].func_no = DM_FSYS_CLEAR_INHERIT;
3030 + vecp[i++].u_fc.clear_inherit = xfs_dm_clear_inherit;
3031 + vecp[i].func_no = DM_FSYS_CREATE_BY_HANDLE;
3032 + vecp[i++].u_fc.create_by_handle = xfs_dm_create_by_handle;
3033 + vecp[i].func_no = DM_FSYS_DOWNGRADE_RIGHT;
3034 + vecp[i++].u_fc.downgrade_right = xfs_dm_downgrade_right;
3035 + vecp[i].func_no = DM_FSYS_GET_ALLOCINFO_RVP;
3036 + vecp[i++].u_fc.get_allocinfo_rvp = xfs_dm_get_allocinfo_rvp;
3037 + vecp[i].func_no = DM_FSYS_GET_BULKALL_RVP;
3038 + vecp[i++].u_fc.get_bulkall_rvp = xfs_dm_get_bulkall_rvp;
3039 + vecp[i].func_no = DM_FSYS_GET_BULKATTR_RVP;
3040 + vecp[i++].u_fc.get_bulkattr_rvp = xfs_dm_get_bulkattr_rvp;
3041 + vecp[i].func_no = DM_FSYS_GET_CONFIG;
3042 + vecp[i++].u_fc.get_config = xfs_dm_get_config;
3043 + vecp[i].func_no = DM_FSYS_GET_CONFIG_EVENTS;
3044 + vecp[i++].u_fc.get_config_events = xfs_dm_get_config_events;
3045 + vecp[i].func_no = DM_FSYS_GET_DESTROY_DMATTR;
3046 + vecp[i++].u_fc.get_destroy_dmattr = xfs_dm_get_destroy_dmattr;
3047 + vecp[i].func_no = DM_FSYS_GET_DIOINFO;
3048 + vecp[i++].u_fc.get_dioinfo = xfs_dm_get_dioinfo;
3049 + vecp[i].func_no = DM_FSYS_GET_DIRATTRS_RVP;
3050 + vecp[i++].u_fc.get_dirattrs_rvp = xfs_dm_get_dirattrs_rvp;
3051 + vecp[i].func_no = DM_FSYS_GET_DMATTR;
3052 + vecp[i++].u_fc.get_dmattr = xfs_dm_get_dmattr;
3053 + vecp[i].func_no = DM_FSYS_GET_EVENTLIST;
3054 + vecp[i++].u_fc.get_eventlist = xfs_dm_get_eventlist;
3055 + vecp[i].func_no = DM_FSYS_GET_FILEATTR;
3056 + vecp[i++].u_fc.get_fileattr = xfs_dm_get_fileattr;
3057 + vecp[i].func_no = DM_FSYS_GET_REGION;
3058 + vecp[i++].u_fc.get_region = xfs_dm_get_region;
3059 + vecp[i].func_no = DM_FSYS_GETALL_DMATTR;
3060 + vecp[i++].u_fc.getall_dmattr = xfs_dm_getall_dmattr;
3061 + vecp[i].func_no = DM_FSYS_GETALL_INHERIT;
3062 + vecp[i++].u_fc.getall_inherit = xfs_dm_getall_inherit;
3063 + vecp[i].func_no = DM_FSYS_INIT_ATTRLOC;
3064 + vecp[i++].u_fc.init_attrloc = xfs_dm_init_attrloc;
3065 + vecp[i].func_no = DM_FSYS_MKDIR_BY_HANDLE;
3066 + vecp[i++].u_fc.mkdir_by_handle = xfs_dm_mkdir_by_handle;
3067 + vecp[i].func_no = DM_FSYS_PROBE_HOLE;
3068 + vecp[i++].u_fc.probe_hole = xfs_dm_probe_hole;
3069 + vecp[i].func_no = DM_FSYS_PUNCH_HOLE;
3070 + vecp[i++].u_fc.punch_hole = xfs_dm_punch_hole;
3071 + vecp[i].func_no = DM_FSYS_READ_INVIS_RVP;
3072 + vecp[i++].u_fc.read_invis_rvp = xfs_dm_read_invis_rvp;
3073 + vecp[i].func_no = DM_FSYS_RELEASE_RIGHT;
3074 + vecp[i++].u_fc.release_right = xfs_dm_release_right;
3075 + vecp[i].func_no = DM_FSYS_REMOVE_DMATTR;
3076 + vecp[i++].u_fc.remove_dmattr = xfs_dm_remove_dmattr;
3077 + vecp[i].func_no = DM_FSYS_REQUEST_RIGHT;
3078 + vecp[i++].u_fc.request_right = xfs_dm_request_right;
3079 + vecp[i].func_no = DM_FSYS_SET_DMATTR;
3080 + vecp[i++].u_fc.set_dmattr = xfs_dm_set_dmattr;
3081 + vecp[i].func_no = DM_FSYS_SET_EVENTLIST;
3082 + vecp[i++].u_fc.set_eventlist = xfs_dm_set_eventlist;
3083 + vecp[i].func_no = DM_FSYS_SET_FILEATTR;
3084 + vecp[i++].u_fc.set_fileattr = xfs_dm_set_fileattr;
3085 + vecp[i].func_no = DM_FSYS_SET_INHERIT;
3086 + vecp[i++].u_fc.set_inherit = xfs_dm_set_inherit;
3087 + vecp[i].func_no = DM_FSYS_SET_REGION;
3088 + vecp[i++].u_fc.set_region = xfs_dm_set_region;
3089 + vecp[i].func_no = DM_FSYS_SYMLINK_BY_HANDLE;
3090 + vecp[i++].u_fc.symlink_by_handle = xfs_dm_symlink_by_handle;
3091 + vecp[i].func_no = DM_FSYS_SYNC_BY_HANDLE;
3092 + vecp[i++].u_fc.sync_by_handle = xfs_dm_sync_by_handle;
3093 + vecp[i].func_no = DM_FSYS_UPGRADE_RIGHT;
3094 + vecp[i++].u_fc.upgrade_right = xfs_dm_upgrade_right;
3095 + vecp[i].func_no = DM_FSYS_WRITE_INVIS_RVP;
3096 + vecp[i++].u_fc.write_invis_rvp = xfs_dm_write_invis_rvp;
3097 + vecp[i].func_no = DM_FSYS_OBJ_REF_HOLD;
3098 + vecp[i++].u_fc.obj_ref_hold = xfs_dm_obj_ref_hold;
3099 +
3100 + return(0);
3101 +}
3102 +
3103 +
3104 +/* xfs_dm_send_mmap_event - send events needed for memory mapping a file.
3105 + *
3106 + * This is a workaround called for files that are about to be
3107 + * mapped. DMAPI events are not being generated at a low enough level
3108 + * in the kernel for page reads/writes to generate the correct events.
3109 + * So for memory-mapped files we generate read or write events for the
3110 + * whole byte range being mapped. If the mmap call can never cause a
3111 + * write to the file, then only a read event is sent.
3112 + *
3113 + * Code elsewhere prevents adding managed regions to a file while it
3114 + * is still mapped.
3115 + */
3116 +
3117 +STATIC int
3118 +xfs_dm_send_mmap_event(
3119 + struct vm_area_struct *vma,
3120 + unsigned int wantflag)
3121 +{
3122 + xfs_inode_t *ip;
3123 + int error = 0;
3124 + dm_eventtype_t max_event = DM_EVENT_READ;
3125 + xfs_fsize_t filesize;
3126 + xfs_off_t length, end_of_area, evsize, offset;
3127 + int iolock;
3128 +
3129 + if (!vma->vm_file)
3130 + return 0;
3131 +
3132 + ip = XFS_I(vma->vm_file->f_dentry->d_inode);
3133 +
3134 + if (!S_ISREG(vma->vm_file->f_dentry->d_inode->i_mode) ||
3135 + !(ip->i_mount->m_flags & XFS_MOUNT_DMAPI))
3136 + return 0;
3137 +
3138 + /* If they specifically asked for 'read', then give it to them.
3139 + * Otherwise, see if it's possible to give them 'write'.
3140 + */
3141 + if( wantflag & VM_READ ){
3142 + max_event = DM_EVENT_READ;
3143 + }
3144 + else if( ! (vma->vm_flags & VM_DENYWRITE) ) {
3145 + if((wantflag & VM_WRITE) || (vma->vm_flags & VM_WRITE))
3146 + max_event = DM_EVENT_WRITE;
3147 + }
3148 +
3149 + if( (wantflag & VM_WRITE) && (max_event != DM_EVENT_WRITE) ){
3150 + return -EACCES;
3151 + }
3152 +
3153 + /* Figure out how much of the file is being requested by the user. */
3154 + offset = 0; /* beginning of file, for now */
3155 + length = 0; /* whole file, for now */
3156 +
3157 + filesize = ip->i_new_size;
3158 + if (filesize < ip->i_size) {
3159 + filesize = ip->i_size;
3160 + }
3161 +
3162 + /* Set first byte number beyond the map area. */
3163 +
3164 + if (length) {
3165 + end_of_area = offset + length;
3166 + if (end_of_area > filesize)
3167 + end_of_area = filesize;
3168 + } else {
3169 + end_of_area = filesize;
3170 + }
3171 +
3172 + /* Set the real amount being mapped. */
3173 + evsize = end_of_area - offset;
3174 + if (evsize < 0)
3175 + evsize = 0;
3176 +
3177 + if (max_event == DM_EVENT_READ)
3178 + iolock = XFS_IOLOCK_SHARED;
3179 + else
3180 + iolock = XFS_IOLOCK_EXCL;
3181 +
3182 + xfs_ilock(ip, iolock);
3183 + /* If write possible, try a DMAPI write event */
3184 + if (max_event == DM_EVENT_WRITE && DM_EVENT_ENABLED(ip, max_event)) {
3185 + error = xfs_dm_send_data_event(max_event, ip, offset,
3186 + evsize, 0, &iolock);
3187 + goto out_unlock;
3188 + }
3189 +
3190 + /* Try a read event if max_event was != DM_EVENT_WRITE or if it
3191 + * was DM_EVENT_WRITE but the WRITE event was not enabled.
3192 + */
3193 + if (DM_EVENT_ENABLED(ip, DM_EVENT_READ)) {
3194 + error = xfs_dm_send_data_event(DM_EVENT_READ, ip, offset,
3195 + evsize, 0, &iolock);
3196 + }
3197 +out_unlock:
3198 + xfs_iunlock(ip, iolock);
3199 + return -error;
3200 +}
3201 +
3202 +
3203 +STATIC int
3204 +xfs_dm_send_destroy_event(
3205 + xfs_inode_t *ip,
3206 + dm_right_t vp_right) /* always DM_RIGHT_NULL */
3207 +{
3208 + /* Returns positive errors to XFS */
3209 + return -dm_send_destroy_event(ip->i_vnode, vp_right);
3210 +}
3211 +
3212 +
3213 +STATIC int
3214 +xfs_dm_send_namesp_event(
3215 + dm_eventtype_t event,
3216 + struct xfs_mount *mp,
3217 + xfs_inode_t *ip1,
3218 + dm_right_t vp1_right,
3219 + xfs_inode_t *ip2,
3220 + dm_right_t vp2_right,
3221 + const char *name1,
3222 + const char *name2,
3223 + mode_t mode,
3224 + int retcode,
3225 + int flags)
3226 +{
3227 + /* Returns positive errors to XFS */
3228 + return -dm_send_namesp_event(event, mp ? mp->m_super : NULL,
3229 + ip1->i_vnode, vp1_right,
3230 + ip2 ? ip2->i_vnode : NULL, vp2_right,
3231 + name1, name2,
3232 + mode, retcode, flags);
3233 +}
3234 +
3235 +STATIC int
3236 +xfs_dm_send_mount_event(
3237 + struct xfs_mount *mp,
3238 + dm_right_t root_right,
3239 + char *mtpt,
3240 + char *fsname)
3241 +{
3242 + return dm_send_mount_event(mp->m_super, root_right,
3243 + NULL, DM_RIGHT_NULL,
3244 + mp->m_rootip ? VFS_I(mp->m_rootip) : NULL,
3245 + DM_RIGHT_NULL, mtpt, fsname);
3246 +}
3247 +
3248 +STATIC void
3249 +xfs_dm_send_unmount_event(
3250 + struct xfs_mount *mp,
3251 + xfs_inode_t *ip, /* NULL if unmount successful */
3252 + dm_right_t vfsp_right,
3253 + mode_t mode,
3254 + int retcode, /* errno, if unmount failed */
3255 + int flags)
3256 +{
3257 + dm_send_unmount_event(mp->m_super, ip ? ip->i_vnode : NULL,
3258 + vfsp_right, mode, retcode, flags);
3259 +}
3260 +
3261 +
3262 +/*
3263 + * Data migration operations accessed by the rest of XFS.
3264 + * When DMAPI support is configured in, this vector is used.
3265 + */
3266 +
3267 +xfs_dmops_t xfs_dmcore_xfs = {
3268 + .xfs_send_data = xfs_dm_send_data_event,
3269 + .xfs_send_mmap = xfs_dm_send_mmap_event,
3270 + .xfs_send_destroy = xfs_dm_send_destroy_event,
3271 + .xfs_send_namesp = xfs_dm_send_namesp_event,
3272 + .xfs_send_mount = xfs_dm_send_mount_event,
3273 + .xfs_send_unmount = xfs_dm_send_unmount_event,
3274 +};
3275 +EXPORT_SYMBOL(xfs_dmcore_xfs);
3276 +
3277 +STATIC const struct file_operations *
3278 +xfs_dm_get_invis_ops(
3279 + struct inode *ip)
3280 +{
3281 + return &xfs_invis_file_operations;
3282 +}
3283 +
3284 +STATIC int
3285 +xfs_dm_fh_to_inode(
3286 + struct super_block *sb,
3287 + struct inode **inode,
3288 + dm_fid_t *dmfid)
3289 +{
3290 + xfs_mount_t *mp = XFS_M(sb);
3291 + xfs_inode_t *ip;
3292 + xfs_ino_t ino;
3293 + unsigned int igen;
3294 + int error;
3295 +
3296 + *inode = NULL;
3297 +
3298 + if (!dmfid->dm_fid_len) {
3299 + /* filesystem handle */
3300 + *inode = igrab(mp->m_rootip->i_vnode);
3301 + if (!*inode)
3302 + return -ENOENT;
3303 + return 0;
3304 + }
3305 +
3306 + if (dmfid->dm_fid_len != sizeof(*dmfid) - sizeof(dmfid->dm_fid_len))
3307 + return -EINVAL;
3308 +
3309 + ino = dmfid->dm_fid_ino;
3310 + igen = dmfid->dm_fid_gen;
3311 +
3312 + /* fail requests for ino 0 gracefully. */
3313 + if (ino == 0)
3314 + return -ESTALE;
3315 +
3316 + error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);
3317 + if (error)
3318 + return -error;
3319 + if (!ip)
3320 + return -EIO;
3321 +
3322 + if (!ip->i_d.di_mode || ip->i_d.di_gen != igen) {
3323 + xfs_iput_new(ip, XFS_ILOCK_SHARED);
3324 + return -ENOENT;
3325 + }
3326 +
3327 + *inode = ip->i_vnode;
3328 + xfs_iunlock(ip, XFS_ILOCK_SHARED);
3329 + return 0;
3330 +}
3331 +
3332 +STATIC int
3333 +xfs_dm_inode_to_fh(
3334 + struct inode *inode,
3335 + dm_fid_t *dmfid,
3336 + dm_fsid_t *dmfsid)
3337 +{
3338 + xfs_inode_t *ip = XFS_I(inode);
3339 +
3340 + /* Returns negative errors to DMAPI */
3341 +
3342 + if (ip->i_mount->m_fixedfsid == NULL)
3343 + return -EINVAL;
3344 +
3345 + dmfid->dm_fid_len = sizeof(dm_fid_t) - sizeof(dmfid->dm_fid_len);
3346 + dmfid->dm_fid_pad = 0;
3347 + /*
3348 + * use memcpy because the inode is a long long and there's no
3349 + * assurance that dmfid->dm_fid_ino is properly aligned.
3350 + */
3351 + memcpy(&dmfid->dm_fid_ino, &ip->i_ino, sizeof(dmfid->dm_fid_ino));
3352 + dmfid->dm_fid_gen = ip->i_d.di_gen;
3353 +
3354 + memcpy(dmfsid, ip->i_mount->m_fixedfsid, sizeof(*dmfsid));
3355 + return 0;
3356 +}
3357 +
3358 +STATIC void
3359 +xfs_dm_get_fsid(
3360 + struct super_block *sb,
3361 + dm_fsid_t *fsid)
3362 +{
3363 + memcpy(fsid, XFS_M(sb)->m_fixedfsid, sizeof(*fsid));
3364 +}
3365 +
3366 +/*
3367 + * Filesystem operations accessed by the DMAPI core.
3368 + */
3369 +static struct filesystem_dmapi_operations xfs_dmapiops = {
3370 + .get_fsys_vector = xfs_dm_get_dmapiops,
3371 + .fh_to_inode = xfs_dm_fh_to_inode,
3372 + .get_invis_ops = xfs_dm_get_invis_ops,
3373 + .inode_to_fh = xfs_dm_inode_to_fh,
3374 + .get_fsid = xfs_dm_get_fsid,
3375 +};
3376 +
3377 +static int __init
3378 +xfs_dm_init(void)
3379 +{
3380 + printk(KERN_INFO "SGI XFS Data Management API subsystem\n");
3381 +
3382 + dmapi_register(&xfs_fs_type, &xfs_dmapiops);
3383 + return 0;
3384 +}
3385 +
3386 +static void __exit
3387 +xfs_dm_exit(void)
3388 +{
3389 + dmapi_unregister(&xfs_fs_type);
3390 +}
3391 +
3392 +MODULE_AUTHOR("Silicon Graphics, Inc.");
3393 +MODULE_DESCRIPTION("SGI XFS dmapi subsystem");
3394 +MODULE_LICENSE("GPL");
3395 +
3396 +module_init(xfs_dm_init);
3397 +module_exit(xfs_dm_exit);
3398 Index: linux-2.6.27/fs/xfs/dmapi/xfs_dm.h
3399 ===================================================================
3400 --- /dev/null
3401 +++ linux-2.6.27/fs/xfs/dmapi/xfs_dm.h
3402 @@ -0,0 +1,23 @@
3403 +/*
3404 + * Copyright (c) 2006 Silicon Graphics, Inc.
3405 + * All Rights Reserved.
3406 + *
3407 + * This program is free software; you can redistribute it and/or
3408 + * modify it under the terms of the GNU General Public License as
3409 + * published by the Free Software Foundation.
3410 + *
3411 + * This program is distributed in the hope that it would be useful,
3412 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3413 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3414 + * GNU General Public License for more details.
3415 + *
3416 + * You should have received a copy of the GNU General Public License
3417 + * along with this program; if not, write the Free Software Foundation,
3418 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3419 + */
3420 +#ifndef __XFS_DM_H__
3421 +#define __XFS_DM_H__
3422 +
3423 +extern struct file_system_type xfs_fs_type;
3424 +
3425 +#endif /* __XFS_DM_H__ */
3426 Index: linux-2.6.27/fs/xfs/Makefile
3427 ===================================================================
3428 --- linux-2.6.27.orig/fs/xfs/Makefile
3429 +++ linux-2.6.27/fs/xfs/Makefile
3430 @@ -38,6 +38,8 @@ ifeq ($(CONFIG_XFS_QUOTA),y)
3431 xfs-$(CONFIG_PROC_FS) += quota/xfs_qm_stats.o
3432 endif
3433
3434 +obj-$(CONFIG_XFS_DMAPI) += dmapi/
3435 +
3436 xfs-$(CONFIG_XFS_RT) += xfs_rtalloc.o
3437 xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o
3438 xfs-$(CONFIG_PROC_FS) += $(XFS_LINUX)/xfs_stats.o
3439 @@ -107,7 +109,8 @@ xfs-y += $(addprefix $(XFS_LINUX)/, \
3440 xfs_lrw.o \
3441 xfs_super.o \
3442 xfs_vnode.o \
3443 - xfs_xattr.o)
3444 + xfs_xattr.o \
3445 + xfs_ksyms.o)
3446
3447 # Objects in support/
3448 xfs-y += $(addprefix support/, \
3449 Index: linux-2.6.27/fs/xfs/Kconfig
3450 ===================================================================
3451 --- linux-2.6.27.orig/fs/xfs/Kconfig
3452 +++ linux-2.6.27/fs/xfs/Kconfig
3453 @@ -35,6 +35,19 @@ config XFS_QUOTA
3454 with or without the generic quota support enabled (CONFIG_QUOTA) -
3455 they are completely independent subsystems.
3456
3457 +config XFS_DMAPI
3458 + tristate "XFS DMAPI support"
3459 + depends on XFS_FS
3460 + select DMAPI
3461 + help
3462 + The Data Management API is a system interface used to implement
3463 + the interface defined in the X/Open document:
3464 + "Systems Management: Data Storage Management (XDSM) API",
3465 + dated February 1997. This interface is used by hierarchical
3466 + storage management systems.
3467 +
3468 + If unsure, say N.
3469 +
3470 config XFS_POSIX_ACL
3471 bool "XFS POSIX ACL support"
3472 depends on XFS_FS
3473 Index: linux-2.6.27/fs/xfs/xfs_mount.h
3474 ===================================================================
3475 --- linux-2.6.27.orig/fs/xfs/xfs_mount.h
3476 +++ linux-2.6.27/fs/xfs/xfs_mount.h
3477 @@ -341,6 +341,7 @@ typedef struct xfs_mount {
3478 spinlock_t m_sync_lock; /* work item list lock */
3479 int m_sync_seq; /* sync thread generation no. */
3480 wait_queue_head_t m_wait_single_sync_task;
3481 + struct vfsmount *m_vfsmount;
3482 } xfs_mount_t;
3483
3484 /*
3485 Index: linux-2.6.27/fs/xfs/linux-2.6/xfs_super.c
3486 ===================================================================
3487 --- linux-2.6.27.orig/fs/xfs/linux-2.6/xfs_super.c
3488 +++ linux-2.6.27/fs/xfs/linux-2.6/xfs_super.c
3489 @@ -1835,8 +1835,16 @@ xfs_fs_get_sb(
3490 void *data,
3491 struct vfsmount *mnt)
3492 {
3493 - return get_sb_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super,
3494 + int error;
3495 +
3496 + error = get_sb_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super,
3497 mnt);
3498 + if (!error) {
3499 + xfs_mount_t *mp = XFS_M(mnt->mnt_sb);
3500 + mp->m_vfsmount = mnt;
3501 + }
3502 +
3503 + return error;
3504 }
3505
3506 static struct super_operations xfs_super_operations = {
3507 @@ -1861,13 +1869,14 @@ static struct quotactl_ops xfs_quotactl_
3508 .set_xquota = xfs_fs_setxquota,
3509 };
3510
3511 -static struct file_system_type xfs_fs_type = {
3512 +struct file_system_type xfs_fs_type = {
3513 .owner = THIS_MODULE,
3514 .name = "xfs",
3515 .get_sb = xfs_fs_get_sb,
3516 .kill_sb = kill_block_super,
3517 .fs_flags = FS_REQUIRES_DEV,
3518 };
3519 +EXPORT_SYMBOL(xfs_fs_type);
3520
3521 STATIC int __init
3522 xfs_alloc_trace_bufs(void)
3523 Index: linux-2.6.27/fs/xfs/linux-2.6/xfs_file.c
3524 ===================================================================
3525 --- linux-2.6.27.orig/fs/xfs/linux-2.6/xfs_file.c
3526 +++ linux-2.6.27/fs/xfs/linux-2.6/xfs_file.c
3527 @@ -43,6 +43,9 @@
3528 #include <linux/smp_lock.h>
3529
3530 static struct vm_operations_struct xfs_file_vm_ops;
3531 +#ifdef HAVE_DMAPI
3532 +static struct vm_operations_struct xfs_dmapi_file_vm_ops;
3533 +#endif
3534
3535 STATIC_INLINE ssize_t
3536 __xfs_file_read(
3537 @@ -204,6 +207,23 @@ xfs_file_fsync(
3538 return -xfs_fsync(XFS_I(dentry->d_inode));
3539 }
3540
3541 +#ifdef HAVE_DMAPI
3542 +STATIC int
3543 +xfs_vm_fault(
3544 + struct vm_area_struct *vma,
3545 + struct vm_fault *vmf)
3546 +{
3547 + struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
3548 + struct xfs_mount *mp = XFS_M(inode->i_sb);
3549 +
3550 + ASSERT_ALWAYS(mp->m_flags & XFS_MOUNT_DMAPI);
3551 +
3552 + if (XFS_SEND_MMAP(mp, vma, 0))
3553 + return VM_FAULT_SIGBUS;
3554 + return filemap_fault(vma, vmf);
3555 +}
3556 +#endif /* HAVE_DMAPI */
3557 +
3558 /*
3559 * Unfortunately we can't just use the clean and simple readdir implementation
3560 * below, because nfs might call back into ->lookup from the filldir callback
3561 @@ -372,6 +392,11 @@ xfs_file_mmap(
3562 vma->vm_ops = &xfs_file_vm_ops;
3563 vma->vm_flags |= VM_CAN_NONLINEAR | VM_PAGE_MKWRITE2;
3564
3565 +#ifdef HAVE_DMAPI
3566 + if (XFS_M(filp->f_path.dentry->d_inode->i_sb)->m_flags & XFS_MOUNT_DMAPI)
3567 + vma->vm_ops = &xfs_dmapi_file_vm_ops;
3568 +#endif /* HAVE_DMAPI */
3569 +
3570 file_accessed(filp);
3571 return 0;
3572 }
3573 @@ -418,6 +443,47 @@ xfs_file_ioctl_invis(
3574 return error;
3575 }
3576
3577 +#ifdef HAVE_DMAPI
3578 +#ifdef HAVE_VMOP_MPROTECT
3579 +STATIC int
3580 +xfs_vm_mprotect(
3581 + struct vm_area_struct *vma,
3582 + unsigned int newflags)
3583 +{
3584 + struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
3585 + struct xfs_mount *mp = XFS_M(inode->i_sb);
3586 + int error = 0;
3587 +
3588 + if (mp->m_flags & XFS_MOUNT_DMAPI) {
3589 + if ((vma->vm_flags & VM_MAYSHARE) &&
3590 + (newflags & VM_WRITE) && !(vma->vm_flags & VM_WRITE))
3591 + error = XFS_SEND_MMAP(mp, vma, VM_WRITE);
3592 + }
3593 + return error;
3594 +}
3595 +#endif /* HAVE_VMOP_MPROTECT */
3596 +#endif /* HAVE_DMAPI */
3597 +
3598 +#ifdef HAVE_FOP_OPEN_EXEC
3599 +/* If the user is attempting to execute a file that is offline then
3600 + * we have to trigger a DMAPI READ event before the file is marked as busy
3601 + * otherwise the invisible I/O will not be able to write to the file to bring
3602 + * it back online.
3603 + */
3604 +STATIC int
3605 +xfs_file_open_exec(
3606 + struct inode *inode)
3607 +{
3608 + struct xfs_mount *mp = XFS_M(inode->i_sb);
3609 + struct xfs_inode *ip = XFS_I(inode);
3610 +
3611 + if (unlikely(mp->m_flags & XFS_MOUNT_DMAPI) &&
3612 + DM_EVENT_ENABLED(ip, DM_EVENT_READ))
3613 + return -XFS_SEND_DATA(mp, DM_EVENT_READ, ip, 0, 0, 0, NULL);
3614 + return 0;
3615 +}
3616 +#endif /* HAVE_FOP_OPEN_EXEC */
3617 +
3618 /*
3619 * mmap()d file has taken write protection fault and is being made
3620 * writable. We can set the page state up correctly for a writable
3621 @@ -487,3 +553,13 @@ static struct vm_operations_struct xfs_f
3622 .fault = filemap_fault,
3623 ._pmkw.page_mkwrite2 = xfs_vm_page_mkwrite,
3624 };
3625 +
3626 +#ifdef HAVE_DMAPI
3627 +static struct vm_operations_struct xfs_dmapi_file_vm_ops = {
3628 + .fault = xfs_vm_fault,
3629 + ._pmkw.page_mkwrite2 = xfs_vm_page_mkwrite,
3630 +#ifdef HAVE_VMOP_MPROTECT
3631 + .mprotect = xfs_vm_mprotect,
3632 +#endif
3633 +};
3634 +#endif /* HAVE_DMAPI */
3635 Index: linux-2.6.27/fs/xfs/linux-2.6/xfs_linux.h
3636 ===================================================================
3637 --- linux-2.6.27.orig/fs/xfs/linux-2.6/xfs_linux.h
3638 +++ linux-2.6.27/fs/xfs/linux-2.6/xfs_linux.h
3639 @@ -180,6 +180,10 @@
3640 #define xfs_itruncate_data(ip, off) \
3641 (-vmtruncate(VFS_I(ip), (off)))
3642
3643 +#undef HAVE_DMAPI
3644 +#if defined(CONFIG_XFS_DMAPI) || defined(CONFIG_XFS_DMAPI_MODULE)
3645 +#define HAVE_DMAPI
3646 +#endif
3647
3648 /* Move the kernel do_div definition off to one side */
3649
3650 Index: linux-2.6.27/fs/xfs/xfs_dmops.c
3651 ===================================================================
3652 --- linux-2.6.27.orig/fs/xfs/xfs_dmops.c
3653 +++ linux-2.6.27/fs/xfs/xfs_dmops.c
3654 @@ -41,9 +41,21 @@ int
3655 xfs_dmops_get(struct xfs_mount *mp, struct xfs_mount_args *args)
3656 {
3657 if (args->flags & XFSMNT_DMAPI) {
3658 - cmn_err(CE_WARN,
3659 - "XFS: dmapi support not available in this kernel.");
3660 - return EINVAL;
3661 + struct xfs_dmops *ops;
3662 +
3663 + ops = symbol_get(xfs_dmcore_xfs);
3664 + if (!ops) {
3665 + request_module("xfs_dmapi");
3666 + ops = symbol_get(xfs_dmcore_xfs);
3667 + }
3668 +
3669 + if (!ops) {
3670 + cmn_err(CE_WARN, "XFS: no dmapi support available.");
3671 + return EINVAL;
3672 + }
3673 + mp->m_dm_ops = ops;
3674 + } else {
3675 + mp->m_dm_ops = &xfs_dmcore_stub;
3676 }
3677
3678 mp->m_dm_ops = &xfs_dmcore_stub;
3679 @@ -53,4 +65,6 @@ xfs_dmops_get(struct xfs_mount *mp, stru
3680 void
3681 xfs_dmops_put(struct xfs_mount *mp)
3682 {
3683 + if (mp->m_dm_ops != &xfs_dmcore_stub)
3684 + symbol_put(xfs_dmcore_xfs);
3685 }
3686 Index: linux-2.6.27/fs/xfs/linux-2.6/xfs_ksyms.c
3687 ===================================================================
3688 --- /dev/null
3689 +++ linux-2.6.27/fs/xfs/linux-2.6/xfs_ksyms.c
3690 @@ -0,0 +1,99 @@
3691 +/*
3692 + * Copyright (c) 2004-2008 Silicon Graphics, Inc.
3693 + * All Rights Reserved.
3694 + *
3695 + * This program is free software; you can redistribute it and/or
3696 + * modify it under the terms of the GNU General Public License as
3697 + * published by the Free Software Foundation.
3698 + *
3699 + * This program is distributed in the hope that it would be useful,
3700 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3701 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3702 + * GNU General Public License for more details.
3703 + *
3704 + * You should have received a copy of the GNU General Public License
3705 + * along with this program; if not, write the Free Software Foundation,
3706 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3707 + */
3708 +
3709 +#include "xfs.h"
3710 +#include "xfs_fs.h"
3711 +#include "xfs_bit.h"
3712 +#include "xfs_buf.h"
3713 +#include "xfs_log.h"
3714 +#include "xfs_imap.h"
3715 +#include "xfs_inum.h"
3716 +#include "xfs_clnt.h"
3717 +#include "xfs_trans.h"
3718 +#include "xfs_sb.h"
3719 +#include "xfs_ag.h"
3720 +#include "xfs_dir2.h"
3721 +#include "xfs_alloc.h"
3722 +#include "xfs_dmapi.h"
3723 +#include "xfs_quota.h"
3724 +#include "xfs_mount.h"
3725 +#include "xfs_da_btree.h"
3726 +#include "xfs_bmap_btree.h"
3727 +#include "xfs_alloc_btree.h"
3728 +#include "xfs_ialloc_btree.h"
3729 +#include "xfs_dir2_sf.h"
3730 +#include "xfs_attr_sf.h"
3731 +#include "xfs_dinode.h"
3732 +#include "xfs_inode.h"
3733 +#include "xfs_btree.h"
3734 +#include "xfs_ialloc.h"
3735 +#include "xfs_bmap.h"
3736 +#include "xfs_rtalloc.h"
3737 +#include "xfs_error.h"
3738 +#include "xfs_itable.h"
3739 +#include "xfs_rw.h"
3740 +#include "xfs_dir2_data.h"
3741 +#include "xfs_dir2_leaf.h"
3742 +#include "xfs_dir2_block.h"
3743 +#include "xfs_dir2_node.h"
3744 +#include "xfs_dir2_trace.h"
3745 +#include "xfs_acl.h"
3746 +#include "xfs_attr.h"
3747 +#include "xfs_attr_leaf.h"
3748 +#include "xfs_inode_item.h"
3749 +#include "xfs_buf_item.h"
3750 +#include "xfs_extfree_item.h"
3751 +#include "xfs_log_priv.h"
3752 +#include "xfs_trans_priv.h"
3753 +#include "xfs_trans_space.h"
3754 +#include "xfs_utils.h"
3755 +#include "xfs_iomap.h"
3756 +#include "xfs_filestream.h"
3757 +#include "xfs_vnodeops.h"
3758 +#include "xfs_vfsops.h"
3759 +#include "support/ktrace.h"
3760 +
3761 +EXPORT_SYMBOL(xfs_iunlock);
3762 +EXPORT_SYMBOL(xfs_invis_file_operations);
3763 +EXPORT_SYMBOL(xfs_attr_remove);
3764 +EXPORT_SYMBOL(xfs_iunlock_map_shared);
3765 +EXPORT_SYMBOL(xfs_iget);
3766 +EXPORT_SYMBOL(xfs_bmapi);
3767 +EXPORT_SYMBOL(xfs_internal_inum);
3768 +EXPORT_SYMBOL(sys_cred);
3769 +EXPORT_SYMBOL(xfs_attr_set);
3770 +EXPORT_SYMBOL(xfs_trans_reserve);
3771 +EXPORT_SYMBOL(xfs_trans_ijoin);
3772 +EXPORT_SYMBOL(xfs_free_eofblocks);
3773 +EXPORT_SYMBOL(kmem_free);
3774 +EXPORT_SYMBOL(_xfs_trans_commit);
3775 +EXPORT_SYMBOL(xfs_ilock);
3776 +EXPORT_SYMBOL(xfs_attr_get);
3777 +EXPORT_SYMBOL(xfs_readdir);
3778 +EXPORT_SYMBOL(xfs_setattr);
3779 +EXPORT_SYMBOL(xfs_trans_alloc);
3780 +EXPORT_SYMBOL(xfs_trans_cancel);
3781 +EXPORT_SYMBOL(xfs_fsync);
3782 +EXPORT_SYMBOL(xfs_iput_new);
3783 +EXPORT_SYMBOL(xfs_bulkstat);
3784 +EXPORT_SYMBOL(xfs_ilock_map_shared);
3785 +EXPORT_SYMBOL(xfs_iput);
3786 +EXPORT_SYMBOL(xfs_trans_log_inode);
3787 +EXPORT_SYMBOL(xfs_attr_list);
3788 +EXPORT_SYMBOL(kmem_alloc);
3789 +EXPORT_SYMBOL(xfs_change_file_space);