[patch] Re: XFS, Quotas and Samba

Nathan Scott nathans at sgi.com
Sun Sep 9 02:56:05 GMT 2001


hi,

On Thu, Sep 06, 2001 at 04:34:41PM +0200, Jan Kara wrote:
>   Hello,
> 
>   Actually it depends whether the samba code was compiled with
> proper kernel headers. If so the Q_GETQUOTA is defined to be
> right value and so everything should work fine. Ok, to be more
> precise the utils probably won't compile in that case as struct dqblk
> is no more and mem_dqblk should be used instead... But anyway it shouldn't
> break silently.

Hmm ... I can't see any case where the new VFS quota code will
work (ie. Jan's patches/AC kernels/Redhat 7.1+) with the smbd
code, even if the kernel headers happened to correspond to the
running kernel.  As I understand it, the new code returns a u64
byte count in one field (curspace) where before there was a u32
block count (curblocks).  Is that correct?  If so, smbd is in a
bit of strife here cos it peeks at that field in particular...

I took a stab at implementing the fix for this problem and for
XFS quota - the XFS code should be correct, the VFS quota code
(v1/v2 stuff) should be too, but I'm less certain on that - see
attached patch.  The approach is basically to attempt the old
Linux quotactl for non-XFS filesystems - if that fails, try
the new version.  And for XFS filesystems, always use the XFS
quotactl command, which is always the right thing to do.

Bret - could you let me know if this helps you?

cheers.

> 
> > Just a quick followup - this is what I mentioned in my earlier
> > mail to you.  I think your new VFS quota code (as in Alan Cox's
> > series of 2.4 kernels, for the Samba folk) will have exactly the
> > same problem as XFS.  This "grep" would seem to confirm it - but
> > you'll know better than I here:
> > 
> > 11:31 nathans at troppo ~/cvs/quota-tools 73> grep GETQUOTA dqblk*h
> > dqblk_rpc.h:#define Q_RPC_GETQUOTA      0x0300  /* get limits and usage */
> > dqblk_v1.h:#define Q_V1_GETQUOTA        0x300
> > dqblk_v2.h:#define Q_V2_GETQUOTA        0x0D00  /* Get limits and usage */
> > dqblk_xfs.h:#define Q_XFS_GETQUOTA      Q_XGETQUOTA
> > 11:31 nathans at troppo ~/cvs/quota-tools 74> 
> > 
> > The samba code does a good old Q_GETQUOTA (ie. your V1 above).
> > 
> > cheers.
> > 
> > 
> > On Thu, Sep 06, 2001 at 10:59:52AM +1100, Nathan Scott wrote:
> > > hi,
> > > 
> > > On Wed, Sep 05, 2001 at 02:57:39PM +0100, Giddings, Bret wrote:
> > > > I am investigating whether I can replace my expensive Compaq Alphas file
> > > > servers with cheaper (and invariably faster given my budget) Intel based
> > > > ones. I have so far been pleased with the ease with which xfs has installed
> > > > and run on my hardware of choice. To make my life easier, I have picked up
> > > > the pre-built RedHat kernels with xfs support. Everything appears to be fine
> > > > except that when connecting to a share from Samba, the amount of free space
> > > > reported is the amount of free disk space left on the device rather than the
> > > > amount of free space in the users quota (this is on a disk mounted with
> > > > usrquota and a quota set for the users). The usual tools (edquota, setquota
> > > > work as expected).
> > > > 
> > > > I have downloaded the source rpm for samba and it appears that RedHat build
> > > > their smbd to support quotas. I have also checked whether
> > > > /usr/include/sys/quota.h is modified by installing your updated quota rpm
> > > > (quota-3.01pre8) and it isn't. So, is there another reason why quotas don't
> > > > appear to work with xfs/samba?
> > > 
> > > The samba code needs to be updated to support XFS quota under
> > > Linux.  There was someone on the list a little while ago who
> > > was looking to add in the samba support for XFS quota, but I
> > > don't know how far they got.
> > > 
> > > I know very little about samba unfortunately, but it should be
> > > quite simple to add this stuff for XFS - the disk_quotas()
> > > routine in samba-2.2.1a/source/smbd/quotas.c is all that needs
> > > to be changed, by the look of things.
> > > 
> > > For XFS filesystems on Linux this needs to:
> > > - have logic to handle getmntent's of type "xfs" separately;
> > > - issue a quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), ..., &xdq) where
> > >   xdq is of type "struct fs_disk_quota_t" from <linux/xqm.h>
> > > - set *bsize to 512 for XFS
> > > - refer to the code later in that same file for dealing with XFS
> > >   on IRIX - basically, do exactly the same thing and it should
> > >   just work.
> > > - to do it properly, the configure scripts will need to check
> > >   for linux/xqm.h (or might be simpler to keep a local copy? -
> > >   I dunno what sort of policy the samba folk have on this sort of
> > >   thing, but this header isn't going to change and probably isn't
> > >   going to appear in the libc headers for quite awhile...)
> > > 
> > > cheers.
> > > 
> > > -- 
> > > Nathan
> > 
> > -- 
> > Nathan
> --
> Jan Kara <jack at suse.cz>
> SuSE Labs

