]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/suse-2.6.27.39/patches.suse/xfs-dmapi-xfs-enable
Imported linux-2.6.27.39 suse/xen patches.
[ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.suse / xfs-dmapi-xfs-enable
CommitLineData
2cb7cef9
BS
1Date: Thu, 09 Oct 2008 17:11:53 +1100
2From: Donald Douwsma <donaldd@sgi.com>
3Subject: DMAPI support for xfs
4Patch-mainline: ?
5References: bnc#450658
6
7Acked-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
23Index: 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
56Index: 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);
3398Index: 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__ */
3426Index: 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/, \
3449Index: 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
3473Index: 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 /*
3485Index: 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)
3523Index: 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 */
3635Index: 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
3650Index: 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 }
3686Index: 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);