aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorLachlan McIlroy <lachlan@redback.melbourne.sgi.com>2009-01-18 22:22:45 -0500
committerLachlan McIlroy <lachlan@sgi.com>2009-01-18 22:22:45 -0500
commit55622c6df3600267b1d61fa7e8a4d9341de3db24 (patch)
tree57ff209c55fba6688aea5d42f24bde32c449de1c /fs/xfs
parent6c5200ce3c528a8f7695ee62f33ad84d8f84d444 (diff)
parent2809f76afce05a73e08120f455107912aa519647 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/fs/xfs/xfs
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/Kconfig1
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c305
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.h15
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.c184
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c17
-rw-r--r--fs/xfs/quota/xfs_dquot.c36
-rw-r--r--fs/xfs/quota/xfs_dquot.h10
-rw-r--r--fs/xfs/quota/xfs_qm.c9
-rw-r--r--fs/xfs/xfs_inode.c13
-rw-r--r--fs/xfs/xfs_mount.c26
-rw-r--r--fs/xfs/xfs_mount.h3
11 files changed, 294 insertions, 325 deletions
diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
index 3f53dd101f99..29228f5899cd 100644
--- a/fs/xfs/Kconfig
+++ b/fs/xfs/Kconfig
@@ -1,6 +1,7 @@
1config XFS_FS 1config XFS_FS
2 tristate "XFS filesystem support" 2 tristate "XFS filesystem support"
3 depends on BLOCK 3 depends on BLOCK
4 select EXPORTFS
4 help 5 help
5 XFS is a high performance journaling filesystem which originated 6 XFS is a high performance journaling filesystem which originated
6 on the SGI IRIX platform. It is completely multi-threaded, can 7 on the SGI IRIX platform. It is completely multi-threaded, can
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index e5be1e0be802..4bd112313f33 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -50,12 +50,14 @@
50#include "xfs_vnodeops.h" 50#include "xfs_vnodeops.h"
51#include "xfs_quota.h" 51#include "xfs_quota.h"
52#include "xfs_inode_item.h" 52#include "xfs_inode_item.h"
53#include "xfs_export.h"
53 54
54#include <linux/capability.h> 55#include <linux/capability.h>
55#include <linux/dcache.h> 56#include <linux/dcache.h>
56#include <linux/mount.h> 57#include <linux/mount.h>
57#include <linux/namei.h> 58#include <linux/namei.h>
58#include <linux/pagemap.h> 59#include <linux/pagemap.h>
60#include <linux/exportfs.h>
59 61
60/* 62/*
61 * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to 63 * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
@@ -164,97 +166,69 @@ xfs_find_handle(
164 return 0; 166 return 0;
165} 167}
166 168
167
168/* 169/*
169 * Convert userspace handle data into inode. 170 * No need to do permission checks on the various pathname components
170 * 171 * as the handle operations are privileged.
171 * We use the fact that all the fsop_handlereq ioctl calls have a data
172 * structure argument whose first component is always a xfs_fsop_handlereq_t,
173 * so we can pass that sub structure into this handy, shared routine.
174 *
175 * If no error, caller must always iput the returned inode.
176 */ 172 */
177STATIC int 173STATIC int
178xfs_vget_fsop_handlereq( 174xfs_handle_acceptable(
179 xfs_mount_t *mp, 175 void *context,
180 struct inode *parinode, /* parent inode pointer */ 176 struct dentry *dentry)
181 xfs_fsop_handlereq_t *hreq, 177{
182 struct inode **inode) 178 return 1;
179}
180
181/*
182 * Convert userspace handle data into a dentry.
183 */
184struct dentry *
185xfs_handle_to_dentry(
186 struct file *parfilp,
187 void __user *uhandle,
188 u32 hlen)
183{ 189{
184 void __user *hanp;
185 size_t hlen;
186 xfs_fid_t *xfid;
187 xfs_handle_t *handlep;
188 xfs_handle_t handle; 190 xfs_handle_t handle;
189 xfs_inode_t *ip; 191 struct xfs_fid64 fid;
190 xfs_ino_t ino;
191 __u32 igen;
192 int error;
193 192
194 /* 193 /*
195 * Only allow handle opens under a directory. 194 * Only allow handle opens under a directory.
196 */ 195 */
197 if (!S_ISDIR(parinode->i_mode)) 196 if (!S_ISDIR(parfilp->f_path.dentry->d_inode->i_mode))
198 return XFS_ERROR(ENOTDIR); 197 return ERR_PTR(-ENOTDIR);
199 198
200 hanp = hreq->ihandle; 199 if (hlen != sizeof(xfs_handle_t))
201 hlen = hreq->ihandlen; 200 return ERR_PTR(-EINVAL);
202 handlep = &handle; 201 if (copy_from_user(&handle, uhandle, hlen))
203 202 return ERR_PTR(-EFAULT);
204 if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep)) 203 if (handle.ha_fid.fid_len !=
205 return XFS_ERROR(EINVAL); 204 sizeof(handle.ha_fid) - sizeof(handle.ha_fid.fid_len))
206 if (copy_from_user(handlep, hanp, hlen)) 205 return ERR_PTR(-EINVAL);
207 return XFS_ERROR(EFAULT); 206
208 if (hlen < sizeof(*handlep)) 207 memset(&fid, 0, sizeof(struct fid));
209 memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen); 208 fid.ino = handle.ha_fid.fid_ino;
210 if (hlen > sizeof(handlep->ha_fsid)) { 209 fid.gen = handle.ha_fid.fid_gen;
211 if (handlep->ha_fid.fid_len != 210
212 (hlen - sizeof(handlep->ha_fsid) - 211 return exportfs_decode_fh(parfilp->f_path.mnt, (struct fid *)&fid, 3,
213 sizeof(handlep->ha_fid.fid_len)) || 212 FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG,
214 handlep->ha_fid.fid_pad) 213 xfs_handle_acceptable, NULL);
215 return XFS_ERROR(EINVAL); 214}
216 }
217
218 /*
219 * Crack the handle, obtain the inode # & generation #
220 */
221 xfid = (struct xfs_fid *)&handlep->ha_fid;
222 if (xfid->fid_len == sizeof(*xfid) - sizeof(xfid->fid_len)) {
223 ino = xfid->fid_ino;
224 igen = xfid->fid_gen;
225 } else {
226 return XFS_ERROR(EINVAL);
227 }
228
229 /*
230 * Get the XFS inode, building a Linux inode to go with it.
231 */
232 error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);
233 if (error)
234 return error;
235 if (ip == NULL)
236 return XFS_ERROR(EIO);
237 if (ip->i_d.di_gen != igen) {
238 xfs_iput_new(ip, XFS_ILOCK_SHARED);
239 return XFS_ERROR(ENOENT);
240 }
241
242 xfs_iunlock(ip, XFS_ILOCK_SHARED);
243 215
244 *inode = VFS_I(ip); 216STATIC struct dentry *
245 return 0; 217xfs_handlereq_to_dentry(
218 struct file *parfilp,
219 xfs_fsop_handlereq_t *hreq)
220{
221 return xfs_handle_to_dentry(parfilp, hreq->ihandle, hreq->ihandlen);
246} 222}
247 223
248int 224int
249xfs_open_by_handle( 225xfs_open_by_handle(
250 xfs_mount_t *mp,
251 xfs_fsop_handlereq_t *hreq,
252 struct file *parfilp, 226 struct file *parfilp,
253 struct inode *parinode) 227 xfs_fsop_handlereq_t *hreq)
254{ 228{
255 const struct cred *cred = current_cred(); 229 const struct cred *cred = current_cred();
256 int error; 230 int error;
257 int new_fd; 231 int fd;
258 int permflag; 232 int permflag;
259 struct file *filp; 233 struct file *filp;
260 struct inode *inode; 234 struct inode *inode;
@@ -263,19 +237,21 @@ xfs_open_by_handle(
263 if (!capable(CAP_SYS_ADMIN)) 237 if (!capable(CAP_SYS_ADMIN))
264 return -XFS_ERROR(EPERM); 238 return -XFS_ERROR(EPERM);
265 239
266 error = xfs_vget_fsop_handlereq(mp, parinode, hreq, &inode); 240 dentry = xfs_handlereq_to_dentry(parfilp, hreq);
267 if (error) 241 if (IS_ERR(dentry))
268 return -error; 242 return PTR_ERR(dentry);
243 inode = dentry->d_inode;
269 244
270 /* Restrict xfs_open_by_handle to directories & regular files. */ 245 /* Restrict xfs_open_by_handle to directories & regular files. */
271 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { 246 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
272 iput(inode); 247 error = -XFS_ERROR(EPERM);
273 return -XFS_ERROR(EINVAL); 248 goto out_dput;
274 } 249 }
275 250
276#if BITS_PER_LONG != 32 251#if BITS_PER_LONG != 32
277 hreq->oflags |= O_LARGEFILE; 252 hreq->oflags |= O_LARGEFILE;
278#endif 253#endif
254
279 /* Put open permission in namei format. */ 255 /* Put open permission in namei format. */
280 permflag = hreq->oflags; 256 permflag = hreq->oflags;
281 if ((permflag+1) & O_ACCMODE) 257 if ((permflag+1) & O_ACCMODE)
@@ -285,50 +261,45 @@ xfs_open_by_handle(
285 261
286 if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) && 262 if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&
287 (permflag & FMODE_WRITE) && IS_APPEND(inode)) { 263 (permflag & FMODE_WRITE) && IS_APPEND(inode)) {
288 iput(inode); 264 error = -XFS_ERROR(EPERM);
289 return -XFS_ERROR(EPERM); 265 goto out_dput;
290 } 266 }
291 267
292 if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) { 268 if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
293 iput(inode); 269 error = -XFS_ERROR(EACCES);
294 return -XFS_ERROR(EACCES); 270 goto out_dput;
295 } 271 }
296 272
297 /* Can't write directories. */ 273 /* Can't write directories. */
298 if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) { 274 if (S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) {
299 iput(inode); 275 error = -XFS_ERROR(EISDIR);
300 return -XFS_ERROR(EISDIR); 276 goto out_dput;
301 } 277 }
302 278
303 if ((new_fd = get_unused_fd()) < 0) { 279 fd = get_unused_fd();
304 iput(inode); 280 if (fd < 0) {
305 return new_fd; 281 error = fd;
282 goto out_dput;
306 } 283 }
307 284
308 dentry = d_obtain_alias(inode); 285 filp = dentry_open(dentry, mntget(parfilp->f_path.mnt),
309 if (IS_ERR(dentry)) { 286 hreq->oflags, cred);
310 put_unused_fd(new_fd);
311 return PTR_ERR(dentry);
312 }
313
314 /* Ensure umount returns EBUSY on umounts while this file is open. */
315 mntget(parfilp->f_path.mnt);
316
317 /* Create file pointer. */
318 filp = dentry_open(dentry, parfilp->f_path.mnt, hreq->oflags, cred);
319 if (IS_ERR(filp)) { 287 if (IS_ERR(filp)) {
320 put_unused_fd(new_fd); 288 put_unused_fd(fd);
321 return -XFS_ERROR(-PTR_ERR(filp)); 289 return PTR_ERR(filp);
322 } 290 }
323 291
324 if (inode->i_mode & S_IFREG) { 292 if (inode->i_mode & S_IFREG) {
325 /* invisible operation should not change atime */
326 filp->f_flags |= O_NOATIME; 293 filp->f_flags |= O_NOATIME;
327 filp->f_mode |= FMODE_NOCMTIME; 294 filp->f_mode |= FMODE_NOCMTIME;
328 } 295 }
329 296
330 fd_install(new_fd, filp); 297 fd_install(fd, filp);
331 return new_fd; 298 return fd;
299
300 out_dput:
301 dput(dentry);
302 return error;
332} 303}
333 304
334/* 305/*
@@ -359,11 +330,10 @@ do_readlink(
359 330
360int 331int
361xfs_readlink_by_handle( 332xfs_readlink_by_handle(
362 xfs_mount_t *mp, 333 struct file *parfilp,
363 xfs_fsop_handlereq_t *hreq, 334 xfs_fsop_handlereq_t *hreq)
364 struct inode *parinode)
365{ 335{
366 struct inode *inode; 336 struct dentry *dentry;
367 __u32 olen; 337 __u32 olen;
368 void *link; 338 void *link;
369 int error; 339 int error;
@@ -371,26 +341,28 @@ xfs_readlink_by_handle(
371 if (!capable(CAP_SYS_ADMIN)) 341 if (!capable(CAP_SYS_ADMIN))
372 return -XFS_ERROR(EPERM); 342 return -XFS_ERROR(EPERM);
373 343
374 error = xfs_vget_fsop_handlereq(mp, parinode, hreq, &inode); 344 dentry = xfs_handlereq_to_dentry(parfilp, hreq);
375 if (error) 345 if (IS_ERR(dentry))
376 return -error; 346 return PTR_ERR(dentry);
377 347
378 /* Restrict this handle operation to symlinks only. */ 348 /* Restrict this handle operation to symlinks only. */
379 if (!S_ISLNK(inode->i_mode)) { 349 if (!S_ISLNK(dentry->d_inode->i_mode)) {
380 error = -XFS_ERROR(EINVAL); 350 error = -XFS_ERROR(EINVAL);
381 goto out_iput; 351 goto out_dput;
382 } 352 }
383 353
384 if (copy_from_user(&olen, hreq->ohandlen, sizeof(__u32))) { 354 if (copy_from_user(&olen, hreq->ohandlen, sizeof(__u32))) {
385 error = -XFS_ERROR(EFAULT); 355 error = -XFS_ERROR(EFAULT);
386 goto out_iput; 356 goto out_dput;
387 } 357 }
388 358
389 link = kmalloc(MAXPATHLEN+1, GFP_KERNEL); 359 link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
390 if (!link) 360 if (!link) {
391 goto out_iput; 361 error = -XFS_ERROR(ENOMEM);
362 goto out_dput;
363 }
392 364
393 error = -xfs_readlink(XFS_I(inode), link); 365 error = -xfs_readlink(XFS_I(dentry->d_inode), link);
394 if (error) 366 if (error)
395 goto out_kfree; 367 goto out_kfree;
396 error = do_readlink(hreq->ohandle, olen, link); 368 error = do_readlink(hreq->ohandle, olen, link);
@@ -399,32 +371,31 @@ xfs_readlink_by_handle(
399 371
400 out_kfree: 372 out_kfree:
401 kfree(link); 373 kfree(link);
402 out_iput: 374 out_dput:
403 iput(inode); 375 dput(dentry);
404 return error; 376 return error;
405} 377}
406 378
407STATIC int 379STATIC int
408xfs_fssetdm_by_handle( 380xfs_fssetdm_by_handle(
409 xfs_mount_t *mp, 381 struct file *parfilp,
410 void __user *arg, 382 void __user *arg)
411 struct inode *parinode)
412{ 383{
413 int error; 384 int error;
414 struct fsdmidata fsd; 385 struct fsdmidata fsd;
415 xfs_fsop_setdm_handlereq_t dmhreq; 386 xfs_fsop_setdm_handlereq_t dmhreq;
416 struct inode *inode; 387 struct dentry *dentry;
417 388
418 if (!capable(CAP_MKNOD)) 389 if (!capable(CAP_MKNOD))
419 return -XFS_ERROR(EPERM); 390 return -XFS_ERROR(EPERM);
420 if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t))) 391 if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t)))
421 return -XFS_ERROR(EFAULT); 392 return -XFS_ERROR(EFAULT);
422 393
423 error = xfs_vget_fsop_handlereq(mp, parinode, &dmhreq.hreq, &inode); 394 dentry = xfs_handlereq_to_dentry(parfilp, &dmhreq.hreq);
424 if (error) 395 if (IS_ERR(dentry))
425 return -error; 396 return PTR_ERR(dentry);
426 397
427 if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { 398 if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode)) {
428 error = -XFS_ERROR(EPERM); 399 error = -XFS_ERROR(EPERM);
429 goto out; 400 goto out;
430 } 401 }
@@ -434,24 +405,23 @@ xfs_fssetdm_by_handle(
434 goto out; 405 goto out;
435 } 406 }
436 407
437 error = -xfs_set_dmattrs(XFS_I(inode), fsd.fsd_dmevmask, 408 error = -xfs_set_dmattrs(XFS_I(dentry->d_inode), fsd.fsd_dmevmask,
438 fsd.fsd_dmstate); 409 fsd.fsd_dmstate);
439 410
440 out: 411 out:
441 iput(inode); 412 dput(dentry);
442 return error; 413 return error;
443} 414}
444 415
445STATIC int 416STATIC int
446xfs_attrlist_by_handle( 417xfs_attrlist_by_handle(
447 xfs_mount_t *mp, 418 struct file *parfilp,
448 void __user *arg, 419 void __user *arg)
449 struct inode *parinode)
450{ 420{
451 int error; 421 int error = -ENOMEM;
452 attrlist_cursor_kern_t *cursor; 422 attrlist_cursor_kern_t *cursor;
453 xfs_fsop_attrlist_handlereq_t al_hreq; 423 xfs_fsop_attrlist_handlereq_t al_hreq;
454 struct inode *inode; 424 struct dentry *dentry;
455 char *kbuf; 425 char *kbuf;
456 426
457 if (!capable(CAP_SYS_ADMIN)) 427 if (!capable(CAP_SYS_ADMIN))
@@ -467,16 +437,16 @@ xfs_attrlist_by_handle(
467 if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE)) 437 if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE))
468 return -XFS_ERROR(EINVAL); 438 return -XFS_ERROR(EINVAL);
469 439
470 error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq, &inode); 440 dentry = xfs_handlereq_to_dentry(parfilp, &al_hreq.hreq);
471 if (error) 441 if (IS_ERR(dentry))
472 goto out; 442 return PTR_ERR(dentry);
473 443
474 kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL); 444 kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL);
475 if (!kbuf) 445 if (!kbuf)
476 goto out_vn_rele; 446 goto out_dput;
477 447
478 cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; 448 cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
479 error = xfs_attr_list(XFS_I(inode), kbuf, al_hreq.buflen, 449 error = -xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen,
480 al_hreq.flags, cursor); 450 al_hreq.flags, cursor);
481 if (error) 451 if (error)
482 goto out_kfree; 452 goto out_kfree;
@@ -486,10 +456,9 @@ xfs_attrlist_by_handle(
486 456
487 out_kfree: 457 out_kfree:
488 kfree(kbuf); 458 kfree(kbuf);
489 out_vn_rele: 459 out_dput:
490 iput(inode); 460 dput(dentry);
491 out: 461 return error;
492 return -error;
493} 462}
494 463
495int 464int
@@ -564,15 +533,13 @@ xfs_attrmulti_attr_remove(
564 533
565STATIC int 534STATIC int
566xfs_attrmulti_by_handle( 535xfs_attrmulti_by_handle(
567 xfs_mount_t *mp,
568 void __user *arg,
569 struct file *parfilp, 536 struct file *parfilp,
570 struct inode *parinode) 537 void __user *arg)
571{ 538{
572 int error; 539 int error;
573 xfs_attr_multiop_t *ops; 540 xfs_attr_multiop_t *ops;
574 xfs_fsop_attrmulti_handlereq_t am_hreq; 541 xfs_fsop_attrmulti_handlereq_t am_hreq;
575 struct inode *inode; 542 struct dentry *dentry;
576 unsigned int i, size; 543 unsigned int i, size;
577 char *attr_name; 544 char *attr_name;
578 545
@@ -581,19 +548,19 @@ xfs_attrmulti_by_handle(
581 if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t))) 548 if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t)))
582 return -XFS_ERROR(EFAULT); 549 return -XFS_ERROR(EFAULT);
583 550
584 error = xfs_vget_fsop_handlereq(mp, parinode, &am_hreq.hreq, &inode); 551 dentry = xfs_handlereq_to_dentry(parfilp, &am_hreq.hreq);
585 if (error) 552 if (IS_ERR(dentry))
586 goto out; 553 return PTR_ERR(dentry);
587 554
588 error = E2BIG; 555 error = E2BIG;
589 size = am_hreq.opcount * sizeof(xfs_attr_multiop_t); 556 size = am_hreq.opcount * sizeof(xfs_attr_multiop_t);
590 if (!size || size > 16 * PAGE_SIZE) 557 if (!size || size > 16 * PAGE_SIZE)
591 goto out_vn_rele; 558 goto out_dput;
592 559
593 error = ENOMEM; 560 error = ENOMEM;
594 ops = kmalloc(size, GFP_KERNEL); 561 ops = kmalloc(size, GFP_KERNEL);
595 if (!ops) 562 if (!ops)
596 goto out_vn_rele; 563 goto out_dput;
597 564
598 error = EFAULT; 565 error = EFAULT;
599 if (copy_from_user(ops, am_hreq.ops, size)) 566 if (copy_from_user(ops, am_hreq.ops, size))
@@ -615,25 +582,28 @@ xfs_attrmulti_by_handle(
615 582
616 switch (ops[i].am_opcode) { 583 switch (ops[i].am_opcode) {
617 case ATTR_OP_GET: 584 case ATTR_OP_GET:
618 ops[i].am_error = xfs_attrmulti_attr_get(inode, 585 ops[i].am_error = xfs_attrmulti_attr_get(
619 attr_name, ops[i].am_attrvalue, 586 dentry->d_inode, attr_name,
620 &ops[i].am_length, ops[i].am_flags); 587 ops[i].am_attrvalue, &ops[i].am_length,
588 ops[i].am_flags);
621 break; 589 break;
622 case ATTR_OP_SET: 590 case ATTR_OP_SET:
623 ops[i].am_error = mnt_want_write(parfilp->f_path.mnt); 591 ops[i].am_error = mnt_want_write(parfilp->f_path.mnt);
624 if (ops[i].am_error) 592 if (ops[i].am_error)
625 break; 593 break;
626 ops[i].am_error = xfs_attrmulti_attr_set(inode, 594 ops[i].am_error = xfs_attrmulti_attr_set(
627 attr_name, ops[i].am_attrvalue, 595 dentry->d_inode, attr_name,
628 ops[i].am_length, ops[i].am_flags); 596 ops[i].am_attrvalue, ops[i].am_length,
597 ops[i].am_flags);
629 mnt_drop_write(parfilp->f_path.mnt); 598 mnt_drop_write(parfilp->f_path.mnt);
630 break; 599 break;
631 case ATTR_OP_REMOVE: 600 case ATTR_OP_REMOVE:
632 ops[i].am_error = mnt_want_write(parfilp->f_path.mnt); 601 ops[i].am_error = mnt_want_write(parfilp->f_path.mnt);
633 if (ops[i].am_error) 602 if (ops[i].am_error)
634 break; 603 break;
635 ops[i].am_error = xfs_attrmulti_attr_remove(inode, 604 ops[i].am_error = xfs_attrmulti_attr_remove(
636 attr_name, ops[i].am_flags); 605 dentry->d_inode, attr_name,
606 ops[i].am_flags);
637 mnt_drop_write(parfilp->f_path.mnt); 607 mnt_drop_write(parfilp->f_path.mnt);
638 break; 608 break;
639 default: 609 default:
@@ -647,9 +617,8 @@ xfs_attrmulti_by_handle(
647 kfree(attr_name); 617 kfree(attr_name);
648 out_kfree_ops: 618 out_kfree_ops:
649 kfree(ops); 619 kfree(ops);
650 out_vn_rele: 620 out_dput:
651 iput(inode); 621 dput(dentry);
652 out:
653 return -error; 622 return -error;
654} 623}
655 624
@@ -1440,23 +1409,23 @@ xfs_file_ioctl(
1440 1409
1441 if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) 1410 if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
1442 return -XFS_ERROR(EFAULT); 1411 return -XFS_ERROR(EFAULT);
1443 return xfs_open_by_handle(mp, &hreq, filp, inode); 1412 return xfs_open_by_handle(filp, &hreq);
1444 } 1413 }
1445 case XFS_IOC_FSSETDM_BY_HANDLE: 1414 case XFS_IOC_FSSETDM_BY_HANDLE:
1446 return xfs_fssetdm_by_handle(mp, arg, inode); 1415 return xfs_fssetdm_by_handle(filp, arg);
1447 1416
1448 case XFS_IOC_READLINK_BY_HANDLE: { 1417 case XFS_IOC_READLINK_BY_HANDLE: {
1449 xfs_fsop_handlereq_t hreq; 1418 xfs_fsop_handlereq_t hreq;
1450 1419
1451 if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) 1420 if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
1452 return -XFS_ERROR(EFAULT); 1421 return -XFS_ERROR(EFAULT);
1453 return xfs_readlink_by_handle(mp, &hreq, inode); 1422 return xfs_readlink_by_handle(filp, &hreq);
1454 } 1423 }
1455 case XFS_IOC_ATTRLIST_BY_HANDLE: 1424 case XFS_IOC_ATTRLIST_BY_HANDLE:
1456 return xfs_attrlist_by_handle(mp, arg, inode); 1425 return xfs_attrlist_by_handle(filp, arg);
1457 1426
1458 case XFS_IOC_ATTRMULTI_BY_HANDLE: 1427 case XFS_IOC_ATTRMULTI_BY_HANDLE:
1459 return xfs_attrmulti_by_handle(mp, arg, filp, inode); 1428 return xfs_attrmulti_by_handle(filp, arg);
1460 1429
1461 case XFS_IOC_SWAPEXT: { 1430 case XFS_IOC_SWAPEXT: {
1462 struct xfs_swapext sxp; 1431 struct xfs_swapext sxp;
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.h b/fs/xfs/linux-2.6/xfs_ioctl.h
index 8c16bf2d7e03..7bd7c6afc1eb 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.h
+++ b/fs/xfs/linux-2.6/xfs_ioctl.h
@@ -34,16 +34,13 @@ xfs_find_handle(
34 34
35extern int 35extern int
36xfs_open_by_handle( 36xfs_open_by_handle(
37 xfs_mount_t *mp,
38 xfs_fsop_handlereq_t *hreq,
39 struct file *parfilp, 37 struct file *parfilp,
40 struct inode *parinode); 38 xfs_fsop_handlereq_t *hreq);
41 39
42extern int 40extern int
43xfs_readlink_by_handle( 41xfs_readlink_by_handle(
44 xfs_mount_t *mp, 42 struct file *parfilp,
45 xfs_fsop_handlereq_t *hreq, 43 xfs_fsop_handlereq_t *hreq);
46 struct inode *parinode);
47 44
48extern int 45extern int
49xfs_attrmulti_attr_get( 46xfs_attrmulti_attr_get(
@@ -67,6 +64,12 @@ xfs_attrmulti_attr_remove(
67 char *name, 64 char *name,
68 __uint32_t flags); 65 __uint32_t flags);
69 66
67extern struct dentry *
68xfs_handle_to_dentry(
69 struct file *parfilp,
70 void __user *uhandle,
71 u32 hlen);
72
70extern long 73extern long
71xfs_file_ioctl( 74xfs_file_ioctl(
72 struct file *filp, 75 struct file *filp,
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
index 50903ad3182e..c70c4e3db790 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -17,6 +17,7 @@
17 */ 17 */
18#include <linux/compat.h> 18#include <linux/compat.h>
19#include <linux/ioctl.h> 19#include <linux/ioctl.h>
20#include <linux/mount.h>
20#include <asm/uaccess.h> 21#include <asm/uaccess.h>
21#include "xfs.h" 22#include "xfs.h"
22#include "xfs_fs.h" 23#include "xfs_fs.h"
@@ -340,96 +341,24 @@ xfs_compat_handlereq_copyin(
340 return 0; 341 return 0;
341} 342}
342 343
343/* 344STATIC struct dentry *
344 * Convert userspace handle data into inode. 345xfs_compat_handlereq_to_dentry(
345 * 346 struct file *parfilp,
346 * We use the fact that all the fsop_handlereq ioctl calls have a data 347 compat_xfs_fsop_handlereq_t *hreq)
347 * structure argument whose first component is always a xfs_fsop_handlereq_t,
348 * so we can pass that sub structure into this handy, shared routine.
349 *
350 * If no error, caller must always iput the returned inode.
351 */
352STATIC int
353xfs_vget_fsop_handlereq_compat(
354 xfs_mount_t *mp,
355 struct inode *parinode, /* parent inode pointer */
356 compat_xfs_fsop_handlereq_t *hreq,
357 struct inode **inode)
358{ 348{
359 void __user *hanp; 349 return xfs_handle_to_dentry(parfilp,
360 size_t hlen; 350 compat_ptr(hreq->ihandle), hreq->ihandlen);
361 xfs_fid_t *xfid;
362 xfs_handle_t *handlep;
363 xfs_handle_t handle;
364 xfs_inode_t *ip;
365 xfs_ino_t ino;
366 __u32 igen;
367 int error;
368
369 /*
370 * Only allow handle opens under a directory.
371 */
372 if (!S_ISDIR(parinode->i_mode))
373 return XFS_ERROR(ENOTDIR);
374
375 hanp = compat_ptr(hreq->ihandle);
376 hlen = hreq->ihandlen;
377 handlep = &handle;
378
379 if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep))
380 return XFS_ERROR(EINVAL);
381 if (copy_from_user(handlep, hanp, hlen))
382 return XFS_ERROR(EFAULT);
383 if (hlen < sizeof(*handlep))
384 memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen);
385 if (hlen > sizeof(handlep->ha_fsid)) {
386 if (handlep->ha_fid.fid_len !=
387 (hlen - sizeof(handlep->ha_fsid) -
388 sizeof(handlep->ha_fid.fid_len)) ||
389 handlep->ha_fid.fid_pad)
390 return XFS_ERROR(EINVAL);
391 }
392
393 /*
394 * Crack the handle, obtain the inode # & generation #
395 */
396 xfid = (struct xfs_fid *)&handlep->ha_fid;
397 if (xfid->fid_len == sizeof(*xfid) - sizeof(xfid->fid_len)) {
398 ino = xfid->fid_ino;
399 igen = xfid->fid_gen;
400 } else {
401 return XFS_ERROR(EINVAL);
402 }
403
404 /*
405 * Get the XFS inode, building a Linux inode to go with it.
406 */
407 error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);
408 if (error)
409 return error;
410 if (ip == NULL)
411 return XFS_ERROR(EIO);
412 if (ip->i_d.di_gen != igen) {
413 xfs_iput_new(ip, XFS_ILOCK_SHARED);
414 return XFS_ERROR(ENOENT);
415 }
416
417 xfs_iunlock(ip, XFS_ILOCK_SHARED);
418
419 *inode = VFS_I(ip);
420 return 0;
421} 351}
422 352
423STATIC int 353STATIC int
424xfs_compat_attrlist_by_handle( 354xfs_compat_attrlist_by_handle(
425 xfs_mount_t *mp, 355 struct file *parfilp,
426 void __user *arg, 356 void __user *arg)
427 struct inode *parinode)
428{ 357{
429 int error; 358 int error;
430 attrlist_cursor_kern_t *cursor; 359 attrlist_cursor_kern_t *cursor;
431 compat_xfs_fsop_attrlist_handlereq_t al_hreq; 360 compat_xfs_fsop_attrlist_handlereq_t al_hreq;
432 struct inode *inode; 361 struct dentry *dentry;
433 char *kbuf; 362 char *kbuf;
434 363
435 if (!capable(CAP_SYS_ADMIN)) 364 if (!capable(CAP_SYS_ADMIN))
@@ -446,17 +375,17 @@ xfs_compat_attrlist_by_handle(
446 if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE)) 375 if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE))
447 return -XFS_ERROR(EINVAL); 376 return -XFS_ERROR(EINVAL);
448 377
449 error = xfs_vget_fsop_handlereq_compat(mp, parinode, &al_hreq.hreq, 378 dentry = xfs_compat_handlereq_to_dentry(parfilp, &al_hreq.hreq);
450 &inode); 379 if (IS_ERR(dentry))
451 if (error) 380 return PTR_ERR(dentry);
452 goto out;
453 381
382 error = -ENOMEM;
454 kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL); 383 kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL);
455 if (!kbuf) 384 if (!kbuf)
456 goto out_vn_rele; 385 goto out_dput;
457 386
458 cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; 387 cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
459 error = xfs_attr_list(XFS_I(inode), kbuf, al_hreq.buflen, 388 error = -xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen,
460 al_hreq.flags, cursor); 389 al_hreq.flags, cursor);
461 if (error) 390 if (error)
462 goto out_kfree; 391 goto out_kfree;
@@ -466,22 +395,20 @@ xfs_compat_attrlist_by_handle(
466 395
467 out_kfree: 396 out_kfree:
468 kfree(kbuf); 397 kfree(kbuf);
469 out_vn_rele: 398 out_dput:
470 iput(inode); 399 dput(dentry);
471 out: 400 return error;
472 return -error;
473} 401}
474 402
475STATIC int 403STATIC int
476xfs_compat_attrmulti_by_handle( 404xfs_compat_attrmulti_by_handle(
477 xfs_mount_t *mp, 405 struct file *parfilp,
478 void __user *arg, 406 void __user *arg)
479 struct inode *parinode)
480{ 407{
481 int error; 408 int error;
482 compat_xfs_attr_multiop_t *ops; 409 compat_xfs_attr_multiop_t *ops;
483 compat_xfs_fsop_attrmulti_handlereq_t am_hreq; 410 compat_xfs_fsop_attrmulti_handlereq_t am_hreq;
484 struct inode *inode; 411 struct dentry *dentry;
485 unsigned int i, size; 412 unsigned int i, size;
486 char *attr_name; 413 char *attr_name;
487 414
@@ -491,20 +418,19 @@ xfs_compat_attrmulti_by_handle(
491 sizeof(compat_xfs_fsop_attrmulti_handlereq_t))) 418 sizeof(compat_xfs_fsop_attrmulti_handlereq_t)))
492 return -XFS_ERROR(EFAULT); 419 return -XFS_ERROR(EFAULT);
493 420
494 error = xfs_vget_fsop_handlereq_compat(mp, parinode, &am_hreq.hreq, 421 dentry = xfs_compat_handlereq_to_dentry(parfilp, &am_hreq.hreq);
495 &inode); 422 if (IS_ERR(dentry))
496 if (error) 423 return PTR_ERR(dentry);
497 goto out;
498 424
499 error = E2BIG; 425 error = E2BIG;
500 size = am_hreq.opcount * sizeof(compat_xfs_attr_multiop_t); 426 size = am_hreq.opcount * sizeof(compat_xfs_attr_multiop_t);
501 if (!size || size > 16 * PAGE_SIZE) 427 if (!size || size > 16 * PAGE_SIZE)
502 goto out_vn_rele; 428 goto out_dput;
503 429
504 error = ENOMEM; 430 error = ENOMEM;
505 ops = kmalloc(size, GFP_KERNEL); 431 ops = kmalloc(size, GFP_KERNEL);
506 if (!ops) 432 if (!ops)
507 goto out_vn_rele; 433 goto out_dput;
508 434
509 error = EFAULT; 435 error = EFAULT;
510 if (copy_from_user(ops, compat_ptr(am_hreq.ops), size)) 436 if (copy_from_user(ops, compat_ptr(am_hreq.ops), size))
@@ -527,20 +453,29 @@ xfs_compat_attrmulti_by_handle(
527 453
528 switch (ops[i].am_opcode) { 454 switch (ops[i].am_opcode) {
529 case ATTR_OP_GET: 455 case ATTR_OP_GET:
530 ops[i].am_error = xfs_attrmulti_attr_get(inode, 456 ops[i].am_error = xfs_attrmulti_attr_get(
531 attr_name, 457 dentry->d_inode, attr_name,
532 compat_ptr(ops[i].am_attrvalue), 458 compat_ptr(ops[i].am_attrvalue),
533 &ops[i].am_length, ops[i].am_flags); 459 &ops[i].am_length, ops[i].am_flags);
534 break; 460 break;
535 case ATTR_OP_SET: 461 case ATTR_OP_SET:
536 ops[i].am_error = xfs_attrmulti_attr_set(inode, 462 ops[i].am_error = mnt_want_write(parfilp->f_path.mnt);
537 attr_name, 463 if (ops[i].am_error)
464 break;
465 ops[i].am_error = xfs_attrmulti_attr_set(
466 dentry->d_inode, attr_name,
538 compat_ptr(ops[i].am_attrvalue), 467 compat_ptr(ops[i].am_attrvalue),
539 ops[i].am_length, ops[i].am_flags); 468 ops[i].am_length, ops[i].am_flags);
469 mnt_drop_write(parfilp->f_path.mnt);
540 break; 470 break;
541 case ATTR_OP_REMOVE: 471 case ATTR_OP_REMOVE:
542 ops[i].am_error = xfs_attrmulti_attr_remove(inode, 472 ops[i].am_error = mnt_want_write(parfilp->f_path.mnt);
543 attr_name, ops[i].am_flags); 473 if (ops[i].am_error)
474 break;
475 ops[i].am_error = xfs_attrmulti_attr_remove(
476 dentry->d_inode, attr_name,
477 ops[i].am_flags);
478 mnt_drop_write(parfilp->f_path.mnt);
544 break; 479 break;
545 default: 480 default:
546 ops[i].am_error = EINVAL; 481 ops[i].am_error = EINVAL;
@@ -553,22 +488,20 @@ xfs_compat_attrmulti_by_handle(
553 kfree(attr_name); 488 kfree(attr_name);
554 out_kfree_ops: 489 out_kfree_ops:
555 kfree(ops); 490 kfree(ops);
556 out_vn_rele: 491 out_dput:
557 iput(inode); 492 dput(dentry);
558 out:
559 return -error; 493 return -error;
560} 494}
561 495
562STATIC int 496STATIC int
563xfs_compat_fssetdm_by_handle( 497xfs_compat_fssetdm_by_handle(
564 xfs_mount_t *mp, 498 struct file *parfilp,
565 void __user *arg, 499 void __user *arg)
566 struct inode *parinode)
567{ 500{
568 int error; 501 int error;
569 struct fsdmidata fsd; 502 struct fsdmidata fsd;
570 compat_xfs_fsop_setdm_handlereq_t dmhreq; 503 compat_xfs_fsop_setdm_handlereq_t dmhreq;
571 struct inode *inode; 504 struct dentry *dentry;
572 505
573 if (!capable(CAP_MKNOD)) 506 if (!capable(CAP_MKNOD))
574 return -XFS_ERROR(EPERM); 507 return -XFS_ERROR(EPERM);
@@ -576,12 +509,11 @@ xfs_compat_fssetdm_by_handle(
576 sizeof(compat_xfs_fsop_setdm_handlereq_t))) 509 sizeof(compat_xfs_fsop_setdm_handlereq_t)))
577 return -XFS_ERROR(EFAULT); 510 return -XFS_ERROR(EFAULT);
578 511
579 error = xfs_vget_fsop_handlereq_compat(mp, parinode, &dmhreq.hreq, 512 dentry = xfs_compat_handlereq_to_dentry(parfilp, &dmhreq.hreq);
580 &inode); 513 if (IS_ERR(dentry))
581 if (error) 514 return PTR_ERR(dentry);
582 return -error;
583 515
584 if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { 516 if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode)) {
585 error = -XFS_ERROR(EPERM); 517 error = -XFS_ERROR(EPERM);
586 goto out; 518 goto out;
587 } 519 }
@@ -591,11 +523,11 @@ xfs_compat_fssetdm_by_handle(
591 goto out; 523 goto out;
592 } 524 }
593 525
594 error = -xfs_set_dmattrs(XFS_I(inode), fsd.fsd_dmevmask, 526 error = -xfs_set_dmattrs(XFS_I(dentry->d_inode), fsd.fsd_dmevmask,
595 fsd.fsd_dmstate); 527 fsd.fsd_dmstate);
596 528
597out: 529out:
598 iput(inode); 530 dput(dentry);
599 return error; 531 return error;
600} 532}
601 533
@@ -722,21 +654,21 @@ xfs_file_compat_ioctl(
722 654
723 if (xfs_compat_handlereq_copyin(&hreq, arg)) 655 if (xfs_compat_handlereq_copyin(&hreq, arg))
724 return -XFS_ERROR(EFAULT); 656 return -XFS_ERROR(EFAULT);
725 return xfs_open_by_handle(mp, &hreq, filp, inode); 657 return xfs_open_by_handle(filp, &hreq);
726 } 658 }
727 case XFS_IOC_READLINK_BY_HANDLE_32: { 659 case XFS_IOC_READLINK_BY_HANDLE_32: {
728 struct xfs_fsop_handlereq hreq; 660 struct xfs_fsop_handlereq hreq;
729 661
730 if (xfs_compat_handlereq_copyin(&hreq, arg)) 662 if (xfs_compat_handlereq_copyin(&hreq, arg))
731 return -XFS_ERROR(EFAULT); 663 return -XFS_ERROR(EFAULT);
732 return xfs_readlink_by_handle(mp, &hreq, inode); 664 return xfs_readlink_by_handle(filp, &hreq);
733 } 665 }
734 case XFS_IOC_ATTRLIST_BY_HANDLE_32: 666 case XFS_IOC_ATTRLIST_BY_HANDLE_32:
735 return xfs_compat_attrlist_by_handle(mp, arg, inode); 667 return xfs_compat_attrlist_by_handle(filp, arg);
736 case XFS_IOC_ATTRMULTI_BY_HANDLE_32: 668 case XFS_IOC_ATTRMULTI_BY_HANDLE_32:
737 return xfs_compat_attrmulti_by_handle(mp, arg, inode); 669 return xfs_compat_attrmulti_by_handle(filp, arg);
738 case XFS_IOC_FSSETDM_BY_HANDLE_32: 670 case XFS_IOC_FSSETDM_BY_HANDLE_32:
739 return xfs_compat_fssetdm_by_handle(mp, arg, inode); 671 return xfs_compat_fssetdm_by_handle(filp, arg);
740 default: 672 default:
741 return -XFS_ERROR(ENOIOCTLCMD); 673 return -XFS_ERROR(ENOIOCTLCMD);
742 } 674 }
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 95a971080368..c71e226da7f5 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -1197,6 +1197,7 @@ xfs_fs_remount(
1197 struct xfs_mount *mp = XFS_M(sb); 1197 struct xfs_mount *mp = XFS_M(sb);
1198 substring_t args[MAX_OPT_ARGS]; 1198 substring_t args[MAX_OPT_ARGS];
1199 char *p; 1199 char *p;
1200 int error;
1200 1201
1201 while ((p = strsep(&options, ",")) != NULL) { 1202 while ((p = strsep(&options, ",")) != NULL) {
1202 int token; 1203 int token;
@@ -1247,11 +1248,25 @@ xfs_fs_remount(
1247 } 1248 }
1248 } 1249 }
1249 1250
1250 /* rw/ro -> rw */ 1251 /* ro -> rw */
1251 if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & MS_RDONLY)) { 1252 if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & MS_RDONLY)) {
1252 mp->m_flags &= ~XFS_MOUNT_RDONLY; 1253 mp->m_flags &= ~XFS_MOUNT_RDONLY;
1253 if (mp->m_flags & XFS_MOUNT_BARRIER) 1254 if (mp->m_flags & XFS_MOUNT_BARRIER)
1254 xfs_mountfs_check_barriers(mp); 1255 xfs_mountfs_check_barriers(mp);
1256
1257 /*
1258 * If this is the first remount to writeable state we
1259 * might have some superblock changes to update.
1260 */
1261 if (mp->m_update_flags) {
1262 error = xfs_mount_log_sb(mp, mp->m_update_flags);
1263 if (error) {
1264 cmn_err(CE_WARN,
1265 "XFS: failed to write sb changes");
1266 return error;
1267 }
1268 mp->m_update_flags = 0;
1269 }
1255 } 1270 }
1256 1271
1257 /* rw -> ro */ 1272 /* rw -> ro */
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c
index d68b4e1cf1d1..6543c0b29753 100644
--- a/fs/xfs/quota/xfs_dquot.c
+++ b/fs/xfs/quota/xfs_dquot.c
@@ -73,6 +73,8 @@ int xfs_dqreq_num;
73int xfs_dqerror_mod = 33; 73int xfs_dqerror_mod = 33;
74#endif 74#endif
75 75
76static struct lock_class_key xfs_dquot_other_class;
77
76/* 78/*
77 * Allocate and initialize a dquot. We don't always allocate fresh memory; 79 * Allocate and initialize a dquot. We don't always allocate fresh memory;
78 * we try to reclaim a free dquot if the number of incore dquots are above 80 * we try to reclaim a free dquot if the number of incore dquots are above
@@ -139,7 +141,15 @@ xfs_qm_dqinit(
139 ASSERT(dqp->q_trace); 141 ASSERT(dqp->q_trace);
140 xfs_dqtrace_entry(dqp, "DQRECLAIMED_INIT"); 142 xfs_dqtrace_entry(dqp, "DQRECLAIMED_INIT");
141#endif 143#endif
142 } 144 }
145
146 /*
147 * In either case we need to make sure group quotas have a different
148 * lock class than user quotas, to make sure lockdep knows we can
149 * locks of one of each at the same time.
150 */
151 if (!(type & XFS_DQ_USER))
152 lockdep_set_class(&dqp->q_qlock, &xfs_dquot_other_class);
143 153
144 /* 154 /*
145 * log item gets initialized later 155 * log item gets initialized later
@@ -1383,6 +1393,12 @@ xfs_dqunlock_nonotify(
1383 mutex_unlock(&(dqp->q_qlock)); 1393 mutex_unlock(&(dqp->q_qlock));
1384} 1394}
1385 1395
1396/*
1397 * Lock two xfs_dquot structures.
1398 *
1399 * To avoid deadlocks we always lock the quota structure with
1400 * the lowerd id first.
1401 */
1386void 1402void
1387xfs_dqlock2( 1403xfs_dqlock2(
1388 xfs_dquot_t *d1, 1404 xfs_dquot_t *d1,
@@ -1392,18 +1408,16 @@ xfs_dqlock2(
1392 ASSERT(d1 != d2); 1408 ASSERT(d1 != d2);
1393 if (be32_to_cpu(d1->q_core.d_id) > 1409 if (be32_to_cpu(d1->q_core.d_id) >
1394 be32_to_cpu(d2->q_core.d_id)) { 1410 be32_to_cpu(d2->q_core.d_id)) {
1395 xfs_dqlock(d2); 1411 mutex_lock(&d2->q_qlock);
1396 xfs_dqlock(d1); 1412 mutex_lock_nested(&d1->q_qlock, XFS_QLOCK_NESTED);
1397 } else { 1413 } else {
1398 xfs_dqlock(d1); 1414 mutex_lock(&d1->q_qlock);
1399 xfs_dqlock(d2); 1415 mutex_lock_nested(&d2->q_qlock, XFS_QLOCK_NESTED);
1400 }
1401 } else {
1402 if (d1) {
1403 xfs_dqlock(d1);
1404 } else if (d2) {
1405 xfs_dqlock(d2);
1406 } 1416 }
1417 } else if (d1) {
1418 mutex_lock(&d1->q_qlock);
1419 } else if (d2) {
1420 mutex_lock(&d2->q_qlock);
1407 } 1421 }
1408} 1422}
1409 1423
diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/quota/xfs_dquot.h
index 7e455337e2ba..d443e93b4331 100644
--- a/fs/xfs/quota/xfs_dquot.h
+++ b/fs/xfs/quota/xfs_dquot.h
@@ -97,6 +97,16 @@ typedef struct xfs_dquot {
97#define dq_hashlist q_lists.dqm_hashlist 97#define dq_hashlist q_lists.dqm_hashlist
98#define dq_flags q_lists.dqm_flags 98#define dq_flags q_lists.dqm_flags
99 99
100/*
101 * Lock hierachy for q_qlock:
102 * XFS_QLOCK_NORMAL is the implicit default,
103 * XFS_QLOCK_NESTED is the dquot with the higher id in xfs_dqlock2
104 */
105enum {
106 XFS_QLOCK_NORMAL = 0,
107 XFS_QLOCK_NESTED,
108};
109
100#define XFS_DQHOLD(dqp) ((dqp)->q_nrefs++) 110#define XFS_DQHOLD(dqp) ((dqp)->q_nrefs++)
101 111
102#ifdef DEBUG 112#ifdef DEBUG
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 6b13960cf318..7a2beb64314f 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -1070,6 +1070,13 @@ xfs_qm_sync(
1070 return 0; 1070 return 0;
1071} 1071}
1072 1072
1073/*
1074 * The hash chains and the mplist use the same xfs_dqhash structure as
1075 * their list head, but we can take the mplist qh_lock and one of the
1076 * hash qh_locks at the same time without any problem as they aren't
1077 * related.
1078 */
1079static struct lock_class_key xfs_quota_mplist_class;
1073 1080
1074/* 1081/*
1075 * This initializes all the quota information that's kept in the 1082 * This initializes all the quota information that's kept in the
@@ -1105,6 +1112,8 @@ xfs_qm_init_quotainfo(
1105 } 1112 }
1106 1113
1107 xfs_qm_list_init(&qinf->qi_dqlist, "mpdqlist", 0); 1114 xfs_qm_list_init(&qinf->qi_dqlist, "mpdqlist", 0);
1115 lockdep_set_class(&qinf->qi_dqlist.qh_lock, &xfs_quota_mplist_class);
1116
1108 qinf->qi_dqreclaims = 0; 1117 qinf->qi_dqreclaims = 0;
1109 1118
1110 /* mutex used to serialize quotaoffs */ 1119 /* mutex used to serialize quotaoffs */
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index be2ca4d67b53..e7ae08d1df48 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -424,6 +424,19 @@ xfs_iformat(
424 case XFS_DINODE_FMT_LOCAL: 424 case XFS_DINODE_FMT_LOCAL:
425 atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); 425 atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
426 size = be16_to_cpu(atp->hdr.totsize); 426 size = be16_to_cpu(atp->hdr.totsize);
427
428 if (unlikely(size < sizeof(struct xfs_attr_sf_hdr))) {
429 xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
430 "corrupt inode %Lu "
431 "(bad attr fork size %Ld).",
432 (unsigned long long) ip->i_ino,
433 (long long) size);
434 XFS_CORRUPTION_ERROR("xfs_iformat(8)",
435 XFS_ERRLEVEL_LOW,
436 ip->i_mount, dip);
437 return XFS_ERROR(EFSCORRUPTED);
438 }
439
427 error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size); 440 error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size);
428 break; 441 break;
429 case XFS_DINODE_FMT_EXTENTS: 442 case XFS_DINODE_FMT_EXTENTS:
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 3c97c6463a4e..35300250e86d 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -45,7 +45,6 @@
45#include "xfs_fsops.h" 45#include "xfs_fsops.h"
46#include "xfs_utils.h" 46#include "xfs_utils.h"
47 47
48STATIC int xfs_mount_log_sb(xfs_mount_t *, __int64_t);
49STATIC int xfs_uuid_mount(xfs_mount_t *); 48STATIC int xfs_uuid_mount(xfs_mount_t *);
50STATIC void xfs_unmountfs_wait(xfs_mount_t *); 49STATIC void xfs_unmountfs_wait(xfs_mount_t *);
51 50
@@ -682,7 +681,7 @@ xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount)
682 * Update alignment values based on mount options and sb values 681 * Update alignment values based on mount options and sb values
683 */ 682 */
684STATIC int 683STATIC int
685xfs_update_alignment(xfs_mount_t *mp, __uint64_t *update_flags) 684xfs_update_alignment(xfs_mount_t *mp)
686{ 685{
687 xfs_sb_t *sbp = &(mp->m_sb); 686 xfs_sb_t *sbp = &(mp->m_sb);
688 687
@@ -736,11 +735,11 @@ xfs_update_alignment(xfs_mount_t *mp, __uint64_t *update_flags)
736 if (xfs_sb_version_hasdalign(sbp)) { 735 if (xfs_sb_version_hasdalign(sbp)) {
737 if (sbp->sb_unit != mp->m_dalign) { 736 if (sbp->sb_unit != mp->m_dalign) {
738 sbp->sb_unit = mp->m_dalign; 737 sbp->sb_unit = mp->m_dalign;
739 *update_flags |= XFS_SB_UNIT; 738 mp->m_update_flags |= XFS_SB_UNIT;
740 } 739 }
741 if (sbp->sb_width != mp->m_swidth) { 740 if (sbp->sb_width != mp->m_swidth) {
742 sbp->sb_width = mp->m_swidth; 741 sbp->sb_width = mp->m_swidth;
743 *update_flags |= XFS_SB_WIDTH; 742 mp->m_update_flags |= XFS_SB_WIDTH;
744 } 743 }
745 } 744 }
746 } else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN && 745 } else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN &&
@@ -905,7 +904,6 @@ xfs_mountfs(
905 xfs_sb_t *sbp = &(mp->m_sb); 904 xfs_sb_t *sbp = &(mp->m_sb);
906 xfs_inode_t *rip; 905 xfs_inode_t *rip;
907 __uint64_t resblks; 906 __uint64_t resblks;
908 __int64_t update_flags = 0LL;
909 uint quotamount, quotaflags; 907 uint quotamount, quotaflags;
910 int uuid_mounted = 0; 908 int uuid_mounted = 0;
911 int error = 0; 909 int error = 0;
@@ -933,7 +931,7 @@ xfs_mountfs(
933 "XFS: correcting sb_features alignment problem"); 931 "XFS: correcting sb_features alignment problem");
934 sbp->sb_features2 |= sbp->sb_bad_features2; 932 sbp->sb_features2 |= sbp->sb_bad_features2;
935 sbp->sb_bad_features2 = sbp->sb_features2; 933 sbp->sb_bad_features2 = sbp->sb_features2;
936 update_flags |= XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2; 934 mp->m_update_flags |= XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2;
937 935
938 /* 936 /*
939 * Re-check for ATTR2 in case it was found in bad_features2 937 * Re-check for ATTR2 in case it was found in bad_features2
@@ -947,11 +945,11 @@ xfs_mountfs(
947 if (xfs_sb_version_hasattr2(&mp->m_sb) && 945 if (xfs_sb_version_hasattr2(&mp->m_sb) &&
948 (mp->m_flags & XFS_MOUNT_NOATTR2)) { 946 (mp->m_flags & XFS_MOUNT_NOATTR2)) {
949 xfs_sb_version_removeattr2(&mp->m_sb); 947 xfs_sb_version_removeattr2(&mp->m_sb);
950 update_flags |= XFS_SB_FEATURES2; 948 mp->m_update_flags |= XFS_SB_FEATURES2;
951 949
952 /* update sb_versionnum for the clearing of the morebits */ 950 /* update sb_versionnum for the clearing of the morebits */
953 if (!sbp->sb_features2) 951 if (!sbp->sb_features2)
954 update_flags |= XFS_SB_VERSIONNUM; 952 mp->m_update_flags |= XFS_SB_VERSIONNUM;
955 } 953 }
956 954
957 /* 955 /*
@@ -960,7 +958,7 @@ xfs_mountfs(
960 * allocator alignment is within an ag, therefore ag has 958 * allocator alignment is within an ag, therefore ag has
961 * to be aligned at stripe boundary. 959 * to be aligned at stripe boundary.
962 */ 960 */
963 error = xfs_update_alignment(mp, &update_flags); 961 error = xfs_update_alignment(mp);
964 if (error) 962 if (error)
965 goto error1; 963 goto error1;
966 964
@@ -1137,10 +1135,12 @@ xfs_mountfs(
1137 } 1135 }
1138 1136
1139 /* 1137 /*
1140 * If fs is not mounted readonly, then update the superblock changes. 1138 * If this is a read-only mount defer the superblock updates until
1139 * the next remount into writeable mode. Otherwise we would never
1140 * perform the update e.g. for the root filesystem.
1141 */ 1141 */
1142 if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) { 1142 if (mp->m_update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) {
1143 error = xfs_mount_log_sb(mp, update_flags); 1143 error = xfs_mount_log_sb(mp, mp->m_update_flags);
1144 if (error) { 1144 if (error) {
1145 cmn_err(CE_WARN, "XFS: failed to write sb changes"); 1145 cmn_err(CE_WARN, "XFS: failed to write sb changes");
1146 goto error4; 1146 goto error4;
@@ -1820,7 +1820,7 @@ xfs_uuid_mount(
1820 * be altered by the mount options, as well as any potential sb_features2 1820 * be altered by the mount options, as well as any potential sb_features2
1821 * fixup. Only the first superblock is updated. 1821 * fixup. Only the first superblock is updated.
1822 */ 1822 */
1823STATIC int 1823int
1824xfs_mount_log_sb( 1824xfs_mount_log_sb(
1825 xfs_mount_t *mp, 1825 xfs_mount_t *mp,
1826 __int64_t fields) 1826 __int64_t fields)
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 9bb41a9f765d..f5e9937f9bdb 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -327,6 +327,8 @@ typedef struct xfs_mount {
327 spinlock_t m_sync_lock; /* work item list lock */ 327 spinlock_t m_sync_lock; /* work item list lock */
328 int m_sync_seq; /* sync thread generation no. */ 328 int m_sync_seq; /* sync thread generation no. */
329 wait_queue_head_t m_wait_single_sync_task; 329 wait_queue_head_t m_wait_single_sync_task;
330 __int64_t m_update_flags; /* sb flags we need to update
331 on the next remount,rw */
330} xfs_mount_t; 332} xfs_mount_t;
331 333
332/* 334/*
@@ -512,6 +514,7 @@ extern int xfs_mod_incore_sb_unlocked(xfs_mount_t *, xfs_sb_field_t,
512 int64_t, int); 514 int64_t, int);
513extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *, 515extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
514 uint, int); 516 uint, int);
517extern int xfs_mount_log_sb(xfs_mount_t *, __int64_t);
515extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int); 518extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
516extern int xfs_readsb(xfs_mount_t *, int); 519extern int xfs_readsb(xfs_mount_t *, int);
517extern void xfs_freesb(xfs_mount_t *); 520extern void xfs_freesb(xfs_mount_t *);