-- 
Nathan
-------------- next part --------------
diff -Naur samba-2.2.1a/source/smbd/quotas.c samba-2.2.1a+ns/source/smbd/quotas.c
--- samba-2.2.1a/source/smbd/quotas.c	Thu Jul  5 21:02:03 2001
+++ samba-2.2.1a+ns/source/smbd/quotas.c	Sun Sep  9 09:29:58 2001
@@ -44,13 +44,10 @@
 #ifdef LINUX
 
 #include <sys/types.h>
-#include <asm/types.h>
+#include <linux/types.h>
 #include <sys/quota.h>
-
 #include <mntent.h>
-#include <linux/unistd.h>
-
-_syscall4(int, quotactl, int, cmd, const char *, special, int, id, caddr_t, addr);
+#include "quotas.h"
 
 /****************************************************************************
 try to get the disk space from disk quotas (LINUX version)
@@ -59,18 +56,20 @@
 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
 {
   int r;
-  struct dqblk D;
+  v1_kern_dqblk_t D1;
+  v2_kern_dqblk_t D2;
+  fs_disk_quota_t DX;
   SMB_STRUCT_STAT S;
   FILE *fp;
   struct mntent *mnt;
   SMB_DEV_T devno;
   int found;
   uid_t euser_id;
+  static int version = 1;	/* VFS quota version */
 
   euser_id = geteuid();
-  
+
   /* find the block device file */
-  
   if ( sys_stat(path, &S) == -1 ) {
     return(False) ;
   }
@@ -91,47 +90,109 @@
   endmntent(fp) ;
   
   if (!found) {
-      return(False);
-    }
+    return(False);
+  }
 
   save_re_uid();
   set_effective_uid(0);  
-  r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D);
+  if (strcmp(mnt->mnt_type, "xfs") == 0)
+    r = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&DX);
+  else {
+    if (version == 1) {
+      r = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D1);
+      if (r == EINVAL)
+        version = 2;
+    }
+    if (version == 2)
+      r = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D2);
+  }
   restore_re_uid();
 
-  /* Use softlimit to determine disk space, except when it has been exceeded */
-  *bsize = 1024;
   if (r)
