{"action":"created","comment":{"url":"https://api.github.com/repos/docker/docker/pulls/comments/79534174","id":79534174,"diff_hunk":"@@ -0,0 +1,292 @@\n+// +build linux\n+\n+//\n+// projectquota.go - implements XFS project quota controls\n+// for setting quota limits on a newly created directory.\n+// It currently supports the legacy XFS specific ioctls.\n+//\n+// TODO: use generic quota control ioctl FS_IOC_FS{GET,SET}XATTR\n+//       for both xfs/ext4 for kernel version >= v4.5\n+//\n+\n+package graphdriver\n+\n+/*\n+#include <stdlib.h>\n+#include <dirent.h>\n+#include <linux/fs.h>\n+#include <linux/quota.h>\n+#include <linux/dqblk_xfs.h>\n+struct fsxattr {\n+\t__u32\t\tfsx_xflags;\n+\t__u32\t\tfsx_extsize;\n+\t__u32\t\tfsx_nextents;\n+\t__u32\t\tfsx_projid;\n+\tunsigned char\tfsx_pad[12];\n+};\n+#define FS_XFLAG_PROJINHERIT\t0x00000200\n+#define FS_IOC_FSGETXATTR\t\t_IOR ('X', 31, struct fsxattr)\n+#define FS_IOC_FSSETXATTR\t\t_IOW ('X', 32, struct fsxattr)\n+\n+#define PRJQUOTA\t2\n+#define XFS_PROJ_QUOTA\t2\n+#define Q_XSETPQLIM QCMD(Q_XSETQLIM, PRJQUOTA)\n+#define Q_XGETPQUOTA QCMD(Q_XGETQUOTA, PRJQUOTA)\n+*/\n+import \"C\"\n+import (\n+\t\"fmt\"\n+\t\"io/ioutil\"\n+\t\"os\"\n+\t\"path\"\n+\t\"path/filepath\"\n+\t\"syscall\"\n+\t\"unsafe\"\n+\n+\t\"github.com/Sirupsen/logrus\"\n+)\n+\n+// Quota limit params - currently we only control blocks hard limit\n+type Quota struct {\n+\tSize uint64\n+}\n+\n+// QuotaCtl - Context to be used by storage driver (e.g. overlay)\n+// who wants to apply project quotas to container dirs\n+type QuotaCtl struct {\n+\tbackingFsDev  string\n+\tnextProjectID uint32\n+\tquotas        map[string]uint32\n+}\n+\n+// NewQuotaCtl - initialize project quota support by finding the first project id\n+// to be used for the next container create\n+func NewQuotaCtl(basePath string) (*QuotaCtl, error) {\n+\t//\n+\t// get max project id for next use\n+\t//\n+\tmaxProjectID, err := getMaxProjectID(basePath)","path":"daemon/graphdriver/projectquota.go","position":68,"original_position":68,"commit_id":"b18464e8e4e92df30216dcb9e08a97a210f77320","original_commit_id":"b18464e8e4e92df30216dcb9e08a97a210f77320","user":{"login":"amir73il","id":453028,"avatar_url":"https://avatars.githubusercontent.com/u/453028?v=3","gravatar_id":"","url":"https://api.github.com/users/amir73il","html_url":"https://github.com/amir73il","followers_url":"https://api.github.com/users/amir73il/followers","following_url":"https://api.github.com/users/amir73il/following{/other_user}","gists_url":"https://api.github.com/users/amir73il/gists{/gist_id}","starred_url":"https://api.github.com/users/amir73il/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/amir73il/subscriptions","organizations_url":"https://api.github.com/users/amir73il/orgs","repos_url":"https://api.github.com/users/amir73il/repos","events_url":"https://api.github.com/users/amir73il/events{/privacy}","received_events_url":"https://api.github.com/users/amir73il/received_events","type":"User","site_admin":false},"body":"We do not get to directory scanning, because the first thing that getMaxProjectID() does is get the project id of the home directory. This test will fail if no pquota support.\r\nIf pquota is supported and home directory does not have a project id the check will succeed and return value of 0.\r\nThere is also a 'hidden' feature here - project quota can be used to set a quota limit (using xfs_quota tool) on the entire storage driver directory (/var/lib/docker/overlay2), to set it apart from the rest of the system. In that case, the root project id will be used as a \"start offset\" (e.g. echo docker:999 > /etc/projid) and all containers will be assigned project ids > 1000.\r\nThis is a way to prevent xfs_quota management from conflicting with docker.\r\nI did not document this feature because I did not want to complicate. It can be documented later on in advanced documentation.","created_at":"2016-09-20T04:21:57Z","updated_at":"2016-09-20T04:21:57Z","html_url":"https://github.com/docker/docker/pull/24771#discussion_r79534174","pull_request_url":"https://api.github.com/repos/docker/docker/pulls/24771","_links":{"self":{"href":"https://api.github.com/repos/docker/docker/pulls/comments/79534174"},"html":{"href":"https://github.com/docker/docker/pull/24771#discussion_r79534174"},"pull_request":{"href":"https://api.github.com/repos/docker/docker/pulls/24771"}}},"pull_request":{"url":"https://api.github.com/repos/docker/docker/pulls/24771","id":77869391,"html_url":"https://github.com/docker/docker/pull/24771","diff_url":"https://github.com/docker/docker/pull/24771.diff","patch_url":"https://github.com/docker/docker/pull/24771.patch","issue_url":"https://api.github.com/repos/docker/docker/issues/24771","number":24771,"state":"open","locked":false,"title":"Implement XFS quota for overlay2","user":{"login":"amir73il","id":453028,"avatar_url":"https://avatars.githubusercontent.com/u/453028?v=3","gravatar_id":"","url":"https://api.github.com/users/amir73il","html_url":"https://github.com/amir73il","followers_url":"https://api.github.com/users/amir73il/followers","following_url":"https://api.github.com/users/amir73il/following{/other_user}","gists_url":"https://api.github.com/users/amir73il/gists{/gist_id}","starred_url":"https://api.github.com/users/amir73il/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/amir73il/subscriptions","organizations_url":"https://api.github.com/users/amir73il/orgs","repos_url":"https://api.github.com/users/amir73il/repos","events_url":"https://api.github.com/users/amir73il/events{/privacy}","received_events_url":"https://api.github.com/users/amir73il/received_events","type":"User","site_admin":false},"body":"<!--\r\nPlease make sure you've read and understood our contributing guidelines;\r\nhttps://github.com/docker/docker/blob/master/CONTRIBUTING.md\r\n\r\n** Make sure all your commits include a signature generated with `git commit -s` **\r\n\r\nFor additional information on our contributing process, read our contributing\r\nguide https://docs.docker.com/opensource/code/\r\n\r\nIf this is a bug fix, make sure your description includes \"fixes #xxxx\", or\r\n\"closes #xxxx\"\r\n\r\nPlease provide the following information:\r\n-->\r\n\r\n**- What I did**\r\n\r\nEverybody wants to set disk quota limits on their containers.\r\nDevicemapper got support for --storage-opt size, then zfs\r\nand btrfs.\r\n\r\nThis pull request adds support for --storage-opt size to overlay2.\r\n\r\nThe semantics of the size parameter are slightly different then those of devmapper/zfs/btrfs.\r\nFor the latter, it means total size limit of composite base image + diff.\r\nFor overlay, it means size limit for the diff directory.\r\nI chose to use the same parameter to simplify things a bit.\r\n\r\n**- How I did it**\r\n\r\nThe overlay2 driver (just as well as overlay and aufs) uses directories\r\nto store the file differences from base image.\r\nXFS supports the project quotas feature, which allows setting a disk quota\r\nfor a sub directory and its descendants when the directory is created.\r\nThe --storage-opt size option to overlay2 utilizes XFS project quotas to\r\nset a hard limit on the disk usage of a container directory.\r\nThe option is therefore applicable only when backing fs is xfs and\r\nonly when it was mounted with the 'pquota' mount option to enable\r\nproject quota support. \r\n\r\n**Why only overlay2?**\r\nSame support could be added to aufs, but it seems to belong to the past,\r\nso I left it there.\r\noverlay (1) cannot use project quotas, because hardlinks are not allowed across\r\ndirectories that are assigned to different project quotas.\r\n\r\n**Why only xfs?**\r\nXFS has had project quotas for a long time. Ext4 is gained project quota support\r\nin kernel v4.5 and the quota control API has been generalized to fit\r\nboth XFS and Ext4.\r\nWhen these kernels get to distributions, the specific XFS project quota code can\r\nbe amended to serve overlay2 over both xfs and ext4 backing fs.\r\n\r\n**Known issues**\r\n- Driver ignores the /etc/projid configuration file, so it does not coordinate container project id's with the xfs_quota tool.\r\n- Project quota entries are not cleared when container is removed.\r\n\r\n**- How to verify it**\r\n\r\n<pre>\r\n# grep xfs /etc/fstab\r\n/dev/mapper/test-xfs /var/lib/docker xfs pquota 0 0\r\n\r\n# mount | grep xfs\r\n/dev/mapper/test-xfs on /var/lib/docker type xfs (rw,relatime,attr2,inode64,prjquota)\r\n\r\n# dockerd --storage-driver=overlay2 -D&\r\n# docker run --storage-opt size=5g -t -i ubuntu /bin/bash\r\n...\r\nroot@3812172791eb:/# df -h .\r\nFilesystem      Size  Used Avail Use% Mounted on\r\noverlay         5.0G   12K  5.0G   1% /\r\n</pre>\r\n \r\n**- Description for the changelog**\r\n<!--\r\nWrite a short (one line) summary that describes the changes in this\r\npull request for inclusion in the changelog:\r\n-->\r\nAdds support for --storage-opt size to overlay2 over xfs.\r\n\r\n\r\n**- A picture of a cute animal (not mandatory but encouraged)**\r\n![cutebunny](https://cloud.githubusercontent.com/assets/453028/16928038/371a360a-4d39-11e6-97ea-dcd3ebbd2361.jpg)\r\n\r\n","created_at":"2016-07-18T20:00:55Z","updated_at":"2016-09-20T04:21:57Z","closed_at":null,"merged_at":null,"merge_commit_sha":"801cb1c1c5a550187d029aedfe9ad6a97a9fb24e","assignee":{"login":"crosbymichael","id":749551,"avatar_url":"https://avatars.githubusercontent.com/u/749551?v=3","gravatar_id":"","url":"https://api.github.com/users/crosbymichael","html_url":"https://github.com/crosbymichael","followers_url":"https://api.github.com/users/crosbymichael/followers","following_url":"https://api.github.com/users/crosbymichael/following{/other_user}","gists_url":"https://api.github.com/users/crosbymichael/gists{/gist_id}","starred_url":"https://api.github.com/users/crosbymichael/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/crosbymichael/subscriptions","organizations_url":"https://api.github.com/users/crosbymichael/orgs","repos_url":"https://api.github.com/users/crosbymichael/repos","events_url":"https://api.github.com/users/crosbymichael/events{/privacy}","received_events_url":"https://api.github.com/users/crosbymichael/received_events","type":"User","site_admin":false},"assignees":[{"login":"crosbymichael","id":749551,"avatar_url":"https://avatars.githubusercontent.com/u/749551?v=3","gravatar_id":"","url":"https://api.github.com/users/crosbymichael","html_url":"https://github.com/crosbymichael","followers_url":"https://api.github.com/users/crosbymichael/followers","following_url":"https://api.github.com/users/crosbymichael/following{/other_user}","gists_url":"https://api.github.com/users/crosbymichael/gists{/gist_id}","starred_url":"https://api.github.com/users/crosbymichael/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/crosbymichael/subscriptions","organizations_url":"https://api.github.com/users/crosbymichael/orgs","repos_url":"https://api.github.com/users/crosbymichael/repos","events_url":"https://api.github.com/users/crosbymichael/events{/privacy}","received_events_url":"https://api.github.com/users/crosbymichael/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/docker/docker/pulls/24771/commits","review_comments_url":"https://api.github.com/repos/docker/docker/pulls/24771/comments","review_comment_url":"https://api.github.com/repos/docker/docker/pulls/comments{/number}","comments_url":"https://api.github.com/repos/docker/docker/issues/24771/comments","statuses_url":"https://api.github.com/repos/docker/docker/statuses/b18464e8e4e92df30216dcb9e08a97a210f77320","head":{"label":"aquasecurity:xfs_quota","ref":"xfs_quota","sha":"b18464e8e4e92df30216dcb9e08a97a210f77320","user":{"login":"aquasecurity","id":12783832,"avatar_url":"https://avatars.githubusercontent.com/u/12783832?v=3","gravatar_id":"","url":"https://api.github.com/users/aquasecurity","html_url":"https://github.com/aquasecurity","followers_url":"https://api.github.com/users/aquasecurity/followers","following_url":"https://api.github.com/users/aquasecurity/following{/other_user}","gists_url":"https://api.github.com/users/aquasecurity/gists{/gist_id}","starred_url":"https://api.github.com/users/aquasecurity/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aquasecurity/subscriptions","organizations_url":"https://api.github.com/users/aquasecurity/orgs","repos_url":"https://api.github.com/users/aquasecurity/repos","events_url":"https://api.github.com/users/aquasecurity/events{/privacy}","received_events_url":"https://api.github.com/users/aquasecurity/received_events","type":"Organization","site_admin":false},"repo":{"id":61470833,"name":"docker","full_name":"aquasecurity/docker","owner":{"login":"aquasecurity","id":12783832,"avatar_url":"https://avatars.githubusercontent.com/u/12783832?v=3","gravatar_id":"","url":"https://api.github.com/users/aquasecurity","html_url":"https://github.com/aquasecurity","followers_url":"https://api.github.com/users/aquasecurity/followers","following_url":"https://api.github.com/users/aquasecurity/following{/other_user}","gists_url":"https://api.github.com/users/aquasecurity/gists{/gist_id}","starred_url":"https://api.github.com/users/aquasecurity/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aquasecurity/subscriptions","organizations_url":"https://api.github.com/users/aquasecurity/orgs","repos_url":"https://api.github.com/users/aquasecurity/repos","events_url":"https://api.github.com/users/aquasecurity/events{/privacy}","received_events_url":"https://api.github.com/users/aquasecurity/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/aquasecurity/docker","description":"Docker - the open-source application container engine","fork":true,"url":"https://api.github.com/repos/aquasecurity/docker","forks_url":"https://api.github.com/repos/aquasecurity/docker/forks","keys_url":"https://api.github.com/repos/aquasecurity/docker/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aquasecurity/docker/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aquasecurity/docker/teams","hooks_url":"https://api.github.com/repos/aquasecurity/docker/hooks","issue_events_url":"https://api.github.com/repos/aquasecurity/docker/issues/events{/number}","events_url":"https://api.github.com/repos/aquasecurity/docker/events","assignees_url":"https://api.github.com/repos/aquasecurity/docker/assignees{/user}","branches_url":"https://api.github.com/repos/aquasecurity/docker/branches{/branch}","tags_url":"https://api.github.com/repos/aquasecurity/docker/tags","blobs_url":"https://api.github.com/repos/aquasecurity/docker/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aquasecurity/docker/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aquasecurity/docker/git/refs{/sha}","trees_url":"https://api.github.com/repos/aquasecurity/docker/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aquasecurity/docker/statuses/{sha}","languages_url":"https://api.github.com/repos/aquasecurity/docker/languages","stargazers_url":"https://api.github.com/repos/aquasecurity/docker/stargazers","contributors_url":"https://api.github.com/repos/aquasecurity/docker/contributors","subscribers_url":"https://api.github.com/repos/aquasecurity/docker/subscribers","subscription_url":"https://api.github.com/repos/aquasecurity/docker/subscription","commits_url":"https://api.github.com/repos/aquasecurity/docker/commits{/sha}","git_commits_url":"https://api.github.com/repos/aquasecurity/docker/git/commits{/sha}","comments_url":"https://api.github.com/repos/aquasecurity/docker/comments{/number}","issue_comment_url":"https://api.github.com/repos/aquasecurity/docker/issues/comments{/number}","contents_url":"https://api.github.com/repos/aquasecurity/docker/contents/{+path}","compare_url":"https://api.github.com/repos/aquasecurity/docker/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aquasecurity/docker/merges","archive_url":"https://api.github.com/repos/aquasecurity/docker/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aquasecurity/docker/downloads","issues_url":"https://api.github.com/repos/aquasecurity/docker/issues{/number}","pulls_url":"https://api.github.com/repos/aquasecurity/docker/pulls{/number}","milestones_url":"https://api.github.com/repos/aquasecurity/docker/milestones{/number}","notifications_url":"https://api.github.com/repos/aquasecurity/docker/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aquasecurity/docker/labels{/name}","releases_url":"https://api.github.com/repos/aquasecurity/docker/releases{/id}","deployments_url":"https://api.github.com/repos/aquasecurity/docker/deployments","created_at":"2016-06-19T08:21:04Z","updated_at":"2016-06-19T08:21:18Z","pushed_at":"2016-09-19T19:10:59Z","git_url":"git://github.com/aquasecurity/docker.git","ssh_url":"git@github.com:aquasecurity/docker.git","clone_url":"https://github.com/aquasecurity/docker.git","svn_url":"https://github.com/aquasecurity/docker","homepage":"http://www.docker.com","size":102641,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"docker:master","ref":"master","sha":"772db11fd0cfdf3c22fb93ba69742e81c4a695bb","user":{"login":"docker","id":5429470,"avatar_url":"https://avatars.githubusercontent.com/u/5429470?v=3","gravatar_id":"","url":"https://api.github.com/users/docker","html_url":"https://github.com/docker","followers_url":"https://api.github.com/users/docker/followers","following_url":"https://api.github.com/users/docker/following{/other_user}","gists_url":"https://api.github.com/users/docker/gists{/gist_id}","starred_url":"https://api.github.com/users/docker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/docker/subscriptions","organizations_url":"https://api.github.com/users/docker/orgs","repos_url":"https://api.github.com/users/docker/repos","events_url":"https://api.github.com/users/docker/events{/privacy}","received_events_url":"https://api.github.com/users/docker/received_events","type":"Organization","site_admin":false},"repo":{"id":7691631,"name":"docker","full_name":"docker/docker","owner":{"login":"docker","id":5429470,"avatar_url":"https://avatars.githubusercontent.com/u/5429470?v=3","gravatar_id":"","url":"https://api.github.com/users/docker","html_url":"https://github.com/docker","followers_url":"https://api.github.com/users/docker/followers","following_url":"https://api.github.com/users/docker/following{/other_user}","gists_url":"https://api.github.com/users/docker/gists{/gist_id}","starred_url":"https://api.github.com/users/docker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/docker/subscriptions","organizations_url":"https://api.github.com/users/docker/orgs","repos_url":"https://api.github.com/users/docker/repos","events_url":"https://api.github.com/users/docker/events{/privacy}","received_events_url":"https://api.github.com/users/docker/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/docker/docker","description":"Docker - the open-source application container engine","fork":false,"url":"https://api.github.com/repos/docker/docker","forks_url":"https://api.github.com/repos/docker/docker/forks","keys_url":"https://api.github.com/repos/docker/docker/keys{/key_id}","collaborators_url":"https://api.github.com/repos/docker/docker/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/docker/docker/teams","hooks_url":"https://api.github.com/repos/docker/docker/hooks","issue_events_url":"https://api.github.com/repos/docker/docker/issues/events{/number}","events_url":"https://api.github.com/repos/docker/docker/events","assignees_url":"https://api.github.com/repos/docker/docker/assignees{/user}","branches_url":"https://api.github.com/repos/docker/docker/branches{/branch}","tags_url":"https://api.github.com/repos/docker/docker/tags","blobs_url":"https://api.github.com/repos/docker/docker/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/docker/docker/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/docker/docker/git/refs{/sha}","trees_url":"https://api.github.com/repos/docker/docker/git/trees{/sha}","statuses_url":"https://api.github.com/repos/docker/docker/statuses/{sha}","languages_url":"https://api.github.com/repos/docker/docker/languages","stargazers_url":"https://api.github.com/repos/docker/docker/stargazers","contributors_url":"https://api.github.com/repos/docker/docker/contributors","subscribers_url":"https://api.github.com/repos/docker/docker/subscribers","subscription_url":"https://api.github.com/repos/docker/docker/subscription","commits_url":"https://api.github.com/repos/docker/docker/commits{/sha}","git_commits_url":"https://api.github.com/repos/docker/docker/git/commits{/sha}","comments_url":"https://api.github.com/repos/docker/docker/comments{/number}","issue_comment_url":"https://api.github.com/repos/docker/docker/issues/comments{/number}","contents_url":"https://api.github.com/repos/docker/docker/contents/{+path}","compare_url":"https://api.github.com/repos/docker/docker/compare/{base}...{head}","merges_url":"https://api.github.com/repos/docker/docker/merges","archive_url":"https://api.github.com/repos/docker/docker/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/docker/docker/downloads","issues_url":"https://api.github.com/repos/docker/docker/issues{/number}","pulls_url":"https://api.github.com/repos/docker/docker/pulls{/number}","milestones_url":"https://api.github.com/repos/docker/docker/milestones{/number}","notifications_url":"https://api.github.com/repos/docker/docker/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/docker/docker/labels{/name}","releases_url":"https://api.github.com/repos/docker/docker/releases{/id}","deployments_url":"https://api.github.com/repos/docker/docker/deployments","created_at":"2013-01-18T18:10:57Z","updated_at":"2016-09-20T03:04:56Z","pushed_at":"2016-09-20T03:29:31Z","git_url":"git://github.com/docker/docker.git","ssh_url":"git@github.com:docker/docker.git","clone_url":"https://github.com/docker/docker.git","svn_url":"https://github.com/docker/docker","homepage":"http://www.docker.com","size":209920,"stargazers_count":35121,"watchers_count":35121,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":10335,"mirror_url":null,"open_issues_count":1974,"forks":10335,"open_issues":1974,"watchers":35121,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/docker/docker/pulls/24771"},"html":{"href":"https://github.com/docker/docker/pull/24771"},"issue":{"href":"https://api.github.com/repos/docker/docker/issues/24771"},"comments":{"href":"https://api.github.com/repos/docker/docker/issues/24771/comments"},"review_comments":{"href":"https://api.github.com/repos/docker/docker/pulls/24771/comments"},"review_comment":{"href":"https://api.github.com/repos/docker/docker/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/docker/docker/pulls/24771/commits"},"statuses":{"href":"https://api.github.com/repos/docker/docker/statuses/b18464e8e4e92df30216dcb9e08a97a210f77320"}}}}
{"actor":{"display_login":"amir73il"}}