-    {
-      if (errno == EDQUOT) 
-       {
-         *dfree =0;
-         *dsize =D.dqb_curblocks;
-         return (True);
-    }
-      else return(False);
+      return(False);
+
+  if (version == 1)
+  {
+    *bsize = 1024;
+    /* Use softlimit to determine disk space, except when its been exceeded */
+    if (
+        (D1.dqb_bsoftlimit && D1.dqb_curblocks>=D1.dqb_bsoftlimit) ||
+        (D1.dqb_bhardlimit && D1.dqb_curblocks>=D1.dqb_bhardlimit) ||
+        (D1.dqb_isoftlimit && D1.dqb_curinodes>=D1.dqb_isoftlimit) ||
+        (D1.dqb_ihardlimit && D1.dqb_curinodes>=D1.dqb_ihardlimit)
+       )
+      {
+        *dfree = 0;
+        *dsize = D1.dqb_curblocks;
+      }
+    else if (D1.dqb_bsoftlimit==0 && D1.dqb_bhardlimit==0)
+      {
+        return(False);
+      }
+    else
+      {
+        if (D1.dqb_bsoftlimit == 0)
+          D1.dqb_bsoftlimit = D1.dqb_bhardlimit;
+        *dfree = D1.dqb_bsoftlimit - D1.dqb_curblocks;
+        *dsize = D1.dqb_bsoftlimit;
+      }
+  }
+  else if (version == 2)
+  {
+    *bsize = 1024;
+    D2.dqb_curspace >>= 10;	/* bytes to Kbytes */
+    /* Use softlimit to determine disk space, except when its been exceeded */
+    if (
+        (D2.dqb_bsoftlimit && D2.dqb_curspace >=D2.dqb_bsoftlimit) ||
+        (D2.dqb_bhardlimit && D2.dqb_curspace >=D2.dqb_bhardlimit) ||
+        (D2.dqb_isoftlimit && D2.dqb_curinodes>=D2.dqb_isoftlimit) ||
+        (D2.dqb_ihardlimit && D2.dqb_curinodes>=D2.dqb_ihardlimit)
+       )
+      {
+        *dfree = 0;
+        *dsize = D2.dqb_curspace;
+      }
+    else if (D2.dqb_bsoftlimit==0 && D2.dqb_bhardlimit==0)
+      {
+        return(False);
+      }
+    else
+      {
+        if (D2.dqb_bsoftlimit == 0)
+          D2.dqb_bsoftlimit = D2.dqb_bhardlimit;
+        *dfree = D2.dqb_bsoftlimit - D2.dqb_curspace;
+        *dsize = D2.dqb_bsoftlimit;
+      }
   }
-  /* Use softlimit to determine disk space, except when it has been exceeded */
-  if (
-      (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
-      (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
-      (D.dqb_isoftlimit && D.dqb_curinodes>=D.dqb_isoftlimit) ||
-      (D.dqb_ihardlimit && D.dqb_curinodes>=D.dqb_ihardlimit)
-     )
+  else if (strcmp(mnt->mnt_type, "xfs") == 0)
+  {
+    *bsize = 512;
+    /* Use softlimit to determine disk space, except when its been exceeded */
+    if (
+        (DX.d_blk_softlimit && DX.d_bcount>=DX.d_blk_softlimit) ||
+        (DX.d_blk_hardlimit && DX.d_bcount>=DX.d_blk_hardlimit) ||
+        (DX.d_ino_softlimit && DX.d_icount>=DX.d_ino_softlimit) ||
+        (DX.d_ino_hardlimit && DX.d_icount>=DX.d_ino_hardlimit)
+       )
     {
       *dfree = 0;
-      *dsize = D.dqb_curblocks;
+      *dsize = DX.d_bcount;
     }
-  else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
+    else if (DX.d_blk_softlimit==0 && DX.d_blk_hardlimit==0)
     {
       return(False);
     }
-  else {
-    if (D.dqb_bsoftlimit == 0)
-      D.dqb_bsoftlimit = D.dqb_bhardlimit;
-    *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
-    *dsize = D.dqb_bsoftlimit;
+    else 
+    {
+      *dfree = (DX.d_blk_softlimit - DX.d_bcount);
+      *dsize = DX.d_blk_softlimit;
+    }
   }
+  else
+  {
+    return(False);
+  }
+
   return (True);
 }
 
diff -Naur samba-2.2.1a/source/smbd/quotas.h samba-2.2.1a+ns/source/smbd/quotas.h
--- samba-2.2.1a/source/smbd/quotas.h	Wed Dec 31 19:00:00 1969
+++ samba-2.2.1a+ns/source/smbd/quotas.h	Sun Sep  9 09:29:58 2001
@@ -0,0 +1,58 @@
+#ifdef LINUX
+
+#define Q_V1_GETQUOTA	0x0300		/* VFS quota, version 1 */
+#define Q_V2_GETQUOTA	0x0D00		/* VFS quota, version 2 */
+#define Q_XGETQUOTA	(('X'<<8)+0x3)	/* XFS quota */
+
+/* struct for Q_V1_GETQUOTA */
+typedef struct v1_kern_dqblk {
+	u_int32_t dqb_bhardlimit;	/* absolute limit on disk blks alloc */
+	u_int32_t dqb_bsoftlimit;	/* preferred limit on disk blks */
+	u_int32_t dqb_curblocks;	/* current block count */
+	u_int32_t dqb_ihardlimit;	/* maximum # allocated inodes */
+	u_int32_t dqb_isoftlimit;	/* preferred inode limit */
+	u_int32_t dqb_curinodes;	/* current # allocated inodes */
+	time_t dqb_btime;		/* time limit for excessive disk use */
+	time_t dqb_itime;		/* time limit for excessive files */
+} v1_kern_dqblk_t;
+
+/* struct for Q_V2_GETQUOTA */
+typedef u_int64_t qsize_t;
+typedef struct v2_kern_dqblk {
+	unsigned int dqb_ihardlimit;
+	unsigned int dqb_isoftlimit;
+	unsigned int dqb_curinodes;
+	unsigned int dqb_bhardlimit;
+	unsigned int dqb_bsoftlimit;
+	qsize_t dqb_curspace;
+	time_t dqb_btime;
+	time_t dqb_itime;
+} v2_kern_dqblk_t;
+
+/* struct for Q_XGETQUOTA */
+typedef struct fs_disk_quota {
+	__s8 d_version;		/* version of this structure */
+	__s8 d_flags;		/* XFS_{USER,PROJ,GROUP}_QUOTA */
+	__u16 d_fieldmask;	/* field specifier */
+	__u32 d_id;		/* user, project, or group ID */
+	__u64 d_blk_hardlimit;	/* absolute limit on disk blks */
+	__u64 d_blk_softlimit;	/* preferred limit on disk blks */
+	__u64 d_ino_hardlimit;	/* maximum # allocated inodes */
+	__u64 d_ino_softlimit;	/* preferred inode limit */
+	__u64 d_bcount;		/* # disk blocks owned by the user */
+	__u64 d_icount;		/* # inodes owned by the user */
+	__s32 d_itimer;		/* zero if within inode limits */
+	__s32 d_btimer;		/* similar to above; for disk blocks */
+	__u16 d_iwarns;		/* # warnings issued wrt num inodes */
+	__u16 d_bwarns;		/* # warnings issued wrt disk blocks */
+	__s32 d_padding2;	/* padding2 - for future use */
+	__u64 d_rtb_hardlimit;	/* absolute limit on realtime blks */
+	__u64 d_rtb_softlimit;	/* preferred limit on RT disk blks */
+	__u64 d_rtbcount;	/* # realtime blocks owned */
+	__s32 d_rtbtimer;	/* similar to above; for RT disk blks */
+	__u16 d_rtbwarns;	/* # warnings issued wrt RT disk blks */
+	__s16 d_padding3;	/* padding3 - for future use */
+	char d_padding4[8];	/* yet more padding */
+} fs_disk_quota_t;
+
+#endif	/* LINUX */


More information about the samba-technical mailing list